I have an STM32F205 processor in a battery backed up circuit. The battery is normally non connected, it can be connected via switch or GPIO. The problem is that if the IWD (Independent Watch Dog) fires whilst the system is running on battery, the GPIO goes low, the battery gets disconnected and the system turns off.
So, I'd like a soft reset, leave the GPIO high, but reset everything else. The IWG will fire after 16 seconds, I've setup a standard timer to run for 15 seconds, both get reset by the standard WD kick. This all works fine, But I now need the timer ISR to do this software reset.
I've tried duplicating the standard 'Reset_Handler' as 'SoftReset_Handler', adding SP init at start. This works ok, runs through SystemInit, runs through main(). Then it encounters os_sys_init_user() that calls os_set_env() all registers and all values in os_set_env() are the same between hard and soft reset with hard, BX LR ends up in SVC_Handler with soft, BX LR ends up in HardFaultHandler
Within the ISR, I've disabled all interrupts in NVIC and cleared all pending interrupts in NVIC.
Because I'm kicking this off from ISR, I'm in 'Handler' Mode instead of 'Thread' Mode, but this is the only difference I can see, other than doing something horrible like putting address of SoftResetHandler on stack and returning, I can't find a way of changing this.
Any ideas?
Does it?
Surely, the default state of a GPIO at reset is that it's an input or high-impedance?
This is really something which should be accounted for in the hardware design - rather than bodged in software ... ?
Any constructive ideas?
1) call
NVIC_SystemReset()
to do a software reset of the processor.
Yes, that resets the whole chip, including the GPIO, as soon as you do that, the pin goes to input, the line goes low, the battery turns off, the system shuts down. I need a softer reset, keep the GPIOs in their current state but reset everything else.
Firstly, the software should never have to reset, so this should never get called. Secondly, if it ever does reset, whilst on mains power a standard full reset is ok. So, we are talking about a condition that should never occur, but it still needs to be handled.
Using our own OS with simpler processor this was relatively easy. Using RTX and STM32F205, the OS and the security / complexity of the Controller make it impossible from my current viewpoint.
So, I'm stuck and asking for ideas as I think I've run out.
"as soon as you do that, the pin goes to input, the line goes low"
The line going low is a result of your hardware design.
You could add a pullup if you want it to be high.
In normal use, it's not supposed to be high, it actually has a pull down on it because the system should not run up when you connect the battery. I have considered adding a capacitor so that it delays the turn off for long enough purely for this condition through a reset, but the project is too late for hardware changes at this stage.
Hmm - that is a pickle, then.
Sorry, don't know what else to suggest - you are fighting the hardware.
:(
Here is the "Secret Sauce" (I am not suggesting that it is a good idea to do this, but I have done much worse.)
__asm void _SoftwareReset(uint32_t VectorBaseAddress) { LDR R4,[R0] ; R4 is the Reset Stack Pointer LDR R5,[R0,#4] ; R5 is the Reset Program Counter MOV R0,#0 ; MOV R6, #0x01000000 ; xSPR Just thumb mode set STMDB R4!, {R5,R6} ; push xSPR and PC MOV R1, R0 MOV R2, R0 MOV R3, R0 STMDB R4!, {R0-R3} ; STMDB R4!, {R0,R1} ; Push 6 "0"'s. Restore R0-R4,R12,LR to 0 MOV SP, R4 ; Starting Stack Pointer -32. ; Will Be Start Stack Pointer after RTI MVN LR, #:NOT:0xFFFFFFF9; // Return to Thread mode using MSP BX LR ; Now do it }
Call this from your "Terminal" Handler as when this is done, you will be at Running the Reset Handler In Thread Mode with the Stack pointer equal to the VectorBase address 0 value. The state of the devices when you call this routine will still be intact.You probably want to disable as many as you can, maybe even just leaving the 1 GPIO port that you still need.
Before you call this, you should disable all interrupts and clear pending interrupts.
Turn off the SysTick and and Running Timers. They will get re enabled after reset.
You can put different values for the Saved R0-R3,R12,LR and use these to indicate that it is a software reset.
; You may want to add something like this at the start of the Reset Handler LDR R4,=WasSoftwareReset LDR R4,[R4] STR R0,[R4] ; Store Startup R0 in Global WasSoftwareReset variable. will be 0 if not your routine What ever you set it too if it was