P2 Interrupts in Catalina
I've been trying to use interrupts in my latest project. However, I seem to be confused on how they work on the P2 and in Catalina.
The P2 docs seem to indicate each cog has it's own set of 3 interrupts. Is this correct?
If so, is this supported by Catalina?
In my experiments, if I setup an interrupt on a cog and then setup the same interrupt number on another cog, the first interrupt gets clobbered.
I've modified a version of the Catalina demo test_interrupts_2.c (attached below) to help me test the behavior.
The code as attached works. (NOTE the while(1) loop for the new cog can't be empty in TINY or COMPACT or the cog seems to shut down)
If the same interrupt number is used in both cogs, only the last to be assigned runs.
#include <stdio.h> #include <propeller2.h> #include <catalina_interrupts.h> // define the stack size each interrupt needs #define INT_STACK_SIZE (MIN_INT_STACK_SIZE + 100) #define COG_STACK_SIZE 500 long int_stack[INT_STACK_SIZE * 3]; long cog_2_stack[COG_STACK_SIZE]; // interrupt_1 - increment the counter INTERRUPTS_PER_SECOND times per second void interrupt_1(void) { // we are a counter interrupt, so add to the counter for next time _add_CT1(_clockfreq()/4); _pinnot(57); } // interrupt_2 - print the current value of the counter every second void interrupt_2(void) { // we are a counter interrupt, so add to the counter for next time _add_CT2(_clockfreq()/2); _pinnot(58); } // interrupt 3 - throw a random spanner into the works! void interrupt_3(void) { // we are a counter interrupt, so add to the counter for next time _add_CT3(_clockfreq()); _pinnot(59); } void cog_2(void) { _set_CT2(_clockfreq()/2); _set_int_2(CT2, &interrupt_2, &int_stack[INT_STACK_SIZE * 2]); while(1) { _pinnot(60); } } void main(void) { int i; // these are counter interrupts so set up the initial counters _set_CT1(_clockfreq()/4); _set_CT3(_clockfreq()/2); _coginit_C(&cog_2, &cog_2_stack[COG_STACK_SIZE]); // set up our interrupt service routines _set_int_1(CT1, &interrupt_1, &int_stack[INT_STACK_SIZE * 1]); _set_int_3(CT3, &interrupt_3, &int_stack[INT_STACK_SIZE * 3]); // now just let the interrupts do their thing while(1) { // toggle the LED to show some activity. _pinnot(56); // waste some time just to slow things down (note that we can't // just use the various _wait functions because doing so stalls // the interrupts - but we also can't use the _iwait functions // because they use interrupt 2 which we want to use ourselves). // For programs wanting to use all the interrupts, busy waiting // may be the only solution ... for (i = 1; i < 1000000; i++) { } } }
Comments
Hello @currentc
Yes, each cog has separate interrupts. I know this works in Catalina because one of the interrupts (#3) is used to implement the multi-threading, and multi-threading can execute on multiple cogs.
(The rest of this post deleted since I have found the problem - see next post)
Ross.
Hello @currentc
Ok - spotted the problem after just a quick look. The code that sets up the C interrupts does indeed assume interrupts are global, and not per cog. It stores the C interrupt configuration data in Hub RAM, where it is getting overwritten if the same number interrupt is used by a different cog. I must have written that code before I fully understood the P2 interrupt design. The code that does the multi-threading was written later, and correctly uses only Cog RAM.
It will be fairly easy to fix - I just need to store the C interrupt configuration data in Cog RAM as well - but this will take me a day or two.
Ross.
Hello @currentc
Fixed. It was easier than I thought because I can still use Hub RAM - I just need to allocate enough space for all cogs. I'll issue a new release with the fix shortly. Here is my test program, which now works as expected in NATIVE, TINY and COMPACT modes. It is a minor variation of your program. Mainly, I have added a delay in the main loop of the cog_2 function - without that it does indeed lock up in COMPACT and TINY modes because of the way the kernel works in these modes - a loop that consists of only a single JMP instruction (which is the code that
while (1) { }
generates) never allows the interrupts to execute (this is not true in NATIVE mode). But it's a fairly pathological case not to have any code in such a loop.Ross.
Hello @currentc
Catalina version 6.5.5 has been released - see this post.
This should address your interrupt issue.
Ross.
Thanks @RossH
This update saved my project. I need more than 3 interrupts to make it work the way I envisioned.
Catalina seems to be the only way to use interrupts on the P2 without being forced to use and maintain assembly. Something I have no desire to do.
I originally wrote a proof of concept interrupt routine in assembly. Then I realized what a pain that was to modify and maintain.
If it hadn't been for Catalina, I would have changed to a different chip. That would have been a shame. The combination of smart pins, interrupts and multiple cores makes the P2 very powerful.
I think that the P2 would have better adoption in the hobby market if it had better documentation and support for programming languages hobbyists already know.
Thanks again for all of your hard work in creating and maintaining Catalina.
Charles
Hello @currentc
No worries. Hope your project goes well.
Ross.