While Loop wait Interrupt Handler - c

I'm writing a C program to program a microcontroller. In practice, when an interrupt handler occurs I go to execute the following code:
uint8_t call_irq_handler = 0; // variable that is modified by the irq handler
uint8_t call_irq_handler_previous = 0;
static __attribute__((interrupt)) void __irq_handler()
{
call_irq_handler_previous = call_irq_handler;
call_irq_handler = call_irq_handler + 1;
}
In main, instead, to wait for the interrupt handler to be executed, I put the following while loop:
while (call_irq_handler == call_irq_handler_previous)
{
count_cmd_write++;
#if DEBUG
printf("...i didn't get interrupt handler for cmd_write...\n");
#else
continue;
#endif
}
If I set DEBUG 1, I have no problem, the code is executed and after a while I exit the while loop. However, if DEBUG 0 then I remain in the while, and therefore the interrupt handler is not taken.
Anyone know why this happens?

I solved the problem by going to insert volatile
volatile uint8_t call_irq_handler = 0; // variable that is modified by the irq handler
volatile uint8_t call_irq_handler_previous = 0;

Related

How to properly set up DMA on a dsPIC33F

I have code written by someone else (for a dsPIC33FJ128MC706A) - which initializes UART1 & PWMs and uses a busy wait in the U1Rx interrupt to get 14 bytes, and timer1 interrupts to update PWM registers if new data arrives (debugged - it enters the _U1RXInterrupt when data is sent)
I tried modifying it to use DMA instead of busy wait. I changed nothing in the initialization, but called the following function after initialization of UART:
unsigned char received_data1 [0x0f] __attribute__((space(dma)));
unsigned char received_data2 [0x0f] __attribute__((space(dma)));
void dma_init(void)
{
DMA0REQ = 0x000b; // IRQSEL = 0b0001011 (UART1RX))
DMA0PAD = (volatile unsigned int) &U1RXREG;
DMA0STA = __builtin_dmaoffset(received_data1);
DMA0STB = __builtin_dmaoffset(received_data2);
DMA0CNT = 0xe;//15 bytes in
DMA0CON = 0x0002; //continuous ping-pong + post-increment
IFS0bits.DMA0IF = 0;
IEC0bits.DMA0IE = 1;
DMA0CONbits.CHEN = 1;
}
This is based on example 22-10 in the FRM with a few slight changes (UART1 receiver instead of UART2). I can't seem to find other examples that don't use library functions (which I didn't even know existed up until I came across those examples).
(Also, to be consistent with the code I got, I put in _ISR after void instead of making interrupt an attribute, but that didn't change anything)
In the example, there was no interrupt for the UART1 receiver - but according to the FRM, it should be enabled. Made sense to me that I don't need to clear the interrupt flag myself (it would kind-of defeat the purpose of DMA if I needed to use the CPU for it).
And yet, when I send data, the breakpoint on DMA0Interrupt doesn't trigger, but the one on the default interrupt does, and I have PWMIF=1 and U1RXIF=1. I also tried commenting out the default ISR and adding a _U1ErrInterrupt even though examining the flags I didn't notice any error flags being raised, just the normal U1RXIF.
I don't understand why this would happen. I haven't changed the PWM code at all, and the PWM flag isn't raised in the original code when I place a breakpoint in the _U1RxInterrupt. I don't even understand how a DMA set-up could cause a PWM error.
The U1RXIF flag seems to be telling me the DMA didn't handle the incoming byte (I assume it's the DMA that clears the flag), which once again relates to the question "what did I do wrong in this DMA setup"
UART initialization code:
in a general initialization function (called by main())
TRISFbits.TRISF2 = 1; /* U1RX */
TRISFbits.TRISF3 = 0; /* U2TX */
also called by main:
void UART1_init_USB (void)
{
/* Fcy 7.3728 MHZ */
U1MODE = 0x8400; /* U1ATX Transmit status and control register */
U1STA = 0x2040; /* Receve status and control register Transmit disabled*/
U1BRG = 0x000f; /* Baund rate control register 115200 bps */
IPC2bits.U1RXIP = 3; /* Receiver Interrupt Priority bits */
IEC0bits.U1RXIE = 1; /* Enable RS232 interrupts */
IFS0bits.U1RXIF = 0;
}
(comments by original code author)

STM32F4 RTC alarm interrupt called without initialization

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.

This simple ARM Cortex-M SysTick based task scheduler wont work. Should I manage preemption myself?

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.

Interrupt-On-Change during execution runtime

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();
}

Interrupt timer stuck when run parallel with while(1)

first code:
//------------------------------------------------------------------------------
/// Interrupt handlers for TC interrupts. Toggles the state of LEDs
//------------------------------------------------------------------------------
char token = 0;
void TC0_IrqHandler(void) {
volatile unsigned int dummy;
dummy = AT91C_BASE_TC0->TC_SR;
if(token == 1) {
PIO_Clear(&leds[0]);
PIO_Set(&leds[1]);
token = 0;
}
else {
PIO_Set(&leds[0]);
PIO_Clear(&leds[1]);
token = 1;
}
}
//------------------------------------------------------------------------------
/// Configure Timer Counter 0 to generate an interrupt every 250ms.
//------------------------------------------------------------------------------
void ConfigureTc(void) {
unsigned int div;
unsigned int tcclks;
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0; // Enable peripheral clock
TC_FindMckDivisor(1, BOARD_MCK, &div, &tcclks); // Configure TC for a 4Hz frequency and trigger on RC compare
TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
AT91C_BASE_TC0->TC_RC = (BOARD_MCK / div) / 1; // timerFreq / desiredFreq
IRQ_ConfigureIT(AT91C_ID_TC0, 0, TC0_IrqHandler); // Configure and enable interrupt on RC compare
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
IRQ_EnableIT(AT91C_ID_TC0);
printf(" -- timer has started \n\r");
TC_Start(AT91C_BASE_TC0);
}
it's just interrupt timer and it's event (handler) but when I run some
while(1) {
// action
after ConfigureTc() it both cycle and interrupt timer are freezes... Why could that be? Should I add another timer and avoid while(1) ?
while(1) {
printf("hello");
}
-- this breaks (freeze) loops (yes, if I don't use timer it works as it must)
I'll venture an actual answer here. IME, 99% of the time my boards 'go out' with no response on any input and no 'heartbeat' LED-flash from the low-priority 'blinky' thread, the CPU has flown off to a prefetch or data abort handler. These handlers are entered by interrupt and most library-defined default handlers do not re-enable interrupts, so stuffing the entire system. Often, they're just endless loops and, with interrupts disabled, that's the end of the story:(
I have changed my default handlers to output suitable 'CRITICAL ERROR' messages to the UART, (by polling it - the OS/interrupts are stuft!).

Resources