MOD54415 IRQ
Re: MOD54415 IRQ
You probably want to have an observe/lockout thread running with the highest priority in the system. If you have that waiting on a semaphore during normal operations, and post to that semaphore in your ISR, it'll drop right to that task, locking out everything else until it yields. In the case where you want to require a hard reset, simply make it impossible to yield. I'm not exactly sure how to ensure emptying the communication peripherals though; there's not an abort capability in the drivers at the moment.
One little note for you with regards to your busy wait loop: you want to declare 'int o' as 'volatile int o'. Otherwise, the compiler will optimize that entire loop out. ('volatile' is a keyword that tells the compiler that the data contained in the variable can change outside of the context that the compiler is aware of, and therefore should not optimize interactions with said variable).
-Dan
One little note for you with regards to your busy wait loop: you want to declare 'int o' as 'volatile int o'. Otherwise, the compiler will optimize that entire loop out. ('volatile' is a keyword that tells the compiler that the data contained in the variable can change outside of the context that the compiler is aware of, and therefore should not optimize interactions with said variable).
-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
Project Engineer
Netburner, Inc
-
- Posts: 192
- Joined: Mon Dec 17, 2012 6:24 am
Re: MOD54415 IRQ
Thanks Dan,
I'm getting the feeling that there's no way to actually make the program exit the ISR and go straight to the main while loop without somehow telling the program counter to go to that point in particular. That's not a big deal for me. I can do something different.
I think I might just stick to changing the trigger edge of the IRQ pin, I think at this stage, trying to make a semaphore work correctly might take a little more time than I have. But thanks for all the help from everyone!!!
Tony
I'm getting the feeling that there's no way to actually make the program exit the ISR and go straight to the main while loop without somehow telling the program counter to go to that point in particular. That's not a big deal for me. I can do something different.
I think I might just stick to changing the trigger edge of the IRQ pin, I think at this stage, trying to make a semaphore work correctly might take a little more time than I have. But thanks for all the help from everyone!!!
Tony
Re: MOD54415 IRQ
The exit() function is part of the C standard library not part of the OS. It is idiomatic to return a 0 for normal termination and an error code value in all other cases. In this case it doesn't matter because nothing is monitoring the return value. Calling exit() will cause an immediate termination of your program. Under the NB, I have to assume it returns control to the OS thread that invoked UserMain. This won't be the same as your while(1); in an ISR (I think of it as a kinder/gentler alternative) but I think it will do what you want. You will have to test to be sure.
I can tell from my test, that the code that runs as a result of calling EnableAutoUpdate() continues to run. I'm thinking that all threads you launched will go out of scope and die when your code terminates. I didn't test the HTTP handler but it might stay alive. The gurus from NB would have to specify exactly what happens.
Calling exit() from an embedded application is pretty unusual and as a kindness to any possible future maintenance programmer you should document in an obvious location why you're doing it. That is true of putting a killer loop in an ISR as well.
Code: Select all
void exit(int return_code)
I can tell from my test, that the code that runs as a result of calling EnableAutoUpdate() continues to run. I'm thinking that all threads you launched will go out of scope and die when your code terminates. I didn't test the HTTP handler but it might stay alive. The gurus from NB would have to specify exactly what happens.
Calling exit() from an embedded application is pretty unusual and as a kindness to any possible future maintenance programmer you should document in an obvious location why you're doing it. That is true of putting a killer loop in an ISR as well.
-
- Posts: 192
- Joined: Mon Dec 17, 2012 6:24 am
Re: MOD54415 IRQ
Thanks Tod, that's good to know!! I've abandoned the idea of a killer loop in my ISR. Instead, I've taken the approach of using what Dan suggested - switching the IRQ trigger - for the time being. But I am going to experiment with the exit() function as well, because I believe there is possible need for it in another part of the software.
For now, my IRQ trigger will switch after exiting the ISR. This makes most sense to me because I don't want to stay in the ISR too long. I'm still trying to figure out how to terminate a particular thread though, and for one reason in particular. This software was built up from the UDPSendRecieve example. So in the UDPReaderMain() thread, I'm using OSLock(), analyzing the incoming data packet and performing my necessary operations, then calling OSUnlock() when done so that the system may return to what it was doing. I did this because I don't want the OS switching tasks when commands come down the pipeline, and the priority change didn't help. I have tested this and it works beautifully. But, if the UDPReaderMain() thread is being executed, and one of my IRQ pins is triggered, I'd like to kill the thread all together so that the system returns to the while(1) loop in the USerMain() thread because the ISR changes variables that need to instantly be addressed, and the code to do that is in the UserMain() while(1) loop. So my only options at this point were assembly code to move the program counter to that location, which would prove to be a nightmare, or, I could possibly set a semaphore from the ISR to call OSTaskDelete() when I exit the ISR that will terminate that task upon re-entry into it. I could then re-call OSTaskCreate and re-create that particular task - or would you consider that to be too risky?
My other issue is if I call OSLock() and terminate the process, I'm pretty sure I'll have to call OSUnlock()... too many variables to ponder!!! Thoughts?
For now, my IRQ trigger will switch after exiting the ISR. This makes most sense to me because I don't want to stay in the ISR too long. I'm still trying to figure out how to terminate a particular thread though, and for one reason in particular. This software was built up from the UDPSendRecieve example. So in the UDPReaderMain() thread, I'm using OSLock(), analyzing the incoming data packet and performing my necessary operations, then calling OSUnlock() when done so that the system may return to what it was doing. I did this because I don't want the OS switching tasks when commands come down the pipeline, and the priority change didn't help. I have tested this and it works beautifully. But, if the UDPReaderMain() thread is being executed, and one of my IRQ pins is triggered, I'd like to kill the thread all together so that the system returns to the while(1) loop in the USerMain() thread because the ISR changes variables that need to instantly be addressed, and the code to do that is in the UserMain() while(1) loop. So my only options at this point were assembly code to move the program counter to that location, which would prove to be a nightmare, or, I could possibly set a semaphore from the ISR to call OSTaskDelete() when I exit the ISR that will terminate that task upon re-entry into it. I could then re-call OSTaskCreate and re-create that particular task - or would you consider that to be too risky?
My other issue is if I call OSLock() and terminate the process, I'm pretty sure I'll have to call OSUnlock()... too many variables to ponder!!! Thoughts?
Re: MOD54415 IRQ
I would try to write UdpReaderMain such that it looks for a kill semaphore in all the right places (you'll have to analyze your code to determine where you need to pend for such a semaphore). When it sees that kill semaphore you should just let it die a natural death. That is the task shouldn't be in a forever loop but something like while (stay_alive){...}. This is much safer than having some other task kill UdpReaderMain with OsTaskDelete.
-
- Posts: 192
- Joined: Mon Dec 17, 2012 6:24 am
Re: MOD54415 IRQ
Tod -
Going to try something only because I stayed late at work last night trying to implement it.
So my UDPReaderMain() function receives the packet, and the packet is comprised of commands. After reading each command, it processes it immediately, loads return data into the buffer and sends it out before exiting the function. I've put a test bool just before the send function like this:
if (!ISR_FLAG)
{ // Send packet out to host
UDPPacket pkt;
pkt.SetSourcePort(port);
pkt.SetDestinationPort(port);
pkt.AddData(data_buff);
pkt.AddDataByte(0);
pkt.Send(ipaddr);
}
else
{
for (volatile int i = 0; i < 20; i++)
{
data_buff = 0;
}
}
this will not crete the outgoing packet, so there will be no internal conflicts when the system returns to the UDPReaderMain() function.
This way when it returns to send out processed data, it will just delete the data before loading the buffer and erase the previous buffer.
These ISR functions only run if a mechanical function occurs... ie. low voltage detected, lockout detected, or manual controller plugged in to the system. I don't want it to continue processing anything if manual overrides occur. I will also include a statement that will make the system idle should it return from an ISR. Semaphores, I like the idea, still learning to use them correctly.
Going to try something only because I stayed late at work last night trying to implement it.
So my UDPReaderMain() function receives the packet, and the packet is comprised of commands. After reading each command, it processes it immediately, loads return data into the buffer and sends it out before exiting the function. I've put a test bool just before the send function like this:
if (!ISR_FLAG)
{ // Send packet out to host
UDPPacket pkt;
pkt.SetSourcePort(port);
pkt.SetDestinationPort(port);
pkt.AddData(data_buff);
pkt.AddDataByte(0);
pkt.Send(ipaddr);
}
else
{
for (volatile int i = 0; i < 20; i++)
{
data_buff = 0;
}
}
this will not crete the outgoing packet, so there will be no internal conflicts when the system returns to the UDPReaderMain() function.
This way when it returns to send out processed data, it will just delete the data before loading the buffer and erase the previous buffer.
These ISR functions only run if a mechanical function occurs... ie. low voltage detected, lockout detected, or manual controller plugged in to the system. I don't want it to continue processing anything if manual overrides occur. I will also include a statement that will make the system idle should it return from an ISR. Semaphores, I like the idea, still learning to use them correctly.
Re: MOD54415 IRQ
Keep in mind if your code is just past the if (!ISR_FLAG) and then the interrupt occurs when you get back from the interrupt you will continue to finish the remainder of the interior of that if block.
Also just to help with your understanding of volatile, since your for loop now actually does something the compiler won't optimize it away so you no longer need the "volatile" keyword, although AFAIK it doesn't hurt anything to have it there.
Also just to help with your understanding of volatile, since your for loop now actually does something the compiler won't optimize it away so you no longer need the "volatile" keyword, although AFAIK it doesn't hurt anything to have it there.
-
- Posts: 513
- Joined: Sat Apr 26, 2008 7:14 am
Re: MOD54415 IRQ
Tony: as you explore semaphores, stay open to OS_FLAGS as a similar, but more capable alternative. Not sure exactly how your code will be structured, but flags may come in handy. On one level, OS_FLAGS are just like semaphores in that they can be used to by one task to signal that an event occurred in another task or ISR: TaskA or ISR_A just posts to a semaphore that TaskX pends on. Sometimes, however, in TaskX you want to accept simultaneous input (pend on) from more than one event. You might want to know either 1) that ALL of several other events have occurred, or 2) that ANY of them have occurred and then act accordingly. OS_FLAGS provide that mechanism by delivering a 32 bit object. Practically, this object works essentially like 32 individual semaphores except that one can post to, or pend on any or all 32 of them in any combination simultaneously by using an appropriate mask. So in a simple scenario, Task A could set b0 of the flag object, TaskB could set b1 of the same OS_FLAGS object, TaskC sets b2, etc. Then TaskX using a simple mask of the desired bits (b0-2 here), can pend on either 1) all bits in the mask (using OS_FLAGSPendAll()) being set, or alternatively, 2) any bits in the mask being set (using OS_Flag_PendAny()). This means that by pending on specific bits or sets of bits in the OS_FLAGS object, the pending task, (TaskX here), can be responsive to and triggered by a set of events occurring in many tasks simultaneously. Additionally, using a different bit or set of bits in the same flag object, TaskX can individually signal the originating tasks, say Tasks A-C, that corresponding events have been handled. In contrast, tasks pending on a semaphore can typically be responsive to and triggered by only one event, usually posted from a single task or ISR. Semaphores a great, but I often find flags more flexible and useful.
-
- Posts: 192
- Joined: Mon Dec 17, 2012 6:24 am
Re: MOD54415 IRQ
Thanks everyone for the input. Todd and Ridgeglider, I think for this particular project, I might not be using semaphores. I have build this project on top of the UDPSendRecieve example, and in the UdpReaderMain() task, I have a switch-case that I need to run interrupted. So I've employed OSLock() to help with the task coming in from the computer. It's receiving only one simple command at a time, and takes no time to process, but I don't want the OS to switch tasks while running. Since the devices I'm trying to control via spi and i2c are employed while the OS is locked out, I do believe that means I cannot use a semaphore. In a previous version of my software, I used the OS lock and the program ran much faster and smoother than expected, and than when I didn't use the OSLock. So at this point, I can maybe try the flags, or just wait for the system to finish. I thought about changing the priority to critical for the switch-case, then back to normal at the end? maybe that would help?