Author Topic: Annoying long runtime bug  (Read 2546 times)

0 Members and 1 Guest are viewing this topic.

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14299
  • Country: fr
Re: Annoying long runtime bug
« Reply #25 on: December 02, 2022, 08:15:42 pm »
We own the memory and we think the world shoud know it!
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8110
  • Country: fi
Re: Annoying long runtime bug
« Reply #26 on: December 03, 2022, 08:38:15 am »
Yes.  But you have 6 UARTS and 3 modules using them.  Who owns the memory?

UART module owns internal state - all the weird things you don't want into the interface.

At very least it owns the types. Of course you can wrap it in a struct and make that opaque (or just not care about the contents), in which case the user can own it. But I prefer the state to be allocated in uart.c.

One option for the interface is opaque struct like FILE*, but in simple microcontroller projects I prefer to use an integer index:
int uart_send(int instance, uint8_t const * buf, size_t len);

uart.c does not need to be just a driver layer. You can do "uart related stuff" in it. For example, if your packet format is simply MSGID - LEN - PAYLOAD - CRC, you can process that in the interrupt handler, completely inside uart.c. Then you can register a callback function:
int uart_register(int instance, int msgid, void (*handler)(uint8_t* payload));

One way to call those callback functions is have some kind of
int uart_yield();
which you call regularly. Put the messages to a FIFO in the UART interrupt handler, and pop them in the regularly called function, call the callbacks there.

Or, you can make the UART interrupt handler trigger a software interrupt (with lower priority), going directly into the handler function.
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5835
  • Country: es
Re: Annoying long runtime bug
« Reply #27 on: December 03, 2022, 10:59:12 am »
First of all, are you getting and ignoring any compiler warning?
Happens all the time, people come here ranting, but say nothing about the "integer overflow" or "variable may be undefined" warnings, pretending they didn't happen.
Are you running dynamic alocations at run time? I mean, not only at the system init, but constantly in the runtime, "alloc this buffer, free this buffer...". If so, I hope you're always checking for valid pointer!
Also make sure the reserved stack is properly set by checking the stack analyzer on the IDE, otherwise the stack and heap might crash!

Do you hate state machines? Just do them right. Do you think a million if/else is a better solution?
"switch (state)" make things so much better, but if you overlook something, it'll happen just like any other line of code in any language, you create a bug, not state machine's fault.

Implement a proper crash handler, make variable checks, timeouts everywhere, even if you do "x=1+1", asume nothing, you some memory areas could be overwritten by a wrong pointer, etc.
If anything goes wrong, enter crash handler and debug where it happened, this will greatly ease the error detection.
Did so in the soldering FW as it grew up, catching the bugs had become really hard, made it much easier.

However ST removed the extended error handler, replacing it with one with no arguments. Fix here:
https://community.st.com/s/question/0D50X00009XkffVSAR/stm32cubemx-v421-errorhandler-definition-issues-in-mainh
Add to main.h:
Code: [Select]
#define GET_MACRO( _0, _1, NAME, ... ) NAME
#define Error_Handler(...) GET_MACRO( _0, ##__VA_ARGS__, Error_Handler1, Error_Handler0 )()
#define Error_Handler0() _Error_Handler( __FILE__, __LINE__ )
#define Error_Handler1(unused) _Error_Handler( char * file, int line )
void _Error_Handler(char *, int);

Then simply call "Error_Handler()" when something goes wrong, it will be "translated" by the macros as "Error_Handler( __FILE__, __LINE__ )"

The error handler is placed at the end of main.c:
Code: [Select]
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* USER CODE END Error_Handler_Debug */
}

The macros will silently modify it to:
Code: [Select]
void Error_Handler( char * file, int line );
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* USER CODE END Error_Handler_Debug */
}

So you can report the crash somehow:
Code: [Select]
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */

  printf("\n\n    SYSTEM CRASH!\n\n    FILE: %s\n   LINE: %d\n", file, line);
  while(1);
)
  /* USER CODE END Error_Handler_Debug */
}

The output will be something like:
Code: [Select]
    SYSTEM CRASH!

    FILE: /core/src/some_file.c
    LINE: 137

You could modify it to add further debug information, like passing variable names, values...
Having the file and line is already a great start point to look for the issue.
« Last Edit: December 03, 2022, 11:17:44 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf