NXP LPC17xx pending interrupts - embedded

I am facing a weird problem with the external interrupts of the LPC17xx series.
I have an external button set to external interrupt 1, falling edge with both an internal as an external pull-up resistor (p2.11):
PinCfg.Funcnum = 1;
PinCfg.OpenDrain = 0;
PinCfg.Pinmode = PINSEL_PINMODE_PULLUP;
PinCfg.Pinnum = 11;
PinCfg.Portnum = 2;
PINSEL_ConfigPin(&PinCfg);
GPIO_SetDir(2,((uint32_t)1<<11),0);
And:
EXTICfg.EXTI_Line = EXTI_EINT1;
EXTICfg.EXTI_Mode = EXTI_MODE_EDGE_SENSITIVE;
EXTICfg.EXTI_polarity = EXTI_POLARITY_LOW_ACTIVE_OR_FALLING_EDGE;
EXTI_Config(&EXTICfg);
EXTI_ClearEXTIFlag(EXTI_EINT1);
And:
NVIC_SetPriority(EINT1_IRQn,1);
NVIC_EnableIRQ(EINT1_IRQn);
This is a part of the ISR (including 200ms button debouncing timer):
void EINT1_IRQHandler(void)
{
EXTI_ClearEXTIFlag(1);
uint32_t tim1Cnt = LPC_TIM1->TC;
if (tim1Cnt > ButtDebounceUs)
{
LPC_TIM1->TC = 0x00000000;
// Do work here
}
}
The "Do work here" section could take some time (e.g. more than 200ms in some cases). This is intended and no problem for the further execution of the program.
The problem is that when the ISR is entered first and I press the button a second time while the ISR is executing (this has to be done fast) a pending interrupt is set and causes the ISR to execute again if it has ended for the first time. This is normal behaviour I guess, since EXTI_ClearEXTIFlag(1) does not clear any pending interrupts in the NVIC. So I added NVIC_ClearPendingIRQ(EINT1_IRQn) to clear the new pending interrupts on several locations in the ISR code to be sure the pending interrupt(s) is/are cleared. Strangely enough this does not work at all.
Some my question is, how can I read the pending interrupts via JTAG/debugger (memory address?). And what is going on here? Can someone explain this behaviour and maybe has a clue how to fix it?
Thanks!

when the ISR is entered first and I press the button a second time [...]
This triggers the EINT1 Flag again, but after you cleared it first. Thats why
NVIC_ClearPendingIRQ(EINT1_IRQn) to clear the new pending interrupt
does not work, as EINT1 still signals the interrupt line. You need to call
EXTI_ClearEXTIFlag(1);
again after the "work" to clear this flag.

I know that it is usually not a good idea to make such a long interrupt routine. But as I have stated in the question, this is intended. I need to make sure not other code in the main task is executed during the ISR.
But to come back to the question: someone else pointed out that it maybe is a good idea to move the EXTI_ClearEXTIFlag(1) to the end of the ISR. In this way no external interrupt can accur, nor any pending can be set during excecution of the ISR. This works, but I am still wondering why clearing the pending interrupt does not work. Maybe this only works for GPIO interrupts?

Related

STM32G0B1CE Can the Boot Option bits be used to jump to system bootloader?

