shift out with CTR
Bobb Fwed
Posts: 1,119
A while back I asked how it can be done, but I never got a straight answer.
I've looked at other peoples' code that have done it, but it is always somewhat hard to decipher CTRs (at least for me...I've never been good with them).
I am trying to shift out a 5-bit value. It should use both CTRs (one for the serial data, one for the clock), I am assuming.
Preferably, it would run at a specific speed (regardless of current clock speed -- but it has to be outputting at a max of about 2MHz).
Any help would be nice. About all I know is that the first CTR would be NCO mode, but controlling the speed and setting up the second CTR so it would output clock pulses between the first CTR's data changes....it escapes me.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
I've looked at other peoples' code that have done it, but it is always somewhat hard to decipher CTRs (at least for me...I've never been good with them).
I am trying to shift out a 5-bit value. It should use both CTRs (one for the serial data, one for the clock), I am assuming.
Preferably, it would run at a specific speed (regardless of current clock speed -- but it has to be outputting at a max of about 2MHz).
Any help would be nice. About all I know is that the first CTR would be NCO mode, but controlling the speed and setting up the second CTR so it would output clock pulses between the first CTR's data changes....it escapes me.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
Comments
For me to understand counters, I had to think about the relationship of FRQx ("Frequency Register") and PHSx ("Phase Register") (I'll just use A for example). The entire job of counter A is to add FRQA to PHSA at certain times, and optionally control 0 or 1 or 2 output pins. Table 6 in the propeller datasheet shows when FRQA will be added to PHSA. In the NCO counter mode, the counter will ALWAYS add FRQA to PHSA (this means at each clock tick, so if you are using a 5MHz crystal and PLL16X, then the counter is doing the accumulation at 80MHz). But the second half of its job is to set the A pin (which you specify when setting the CTRA ("Control Register") register in bits 5..0) to whatever bit 31 is of PHSA.
Now, the trick to shifting data out using the NCO counter mode is to set FRQA to 0, so PHSA never actually gets updated by the counter. However, the counter is still busy doing its job of making sure the A Pin is set to the high bit of the PHSA register. So, to shift out the value we want, we can just load PHSA up with our value, then ROR or ROL the PHSA register a bunch of times, and each time we move a new bit into the PHSA[noparse][[/noparse]31], the counter mirrors that on pin A.
You need to make sure you keep your data line and your clock line in sync. I use both counters where one controls the CLK line and one controls the DataOut line to shift out one bit per instruction (using Propeller Assembly...Spin is too slow and non-deterministic for this to work). However, when you do it this way, you do not get to set the actual clock-out speed...it is a function of the clock speed of the propeller. So running at 80MHz means that the data will be clocked out at 20MHz. If you use PLL8X, then suddenly the data rate is now 10MHz. There isn't an easy way to throttle back the speed using the 2 counters technique.
So you will probably want to use a combination of setting the clock line high and low using a single PASM command each, shift out the data using the NCO counter mode trick, then use a waitcnt to throttle back the speed. If you are running at 80MHz and you want to hit 2MHz clock output rate, then you get to use 10 instructions per bit out (20 MIPS / 2 MHz). You could easily do something like the following (untested) code:
Note that this assumes you want to shift the data out LSB first, and that you set up the counter and phsa and the timing values ahead of time. There is most likely a way to use the video generator, but I have not looked into it at all.
hth,
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
Post Edited (lonesock) : 7/24/2009 7:42:12 PM GMT
You can't use the PLL divider on NCO (or am I not understanding how that works as well).
Here is the code I am using now:
Same number of instructions as your code (not using the CTRs).
I just want a little faster. Maybe output at full speed as long as the clock pin is being controlled by the CTR.
I realize now though that this code is 4MHz (at 80MHz clock). That's twice as fast as the datasheet says the MCP3208 should be able to handle...yet not a single problem; but hey, I always want to go faster! If it is running this fast at 3.3V, it should be able to go about 80% faster at 5V.
Ultimately I could all but ignore CTRs if the propeller did a (nowadays, normal) single-cycle execution of it's ASM code.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
By using a counter as a shift register, you eliminate the need for the MUXC. That saves one instruction. You can also unroll your loop to save the DJNZ. Lonesock's code was as long as yours, because he paced it with a waitcnt, which you did not do.
-Phil
To clarify, I would do something like this:
or
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
I see you've gone back to the loop form, so apparently you don't need it to be any faster than it is. If you had, though, there's a way to send the clock pulse in one instruction, rather than two.
I'm a little bit curious, though: why, if you're starting and stopping an entire cog just to send five bits, do you need the transfer itself to be so fast?
-Phil
and the second counter to send out the clock waveform at 2MHz (for e.g.).
Make sure your 1st data bit is ready to go in PHSA[noparse][[/noparse]31], then set the clock
line high and start your CLK counter. Then in your loop:
If I did that right, the cog will hang until your clock line goes low, then will
move out the next data bit.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
-Phil
That was just me testing ... seeing if I could get something remotely what I wanted to come out.
It is actually (now) already implemented in my MCP3XXX driver: obex.parallax.com/objects/488/ without loops...so ends up being 3 instructions per output bit.
@Phil: That also sounds fast, and there are things I could use on the outgoing and incoming data.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!
Don't forget to shut CTRB down when you're done sending data, or set FRQB to 0. Otherwise, after about 25 seconds, it will send a positive-going edge on its own.
-Phil