Duplicating A 16-bit Timer At 16MHz
idbruce
Posts: 6,197
Hello Everyone
As many of you know, I am currently in the process of porting the 3D printer, Teacup Firmware, for use with the Propeller chip. Teacup was initially written to be utilized at a maximum clock speed of 20MHz, however 16MHz is enabled by default. To make matters worse, the step timer (timer for determing the step rate of the stepper motors) is based upon 16-bit, with a maximum value of 65535, before overflowing.
At the present time, my primary goal is to make the firmware functional for the Propeller chip. In order to avoid a severe slow down in the porting process, I would really like to avoid all the issues related to making it 80MHz compatible, at this point in time. To avoid these complications, I need to duplicate a 16-bit timer, running at 16MHz.
I was previously thinking about using a CTRA..... Now I am thinking perhaps just a function.... But I really don't know if it is possible with either one....
Any help, strategy, or guidance would be greatly appreciated with this issue.
EDIT: The existing source code is based upon a maximum value of 65535.
Bruce
As many of you know, I am currently in the process of porting the 3D printer, Teacup Firmware, for use with the Propeller chip. Teacup was initially written to be utilized at a maximum clock speed of 20MHz, however 16MHz is enabled by default. To make matters worse, the step timer (timer for determing the step rate of the stepper motors) is based upon 16-bit, with a maximum value of 65535, before overflowing.
At the present time, my primary goal is to make the firmware functional for the Propeller chip. In order to avoid a severe slow down in the porting process, I would really like to avoid all the issues related to making it 80MHz compatible, at this point in time. To avoid these complications, I need to duplicate a 16-bit timer, running at 16MHz.
I was previously thinking about using a CTRA..... Now I am thinking perhaps just a function.... But I really don't know if it is possible with either one....
Any help, strategy, or guidance would be greatly appreciated with this issue.
EDIT: The existing source code is based upon a maximum value of 65535.
Bruce
Comments
Since the step portion of the firmware has no idea about clock cycles, I suppose it really doesn't matter if I am off by several clock cycles, it just wants a value of 0-65535. So I could just divide 80000000 by 65535, thus equaling 1220 (rounded).
So I suppose I could do something like the following if I am not mistaken..
Offset = 80000000 / 65535
waitcnt(offset + CNT)
16_bit_clock_cycle++
if 16_bit_clock_cycle > 65535
16_bit_clock_cycle = 0
EDIT: No, thats wrong
The count of each cycle at 16MHz
Oh - basically, you just need a 16-bit version of the propeller's CNT register, but incrementing at 16 MHz instead of 80? Then you would access that 16-bit value in various other parts of code?
Thanks for the input. The problem with the CTRA, is that I have no free pins. Can the counter be used, even if the pin is unavailable? If not, would this do it?
waitcnt(clkfreq / 5 + cnt)
16_bit_clock_cycle++
if 16_bit_clock_cycle > 65535
16_bit_clock_cycle = 0
As mentioned in the post above yours, I have no free pins available, but that looks nice.
Yea, I have two other items on the I2C bus.
To make the CTRx overflow at the same frequency as a 16-bit timer running at 16 MHz, we need to set FRQx to ((2^31 - 1)/(2^16-1)) * (16,000,000 / 80,000,000). I think that math is correct anyway...
Once you have CTRx overflowing at the correct frequency, you just read from it by shifting 16 bits. This has no need for any pins. So long as your DIRA register of that cog isn't set to output for the APIN, you're good-to-go right?
Once again, I don't know the answer, but have wondered about that question in the past.
I truly hope that all is well with you and yours, haven't talked with you in quite some time.
Anyhow, thanks for your input. I was thinking along those lines a while back: http://forums.parallax.com/showthread.php/159950-The-Teacup-Port-A-Work-In-Progress-3D-Printer-Firmware?p=1317424&viewfull=1#post1317424
As I suggested before, use the simulator mode. The simulator mode uses the file simulator/timer_ext.c to simulate the AVR timer interrupts. The Teacup code calls the clock() routine periodically, which calls sim_time_warp() when the SIMULATOR flag is defined. sim_time_warp uses the C time functions to determine when it should call the two timer interrupt routines. Once you get it running in the simulator mode you can simplify the timer code by using CNT instead of the the C timer functions. Another nice thing about this approach is that everything runs in one cog. You won't have to worry about concurrency issues with the timer code running in another cog, and it saves you one cog.
Yes, I am suggesting that you start over, but I think you'll end up with cleaner code in the end.
Oh no..... I am not staring over
Even you said that I am close, and I am. I believe this is the last major obstacle to overcome, and from there it should be a downhill run.
I had to rest my head for a bit, but while I was laying there, I got to thinking.... This firmware has no concept of what frequency it is operating under.... The only requirement at this point is that the step delay be based upon a value between 0-65535. As long as I provide a value within that range, I think the only limiting factor will be the speed at which the machine can physically and electrically operate. In fact, as best as I can recollect, F_CPU is only utilized during movement and speed calculations. hmmmmm....... I will have to gack with you folks.
Theoretically, yes that would work. But waitcnt(5 + cnt) will fail I think. In assembly, I think the smallest number you can use is 9? or was it 13? in any case, it's larger than 5. And you're in spin, not assembly.
It would be if spin was fast enough, but by the time it saves the (6 + cnt) and gets to the waitcnt the cnt has passed that value so you end up with a 56 second wait.
Another note: When using waitcnt you need to use a sync point, otherwise you loop overhead will affect timing -- this is what you want:
Thanks for responding and thanks for the tip Jon. Now I wonder if Prop-GCC would be fast enough.
No. In PASM it takes 4 clock ticks per instruction -- you want to change something every 5 system ticks; there is not time. Using hardware (as the code your porting from did) is the answer.
Or... evaluate what was being done with that time and determine if you have to model it so directly. At 16MHz a 16-bit timer will roll-over 244 times per second. Is the rolloever period being used? In the original code is there a pre-scaler which would mean the counter is not in fact being incremented at a 16MHz rate.
No, what you actually want to do is drive some stepper motors and whatever other hardware bit banging.
That is the name of the game is it not, gcode in, stepper motor action out?
Rather than puzzling how to convert AVR time to Propeller time all that matters is what timing the motors require.
Which leads me to think you want a stepper motor driver. Probably running in a COG of it's own. I'm sure there are examples in obex.
As far as I can decipher at this point, they are just letting the clock rollover and then sutracting. E.G. next_step_time -= 65536;
Nope... There is no prescaler being used, so it is at 16MHz.
Yea, I suppose I could use an external timer somehow, but I am out of input pins. As far as modeling it so directly, well yea, it pretty much has to be accurate. My other option is atempt to go through all the math and make it 80MHz compatible I have been avoiding the math like the plague At least for now, but it is starting to look like I have no choice.
Heater
This code particularly deals with telling the the individual stepper drivers when to step, and it is all based upon mathematical formulas and algorithms utilized in the firmware. Nothing in the OBEX could possibly help me in this situation.
That does not require an emulation of an AVR timer. It only requires that whatever you do on the Prop can do the same thing with the same timing.