2019-03-08 02:16 AM
I have FreeRTOS set up on an STM32F107 performing several tasks of different priority in "parallell".
There is one task of IDLE priority that blinks an LED and one task of Normal priority that receives communication over CAN (triggered by external interrupts). There are also some tasks that reads values off the ADC and uses DMA.
There is also a bootloader in place that can receive new firmware via CAN.
When the MCU is powered it starts in the bootloader, and a custom CAN message kicks it to the application, and everything works fine. The application can receive messages from CAN, blink the LED and execute calculations just fine.
Another custom message can bring it from the application back to the bootloader (via a call to NVIC_SystemReset()), which works. But it is when attempting to bring the MCU back to the application (after NVIC reset) that things start to behave weirdly:
Sometimes, roughly ~60% of the time, the MCU seems to not enable interrupts. The LED blinks just fine (indicating the RTOS is still running its most low-priority task) but the application is not responding to CAN messages. Which to me indicates that interrupts have not been set up correctly.
I have tried putting LED indications on hardware fault handlers and failure to initialize CAN without any success, so I am not sure what the MCU is doing.
I also tried disabling IRQ and all system clocks before calling the NVIC reset without any luck.
Do you have any ideas on how to troubleshoot this further?
Is there any recommended procedure to perform before calling NVIC_SystemReset?
Thanks in advance!
BR,
David
2019-03-12 08:48 AM
Hi David,
The size of the RAM for the STM32F107 is 0x10000 (64K).
So, try using this command:
memset( (uint8_t *) 0x20000000, 0, 0x10000 );
Best Regards,
Alexey
2019-03-13 07:11 AM
Hi Alexey,
Thanks for that, I tried that but the processor still halts before getting to NVIC_Reset() which is the next line.
I guess one thing that could be tried would be to split it up in multiple calls, if there is a restriction on how much memory you can overwrite? I.e. perhaps some counter used by memset can not handle as "high" value as 65535 (0x10000) and gets overflowed?
BR,
David
2019-03-13 07:38 AM
Hi Piranha,
Thank you for your reply and the links to your suggestions.
Our bootloader is written by a third party, so I can not comment exactly on how it jumps to the application.
But from initial inspection it works by changes the vector table with an offset (that matches where the application starts) and then calls the reset isr.
It feels like the jumping procedure in general works, and is reliable. Just that I am missing something that i should be doing before calling NVIC_SystemReset() when going from application to bootloader. Is there any such recommended procedure? For example: always disable interrupts before calling NVIC_SystemReset, or something similar?
BR,
David
2019-03-13 07:54 AM
Goodness gracious NO! Calling memset() to clear ALL of RAM will overwrite your stack. Which means the return from the memset() call will go where??? probably to address zero, which if you haven't changed the memory mapping is the value of the initial stack pointer from the interrupt vector table. Likely not a valid instruction. Nor is the reset vector that follows.
Presuming both your bootloader and main app use the normal "C" startup code, the startup code (that runs before calling your main() function) initializes the RAM areas that the compiler knows about - that is, variables in RAM that are initialized (set to their initial values) and those that are not initialized (set to zero). The only "uninitialized" RAM is areas that the compiler doesn't think you are using.
Does it ALWAYS work when you power on, enter bootloader, get CAN message to run the app and then run the app? Many many many times in a row?
Do you have any external devices that the CPU communicates with that may not be getting fully re-initialized after the soft reboot?
Does the bootloader disable the CAN interface before running the main app? Does the main app re-initialize the CAN interface or does it expect it to be already configured by the bootloader? Does your main app re-initialize the clock tree? Is the CAN port actually running at the correct baud rate (you will probably have to put a scope on the serial lines and look at any data the CPU may transmit, and you may have to force the CPU to transmit something so you can see it).
2019-03-13 08:14 AM
Hi Bob,
Why do you need the stack if the next command is a reset?
Probably clear the memory can be applied using the for a loop.
Best Regards,
Alexey
2019-03-13 08:28 AM
Hi Bob,
Thanks for the answer! Yes, it does indeed ALWAYS work when I start from a powered down state, enter bootloader, get a CAN message to run the app. Then I can always get more CAN messages and do different things and interact with peripherals.
There are external devices, but these are managed on other tasks, which are not blocking anything (they should be stopped when an interrupt comes for the CAN message anyways). So I really think it is software related.
I am in conversation with the guy who wrote the bootloader, so I can not answer directly if it de-activates CAN or not (I will add this information as soon as I have it). But I definitely initialize it when the app is starting up, and I have an assertion of the CAN initialization which lights a Blue LED if it went OK (according to HAL) and Red if it fails. When running the test case it lights blue, both when application is started for the first time, and for the second time after switching to bootloader first. This shows me that CAN has been properly initialized (at least from the HAL drivers point of view).
I also had a look with an oscilloscope at the bits on the wire from the CAN hardware driver chip to the STM32 RX pin and they look OK, and still no interrupt is generated on the MCU.
Please let me know what you think.
Best Regards,
David
2019-03-13 08:58 AM
Hi David,
I have tried this code:
uint32_t* pointer = (uint32_t*)0x20000000;
for ( uint32_t index = 0; index < 0x4000; index++ )
pointer[index] = 0;
NVIC_SystemReset();
This code restart the CPU after cleaning the RAM.
Best Regards,
Alexey
2019-03-13 09:18 AM
Probably trashing the stack in the process. If I were clearing all memory, I'd likely do it in Reset_Handler, in assembler, before the interrupts are up, and without calling any subroutines or dependencies.
>>What pin do you mean exactly?
Like other ICs or FPGA, driving a High level on the pins and preventing the device resetting properly. The NVIC_SystemReset should be effective at restarting the CPU with a defined pulse width.
2019-03-13 09:20 AM
Depends on the memset() implementation and whether is pushs registers and return address on the stack.
One might want to have helpful code in the HardFault Handler to determine if it cratered there.
2019-03-13 09:31 AM
Hi Clive,
You are rigth.
But it too complicated to do it in the Reset_Handler.
This is just a try, if it helps, good, if not, next solution.
Best Regards,
Alxey