NVIC_SystemReset() stuck in while loop (STM32F302VB) - arm

I'm currently developing on a STM32F302VB and I need to perform a software reset. On all my previous projects (with STM32F427 and STM32F030C8), I've always used the NVIC_SystemReset() function successfully. But for some reason it won't work with this chip.
The implementation is in CMSIS core_cm4.h and is as follows:
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}
The function is called and all instructions are executed, but it gets stuck in the while loop, and reset never happens. I then have to reset it via JTAG to get it out of that state.
I checked the programming manual and the implementation seems fine (not surprising since it works perfectly on F4 and F0).
I really don't know what the problem might be, does someone have an idea what's going on?
Edit: The function is still not working but as a workaround, after the function gets stuck, I pull down the nRST pin and then up. It's ugly, but it works for now. I would rather do it all in software though.

Tony K was right in his comment, the nRST pin was indeed being pulled high externally, because of a routing mistake.
And contrary to what I thought, the nRST pin is taken into account even in a software reset: the reference manual says: "[Reset] sources act on the NRST pin and it is always kept low during the delay phase", so I should have known!
Removing the pull-up did the trick, the NVIC_SystemReset() function now works as expected!
Thank you very much!

Related

SysTick interrupt does not fire if GDB attached before it is enabled

I have an ATSAMD21E18A micro that I am using with semi-hosting. In order for the semi-hosting to work, GDB needs to be "attached" before the first bkpt instruction. On the other hand, I have inexplicably found that the SysTick interrupt will not fire if GDB was already attached when I configured it. If I want to the SysTick interrupt to fire, I have to perform a reset (power-off via a button) and tell GDB to continue when it hasn't yet configured the micro (that is, it hasn't sent breakpoints over or anything else), and then hit Ctrl-C to initialize debugging mode after the SysTick configuration but before we get to initialise_monitor_handles.
I have verified that the start function is only copying over the relocatable data segment, zeroing the zero segment, and setting the right initial stack pointer value. We are writing our code without libraries like CMSIS.
Also I can confirm that I have no issues when the debugger is not attached (JLinkGDBServer through an Atmel SAM-ICE), besides needing to remove the semi-hosting stuff.
Also, the SysTick COUNT does still correctly count even when the interrupts themselves don't fire. Also the SysTick pending interrupt bit PENDSTSET in ICSR, is in fact set when this happens.
My code follows:
int main()
{
// enable system timer interrupt
SYS_TICK->STATUS = 0; // (CSR)
SYS_TICK->PERIOD = 48000; // (RVR) fire at 1khz for 48mhz clock
SYS_TICK->STATUS = 0b111; // use processor clock, w/ interrupt, and enabled
SYS_TICK->COUNT = 1; // (CVR) avoid high unknown value
// dumb busy loop
util_idle_ms(2000); // <<< I hit Ctrl-C to break here!
initialise_monitor_handles();
// ... more system initialization and everything else
}
I have seen some similar seeming questions here on StackOverflow, but they seemed to be too vague to get good answers.
Edit:
Here are possibly relevant register values taken during the busy loop for the run that doesn't call the SysTick handler (no hard reset, GDB attached before SysTick configured):
SYS_TICK_CSR/STATUS: 0x10007
SYS_TICK_RVR/PERIOD: 48000
SYS_TICK_CVR/COUNT: 5245 (varies of course)
NVC_ISER: 0 (and we expect this since SysTick is considered an exception, and not an interrupt)
DHCSR: 0x30003/0x1030003 (C_MASKINTS is not set; I've seen both values show up)
ICSR: 0x400f00f (it really wants to run the SysTick handler)
PRIMASK: 0
xPSR: 0x2100000f (IPSR is 0x0f/SysTick)
And for the run that calls the SysTick handler just fine (hard reset with GDB attaching after SysTick configuration):
SYS_TICK_CSR/STATUS: 0x10007
SYS_TICK_RVR/PERIOD: 48000
SYS_TICK_CVR/COUNT: 16892 (varies of course)
NVC_ISER: 0
DHCSR: 0x10003/0x1030003 (I've seen both values show up)
ICSR: 0 (SysTick handler already run)
PRIMASK: 0
xPSR: 0x2100000f
So the register values here do not yet seem to reveal anything new to me... Please help inform me of other potentially relevant registers to check!
Just for interest, the reason this is important to me is because I have gotten gprof to work on this chip, based on https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/
And although I do have to hit Ctrl-C at just the right time after a hard reset, it does work like this!
Edit
I have found that I had a misunderstanding where I thought running load in GDB performed a soft reset. I have since found that although it returns execution to reset vector, various peripherals and other registers are not in fact reset. If I perform a soft reset in GDB with monitor reset then I don't need to Ctrl-C during a delay to attach GDB and both SysTick and SemiHosting will work.
The problem occurs when SysTick is configured and then load is run in GDB, without an explicit hard or soft reset. In this case, SysTick does not fire interrupts. Most of my debugging went like this, loading new code and immediately expecting it to work so I could evaluate it. Just running monitor reset is a better workaround than before, but I still would prefer to know the reason for SysTick's misbehavior!
I would visit the ARMĀ® v6-M Architecture Reference Manual and see if you can get some direction from that. https://static.docs.arm.com/ddi0419/d/DDI0419D_armv6m_arm.pdf
Observe that state of the registers related to the Systick that you didn't include in your question. If you can't figure out the problem based on those registers, edit your question and post the register values here (the NVIC ISER, all registers related to systick config, the DHCSR, and any others you think are related). They will be the key to getting more feedback.
The Debug Halting Control and Status Register (DHCSR) has the ability to mask interrupts including the systick. Maybe this is being set by the debugger?
bit 3 of the DHCSR looks relevant
I would also check that the SYST_RVR (Systick reload value register) is being set to something sane.
I don't have the rep to comment on your question, but I'm hoping this can get you going in a productive direction :)

PIC32 WDT reset not working on some PIC32

I have a PIC32 reset function:
void reset_cpu(void)
{
WDTCON=0x8000;
EnableWDT(); // enable the WDT
ClearWDT();
while(1){};
}
It works on a PIC32MX360F512L but not on a PIC32MX695F512L. It just spins forever. Can anyone tell me why, or suggest another way to reset my processor?
If you are using plib.h, you can simply call this function:
void reset_cpu(void)
{
SoftReset();
while(1){};
}
This has the advantage to trigger an instant reset. From reset.h:
How it works: The following steps are performed by this function:
Step 1 - Execute "unlock" sequence to access the RSWRST register.
Step 2 - Write a '1' to RSWRST.SWRST bit to arm the software reset.
Step 3 - A Read of the RSWRST register must follow the write. This action triggers the software reset, which should occur on the next
clock cycle.
Bear in mind plib is obsolete and will soon be removed from MPLAB XC32. Worth considering Harmony for new designs: http://www.microchip.com/mplabharmony
Nothing immediately stands out to me when looking at the datasheets for both of the microcontrollers. However, I do have a couple of suggestions.
First, in your function you are doing the following:
WDTCON=0x8000;
EnableWDT();
If you look at plib.h you will see that it refers to wdt.h. In wdt.h you can see that EnableWDT() is simply a macro that expands to the following:
WDTCONSET = _WDTCON_WDTCLR_MASK
Where the mask is 0x00008000. Basically, you are performing the same operation twice. Just let the macro take care of enabling it.
Also, since you are using the watchdog to reset your device, there is no need to clear the watchdog. ClearWDT() just resets the watchdog and makes your while(1) loop run longer. So, I would write your function like this:
void reset_cpu(void)
{
EnableWDT();
while(1){};
}
Finally, I would recommend taking a look to ensure that you have the correct processor selected in your IDE. I am not certain that this would cause your problem, but if you had the PIC32MX360F512L selected and tried running it on the PIC32MX695F512L, you could end up with the wrong register definitions (assuming that you are using #include "xc.h").
I would also check on how you are setting your device configuration bits. It is possible to set a very long timeout on the watchdog.

Watchdog configuration on Stellaris Launchpad LM4F120

I try to configure the watchdog timer on Stellaris Launchpad LM4F120.
The code is the following:
void configure_watchdog(void) {
SYSCTL_RCGCWD_R = 0x1; /* Enabling Clock for WD0 */
WATCHDOG0_LOAD_R = 0xffffffff; /* Setting initial value */
WATCHDOG0_CTL_R = WDT_CTL_INTEN; /* Enabling interrupt generation */
}
This supposed to be enough in accordance to the datasheet.
The problem is that controller always falls to FaultISR and resets after it. I can't understand why.
What am I doing wrong?
EDIT: The controller does not reset. It just goes to FaultISR
Jumping to an ISR when the watchdog expires sounds like the correct behavior. What exactly are you doing inside your ISR code? If you are resetting the watchdog inside the ISR, then you shouldn't be seeing the microcontroller reset itself (based on your posted configuration code, at least). After you set up the watchdog, read the configuration register back out and make sure that it holds the value that you expect. Some of the bits in that register can only be set under certain circumstances, and it's possible that you're not running with the settings that you think you're using.
You mentioned that you were trying to use the watchdog timer as a generic downcounter. Could you use one of the general-purpose timers instead of the watchdog? You would still get an interrupt when time expired, but regular timers don't have the ability to reset the entire system.
You have to keep servicing the watchdog, otherwise it times out and calls whatever is setup for that exception. FaultISR would appear to be that in your case.
If you want the watchdog to do something else on the timeout you need to figure out how your particular toolchain connects functions to exception sources and map your new function correctly.
If you don't want the watchdog to expire (which is usually what it's there for, to catch errant code) then you need to service it regularly. The compiler vendor often provides a function or intrinsic to do this.

Struggling to implement tickless support for FreeRTOS on an xmega256a3

I'm struggling to get tickless support working for our xmega256a3 port of FreeRTOS. Looking around, trying to understand under the hood better, I was surprised to see the following line in vTaskStepTick():
configASSERT( xTicksToJump <= xNextTaskUnblockTime );
I don't have configASSERT turned on, but I would think that if I did, that would be raising issues regularly. xTicksToJump is a delta time, but xNextTaskUnblockTime, if I read the code correctly, is an absolute tick time? Did I get that wrong?
My sleep function, patterned after the documentation example looks like this:
static uint16_t TickPeriod;
void sleepXmega(portTickType expectedIdleTime)
{
TickPeriod = RTC.PER; // note the period being used for ticking on the RTC so we can restore it when we wake up
cli(); // no interrupts while we put ourselves to bed
SLEEP_CTRL = SLEEP_SMODE_PSAVE_gc | SLEEP_SEN_bm; // enable sleepability
setRTCforSleep(); // reconfigure the RTC for sleeping
while (RTC.STATUS & RTC_SYNCBUSY_bm);
RTC.COMP = expectedIdleTime - 4; // set the RTC.COMP to be a little shorter than our idle time, seems to be about a 4 tick overhead
while (RTC.STATUS & RTC_SYNCBUSY_bm);
sei(); // need the interrupt to wake us
cpu_sleep(); // lights out
cli(); // disable interrupts while we rub the sleep out of our eyes
while (RTC.STATUS & RTC_SYNCBUSY_bm);
SLEEP.CTRL &= (~SLEEP_SEN_bm); // Disable Sleep
vTaskStepTick(RTC.CNT); // note how long we were really asleep for
setRTCforTick(TickPeriod); // repurpose RTC back to its original use for ISR tick generation
sei(); // back to our normal interruptable self
}
If anyone sees an obvious problem there, I would love to hear it. The behavior it demonstrates is kind of interesting. For testing, I'm running a simple task loop that delays 2000ms, and then simply toggles a pin I can watch on my scope. Adding some printf's to my function there, it will do the first one correctly, but after I exit it, it immediately reenters, but with a near 65535 value. Which it dutifully waits out, and then gets the next one correct again, and then wrong (long) again, alternating back and forth.

The Cleanest Reset for an ARM Processor

Lately, I've been cleaning up some some C code that runs on an ARM7 controller. In some situations (upgrade, fatal error, etc...) the program will perform a reset. Presently it just jumps to 0 and assumes that the start-up code will reinitialize everything correctly. It got me to thinking about what would be the best procedure a la "Leave No Trace" for an ARM reset. Here is my first crack at it:
void Reset(void)
{
/* Disable interrupts */
__disable_interrupts();
/* Reset peripherals, externals and processor */
AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY | AT91C_RSTC_PERRST | AT91C_RSTC_EXTRST| AT91C_RSTC_PROCRST;
while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);
/* Jump to the reset vector */
(*(void(*)())0)();
}
This code assumes the IAR ARM compiler and the At91Lib. Anything I haven't considered?
The very best solution to accomplish a "hard reset", as opposed to simply jumping through the reset vector, is to force a watchdog timer reset -- if you have one, that is.
Since your title is "cleanest reset", that's my advice. If you simply do a "jump to reset vector", the system could be in any number of states (peripherals still active, ADC conversions in progress, etc...)
I agree with #Dan that if your system has a watchdog timer available, that should provide the cleanest whole-board reset. BUT... If your processor is an ARMv7-M architecture (e.g. Cortex-M3, etc), you may be able to do the following even if you do NOT have a watchdog timer available, depending on your particular implementation:
#define SYSRESETREQ (1<<2)
#define VECTKEY (0x05fa0000UL)
#define VECTKEY_MASK (0x0000ffffUL)
#define AIRCR (*(uint32_t*)0xe000ed0cUL) // fixed arch-defined address
#define REQUEST_EXTERNAL_RESET (AIRCR=(AIRCR&VECTKEY_MASK)|VECTKEY|SYSRESETREQ)
printf("\nRequesting an external reset...\n");
fflush(stdout);
REQUEST_EXTERNAL_RESET;
printf("\nIt doesn't seem to have worked.\n");
fflush(stdout);
See the ARMv7-M Architecture Reference Manual, search for AIRCR and SYSRESETREQ.
This may be effectively the same solution as what "Judge Maygarden" posted, but the identifiers used in his post appear to be Atmel-specific, while the AIRCR register & SYSRESETREQ bits are defined by the underlying ARMv7-M architecture, not by Atmel.
That should do the trick. I use a similar function with an Atmel SAM3U. I never bothered to poll the status register, but that's a good idea and I'm going to go add that right now!
However, you should never get to the reset vector line since the processor will have already reset. IAR has an __noreturn attribute for use in these cases to allow further compiler optimization. I also load my reset function into ram (see __ramfunc) since I use at the end of firmware updates where the microcontroller can't run from flash.
Also, you shouldn't need AT91C_RSTC_EXTRST flag unless you are controlling the reset of external devices with that line.
__noreturn void Reset(void)
{
__disable_interrupts();
AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY |
AT91C_RSTC_PERRST |
AT91C_RSTC_EXTRST |
AT91C_RSTC_PROCRST;
while (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP);
}
These days, wouldn't using CMSIS __NVIC_SystemReset(void) be cleanest?

Resources