Duplicating AVR Interrupts With The Propeller
idbruce
Posts: 6,197
As everyone knows, I have recently admitted defeat in the battle of the Teacup port
It was a bloody battle.... I tore that code to shreds, and in return, the code tore me to shreds. I suppose it is needless to say that I underestimated my advesary, and that was a huge mistake on my part. Before going into battle against such a worthy opponent, it would have been wise of me to study my opponents tactics and preplan counter measures.
As Propeller enthusiasts, we might as well face the fact that we have been outflanked, at least for the moment. It is still my opinion, that the Propeller would perform much better than the AVR in a CNC environment, but the AVR has many years of coding support, for this particular application, and that coding support is based around the use of interrupts.
As it pertains to the Propeller, there is a plethora of existing C code that is most likely unusable, because of the use of interrupts within the existing code, and a lot of this code is open source, which means it is up for grabs. To extend all of our capabilities and open ourselves up to a much wider array of existing source code, as a team, we must find a valid solution to replacing these interrupts. It would be in all of our best interest to accomplish this task, and in my opinion, the sooner we accomplish this task, the sooner we will have access to many more capabilities.
Someone recently said, and I am paraphrasing, "Or you could roll up your sleeves and write you own". While I agree with this comment 101%, I do believe there are times when it is highly beneficial to just use someone elses work, such as the Teacup firmware, which has years of coding effort behind it, from several people. For one person to write similar firmware, they would be at the keyboard an awful long time.
So instead of rolling up our sleeves and spending years behind the keyboard, let's open ourselves up to a broader horizon, by overcoming the use of interrupts. Of course I am still jumping the gun, because I do not know my advesary very well or the tactics that may be implemented, but I do know that we need counter-tactics to the AVR cli() and sei() functions, interrupts, and the use of timers.
I am hoping that this will become a serious thread of discussion that works toward a solution of this problem.
It was a bloody battle.... I tore that code to shreds, and in return, the code tore me to shreds. I suppose it is needless to say that I underestimated my advesary, and that was a huge mistake on my part. Before going into battle against such a worthy opponent, it would have been wise of me to study my opponents tactics and preplan counter measures.
As Propeller enthusiasts, we might as well face the fact that we have been outflanked, at least for the moment. It is still my opinion, that the Propeller would perform much better than the AVR in a CNC environment, but the AVR has many years of coding support, for this particular application, and that coding support is based around the use of interrupts.
As it pertains to the Propeller, there is a plethora of existing C code that is most likely unusable, because of the use of interrupts within the existing code, and a lot of this code is open source, which means it is up for grabs. To extend all of our capabilities and open ourselves up to a much wider array of existing source code, as a team, we must find a valid solution to replacing these interrupts. It would be in all of our best interest to accomplish this task, and in my opinion, the sooner we accomplish this task, the sooner we will have access to many more capabilities.
Someone recently said, and I am paraphrasing, "Or you could roll up your sleeves and write you own". While I agree with this comment 101%, I do believe there are times when it is highly beneficial to just use someone elses work, such as the Teacup firmware, which has years of coding effort behind it, from several people. For one person to write similar firmware, they would be at the keyboard an awful long time.
So instead of rolling up our sleeves and spending years behind the keyboard, let's open ourselves up to a broader horizon, by overcoming the use of interrupts. Of course I am still jumping the gun, because I do not know my advesary very well or the tactics that may be implemented, but I do know that we need counter-tactics to the AVR cli() and sei() functions, interrupts, and the use of timers.
I am hoping that this will become a serious thread of discussion that works toward a solution of this problem.
Comments
It is an interesting task you present.
Well I think there will be a lot more involved than cog usage. I think it will be a combination of multiple cogs, flags, while loops, and functions. For example, let's say you have the main cog that runs it code until it comes to a place where a cli() or sei() would be, at which point, that cog would execute a while loop ending on flag value X. Just a thought.
Using that interrupt in the C program is more of a problem. How do you get it to stop executing the current code, save the state, and start executing the isr code? Simple enough to do with byte code where it could be done as part of the byte code interpreter, but how would that be done for C on the propeller? Seems like the folks at Parallax who are working on C would have to have a hand in it.
PS - I'm with SwimDude.
Okay, so you are both against the idea. I say consider ALL the available source code, not just one project or set of source code files. ALL of the source code which utilizes interrupts would probably be more than millions upon millions of hours of coding. Consider GitHub and ALL the AVR source code. By achieving a solution, ALL that code would be at our disposal.
One battle for millions of hours of coding..... Seems like it would be a worthy effort.
I say it would be time well spent.
You and I were typing and posting at approximately the same time, please refer to Post #6.
Teacup is just an example in this case. AVR is a quick solution for me, one purchase and I am done.
The point and goal of this thread is to promote a solution to all the available AVR source code, not just Teacup. One solution for numerous projects and firmware, instead of a solution for each piece of firmware.
By developing interrupt routines or a common workaround procedure, we gain access to a whole lot of currently unusable code, but still retain the extreme benefit of having an eight core processor. Now that sounds soooo much more appealing than a single core processor that runs on interrupts.
As stated below, "Necessity is the mother of invention."
- WE WANT MORE SOURCE CODE - WE WANT MORE SOURCE CODE - WE WANT MORE SOURCE CODE -
Chant with me
It would not work exactly the same.
It would probably be horrible slow,
There would still be a lot of work to do to adapt the Arduino code. Nobody would bother.
You would just be importing a huge tangled mess of unintelligible code to the Propeller world.
It's impossible
(No really)
I am a long way from being a C guru, and only have a bit of general knowledge about compilers so I am not sure if the effort would be worth it or not. My guess is that implementing simulated interrupts is possible with some effort. How much of those millions of hours of code become useful as a result is another matter. Seems like we loose all the advantages a multi core mcu to make use of software that makes very little use of it's potential. Better IMHO to learn from and use the existing code as a guide to create code more suited to the propeller.
I am not exactly sure where all this source code lies, but I do know that there is a lot of AVR code out there that rely upon the ISR timers. In my current case and in the case of most 3D printers, most variants are of RepRap, which is AVR based. You can find a lot of CNC code based upon the AVR, which utilizes the ISR timers. Other options are Linux, which I have not investigated.
Using Teacup as an example, there are two comparators, which are initialised as follows:
Source: Teacup Firmware
ComparatorB has the tasks of running clock_tick() and dda_clock(), basically this pops off every 2ms and has the tasks of updating various program time flags and updating the current position of all axes during a movement, as well as maintaining the current status of other variables. During this time frame, the ISR has control over these variables, which are in various locations throughout the firmware. This routine really isn't a HUGE issue, but still an important issue nonetheless.
ComparatorA has the task of telling an individual axis when to step, with the queue_step() function. Handling queue_step() is actually quite complicated, because it can be run both inside and outside of the interrupt service routines, or at least that is the way I understand it. Meanwhile, the queue is modified both inside and outside of the interrupt service routines, which further complicates the issues by many fold. Very complicated stuff, just to describe it.
My point is why not have the best of both worlds.
For example, let's say that you have a complicated task to perform, for which there is AVR source code readily available, but you also have other tasks that would be highly suited to work with individual cogs. Why not have the option of dedicating say perhaps three cogs to ISRs, and have the remaining five cogs available to do what ever you want.
For all those partaking in this discussion, I am not suggesting that the ISR limit our options, I am suggesting that they provide us with more options. Perhaps a single header and source code file may be all that is needed to add such type of support.
Making the prop use code written for interupts will be doing the hard way the hard way.
Consider writing a C compiler using your own version of BASIC writtien in SPIN. This might be considered the long way around the block.
You really should simply figure out your functional requirements up front, and write an application that does that. Code Re-use is very misunderstood, and gets folks in all kinds of trouble. Code re-use means "use it for reference" but as some point you actually have to do the effort of figuring out and understanding exactly what you are doing, and make sure you do that. Otherewise you end up pissing in the dark.
There are timer interrupts and there are pin state interrupts (I think these are called external interrupts). So much of the way the code gets converted to Spin or PASM depends on what the code is doing.
Some timer interrupts can be simulated with a waitcnt. Other timer interrupts are better simulated with "if nowTime - earlierTime > timeInterval" type of code.
Similarly the various external interrupts can be handled in a variety of ways. If the state of the pin change is fast, you may want to use a waitpxx statement (which will block the cog) alternately you many want to poll the pin. I know the standard way to read quadrature encoders with an AVR is to use pin interrupts while with a Propeller quadrature encoders are generally read by polling the input pins. However there are also quadrature encoder objects which use waitpxx statements. The best substitution depends on the specifics of the project.
As others have suggested, usually the Propeller offers an alternate way of accomplishing the same thing in a more elegant way than using interrupts.
A universal swallow-any-code solution is a mirage. - it is not only interrupts you seek to clone, it is the underlying peripherals as well.
However, porting code using PropGCC could have some 'assists', but all this is not really novice territory.
First step should be to extract from the AVR tools, all the interrupts, their Code sizes and the variables they use, and some indication of fire rates.
Main flow C code, does not know where/when the interrupts are, but it does interact via flags (see your example where the INT stops itself, expecting something else to restart).
There is scope to have AVR ISR() compiler directives guide a PropGCC user to a COG targeted compile, where you try to [pack/map one interrupt => one COG]
This is non trivial, as your example shows INTs calling other functions - if you are lucky they may be simple expanded in-line.
Obvious ceilings are when you run out of COGS, or run out of code space in any one COG.
C is supposed to be portable but that's possible when people add chip-specific code or use chip-specific libraries.
Another problem is that C was not designed for microcontrollers which tend to be very limited especially in memory.
C libraries tend to be large especially for things like Floating Point.
What library functions does Teacup need?
Do any of these already exist as Spin, PASM, or C?
As you said if this were on a PC then this would never be an issue.
Also you keep saying that you need more memory.
The Propeller can use an external EEPROM and there is already code for that including C.
The Hydra uses a 128K EEPROM since games require a lot of space for graphics.
As others have said if you want to cripple the Propeller then implement interrupts on it otherwise tell us what you need done and if it doesn't exist we can make something.
However, because C was designed on machines with very limited memory spaces, comparable to todays micro-controllers, and because it is basically a simple abstraction over what many computers actually do in hardware, it actually works very well for micro-controllers.
The success of the Arduino is a testament to that fact. C is used effectively with even smaller devices than that.
C on the Propeller is problematic. prop-gcc can compile to native code but then you are stuck with having to fit your code into 500 odd instructions. After that you need LMM to put the generated code into HUB space. Basically an interpreter. This is not nice because LLM slows execution down by a factor of 4 or more and the code space get's quickly eaten as all the instructions are 32 bits wide.
Basically the Propeller does not conform to the abstraction C is making. I believe this is true for all other compiled languages like Pascal, Ada, etc etc.