I have seen that there are quite a few questions about jumping from an app to the ST system bootloader, for example this one. These use the method of setting the MSP and PC then doing the jump with a function pointer.
This seems to cause an issue with the system bootloader dual-bank management whereby the first jump fails and a second jump needs to be done.
My question is - would it be possible/better to use the user option bytes to jump to the bootloader instead?
Since the OB register is read during boot in the OBL phase, if we set both the "nBOOT1 bit" and "nBOOT_SEL bit" and clear the "nBOOT0 bit" then do a soft reset would this avoid the empty check weirdness and let us jump to the bootloader in one go?
(Just for context - this would be the first step of doing updates via CAN as the MCU in question has a CAN bootloader built in)
Thanks in advance!
After some time tinkering with a dev board and with some help from Tilen Majerle I found that this is indeed possible and does work well.
I added the following in my main() while(1) loop so that when the blue button is pressed, the user option bits are modified and a reset is performed.
I found that we don't have to do the soft reset ourselves as the HAL_FLASH_OB_Launch() function triggers the reset for us, after which we should boot into system memory according to the reference manual page 67.
Also I found that the flash and option bytes must be unlocked before setting the option bytes, but not locked afterwards or the reset won't occur.
Here is the code to do it:
if(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
{
// Basic de-bounce for testing
HAL_Delay(100);
while(HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
{
__NOP();
}
// Read, modify & write user option bits
// nBOOT1 = 1, nBOOT_SEL = 1, nBOOT0 = 0; will select system memory as boot area
uint32_t optBits = FLASH->OPTR;
optBits = (optBits | FLASH_OPTR_nBOOT1 | FLASH_OPTR_nBOOT_SEL);
optBits &= ~(FLASH_OPTR_nBOOT0);
// Unlock flash
HAL_FLASH_Unlock();
// Clear OPTLOCK
HAL_FLASH_OB_Unlock();
// Set up struct with desired bits
FLASH_OBProgramInitTypeDef optionBytesSetting = {0};
optionBytesSetting.OptionType = OPTIONBYTE_USER;
optionBytesSetting.USERConfig = optBits;
optionBytesSetting.USERType = OB_USER_nBOOT0;
// Write Option Bytes
HAL_FLASHEx_OBProgram(&optionBytesSetting);
HAL_Delay(10);
// Soft reset
HAL_FLASH_OB_Launch();
NVIC_SystemReset(); // is not reached
}
I verified that the flash OPTR register is modified correctly (it goes from 0xFFFFFEAA to 0xFBFFFEAA, essentially just the nBOOT0 bit is cleared as the other two bits were already set). The MCU does reset at HAL_FLASH_OB_Launch() as expected and pausing the program reveals that after reset it is running the system bootloader based on the PC address.
I also verified it using STM32CubeProgrammer which allows me to view the PC and option bytes, plus lets me set nBOOT0 back to 1 and boot the board to my app.
As for reverting the OB settings programmatically, you could either use the Write Memory command before jumping to the app, or you could use the Go command to jump to the app then modify the option bytes first thing in your app.

Bits Are Scrambled

The Problem: I send one value into a UART and nulls emerge on the other UART.
--- Details ---
These are both PIC processors (PIC24 and PIC32)
They are both hard wired onto a printed circuit board.
They are communicating, each via one of the UART modules which reside within them.
They are (ostensibly; according to docs) both configured for 115200 bps, 8-N-1
No handshaking, no CTS enabled, no RTS enabled; I'm just putting bytes on the wire and out they go.
(These are short little 4-byte commands and responses which fits pretty neatly)
The PIC32 is going 80 MHz.
The PIC24 has F[cy] = 14745600
i.e., it is going 14.7456 MHz
The PIC24 sends four bytes (a specific command sequence)
When I set a breakpoint at the Interrupt Service Routine for the UART, The PIC32 shows nulls, then I am seeing repeated hits on the (PIC32 code) breakpoint after the first four, and I continue to see nulls (which makes sense since the PIC24 is not sending anything)
i.e., the UART appears to be repeatedly generating interrupts when there is no reason
I did not write the code on the PIC32 side, and I am learning daily how it works.
Then I let the code just run, and I inevitably wind up on a line that says
52570 1D01_335C 9D01_335C _general_execption_handler sdbbp 0x0
When I get there,
The cause register holds 0080181C
The EPC register holds 9D00F228
The SP register holds 9F8FFFA0
This happened like clockwork, so I got suspicious of the __ISR that would not stop. MpLab showed me this...
432:
433: //*********************************************************//
434: void __ISR(_UART1_VECTOR, ipl5) IntUart1Handler(void) //MCU communication port
435: {
9D00F204 415DE800 rdpgpr sp,sp
9D00F208 401A7000 mfc0 k0,EPC
9D00F20C 401B6000 mfc0 k1,Status
9D00F210 27BDFF88 addiu sp,sp,-120
9D00F214 AFBA0074 sw k0,116(sp)
9D00F218 AFBB0070 sw k1,112(sp)
9D00F21C 7C1B7844 ins k1,zero,1,15
9D00F220 377B1400 ori k1,k1,0x1400
9D00F224 409B6000 mtc0 k1,Status
9D00F228 AFBF0064 sw ra,100(sp) ;<<<-------EPC register always points here
9D00F22C AFBE0060 sw s8,96(sp)
9D00F230 AFB9005C sw t9,92(sp)
9D00F234 AFB80058 sw t8,88(sp)
9D00F238 AFAF0054 sw t7,84(sp)
9D00F23C AFAE0050 sw t6,80(sp)
9D00F240 AFAD004C sw t5,76(sp)
9D00F244 AFAC0048 sw t4,72(sp)
9D00F248 AFAB0044 sw t3,68(sp)
9D00F24C AFAA0040 sw t2,64(sp)
9D00F250 AFA9003C sw t1,60(sp)
9D00F254 AFA80038 sw t0,56(sp)
9D00F258 AFA70034 sw a3,52(sp)
9D00F25C AFA60030 sw a2,48(sp)
9D00F260 AFA5002C sw a1,44(sp)
9D00F264 AFA40028 sw a0,40(sp)
9D00F268 AFA30024 sw v1,36(sp)
9D00F26C AFA20020 sw v0,32(sp)
9D00F270 AFA1001C sw at,28(sp)
9D00F274 00001012 mflo v0
9D00F278 AFA2006C sw v0,108(sp)
9D00F27C 00001810 mfhi v1
9D00F280 AFA30068 sw v1,104(sp)
9D00F284 03A0F021 addu s8,sp,zero
I look a little more closely at the numbers, and I see that at that time, if we add 100 (0x64) to FFA0 (the bottom 16 bits of the SP) we get 0x10004, which I am guessing is 4 too much.
PIC Manual DS61143E-page 50 says that that nomenclature means, SW Store Word Mem[Rs+offset> = Rt and other experts have told me that the cause register is telling me that the EXCCODE bits are 7 which is the code for a bus exception on load or store.
Or, I'm totally guessing here (would love to get some experts' knowledge on this) something is not clearing something and I'm encountering infinite recursion on an int handler.
All of this is starting to make sense.
THE QUESTION
Could someone please suggest the most common reasons for an int like this to be repeatedly hitting me ?
Does anyone see any common relationship between the bogus nuls coming from the UART which could somehow be connected with this endlessly generated int ? Am I even on the right track ?
In your answer, please tell me how to acknowledge the Int from the UART. I know how I do that in the PIC24 (I wrote that code totally, in ASM) but I don't know how this is done in in C on the PIC32. Assembly will be fine. I'll inline it. I'm working with code I didn't write here, and I thank you for your answers
What is the most common reason that the UART (#1, in this case) would be repeatedly generating interrupts ?
The most common reason an interrupt subroutine is called over and over is that the interrupt request is never acknowledged in the routine.
Are you sure you clear the corresponding IRQ bit?
To ease UART debugging you should first connect the UART to a PC and make sure your target can communicate both ways with the PC. With two targets at the same time, you can't determine on which one the problem is apart from inspecting signals with a scope.
On many devices an interrupt must be explicitly cleared to prevent the ISR from simply re-entering when complete.
In most cases a UART will have status bits that indicate the source of the interrupt, knowing that might tell you something, but not telling us makes it difficult to help you. You can inspect the UART registers directly in the debugger, however in some devices the act of reading a bit may in fact clear a bit, and that is true in the debugger too, so be aware of that possibility (check the data sheet/user manual).
Some UARTS require their transmitter to be explicitly switched off to stop transmitting nulls, while others are triggered automatically when data is placed in the tx register and stop after the necessary number of bits are shifted out. Again check the data sheet/manual for the part. If the PIC32 code is known to be working, then since this possible error would be with the PIC24 code, it seems to fit. You can check this simply by using an oscilloscope on the Tx line from the PIC24, if it is transmitting, you will see at least start/stop bit transitions (framing). If there is nothing, then the problem is probably at the PIC32 end.
While you have the scope out, you can check that the bit timing is correct and that you are actually transmitting at 115200. It is easy to get the clocking wrong, and that should be your first check. If the baud rate is incorrect, the PIC32 will likely generate framing error interrupts, which if not handled may persist indefinitely.
Another possibility is that after transmission the PIC24 leaves the line in the "break" state, and that the PIC32 UART is generating "line-break" interrupts. That is why it is important to look at the UART status registers to determine the interrupt cause.
As you can see, there are many possibilities; I think I have covered the most likely ones, but more methodical debugging effort and information gathering on your part is required. I hope I have guided you in this too.
There were the three root causes which were in place...
The interrupt priority level was set at value 6 in the initialization code for UART1
The first line of the interrupt service routine was coded with an interrupt priority level of 5
The first three bytes of UART data were disappearing from the data stream (this is still unsolved)
Here's the not-so-obvious way they were causing the problem
First three bytes never appeared
Fourth byte did appear
Interrupt hit (as level 6) and invoked __ISR routine
__ISR was acting as ipl5 agent
First instruction executed (possibly more, I couldn't debug that accurately)
As soon as the first instruction finished, the "higher" priority 6 interrupt immediately kicked in
This resulted in the same interrupt again
The process repeated itself infinitely.
In short order, Stack Overflow resulted
The Fix
Make sure these two lines of code agree with each other...
The IPL line in the init code, wrong way then the right way
//IPC6bits.U1IP=6; //// Wrong !!! Uart 1 IPL should not be 6 !!!
IPC6bits.U1IP=5; //// Uart 1 IPL = 5 Correct way; matches __ISR
Interrupt Service Routine
void __ISR(_UART1_VECTOR, ipl5) IntUart1Handler(void) //// Operating as IPL 5
:
:
:
:
Poor design decision. If both are on same board SPI would have been more feasible and a lot faster.

Keeping time using timer interrupts an embedded microcontroller

This question is about programming small microcontrollers without an OS. In particular, I'm interested in PICs at the moment, but the question is general.
I've seen several times the following pattern for keeping time:
Timer interrupt code (say the timer fires every second):
...
if (sec_counter > 0)
sec_counter--;
...
Mainline code (non-interrupt):
sec_counter = 500; // 500 seconds
while (sec_counter)
{
// .. do stuff
}
The mainline code may repeat, set the counter to various values (not just seconds) and so on.
It seems to me there's a race condition here when the assignment to sec_counter in the mainline code isn't atomic. For example, in PIC18 the assignment is translated to 4 ASM statements (loading each byte at the time and selecting the right byte from the memory bank before that). If the interrupt code comes in the middle of this, the final value may be corrupted.
Curiously, if the value assigned is less than 256, the assignment is atomic, so there's no problem.
Am I right about this problem?
What patterns do you use to implement such behavior correctly? I see several options:
Disable interrupts before each assignment to sec_counter and enable after - this isn't pretty
Don't use an interrupt, but a separate timer which is started and then polled. This is clean, but uses up a whole timer (in the previous case the 1-sec firing timer can be used for other purposes as well).
Any other ideas?
The PIC architecture is as atomic as it gets. It ensures that all read-modify-write operations to a memory file are 'atomic'. Although it takes 4-clocks to perform the entire read-modify-write, all 4-clocks are consumed in a single instruction and the next instruction uses the next 4-clock cycle. It is the way that the pipeline works. In 8-clocks, two instructions are in the pipeline.
If the value is larger than 8-bit, it becomes an issue as the PIC is an 8-bit machine and larger operands are handled in multiple instructions. That will introduce atomic issues.
You definitely need to disable the interrupt before setting the counter. Ugly as it may be, it is necessary. It is a good practice to ALWAYS disable the interrupt before configuring hardware registers or software variables affecting the ISR method. If you are writing in C, you should consider all operations as non-atomic. If you find that you have to look at the generated assembly too many times, then it may be better to abandon C and program in assembly. In my experience, this is rarely the case.
Regarding the issue discussed, this is what I suggest:
ISR:
if (countDownFlag)
{
sec_counter--;
}
and setting the counter:
// make sure the countdown isn't running
sec_counter = 500;
countDownFlag = true;
...
// Countdown finished
countDownFlag = false;
You need an extra variable and is better to wrap everything in a function:
void startCountDown(int startValue)
{
sec_counter = 500;
countDownFlag = true;
}
This way you abstract the starting method (and hide ugliness if needed). For example you can easily change it to start a hardware timer without affecting the callers of the method.
Write the value then check that it is the value required would seem to be the simplest alternative.
do {
sec_counter = value;
} while (sec_counter != value);
BTW you should make the variable volatile if using C.
If you need to read the value then you can read it twice.
do {
value = sec_counter;
} while (value != sec_counter);
Because accesses to the sec_counter variable are not atomic, there's really no way to avoid disabling interrupts before accessing this variable in your mainline code and restoring interrupt state after the access if you want deterministic behavior. This would probably be a better choice than dedicating a HW timer for this task (unless you have a surplus of timers, in which case you might as well use one).
If you download Microchip's free TCP/IP Stack there are routines in there that use a timer overflow to keep track of elapsed time. Specifically "tick.c" and "tick.h". Just copy those files over to your project.
Inside those files you can see how they do it.
It's not so curious about the less than 256 moves being atomic - moving an 8 bit value is one opcode so that's as atomic as you get.
The best solution on such a microcontroller as the PIC is to disable interrupts before you change the timer value. You can even check the value of the interrupt flag when you change the variable in the main loop and handle it if you want. Make it a function that changes the value of the variable and you could even call it from the ISR as well.
Well, what does the comparison assembly code look like?
Taken to account that it counts downwards, and that it's just a zero compare, it should be safe if it first checks the MSB, then the LSB. There could be corruption, but it doesn't really matter if it comes in the middle between 0x100 and 0xff and the corrupted compare value is 0x1ff.
The way you are using your timer now, it won't count whole seconds anyway, because you might change it in the middle of a cycle.
So, if you don't care about it. The best way, in my opinion, would be to read the value, and then just compare the difference. It takes a couple of OPs more, but has no multi-threading problems.(Since the timer has priority)
If you are more strict about the time value, I would automatically disable the timer once it counts down to 0, and clear the internal counter of the timer and activate once you need it.
Move the code portion that would be on the main() to a proper function, and have it conditionally called by the ISR.
Also, to avoid any sort of delaying or missing ticks, choose this timer ISR to be a high-prio interrupt (the PIC18 has two levels).
One approach is to have an interrupt keep a byte variable, and have something else which gets called at least once every 256 times the counter is hit; do something like:
// ub==unsigned char; ui==unsigned int; ul==unsigned long
ub now_ctr; // This one is hit by the interrupt
ub prev_ctr;
ul big_ctr;
void poll_counter(void)
{
ub delta_ctr;
delta_ctr = (ub)(now_ctr-prev_ctr);
big_ctr += delta_ctr;
prev_ctr += delta_ctr;
}
A slight variation, if you don't mind forcing the interrupt's counter to stay in sync with the LSB of your big counter:
ul big_ctr;
void poll_counter(void)
{
big_ctr += (ub)(now_ctr - big_ctr);
}
No one addressed the issue of reading multibyte hardware registers (for example a timer.
The timer could roll over and increment its second byte while you're reading it.
Say it's 0x0001ffff and you read it. You might get 0x0010ffff, or 0x00010000.
The 16 bit peripheral register is volatile to your code.
For any volatile "variables", I use the double read technique.
do {
t = timer;
} while (t != timer);

Event handling in embedded code

I want to know how events are used in embedded system code.
Main intention is to know how exactly event flags are set/reset in code. and how to identify which task is using which event flag and which bits of the flag are getting set/reset by each task.
Please put your suggestion or comments about it.
Thanks in advance.
(edit 1: copied from clarification in answer below)
Sorry for not specifying the details required. Actually I am interested in the analysis of any application written in C language using vxworks/Itron/OSEK OS. For example there is eventLib library in vxworks to support event handling. I want to know that how one can make use of such system routines to handle events in task. What is event flag(is it global/local...or what ?), how to set bits of any event flag and which can be the possible relationship between task and event flags ??
How task can wait for multiple events in AND and OR mode ??
I came across one example in which the scenario given below looks dangerous, but why ??
Scenarios is ==> *[Task1 : Set(e1), Task2 : Wait(e1) and Set(e2), Task3 : Wait(e2) ]*
I know that multiple event flags waited by one task or circular dependency between multiple tasks(deadlock) are dangerous cases in task-event relationship, but how above scenario is dangerous, I am not getting it....Kindly explain.
(Are there any more such scenarios possible in task-event handling which should be reviewed in code ?? )
I hope above information is sufficient ....
Many embedded systems use Interrupt Service Routines (ISR) to handle events. You would define an ISR for a given "flag" and reset that flag after you handle the event.
For instance say you have a device performing Analog to Digital Conversions (ADC). On the device you could have an ISR that fires each time the ADC completes a conversion and then handle it within the ISR or notify some other task that the data is available (if you want to send it across some communications protocol). After you complete that you would reset the ADC flag so that it can fire again at it's next conversion.
Usually there are a set of ISRs defined in the devices manual. Sometimes they provide general purpose flags that you could also handle as you wish. Each time resetting the flag that caused the routine to fire.
The eventLib in VxWorks is similar to signal() in unix -- it can indicate to a different thread that something occurred. If you need to pass data with the event, you may want to use Message Queues instead.
The events are "global" between the sender and receiver. Since each sender indicates which task the event is intended for, there can be multiple event masks in the system with each sender/receiver pair having their own interpretation.
A basic example:
#define EVENT1 0x00000001
#define EVENT2 0x00000002
#define EVENT3 0x00000004
...
#define EVENT_EXIT 0x80000000
/* Spawn the event handler task (event receiver) */
rcvTaskId = taskSpawn("tRcv",priority,0,stackSize,handleEvents,0,0,0,0,0,0,0,0,0,0);
...
/* Receive thread: Loop to receive events */
STATUS handleEvents(void)
{
UINT32 rcvEventMask = 0xFFFFFFFF;
while(1)
{
UINT32 events = 0;
if (eventReceive(rcvEventMask. EVENTS_WAIT_ANY, WAIT_FOREVER, &events) == OK)
{
/* Process events */
if (events & EVENT1)
handleEvent1();
if (events & EVENT2)
handleEvent2();
...
if (events & EVENT_EXIT)
break;
}
}
return OK;
}
The event sender is typically a hardware driver (BSP) or another thread. When a desired action occurs, the driver builds a mask of all pertinent events and sends them to the receiver task.
The sender needs to obtain the taskID of the receiver. The taskID can be a global,
int RcvTaskID = ERROR;
...
eventSend(RcvTaskID, eventMask);
it can be registered with the driver/sender task by the receiver,
static int RcvTaskID = ERROR;
void DRIVER_setRcvTaskID(int rcvTaskID)
{
RcvTaskID = rcvTaskID;
}
...
eventSend(RcvTaskID, eventMask);
or the driver/sender task can call a receiver API method to send the event (wrapper).
static int RcvTaskID;
void RECV_sendEvents(UINT32 eventMask)
{
eventSend(RcvTaskID, eventMask);
}
This question needs to provide more context. Embedded systems can be created using a wide range of languages, operating systems (including no operating system), frameworks etc. There is nothing universal about how events are created and handled in an embedded system, just as there is nothing universal about how events are created and handled in computing in general.
If you're asking how to set, clear, and check the various bits that represent events, this example may help. The basic strategy is to declare a (usually global) variable and use one bit to represent each condition.
unsigned char bit_flags = 0;
Now we can assign events to the bits:
#define TIMER_EXPIRED 0x01 // 0000 0001
#define DATA_READY 0x02 // 0000 0010
#define BUFFER_OVERFLOW 0x04 // 0000 0100
And we can set, clear, and check bits with bitwise operators:
// Bitwise OR: bit_flags | 00000001 sets the first bit.
bit_flags |= TIMER_EXPIRED; // Set TIMER_EXPIRED bit.
// Bitwise AND w/complement clears bits: flags & 11111101 clears the 2nd bit.
bit_flags &= ~DATA_READY; // Clear DATA_READY bit.
// Bitwise AND tests a bit. The result is BUFFER_OVERFLOW
// if the bit is set, 0 if the bit is clear.
had_ovflow = bit_flags & BUFFER_OVERFLOW;
We can also set or clear combinations of bits:
// Set DATA_READY and BUFFER_OVERFLOW bits.
bit_flags |= (DATA_READY | BUFFER_OVERFLOW);
You'll often see these operations implemented as macros:
#define SET_BITS(bits, data) data |= (bits)
#define CLEAR_BITS(bits, data) data &= ~(bits)
#define CHECK_BITS(bits, data) (data & (bits))
Also, a note about interrupts and interrupt service routines: they need to run fast, so a typical ISR will simply set a flag, increment a counter, or copy some data and exit immediately. Then you can check the flag and attend to the event at your leisure. You probably do not want to undertake lengthy or error-prone activities in your ISR.
Hope that's helpful!
Sorry for not specifying the details required. Actually I am interested in the analysis of any application written in C language using vxworks/Itron/OSEK OS.
For example there is eventLib library in vxworks to support event handling.
I want to know that how one can make use of such system routines to handle events in task. What is event flag(is it global/local...or what ?), how to set bits of any event flag and which can be the possible relationship between task and event flags ??
I hope above information is sufficient ....
If you're interested in using event-driven programming at the embedded level you should really look into QP. It's an excellent lightweight framework and if you get the book "Practical UML Statecharts in C/C++" by Miro Samek you find everything from how to handle system events in an embedded linux kernel (ISR's etc) to handling and creating them in a build with QP as your environment. (Here is a link to an example event).
In one family of embedded systems I designed (for a PIC18Fxx micro with ~128KB flash and 3.5KB RAM), I wrote a library to handle up to 16 timers with 1/16-second resolution (measured by a 16Hz pulse input to the CPU). The code is set up to determine whether any timer is in the Expired state or any dedicated wakeup pin is signaling, and if not, sleep until the next timer would expire or a wakeup input changes state. Quite a handy bit of code, though I should in retrospect probably have designed it to work with multiple groups of eight timers rather than one set of 16.
A key aspect of my timing routines which I have found to be useful is that they mostly aren't driven by interrupts; instead I have a 'poll when convenient' routine which updates the timers off a 16Hz counter. While it sometimes feels odd to have timers which aren't run via interrupt, doing things that way avoids the need to worry about interrupts happening at odd times. If the action controlled by a timer wouldn't be able to happen within an interrupt (due to stack nesting and other limitations), there's no need to worry about the timer in an interrupt--just keep track of how much time has passed.

Precisely time a function call

I am using a microcontroller with a C51 core. I have a fairly timeconsuming and large subroutine that needs to be called every 500ms. An RTOS is not being used.
The way I am doing it right now is that I have an existing Timer interrupt of 10 ms. I set a flag after every 50 interrupts that is checked for being true in the main program loop. If the Flag is true the subroutine is called. The issue is that by the time the program loop comes round to servicing the flag, it is already more than 500ms,sometimes even >515 ms in case of certain code paths. The time taken is not accurately predictable.
Obviously, the subroutine cannot be called from inside the timer interrupt due to that large time it takes to execute.The subroutine takes 50ms to 89ms depending upon various conditions.
Is there a way to ensure that the subroutine is called in exactly 500ms each time?
I think you have some conflicting/not-thought-through requirements here. You say that you can't call this code from the timer ISR because it takes too long to run (implying that it is a lower-priority than something else which would be delayed), but then you are being hit by the fact that something else which should have been lower-priority is delaying it when you run it from the foreground path ('program loop').
If this work must happen at exactly 500ms, then run it from the timer routine, and deal with the fall-out from that. This is effectively what a pre-emptive RTOS would be doing anyway.
If you want it to run from the 'program loop', then you will have to make sure than nothing else which runs from that loop ever takes more than the maximum delay you can tolerate - often that means breaking your other long-running work into state-machines which can do a little bit of work per pass through the loop.
I don't think there's a way to guarantee it but this solution may provide an acceptable alternative.
Might I suggest not setting a flag but instead modifying a value?
Here's how it could work.
1/ Start a value at zero.
2/ Every 10ms interrupt, increase this value by 10 in the ISR (interrupt service routine).
3/ In the main loop, if the value is >= 500, subtract 500 from the value and do your 500ms activities.
You will have to be careful to watch for race conditions between the timer and main program in modifying the value.
This has the advantage that the function runs as close as possible to the 500ms boundaries regardless of latency or duration.
If, for some reason, your function starts 20ms late in one iteration, the value will already be 520 so your function will then set it to 20, meaning it will only wait 480ms before the next iteration.
That seems to me to be the best way to achieve what you want.
I haven't touched the 8051 for many years (assuming that's what C51 is targeting which seems a safe bet given your description) but it may have an instruction which will subtract 50 without an interrupt being possible. However, I seem to remember the architecture was pretty simple so you may have to disable or delay interrupts while it does the load/modify/store operation.
volatile int xtime = 0;
void isr_10ms(void) {
xtime += 10;
}
void loop(void) {
while (1) {
/* Do all your regular main stuff here. */
if (xtime >= 500) {
xtime -= 500;
/* Do your 500ms activity here */
}
}
}
You can also use two flags - a "pre-action" flag, and a "trigger" flag (using Mike F's as a starting point):
#define PREACTION_HOLD_TICKS (2)
#define TOTAL_WAIT_TICKS (10)
volatile unsigned char pre_action_flag;
volatile unsigned char trigger_flag;
static isr_ticks;
interrupt void timer0_isr (void) {
isr_ticks--;
if (!isr_ticks) {
isr_ticks=TOTAL_WAIT_TICKS;
trigger_flag=1;
} else {
if (isr_ticks==PREACTION_HOLD_TICKS)
preaction_flag=1;
}
}
// ...
int main(...) {
isr_ticks = TOTAL_WAIT_TICKS;
preaction_flag = 0;
tigger_flag = 0;
// ...
while (1) {
if (preaction_flag) {
preaction_flag=0;
while(!trigger_flag)
;
trigger_flag=0;
service_routine();
} else {
main_processing_routines();
}
}
}
A good option is to use an RTOS or write your own simple RTOS.
An RTOS to meet your needs will only need to do the following:
schedule periodic tasks
schedule round robin tasks
preform context switching
Your requirements are the following:
execute a periodic task every 500ms
in the extra time between execute round robin tasks ( doing non-time critical operations )
An RTOS like this will guarantee a 99.9% chance that your code will execute on time. I can't say 100% because whatever operations your do in your ISR's may interfere with the RTOS. This is a problem with 8-bit micro-controllers that can only execute one instruction at a time.
Writing an RTOS is tricky, but do-able. Here is an example of small ( 900 lines ) RTOS targeted at ATMEL's 8-bit AVR platform.
The following is the Report and Code created for the class CSC 460: Real Time Operating Systems ( at the University of Victoria ).
Would this do what you need?
#define FUDGE_MARGIN 2 //In 10ms increments
volatile unsigned int ticks = 0;
void timer_10ms_interrupt( void ) { ticks++; }
void mainloop( void )
{
unsigned int next_time = ticks+50;
while( 1 )
{
do_mainloopy_stuff();
if( ticks >= next_time-FUDGE_MARGIN )
{
while( ticks < next_time );
do_500ms_thingy();
next_time += 50;
}
}
}
NB: If you got behind with servicing your every-500ms task then this would queue them up, which may not be what you want.
One straightforward solution is to have a timer interrupt that fires off at 500ms...
If you have some flexibility in your hardware design, you can cascade the output of one timer to a second stage counter to get you a long time base. I forget, but I vaguely recall being able to cascade timers on the x51.
Ah, one more alternative for consideration -- the x51 architecture allow two levels of interrupt priorities. If you have some hardware flexibility, you can cause one of the external interrupt pins to be raised by the timer ISR at 500ms intervals, and then let the lower-level interrupt processing of your every-500ms code to occur.
Depending on your particular x51, you might be able to also generate a lower priority interrupt completely internal to your device.
See part 11.2 in this document I found on the web: http://www.esacademy.com/automation/docs/c51primer/c11.htm
Why do you have a time-critical routine that takes so long to run?
I agree with some of the others that there may be an architectural issue here.
If the purpose of having precise 500ms (or whatever) intervals is to have signal changes occuring at specific time intervals, you may be better off with a fast ISR that ouputs the new signals based on a previous calculation, and then set a flag that would cause the new calculation to run outside of the ISR.
Can you better describe what this long-running routine is doing, and what the need for the specific interval is for?
Addition based on the comments:
If you can insure that the time in the service routine is of a predictable duration, you might get away with missing the timer interrupt postings...
To take your example, if your timer interrupt is set for 10 ms periods, and you know your service routine will take 89ms, just go ahead and count up 41 timer interrupts, then do your 89 ms activity and miss eight timer interrupts (42nd to 49th).
Then, when your ISR exits (and clears the pending interrupt), the "first" interrupt of the next round of 500ms will occur about a ms later.
Given that you're "resource maxed" suggests that you have your other timer and interrupt sources also in use -- which means that relying on the main loop to be timed accurately isn't going to work, because those other interrupt sources could fire at the wrong moment.
If I'm interpretting your question correctly, you have:
a main loop
some high priority operation that needs to be run every 500ms, for a duration of up to 89ms
a 10ms timer that also performs a small number of operations.
There are three options as I see it.
The first is to use a second timer of a lower priority for your 500ms operations. You can still process your 10ms interrupt, and once complete continue servicing your 500ms timer interrupt.
Second option - doe you actually need to service your 10ms interrupt every 10ms? Is it doing anything other than time keeping? If not, and if your hardware will allow you to determine the number of 10ms ticks that have passed while processing your 500ms op's (ie. by not using the interrupts themselves), then can you start your 500ms op's within the 10ms interrupt and process the 10ms ticks that you missed when you're done.
Third option: To follow on from Justin Tanner's answer, it sounds like you could produce your own preemptive multitasking kernel to fill your requirements without too much trouble.
It sounds like all you need is two tasks - one for the main super loop and one for your 500ms task.
The code to swap between two contexts (ie. two copies of all of your registers, using different stack pointers) is very simple, and usually consists of a series of register pushes (to save the current context), a series of register pops (to restore your new context) and a return from interrupt instruction. Once your 500ms op's are complete, you restore the original context.
(I guess that strictly this is a hybrid of preemptive and cooperative multitasking, but that's not important right now)
edit:
There is a simple fourth option. Liberally pepper your main super loop with checks for whether the 500ms has elapsed, both before and after any lengthy operations.
Not exactly 500ms, but you may be able to reduce the latency to a tolerable level.