This is great news :-) and thank you for your hard work. How do I get access to these changes?
They will be in the next release. I am working on a significant piece of new functionality which will probably take me a few more weeks.
There are a few things I have found after a couple of days of writing code, testing, and comparing a known working system and the Propeller 2 chip and I really need C99 support. I have found that while porting the code over, the variables need to be initialized throughout the code and not at the beginning as in C89. C89 ANSI works for most cases but not in my particular application.
Post an example of code you think won't work and I (or others here) can probably tell you how to make it work. Mostly this is trivial - the cases that I have found are not trivial are usually cases where you should not be doing this anyway because the results are unpredictable (e..g. using "goto" to jump over declarations).
I have protected sections of code and initializing them, in the beginning, doesn't work for what I need. Is there a way to enable C99 support for Catalina Geany?
You will have to elaborate on this - I know "protected" as a C++ term, but not as applied to C. Perhaps you are depending on specific compiler behaviour? Converting LCC to C99 has been done, but I don't need it, and I have too much on my "to do" list to make any promises on this one.
I am porting code that I know for a fact works perfectly on two other chips to the Propeller 2 chip and it's not working as intended. Maybe it could be the interrupt-driven architecture in the other chips that is causing it to work compared to the Propeller 2 chip. I don't have a side-by-side comparison to rule that out. I did notice when I run through one of the loops the structure starts out initialized as NULL and then when called it runs as expected but does not go back to NULL when finished and therefore does not complete the cycle. Is there any reason why NULL can't be used?
>
Could be the archirtecture of the Propeller, which requires you to do some things differently. Or again, you may be referring to the behaviour of specific compilers. C has rules about when things are initialized, but some compilers will also initialize in other circumstances (e.g. when allocating new memory). You'd have to post more details. I have been caught out by this one myself several times!
Happy to help, but if you choose another route then good luck with your project. Just remember that Catalina will still be here if you discover you need what it can do which other compilers cannot
This is great news :-) and thank you for your hard work. How do I get access to these changes?
They will be in the next release. I am working on a significant piece of new functionality which will probably take me a few more weeks.
There are a few things I have found after a couple of days of writing code, testing, and comparing a known working system and the Propeller 2 chip and I really need C99 support. I have found that while porting the code over, the variables need to be initialized throughout the code and not at the beginning as in C89. C89 ANSI works for most cases but not in my particular application.
Post an example of code you think won't work and I (or others here) can probably tell you how to make it work. Mostly this is trivial - the cases that I have found are not trivial are usually cases where you should not be doing this anyway because the results are unpredictable (e..g. using "goto" to jump over declarations).
I have protected sections of code and initializing them, in the beginning, doesn't work for what I need. Is there a way to enable C99 support for Catalina Geany?
You will have to elaborate on this - I know "protected" as a C++ term, but not as applied to C. Perhaps you are depending on specific compiler behaviour? Converting LCC to C99 has been done, but I don't need it, and I have too much on my "to do" list to make any promises on this one.
I am porting code that I know for a fact works perfectly on two other chips to the Propeller 2 chip and it's not working as intended. Maybe it could be the interrupt-driven architecture in the other chips that is causing it to work compared to the Propeller 2 chip. I don't have a side-by-side comparison to rule that out. I did notice when I run through one of the loops the structure starts out initialized as NULL and then when called it runs as expected but does not go back to NULL when finished and therefore does not complete the cycle. Is there any reason why NULL can't be used?
>
Could be the archirtecture of the Propeller, which requires you to do some things differently. Or again, you may be referring to the behaviour of specific compilers. C has rules about when things are initialized, but some compilers will also initialize in other circumstances (e.g. when allocating new memory). You'd have to post more details. I have been caught out by this one myself several times!
Happy to help, but if you choose another route then good luck with your project. Just remember that Catalina will still be here if you discover you need what it can do which other compilers cannot
Ross.
I have a feeling it has something to do with the interrupt code and at this time I don't know of a way around it. Just to give an idea of what I am doing, take a look at the Grbl code and you'll see the interrupt-driven stepper output in the stepper.c file. This is basically what I am trying to do but my code is "different" as it drives the stepper motors differently and I heavily modified the planner functionality. Looking at that code on their GitHub will give you an idea if it is portable to Propeller 2 or not. Maybe it is my lack of knowledge of programming that is at fault but that doesn't make much sense because I was able to find a more efficient way to drive stepper motors...
This is great news :-) and thank you for your hard work. How do I get access to these changes?
They will be in the next release. I am working on a significant piece of new functionality which will probably take me a few more weeks.
There are a few things I have found after a couple of days of writing code, testing, and comparing a known working system and the Propeller 2 chip and I really need C99 support. I have found that while porting the code over, the variables need to be initialized throughout the code and not at the beginning as in C89. C89 ANSI works for most cases but not in my particular application.
Post an example of code you think won't work and I (or others here) can probably tell you how to make it work. Mostly this is trivial - the cases that I have found are not trivial are usually cases where you should not be doing this anyway because the results are unpredictable (e..g. using "goto" to jump over declarations).
I have protected sections of code and initializing them, in the beginning, doesn't work for what I need. Is there a way to enable C99 support for Catalina Geany?
You will have to elaborate on this - I know "protected" as a C++ term, but not as applied to C. Perhaps you are depending on specific compiler behaviour? Converting LCC to C99 has been done, but I don't need it, and I have too much on my "to do" list to make any promises on this one.
I am porting code that I know for a fact works perfectly on two other chips to the Propeller 2 chip and it's not working as intended. Maybe it could be the interrupt-driven architecture in the other chips that is causing it to work compared to the Propeller 2 chip. I don't have a side-by-side comparison to rule that out. I did notice when I run through one of the loops the structure starts out initialized as NULL and then when called it runs as expected but does not go back to NULL when finished and therefore does not complete the cycle. Is there any reason why NULL can't be used?
>
Could be the archirtecture of the Propeller, which requires you to do some things differently. Or again, you may be referring to the behaviour of specific compilers. C has rules about when things are initialized, but some compilers will also initialize in other circumstances (e.g. when allocating new memory). You'd have to post more details. I have been caught out by this one myself several times!
Happy to help, but if you choose another route then good luck with your project. Just remember that Catalina will still be here if you discover you need what it can do which other compilers cannot
Ross.
If you look closely at the code, they have variables declared throughout the functions. My hunch is that may be causing the problem but maybe not who knows...
I have a feeling it has something to do with the interrupt code and at this time I don't know of a way around it. Just to give an idea of what I am doing, take a look at the Grbl code and you'll see the interrupt-driven stepper output in the stepper.c file.
It may indeed be the interrupts causing your problem. However, I suspect otherwise. Looking at the grbl code, the first thing I read is ...
The controller is written in highly optimized C utilizing every clever feature of the AVR-chips to achieve precise timing and asynchronous operation. It is able to maintain up to 30kHz of stable, jitter free control pulses.
I doubt such code would be easily portable to another chip.
Then there is this ...
NOTE: This interrupt must be as efficient as possible and complete before the next ISR tick, which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in ISR is 5usec typical and 25usec maximum, well below requirement.
33 usec between interrupts? If my maths is correct, at 180Mhz that's about 6000 clocks between interrupts. I have just tested Catalina and it can handle interrupts at that rate (I ran three), but I don't know if it will be able to perform all the processing in the stepper ISR in 5 us (i.e. 900 clocks) - you should isolate that function and test that. Even if it can, the overhead of the ISR and the interrupt handling may not leave the rest of your program enough time to run. Again, you should test that.
Also, Catalina currently has a limitation that you can't execute one of the wait functions (i.e. the _waitus(), _waitms(), _waitsec() functions) while using interrupts - interrupts are stalled during the waits. I am looking at removing this limitation, but it is present in the current release. Perhaps this is your problem?
If you look closely at the code, they have variables declared throughout the functions. My hunch is that may be causing the problem but maybe not who knows...
I sincerely doubt that. Looking just at the stepper.c code, I can't see anything in the variable declarations that cannot easily be ported to ANSI C.
@Electrodude said:
@enorton Flexprop supports C99. Why don't you give it another try?
My copy of flexprop says "The code generated by FlexSpin is not interrupt safe, so it is not possible to run interrupt service routines (ISRs) in the same COG as compiled code. "
However, this warning may only apply to Spin, not C. Can you clarify?
I have a feeling it has something to do with the interrupt code and at this time I don't know of a way around it. Just to give an idea of what I am doing, take a look at the Grbl code and you'll see the interrupt-driven stepper output in the stepper.c file.
It may indeed be the interrupts causing your problem. However, I suspect otherwise. Looking at the grbl code, the first thing I read is ...
The controller is written in highly optimized C utilizing every clever feature of the AVR-chips to achieve precise timing and asynchronous operation. It is able to maintain up to 30kHz of stable, jitter free control pulses.
I doubt such code would be easily portable to another chip.
Then there is this ...
NOTE: This interrupt must be as efficient as possible and complete before the next ISR tick, which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in ISR is 5usec typical and 25usec maximum, well below requirement.
33 usec between interrupts? If my maths is correct, at 180Mhz that's about 6000 clocks between interrupts. I have just tested Catalina and it can handle interrupts at that rate (I ran three), but I don't know if it will be able to perform all the processing in the stepper ISR in 5 us (i.e. 900 clocks) - you should isolate that function and test that. Even if it can, the overhead of the ISR and the interrupt handling may not leave the rest of your program enough time to run. Again, you should test that.
Also, Catalina currently has a limitation that you can't execute one of the wait functions (i.e. the _waitus(), _waitms(), _waitsec() functions) while using interrupts - interrupts are stalled during the waits. I am looking at removing this limitation, but it is present in the current release. Perhaps this is your problem?
If you look closely at the code, they have variables declared throughout the functions. My hunch is that may be causing the problem but maybe not who knows...
I sincerely doubt that. Looking just at the stepper.c code, I can't see anything in the variable declarations that cannot easily be ported to ANSI C.
Ross.
Well, keep in mind I have enhanced my version extensively and given you that as an example. Currently, I am not using the P2 interrupts because of weird behavior but can try and revisit it and see what is going on with it. I chose the other path and tried using a separate cog for the stepper interrupt code to see if that works and right now I have it almost working but it isn't completing the stepper loop. I am simulating a timer firing in a sense and basically looping through the code. Maybe that is causing part of the problem. I don't know enough about the P2 chip to dig in deeper and see where the problem is coming from.
I am aware that the wait functions are blocking and try not to use them unless it is called for.
I have a feeling it has something to do with the interrupt code and at this time I don't know of a way around it. Just to give an idea of what I am doing, take a look at the Grbl code and you'll see the interrupt-driven stepper output in the stepper.c file.
It may indeed be the interrupts causing your problem. However, I suspect otherwise. Looking at the grbl code, the first thing I read is ...
The controller is written in highly optimized C utilizing every clever feature of the AVR-chips to achieve precise timing and asynchronous operation. It is able to maintain up to 30kHz of stable, jitter free control pulses.
I doubt such code would be easily portable to another chip.
Then there is this ...
NOTE: This interrupt must be as efficient as possible and complete before the next ISR tick, which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in ISR is 5usec typical and 25usec maximum, well below requirement.
33 usec between interrupts? If my maths is correct, at 180Mhz that's about 6000 clocks between interrupts. I have just tested Catalina and it can handle interrupts at that rate (I ran three), but I don't know if it will be able to perform all the processing in the stepper ISR in 5 us (i.e. 900 clocks) - you should isolate that function and test that. Even if it can, the overhead of the ISR and the interrupt handling may not leave the rest of your program enough time to run. Again, you should test that.
Also, Catalina currently has a limitation that you can't execute one of the wait functions (i.e. the _waitus(), _waitms(), _waitsec() functions) while using interrupts - interrupts are stalled during the waits. I am looking at removing this limitation, but it is present in the current release. Perhaps this is your problem?
If you look closely at the code, they have variables declared throughout the functions. My hunch is that may be causing the problem but maybe not who knows...
I sincerely doubt that. Looking just at the stepper.c code, I can't see anything in the variable declarations that cannot easily be ported to ANSI C.
Ross.
Porting the code to another processor is not an easy task but have done it and have been successful. I have two very stable versions in use around the world and they are fast. My problem isn't the step rates it is the amount of data that needs to be processed by the stepper interrupt and the UART and that is where the P2 hopefully comes in. I need to share the burden to get higher throughput and that is the challenge i am facing now.
Well, keep in mind I have enhanced my version extensively and given you that as an example. Currently, I am not using the P2 interrupts because of weird behavior but can try and revisit it and see what is going on with it. I chose the other path and tried using a separate cog for the stepper interrupt code to see if that works and right now I have it almost working but it isn't completing the stepper loop. I am simulating a timer firing in a sense and basically looping through the code. Maybe that is causing part of the problem. I don't know enough about the P2 chip to dig in deeper and see where the problem is coming from.
Yes, on the Propeller it is better not to use interrupts if possible. Much better to use a separate cog instead. I'm not really sure why they were added to the Propeller 2 - the Propeller 1 didn't have them, and once people got used to true multiprocessing I don't think they missed them much (I certainly didn't!). But as you have demonstrated, there is software out there that assumes they are available, so it is nice to have them in the toolbox "just in case".
Can you describe the "weird behavior" in more detail? Catalina uses interrupts itself on the Propeller 2 to implement its multi-tasking capabilities, so I would like to be aware if there are any problems.
I am aware that the wait functions are blocking and try not to use them unless it is called for.
Well, keep in mind I have enhanced my version extensively and given you that as an example. Currently, I am not using the P2 interrupts because of weird behavior but can try and revisit it and see what is going on with it. I chose the other path and tried using a separate cog for the stepper interrupt code to see if that works and right now I have it almost working but it isn't completing the stepper loop. I am simulating a timer firing in a sense and basically looping through the code. Maybe that is causing part of the problem. I don't know enough about the P2 chip to dig in deeper and see where the problem is coming from.
Yes, on the Propeller it is better not to use interrupts if possible. Much better to use a separate cog instead. I'm not really sure why they were added to the Propeller 2 - the Propeller 1 didn't have them, and once people got used to true multiprocessing I don't think they missed them much (I certainly didn't!). But as you have demonstrated, there is software out there that assumes they are available, so it is nice to have them in the toolbox "just in case".
Can you describe the "weird behavior" in more detail? Catalina uses interrupts itself on the Propeller 2 to implement its multi-tasking capabilities, so I would like to be aware if there are any problems.
I am aware that the wait functions are blocking and try not to use them unless it is called for.
Good.
Ok, I have some good news to report. I can successfully go through one loop of several segments successfully but that is it. If I tell it to move some more the whole thing freezes up and not sure if the stepper "interrupt" cog is off in la la land after the first successful attempt or what but it doesn't like it, Some ting wong. I will continue messing around with the code to see what is going on.
Is there an easy way to start and stop the cogs at will? I know there is a cog stop but didn't see a start unless I can use the cog start function... Hmm I will try that and see...
The weird behavior is a loop-like effect when triggering the interrupt. Is that normal? I placed code in the interrupt to see what was going on and it would toggle an output continuously and freeze up the chip.
@RossH said:
Yes, on the Propeller it is better not to use interrupts if possible. Much better to use a separate cog instead. I'm not really sure why they were added to the Propeller 2 - the Propeller 1 didn't have them, and once people got used to true multiprocessing I don't think they missed them much (I certainly didn't!). But as you have demonstrated, there is software out there that assumes they are available, so it is nice to have them in the toolbox "just in case".
I think interrupts were added for a few reasons
a) As you say, ported code often assumes an interrupt.
b) "better to use a separate cog" is fine, until you run out of COGS, so interrupts allows an incremental/fractional use of cogs
c) it was possible to do so
@RossH said:
NOTE: This interrupt must be as efficient as possible and complete before the next ISR tick, which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in ISR is 5usec typical and 25usec maximum, well below requirement.
33 usec between interrupts? If my maths is correct, at 180Mhz that's about 6000 clocks between interrupts. I have just tested Catalina and it can handle interrupts at that rate (I ran three), but I don't know if it will be able to perform all the processing in the stepper ISR in 5 us (i.e. 900 clocks) - you should isolate that function and test that. Even if it can, the overhead of the ISR and the interrupt handling may not leave the rest of your program enough time to run. Again, you should test that.
I think gbrl 'worked backwards' here - they tuned the interrupt code, and timed it, and then set the fastest rate to be a tad longer than that longest time. So it is highly MCU tuned.
FWIR that's just setting a maximum step rate, so you could use a similar tune approach on P2.
ie relax the interrupt rate first, until you prove it works at a known safe lower speed, and then decrease the time, after measuring what the actual max needed is.
AVR is much more primitive in pulse generation than P2, so once the SW-clone version is operational, it may be possible to use the P2 smart pins hardware to improve the granularity and update rate, if that is really needed ?
@RossH said:
Also, Catalina currently has a limitation that you can't execute one of the wait functions (i.e. the _waitus(), _waitms(), _waitsec() functions) while using interrupts - interrupts are stalled during the waits.
I am looking at removing this limitation, but it is present in the current release.
Maybe two versions are needed ?
Sometimes you need to wait exactly for a time, but more often you need to wait at least some time.
I'm rusty, but IIRC the wait opcode in P2 had a tweak to better support the second form, in that a 'greater than' test is applied, not an equals test.
The weird behavior is a loop-like effect when triggering the interrupt. Is that normal? I placed code in the interrupt to see what was going on and it would toggle an output continuously and freeze up the chip.
That doesn't sound right. Also, what type of interrupt was this? A timer interrupt?
Can you post some code (cut down if necessary)? Just showing your ISR and how you are setting up the interrupt and/or triggering it (if it is a timer).
I have just been playing around with timers and interrupts, and I realize I can make the timers interrupt-safe just by using POLLCTx instead of WAITCTx - i.e. by busy waiting. Consumes more power and reduces the accuracy very slightly (only by a few clocks, which is probably ok). This will allow all the _wait functions to work with interrupts. I can make this automatic - i.e. use WAITCTx unless you compile with the interrupt library - in that case use POLLCTx. ***
However, this is now getting a bit complex - the next version of Catalina will use timer 2 for the _wait functions, and timer 3 for multi-tasking, which leaves only timer 1 for general use in a multi-threaded program that also needs the _wait functions. Of course, timer 2 is still available if you don't use the _wait functions, and timer 3 is still available if your program is single-threaded. But you have to remember all that!
Ross.
*** EDIT: No, I can't make this choice automatic. I will have to provide alternate versions that are "interrupt safe".
I'm rusty, but IIRC the wait opcode in P2 had a tweak to better support the second form, in that a 'greater than' test is applied, not an equals test.
I am guessing this is the WAITCTx instructions. But the problem is that from C even just the overhead of the function call and return to the _wait functions consumes some clocks (the precise amount depends on many things - e.g. the memory model in use, interrupts, whether the program is single-threaded or multi-threaded). So it is difficult to achieve exact timing in C.
The closest you can get is to write a function to set the timer up yourself (e.g. suppose we want timer 1), such as:
void set_timer_1(uint32_t time) {
PASM(
"getct r0\n"
"addct1 r0, r2\n" // parameter 'time' is passed in r2
);
}
and then use an inline PASM instruction when you want to wait for it - e.g.
... some C code ...
set_timer_1(MY_TIMEOUT);
... some more C code that hopefully takes less than MY_TIMEOUT clocks ...
PASM(" waitct1")
... more C code ...
The weird behavior is a loop-like effect when triggering the interrupt. Is that normal? I placed code in the interrupt to see what was going on and it would toggle an output continuously and freeze up the chip.
That doesn't sound right. Also, what type of interrupt was this? A timer interrupt?
Can you post some code (cut down if necessary)? Just showing your ISR and how you are setting up the interrupt and/or triggering it (if it is a timer).
I have just been playing around with timers and interrupts, and I realize I can make the timers interrupt-safe just by using POLLCTx instead of WAITCTx - i.e. by busy waiting. Consumes more power and reduces the accuracy very slightly (only by a few clocks, which is probably ok). This will allow all the _wait functions to work with interrupts. I can make this automatic - i.e. use WAITCTx unless you compile with the interrupt library - in that case use POLLCTx. ***
However, this is now getting a bit complex - the next version of Catalina will use timer 2 for the _wait functions, and timer 3 for multi-tasking, which leaves only timer 1 for general use in a multi-threaded program that also needs the _wait functions. Of course, timer 2 is still available if you don't use the _wait functions, and timer 3 is still available if your program is single-threaded. But you have to remember all that!
Ross.
*** EDIT: No, I can't make this choice automatic. I will have to provide alternate versions that are "interrupt safe".
OMG I feel like a retard.... I GOT IT WORKING!!!!!!! Nothing wrong with Catalina Geany at all. It was a stupid RETURN going back to the main program hosing the "interrupt" processor. All in all, I am happy now woohoo!!!
OMG I feel like a retard.... I GOT IT WORKING!!!!!!! Nothing wrong with Catalina Geany at all. It was a stupid RETURN going back to the main program hosing the "interrupt" processor. All in all, I am happy now woohoo!!!
>
That should be enough. When you finish your program you can try reducing it if you need the space. I don't have an automated way of determining how much stack space is needed, but you can get an estimate by allocating a local variable in the top function and saving its address in a global (as a *long static), then doing the same in the deepest place in your code (and storing it in another *long static) - then taking the difference. For example:
#include <stdio.h>
static unsigned long *top;
static unsigned long *bottom;
void func3() {
unsigned long a;
bottom = &a;
}
void func2() {
func3();
}
void func1() {
func2();
}
void main() {
unsigned long size;
top = &size;
func1();
printf("stack addr at top = %08lX (hex)\n", (unsigned long)top);
printf("stack addr at bottom = %08lX (hex)\n", (unsigned long)bottom);
size = top - bottom;
printf("\nstack size = %ld longs (decimal)\n", (unsigned long)size);
}
Then add a few extra longs for safety - especially if you use multi-threading, in which case you will need an extra 40 longs or so. There is a constant defined for this called MIN_THREAD_STACK_SIZE in catalina_threads.h
When can I get the changes you have made for the tx and rx count functions for the serial interface? Please let me know when you have some time.
>
Doing a proper release takes time - mainly for testing. But if you are willing to risk a pre-release version I could probably have one by the end of the week.
OMG I feel like a retard.... I GOT IT WORKING!!!!!!! Nothing wrong with Catalina Geany at all. It was a stupid RETURN going back to the main program hosing the "interrupt" processor. All in all, I am happy now woohoo!!!
>
That should be enough. When you finish your program you can try reducing it if you need the space. I don't have an automated way of determining how much stack space is needed, but you can get an estimate by allocating a local variable in the top function and saving its address in a global (as a *long static), then doing the same in the deepest place in your code (and storing it in another *long static) - then taking the difference. For example:
#include <stdio.h>
static unsigned long *top;
static unsigned long *bottom;
void func3() {
unsigned long a;
bottom = &a;
}
void func2() {
func3();
}
void func1() {
func2();
}
void main() {
unsigned long size;
top = &size;
func1();
printf("stack addr at top = %08lX (hex)\n", (unsigned long)top);
printf("stack addr at bottom = %08lX (hex)\n", (unsigned long)bottom);
size = top - bottom;
printf("\nstack size = %ld longs (decimal)\n", (unsigned long)size);
}
Then add a few extra longs for safety - especially if you use multi-threading, in which case you will need an extra 40 longs or so. There is a constant defined for this called MIN_THREAD_STACK_SIZE in catalina_threads.h
When can I get the changes you have made for the tx and rx count functions for the serial interface? Please let me know when you have some time.
>
Doing a proper release takes time - mainly for testing. But if you are willing to risk a pre-release version I could probably have one by the end of the week.
Ross.
Ok great. I will address the stack size after I add the other control stuff. Right now it runs full throttle without the timing and other backend stuff added. It will be tight but think I can get it all to fit.
Whenever you are ready to send over your updates I can test it out and report back how it went. I have other stuff to focus on at the moment so no rush.
One thing ill be searching for is a way to add an ethernet to serial bridge in one of the cogs. Now that I'm getting more familiar and comfortable with the chip the more I want to try new things.
Another thing I want to explore is a way to do i2c and spi with the smart pins at some point. Many things to work on
The thing I love about the Propeller is that there is always something new to work on
The thing I hate about the Propeller is that there is always something new to work on .... when you should be getting on with other things
Are there any Catalina C code examples for the smart pins? I want to output a pulse that I can control with a smart pin and feed it back into the P2. I also want to play with the sync pins. Any help is appreciated.
@RossH said:
Also, in Catalina, if you #include <propeller.h> then the special registers (INA, INB, OUTA, OUTB, DIRA, DIRB etc) all become special symbols, so you can just say things like:
#include <propeller.h>
void main() {
register int x;
DIRA = 0x00FF;
OUTA |= 0x00AA;
x = INA;
}
Hey Ross,
I tried to control a group of IO pins like in your example, but they do not go high or low. I can control them using _pinl() and _pinh() not the OUTA and DIRA as shown. Please help. As an example, I need to control pins 24 ... 31 (8 bits) and leave all the others alone.
@RossH said:
Also, in Catalina, if you #include <propeller.h> then the special registers (INA, INB, OUTA, OUTB, DIRA, DIRB etc) all become special symbols, so you can just say things like:
#include <propeller.h>
void main() {
register int x;
DIRA = 0x00FF;
OUTA |= 0x00AA;
x = INA;
}
Hey Ross,
I tried to control a group of IO pins like in your example, but they do not go high or low. I can control them using _pinl() and _pinh() not the OUTA and DIRA as shown. Please help. As an example, I need to control pins 24 ... 31 (8 bits) and leave all the others alone.
That program should work on both the P1 and the P2. But two things to note:
For this trivial program, you might want to stop it exiting, since that would reset the pins and you might not see any activity on the pins at all.
This trivial program only works on port A, which is pins 0 .. 31. If your program needs pins 32 .. 63 then you need to use Port B.
For example, here is a very similar program which turns on multiple LEDs on the P2 EVAL board (i.e. the LEDs on pins 56 .. 61) but leaves all the other pins alone:
#include <propeller.h>
void main() {
DIRB |= 0x3F000000; // set LED pins (56 .. 61) to output
OUTB &= ~0x3F000000; // turn LEDs on (active low!)
while(1); // don't exit, since this will turn LEDs off again!
}
@RossH said:
Also, in Catalina, if you #include <propeller.h> then the special registers (INA, INB, OUTA, OUTB, DIRA, DIRB etc) all become special symbols, so you can just say things like:
#include <propeller.h>
void main() {
register int x;
DIRA = 0x00FF;
OUTA |= 0x00AA;
x = INA;
}
Hey Ross,
I tried to control a group of IO pins like in your example, but they do not go high or low. I can control them using _pinl() and _pinh() not the OUTA and DIRA as shown. Please help. As an example, I need to control pins 24 ... 31 (8 bits) and leave all the others alone.
That program should work on both the P1 and the P2. But two things to note:
For this trivial program, you might want to stop it exiting, since that would reset the pins and you might not see any activity on the pins at all.
This trivial program only works on port A, which is pins 0 .. 31. If your program needs pins 32 .. 63 then you need to use Port B.
For example, here is a very similar program which turns on multiple LEDs on the P2 EVAL board (i.e. the LEDs on pins 56 .. 61) but leaves all the other pins alone:
#include <propeller.h>
void main() {
DIRB |= 0x3F000000; // set LED pins (56 .. 61) to output
OUTB &= ~0x3F000000; // turn LEDs on (active low!)
while(1); // don't exit, since this will turn LEDs off again!
}
Ross.
EDIT: Oops! Forgot the unary NOT operator!
Ok, so that worked for the B port but does not work for the A port. I wrote the same code but replaced the B with A and nothing. What I am trying to do is toggle based on an eight-bit value. There is a mask of eight bits when they toggle, they need to be sent out all at the same time. They immediately get shut down based on the 8-bit mask to invert all eight bits to form sort of like a pulse on the outputs.
Comments
They will be in the next release. I am working on a significant piece of new functionality which will probably take me a few more weeks.
Post an example of code you think won't work and I (or others here) can probably tell you how to make it work. Mostly this is trivial - the cases that I have found are not trivial are usually cases where you should not be doing this anyway because the results are unpredictable (e..g. using "goto" to jump over declarations).
You will have to elaborate on this - I know "protected" as a C++ term, but not as applied to C. Perhaps you are depending on specific compiler behaviour? Converting LCC to C99 has been done, but I don't need it, and I have too much on my "to do" list to make any promises on this one.
>
Could be the archirtecture of the Propeller, which requires you to do some things differently. Or again, you may be referring to the behaviour of specific compilers. C has rules about when things are initialized, but some compilers will also initialize in other circumstances (e.g. when allocating new memory). You'd have to post more details. I have been caught out by this one myself several times!
Happy to help, but if you choose another route then good luck with your project. Just remember that Catalina will still be here if you discover you need what it can do which other compilers cannot
Ross.
I have a feeling it has something to do with the interrupt code and at this time I don't know of a way around it. Just to give an idea of what I am doing, take a look at the Grbl code and you'll see the interrupt-driven stepper output in the stepper.c file. This is basically what I am trying to do but my code is "different" as it drives the stepper motors differently and I heavily modified the planner functionality. Looking at that code on their GitHub will give you an idea if it is portable to Propeller 2 or not. Maybe it is my lack of knowledge of programming that is at fault but that doesn't make much sense because I was able to find a more efficient way to drive stepper motors...
If you look closely at the code, they have variables declared throughout the functions. My hunch is that may be causing the problem but maybe not who knows...
@enorton Flexprop supports C99. Why don't you give it another try?
It may indeed be the interrupts causing your problem. However, I suspect otherwise. Looking at the grbl code, the first thing I read is ...
I doubt such code would be easily portable to another chip.
Then there is this ...
33 usec between interrupts? If my maths is correct, at 180Mhz that's about 6000 clocks between interrupts. I have just tested Catalina and it can handle interrupts at that rate (I ran three), but I don't know if it will be able to perform all the processing in the stepper ISR in 5 us (i.e. 900 clocks) - you should isolate that function and test that. Even if it can, the overhead of the ISR and the interrupt handling may not leave the rest of your program enough time to run. Again, you should test that.
Also, Catalina currently has a limitation that you can't execute one of the wait functions (i.e. the _waitus(), _waitms(), _waitsec() functions) while using interrupts - interrupts are stalled during the waits. I am looking at removing this limitation, but it is present in the current release. Perhaps this is your problem?
I sincerely doubt that. Looking just at the stepper.c code, I can't see anything in the variable declarations that cannot easily be ported to ANSI C.
Ross.
My copy of flexprop says "The code generated by FlexSpin is not interrupt safe, so it is not possible to run interrupt service routines (ISRs) in the same COG as compiled code. "
However, this warning may only apply to Spin, not C. Can you clarify?
Ross.
Well, keep in mind I have enhanced my version extensively and given you that as an example. Currently, I am not using the P2 interrupts because of weird behavior but can try and revisit it and see what is going on with it. I chose the other path and tried using a separate cog for the stepper interrupt code to see if that works and right now I have it almost working but it isn't completing the stepper loop. I am simulating a timer firing in a sense and basically looping through the code. Maybe that is causing part of the problem. I don't know enough about the P2 chip to dig in deeper and see where the problem is coming from.
I am aware that the wait functions are blocking and try not to use them unless it is called for.
Porting the code to another processor is not an easy task but have done it and have been successful. I have two very stable versions in use around the world and they are fast. My problem isn't the step rates it is the amount of data that needs to be processed by the stepper interrupt and the UART and that is where the P2 hopefully comes in. I need to share the burden to get higher throughput and that is the challenge i am facing now.
Yes, on the Propeller it is better not to use interrupts if possible. Much better to use a separate cog instead. I'm not really sure why they were added to the Propeller 2 - the Propeller 1 didn't have them, and once people got used to true multiprocessing I don't think they missed them much (I certainly didn't!). But as you have demonstrated, there is software out there that assumes they are available, so it is nice to have them in the toolbox "just in case".
Can you describe the "weird behavior" in more detail? Catalina uses interrupts itself on the Propeller 2 to implement its multi-tasking capabilities, so I would like to be aware if there are any problems.
Good.
Ok, I have some good news to report. I can successfully go through one loop of several segments successfully but that is it. If I tell it to move some more the whole thing freezes up and not sure if the stepper "interrupt" cog is off in la la land after the first successful attempt or what but it doesn't like it, Some ting wong. I will continue messing around with the code to see what is going on.
Is there an easy way to start and stop the cogs at will? I know there is a cog stop but didn't see a start unless I can use the cog start function... Hmm I will try that and see...
The weird behavior is a loop-like effect when triggering the interrupt. Is that normal? I placed code in the interrupt to see what was going on and it would toggle an output continuously and freeze up the chip.
I think interrupts were added for a few reasons
a) As you say, ported code often assumes an interrupt.
b) "better to use a separate cog" is fine, until you run out of COGS, so interrupts allows an incremental/fractional use of cogs
c) it was possible to do so
I think gbrl 'worked backwards' here - they tuned the interrupt code, and timed it, and then set the fastest rate to be a tad longer than that longest time. So it is highly MCU tuned.
FWIR that's just setting a maximum step rate, so you could use a similar tune approach on P2.
ie relax the interrupt rate first, until you prove it works at a known safe lower speed, and then decrease the time, after measuring what the actual max needed is.
AVR is much more primitive in pulse generation than P2, so once the SW-clone version is operational, it may be possible to use the P2 smart pins hardware to improve the granularity and update rate, if that is really needed ?
Maybe two versions are needed ?
Sometimes you need to wait exactly for a time, but more often you need to wait at least some time.
I'm rusty, but IIRC the wait opcode in P2 had a tweak to better support the second form, in that a 'greater than' test is applied, not an equals test.
That doesn't sound right. Also, what type of interrupt was this? A timer interrupt?
Can you post some code (cut down if necessary)? Just showing your ISR and how you are setting up the interrupt and/or triggering it (if it is a timer).
I have just been playing around with timers and interrupts, and I realize I can make the timers interrupt-safe just by using POLLCTx instead of WAITCTx - i.e. by busy waiting. Consumes more power and reduces the accuracy very slightly (only by a few clocks, which is probably ok). This will allow all the _wait functions to work with interrupts. I can make this automatic - i.e. use WAITCTx unless you compile with the interrupt library - in that case use POLLCTx. ***
However, this is now getting a bit complex - the next version of Catalina will use timer 2 for the _wait functions, and timer 3 for multi-tasking, which leaves only timer 1 for general use in a multi-threaded program that also needs the _wait functions. Of course, timer 2 is still available if you don't use the _wait functions, and timer 3 is still available if your program is single-threaded. But you have to remember all that!
Ross.
*** EDIT: No, I can't make this choice automatic. I will have to provide alternate versions that are "interrupt safe".
Something to keep in mind in situations like this is stack space - make sure your separate cog - or your interrupt functions - are being given enough!
I am guessing this is the WAITCTx instructions. But the problem is that from C even just the overhead of the function call and return to the _wait functions consumes some clocks (the precise amount depends on many things - e.g. the memory model in use, interrupts, whether the program is single-threaded or multi-threaded). So it is difficult to achieve exact timing in C.
The closest you can get is to write a function to set the timer up yourself (e.g. suppose we want timer 1), such as:
and then use an inline PASM instruction when you want to wait for it - e.g.
Ross.
OMG I feel like a retard.... I GOT IT WORKING!!!!!!! Nothing wrong with Catalina Geany at all. It was a stupid RETURN going back to the main program hosing the "interrupt" processor. All in all, I am happy now woohoo!!!
I set the stack to 1000.
When can I get the changes you have made for the tx and rx count functions for the serial interface? Please let me know when you have some time.
>
Excellent!
>
That should be enough. When you finish your program you can try reducing it if you need the space. I don't have an automated way of determining how much stack space is needed, but you can get an estimate by allocating a local variable in the top function and saving its address in a global (as a *long static), then doing the same in the deepest place in your code (and storing it in another *long static) - then taking the difference. For example:
Then add a few extra longs for safety - especially if you use multi-threading, in which case you will need an extra 40 longs or so. There is a constant defined for this called MIN_THREAD_STACK_SIZE in catalina_threads.h
>
Doing a proper release takes time - mainly for testing. But if you are willing to risk a pre-release version I could probably have one by the end of the week.
Ross.
Yes it is
Ok great. I will address the stack size after I add the other control stuff. Right now it runs full throttle without the timing and other backend stuff added. It will be tight but think I can get it all to fit.
Whenever you are ready to send over your updates I can test it out and report back how it went. I have other stuff to focus on at the moment so no rush.
One thing ill be searching for is a way to add an ethernet to serial bridge in one of the cogs. Now that I'm getting more familiar and comfortable with the chip the more I want to try new things.
Another thing I want to explore is a way to do i2c and spi with the smart pins at some point. Many things to work on
The thing I love about the Propeller is that there is always something new to work on
The thing I hate about the Propeller is that there is always something new to work on .... when you should be getting on with other things
Ugh I know what you mean...
Are there any Catalina C code examples for the smart pins? I want to output a pulse that I can control with a smart pin and feed it back into the P2. I also want to play with the sync pins. Any help is appreciated.
Yes. Look in the demos folder under P2. It's called test_p2_smartpins.c
Ok, thank you
Hey Ross,
I tried to control a group of IO pins like in your example, but they do not go high or low. I can control them using _pinl() and _pinh() not the OUTA and DIRA as shown. Please help. As an example, I need to control pins 24 ... 31 (8 bits) and leave all the others alone.
That program should work on both the P1 and the P2. But two things to note:
For example, here is a very similar program which turns on multiple LEDs on the P2 EVAL board (i.e. the LEDs on pins 56 .. 61) but leaves all the other pins alone:
Ross.
EDIT: Oops! Forgot the unary NOT operator!
Ok, so that worked for the B port but does not work for the A port. I wrote the same code but replaced the B with A and nothing. What I am trying to do is toggle based on an eight-bit value. There is a mask of eight bits when they toggle, they need to be sent out all at the same time. They immediately get shut down based on the 8-bit mask to invert all eight bits to form sort of like a pulse on the outputs.
Doesn't Catalina's
_pinw()
function mimicpinwrite()
from Spin2?Ill try that... Thanks for pointing that out.