RTC alarm interrupt (IRQ number 41) is being called on my development board with STM32F411CEU MCU continuously without even initializing RTC. I have this default interrupt handler (I commented out the Default_Handler in startup_stm32F411ceux.s):
void Default_Handler(void)
{
uint32_t irq_number = __get_IPSR() & IPSR_ISR_Msk;
for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
{
if(nf::HAL_IRQ_map::map[i].irq == irq_number)
{
nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
break;
}
}
HAL_NVIC_ClearPendingIRQ((IRQn_Type) irq_number);
}
On the first line I get the IRQ number and it's always 41 which means RTC alarm interrupt. On the last line I try to clear the IRQ, but the handler gets called continuously. My stack looks like this:
Default_Handler() at hal_irq_map.cpp:15 0x801d3e0
<signal handler called>() at 0xfffffff9
HAL_TIM_Base_Start_IT() at stm32f4xx_hal_tim.c:447 0x8016eec
HAL_InitTick() at stm32f4xx_hal_timebase_tim.c:83 0x80131ea
HAL_Init() at stm32f4xx_hal.c:176 0x8013448
main() at main.c:95 0x8012696
The interrupt gets called over and over again and the stack always looks like this (the program doesn't progress). HAL_Init() is on the first line of main(). I have Stm32CubeIDE and ST-LINK V2.
The questions:
Am I doing something wrong when trying to clear the interrupt?
Why is the RTC alarm interrupt being called without initializing?
EDIT:
I tried this:
void Default_Handler(void)
{
//Check if we handle the interrupt
uint32_t irq_number = __get_IPSR() & IPSR_ISR_Msk;
bool handled = false;
for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
{
if(nf::HAL_IRQ_map::map[i].irq == irq_number)
{
nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
handled = true;
break;
}
}
if(!handled)
HAL_NVIC_DisableIRQ((IRQn_Type) irq_number);
HAL_NVIC_ClearPendingIRQ((IRQn_Type) irq_number);
}
Now I'm disabling the interrupt explicitly, but the same interrupt keeps still firing.
The problem is "half" solved:
__get_IPSR() & IPSR_ISR_Msk doesn't seem to return the correct IRQ number. I'm now getting the IRQ number through HAL_NVIC_GetActive. I'm still new to ARM programming and didn't read the documentation well enough. "Active" IRQ means that it's being handled i.e. its' handler is currently being executed. "Pending" IRQ means that its' handler is to be called as soons as possible. So when you are in the default handler and you want to know which interrupt caused this call, you look for the "active" IRQ.
However, I still don't know why RTC alarm interrupt is pending and why it can't be disabled or cleared. I don't think it's ever even enabled.
Now my Default_Handler looks like this:
void Default_Handler(void)
{
uint32_t irq_number;
for(int i=0; i<50; i++) // loop is for debugging only - comment out when not used
{
if(HAL_NVIC_GetActive((IRQn_Type) i))
{
irq_number = i;
break;
}
}
bool handled = false;
for(int i=0; i<nf::HAL_IRQ_map::n_interrupts;i++)
{
if(HAL_NVIC_GetActive(nf::HAL_IRQ_map::map[i].irq))
{
nf::HAL_IRQ_map::map[i].irq_handler(nf::HAL_IRQ_map::map[i].params);
handled = true;
HAL_NVIC_ClearPendingIRQ(nf::HAL_IRQ_map::map[i].irq);
break;
}
}
if(!handled)
for(;;); //sit here forever
}
When I looped through the IRQ numbers I found out that the actual active IRQ number was TIM1_UP_TIM10_IRQn. But why is Default_Handler being called instead of (the correct handler) TIM1_UP_TIM10_IRQHandler?
I thought maybe it's because I have defined Default_Handler myself. There's two lines in startup_stm32f411ceux.s:
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
TIM1_UP_TIM10_IRQHandler is defined .weak which means that if you define the handler yourself, it's strong definition and will be used instead. The meaning of the second line is a bit fuzzy to me, but I think it means that Default_Handler will be used instead as a handler if TIM1_UP_TIM10_IRQHandler is not defined. In my code there are strong definitions for both TIM1_UP_TIM10_IRQHandler and Default_Handler. For a reason that is unclear to me, the linker chooses Default_Handler as the handler for timer 1 update interrupt.
Trying to define my own Default_Handler weak with either pragma weak or __attribute__((weak)) didn't help. So I simply commented out .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler in startup_stm32f411ceux.s and now TIM1_UP_TIM10_IRQHandler was called correctly.
Related
So, I am doing a very simple time triggered pattern based on ARM Cortex M3.
The idea is:when SysTick is serviced, the task array index is incremented at systick, and so is a function pointer to the task. PendSV handler is called, and calls the task. I am using a Atmel ICE JTAG to debug it.
What happens is that it stucks at first task, and does not even increment the counter. It does not go anywhere.
Code pattern:
#include <asf.h> // atmel software framework. cmsis and board support package.
#define NTASKS 3
typedef void (*TaskFunction)(void);
void task1(void);
void task2(void);
void task3(void);
TaskFunction run = NULL;
uint32_t count1 = 0; //counter for task1
uint32_t count2 = 0; // 2
uint32_t count3 = 0; // 3
TaskFunction tasks[NTASKS] = {task1, task2, task3};
volatile uint8_t tasknum = 0;
void task1(void)
{
while(1)
{
count1++;
}
}
void task2(void)
{
while(1)
{
count2++;
}
}
void task3(void)
{
while(1)
{
count3++;
}
}
void SysTick_Handler(void)
{
tasknum = (tasknum == NTASKS-1) ? 0 : tasknum+1;
run = tasks[tasknum];
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
void PendSV_Handler(void)
{
run();
}
int main(void)
{
sysclk_init();
board_init();
pmc_enable_all_periph_clk();
SysTick_Config(1000);
while(1);
}
This design pattern is fundamentally flawed, I'm afraid.
At the first SysTick event, task1() will be called from within the PendSV handler, which will consequently not return. Further SysTick events will interrupt the PendSV handler and set the PendSV bit again, but unless the running task ends and the PendSV handler is allowed to return it can't possibly be invoked again.
The good news is that a proper context switch on the M3 is only a small amount of assembly language - perhaps 10 lines. You need to do some setup too, to get user mode code to use the process stack pointer and so on, and you need to set up a stack per task, but it's not really all that involved.
If you really want to cancel the running task when a SysTick arrives and launch another, they could all share the same stack; but it would be much easier if this was the process stack so that its stack pointer can be reset from within PendSV without affecting the return from handler mode. You'd also need to do some stack poking to convince PendSV to 'return' to the start of the next task you wanted to run.
The code snippets below come from the manufacturer. I am completely confused as to what they are trying to do. In particular, anything to do with InterruptHandler.
Please comment on the code in the globals section. Does this look right?
Also the various APIs included all have sticking points for me. Are they trying to use a void pointer? ... Plenty to ask, please comment mainly on how they are suggesting the timer2 would work.
...
/**
Section: Global Variables Definitions
*/
void (*TMR2_InterruptHandler)(void);
...
/**
Section: TMR2 APIs
*/
void TMR2_Initialize(void)
{
// Set TMR2 to the options selected in the User Interface
// T2CKPS 1:2; T2OUTPS 1:2; TMR2ON off;
T2CON = 0x11;
// T2CS LFINTOSC;
T2CLKCON = 0x04;
// T2PSYNC Not Synchronized; T2MODE Software control One shot; T2CKPOL Rising Edge; T2CKSYNC Not Synchronized;
T2HLT = 0x08;
// T2RSEL TMR4_postscaled;
T2RST = 0x02;
// PR2 8;
T2PR = 0x08;
// TMR2 0;
T2TMR = 0x00;
// Clearing IF flag before enabling the interrupt.
PIR4bits.TMR2IF = 0;
// Enabling TMR2 interrupt.
PIE4bits.TMR2IE = 1;
// Set Default Interrupt Handler
TMR2_SetInterruptHandler(TMR2_DefaultInterruptHandler);
// Start TMR2
TMR2_Start();
}
void TMR2_ISR(void)
{
// clear the TMR2 interrupt flag
PIR4bits.TMR2IF = 0;
if(TMR2_InterruptHandler)
{
TMR2_InterruptHandler();
}
}
void TMR2_SetInterruptHandler(void* InterruptHandler)
{
TMR2_InterruptHandler = InterruptHandler;
}
void TMR2_DefaultInterruptHandler(void)
{
// add your TMR2 interrupt custom code
// or set custom function using TMR2_SetInterruptHandler()
}
/**
End of File
*/
Thanks,
Steve
edit:
The manufacturer code includes a routine (I can't seem to add it here) for managing high-level interrupts that calls TMR2_ISR if (PIE4bits.TMR2IE == 1 && PIR4bits.TMR2IF == 1) This would seem to negate any TMR2_DefaultInterruptHandler would it not?
Thanks again for your help.
The comments of Garr Godfrey and Martin James provided helpful hints. Thus, I will try to fill the possible gaps:
void (*TMR2_InterruptHandler)(void); is a global variable with a function pointer providing the current interrupt handler.
I would read TMR2_ISR() as "interrupt service routine". From the presented code, it's not clear from where it is called. Suspecting from it's name, it's reasonable to assume that it's called when the interrupt is triggered. It checks whether the global interrupt handler function pointer TMR2_InterruptHandler is not NULL and calls the pointed function in case of success.
If TMR2_Initialize() has been called before then TMR2_InterruptHandler points to function TMR2_DefaultInterruptHandler(). Thus, in this case, the latter is called from TMR2_ISR().
void TMR2_SetInterruptHandler(void* InterruptHandler) is used in TMR2_Initialize(). It sets the current interrupt handler. (Surprise.)
I'm a little bit puzzled because I would make it:
void TMR2_SetInterruptHandler(void (*InterruptHandler)())
This is because my daily work with C++ drilled me for "clean typing" but I remember that C is much more lax about this. (void* is compatible to any pointer.)
As Garr Godfrey already said: "put your code in TMR2_DefaultInterruptHandler"
where it is recommended by the comment
// add your TMR2 interrupt custom code
I am trying to implement the following pseudocode on a cortex-m3 controller, (STM32L151 in particular)
void SysTick_Handler() {
do_high_priority_periodic_tasks(); // not to be interrupted
lower_interrupt_priority();
do_low_priority_periodic_tasks(); // these may be interrupted
}
In other words, run the first part with priority level 0, then somehow lower the current interrupt priority to 15, so that the rest could be preempted by other hardware interrupts.
One idea is to move do_low_priority_periodic_tasks(); into a separate interrupt handler, and invoke this handler through NVIC_SetPendingIRQ() which sets a pending bit in the NVIC->ISPR[] register. This way, the other interrupt would immediately follow SysTick, unless there is anything with priority between 0 and 14 pending.
#define LOWPRIO_IRQn 55
void IRQ55_Handler() {
do_low_priority_periodic_tasks(); // these may be interrupted
}
void SysTick_Handler() {
do_high_priority_periodic_tasks(); // not to be interrupted
NVIC_SetPendingIRQ(LOWPRIO_IRQ);
}
void main() {
HAL_Init();
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
HAL_NVIC_SetPriority(LOWPRIO_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(LOWPRIO_IRQn);
while(1) {
/* main loop */
}
}
I've picked IRQ 55 because it's not occupied on my controller, it would be the AES interrupt handler on a STM32L162, but I'm a bit worried there. Should I pick a different IRQ instead, perhaps an unused DMA channel interrupt? Is it safe to use interrupts 57-67, which are defined in the Cortex-M3 core, but not on the STM32L series? Is there any better way to do it?
Is it safe to use interrupts 57-67, which are defined in the Cortex-M3 core, but not on the STM32L series?
No. Your NVIC may not actually implement them.
But the PendSV is exactly made for this task:
void SysTick_Handler() {
do_high_priority_periodic_tasks(); // not to be interrupted
// Set the PENDSVSET to trigger a PendSV exception
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}
void PendSV_Handler() {
do_low_priority_periodic_tasks(); // these may be interrupted
}
See also this answer about PendSV.
I am using Interrupt-On-Change on RC7 of PIC16LF1618. Here is the initialization bit that I use for I-O-C:
void I_O_C_Initialize (void) {
INTCONbits.IOCIF = 0;
IOCCFbits.IOCCF7 = 0;
INTCONbits.IOCIE = 1;
IOCCP = 0x80;
}
I am able to wake the PIC from a Power-Down Mode (SLEEP) using a positive trigger on RC7. However, I would like to have this trigger available during execution time as well, as if any positive trigger on RC7 should reset the PIC and go to the first line of the main() function.
Could you please let me know on how to achieve this?
P.S: Since the reset needs to happen as quick as possible and is crucial to the execution time, I am unable to add multiple if statements inside the main function to check for the positive trigger on RC7. Hence I am looking for an interrupt option to reset the PIC, even if it is executing a delay or function loops.
Thanks
In most 8-bit PIC devices, and assuming you're using XC8, there is a definition that invokes the required assembly command:
#define RESET() asm("reset")
So, in your interrupt handler, just insert this line of code:
RESET();
The issue has now been resolved. After enabling GIE bit whenever I needed the Interrupt On Change (IOC) during runtime and using the below function, the IOC worked during runtime as well as Power-Down Mode (SLEEP).
void interrupt ISR (void);
void interrupt ISR (void) {
if (RC7==1) {
asm("pagesel foobar");
asm("goto foobar");
}
else
return;
}
asm("foobar:");
while (1) {
IOCCFbits.IOCCF7 = 0;
INTCONbits.GIE = 1;
. //Do the calculations here
. //Here if any Interrupt On Change happens for RC7,
. //the ISR routine would stop all calculations and
. //would return to the start of the loop without
. //resetting any of the registers.
INTCONbits.GIE = 0;
IOCCFbits.IOCCF7 = 0;
SLEEP();
}
I'm new to Embedded programming and multi-threading and I'm trying to understand how Interrupt handlers work in different contexts/scenarios. For the current question, I just want to know how a interrupt handler would work in the following scenario.
We have a data stream coming from a RS232 interface that is processed by some microcontroller. An interrupt handler(of void type) has a read() function which reads the incoming data bytes. If a character is detected then the interrupt handler invokes a function called detectString() which returns TRUE if the string matches the reference string which is "ON". If detectString() returns boolean TRUE it invokes a function called LED_ON() which should turn on an LED for 1 minute. If it returns false it should turn off the LED. Lets say the microcontroller has a clock frequency of 20MHz and an addition operation taken 5 clock cycles.
My questions are as follows
How do we approach this problem with an FSM?
The RS232 interface keeps transmitting data even after the LED is turned on. So am I correct in assuming that the interrupt handler should work with a one thread and the functions that it invokes should work from a different threads?
How would a skeletal program implementing this FSM look like? (a C pseudocode might really help to understand the backbone of the design)
If you are doing this in an interrupt handler, why would you need different threads? It shouldn't matter what else you're doing, as long as interrupts are enabled.
As for FSM, I wouldn't call a "detect_string". RS232 is going to give you one character at a time. It's possible your UART interrupts you only when you've received more than one, but there's usually a time component as well so it would be unwise to count on that. Make your FSM take one input character at a time. Your states would be something like:
=> new state = [Init] (turn LED off if on)
Init: (Get 'O') => new state = [GotO]
Init: (Get anything else) => new state = [Init]
Init: (Timer expires) => who cares? new state = [Init]
GotO: (Get 'N') => new state = [GotON] (turn on LED, set timer)
GotO: (Get anything else) => new state = [Init]
GotO: (Timer expires) => who cares? new state = [GotO]
GotON: (Get anything) => who cares? new state = [GotON]
GotON: (Timer expires) => turn LED off, new state = [Init]
Obviously lots of tinkering you could do with details, but that's the general idea.
A preemptive kernel will usually provide the ability for an interrupt to set an event that a higher priority thread is pending on.
As for the interrupts, one way of implementing something like a state machine is to use nested pointers to function, similar to an asynchronous callback, but with optional nesting: For example:
typedef void (*PFUN)(void);
/* ... */
PFUN pFunInt = UnexpectedInt; /* ptr to function for interrupt */
PFUN pFunIntSeqDone;
/* ... */
void DoSeq(void)
{
pFunIntSeqDone = IntSeqDone;
pFunInt = IntStep0;
/* enable interrupt, start I/O */
}
void IntStep0(void)
{
pFunInt = IntStep1;
/* handle interrupt */
}
void IntStep1(void)
{
pFunInt = IntStep2;
/* handle interrupt */
}
void IntStep2(void)
{
/* done with sequence, disable interrupt */
pFunInt = UnexpectedInt;
pFunIntSeqDone(); /* call end action handler */
}
void IntSeqDone(void)
{
/* interrupt sequence done handling code */
/* set event for pending thread */
}
void UnexpectedInt(void)
{
/* ... error handling code */
}