Yikes, It's been a while since I last posted. GTA5 got in the way, then I got very bored of GTA5 and then I played Skyrim all the way through again to get my head right. GTA5 has almost zero re-play appeal.
Anyway...
For no good reason I wanted to see how fast I could signal asynchronous serial data from a single Cog on a Propeller chip. Like one does.
Studious observers might realise that I'm aiming for minimal code-space usage. This code is pretty compact but I think I can do better.
In fact I think I can reach much faster Baud rates. This code is limited by the waitcnt instruction, which is a little cumbersome when one is trying to wring out every last instruction cycle from a Cog.
By using one or both of a Cog's Counter features (CNTA and CNTB), it might be possible to get something close to 18 MBit of UART speed! This will be at the expense of code size though.
It is interesting to note that Mr Nyquist's observations determine that TX and RX do not necessarily share the same theoretical maximum baud rate. TXing is stateless (effectively) but RXing is stateful because we need to be able to notice edge transitions and compare them to the bit rate we are expecting. Even if I can hammer out TX rates of 18MHz, I'll probably be limited to RX rates of about a quarter of that, maybe less.
Science!
Anyway...
For no good reason I wanted to see how fast I could signal asynchronous serial data from a single Cog on a Propeller chip. Like one does.
CON
_clkmode = XTAL1 | PLL16x
_clkfreq = 5_000_000
PUB Main
coginit(0, @ENTRY_POINT, 0)
DAT
org 0
ENTRY_POINT
or outa, TX 'idle high
or dira, TX 'output
mov byte_to_send, #$41
CALL #SERIAL_SEND_BYTE
mov byte_to_send, #$42
CALL #SERIAL_SEND_BYTE
mov byte_to_send, #$43
CALL #SERIAL_SEND_BYTE
mov byte_to_send, #$44
CALL #SERIAL_SEND_BYTE
mov byte_to_send, #$45
CALL #SERIAL_SEND_BYTE
mov byte_to_send, #$46
CALL #SERIAL_SEND_BYTE
waitpeq $, #0 'hang forever
SERIAL_SEND_BYTE mov ser_bitcount, #10 '8 data bits + start bit + stop bit == 10 bits total to send
mov ser_bitbuf, byte_to_send
or ser_bitbuf, #%1_00000000 '(binary) append the stop bit (we're sending this data LSB first don't forget!)
shl ser_bitbuf, #1 'prepend the start bit (shl shifts in a zero bit on the LSB)
mov ser_time, cnt
add ser_time, #30 '30 clock cycles == approx 2_666_667 baud at 80_000_000MHz !
:ser_loop rcr ser_bitbuf, #1 WC
muxc outa, TX
waitcnt ser_time, #30 '30 clock cycles == approx 2_666_667 baud at 80_000_000MHz !
djnz ser_bitcount, #:ser_loop
SERIAL_SEND_BYTE_ret ret
TX long |< 4
ser_time res 1
ser_bitcount res 1
ser_bitbuf res 1
byte_to_send res 1
fit
As long as you have a 5MHz external crystal on the Prop then you should have something pretty close to 2666667 Baud serial output on pin P4 (crystal accuracy does matter at these speeds!). If not then you'll want to change the "#30" constants to alter the baud rate (keep both values the same and you'll be fine) to compensate for your chosen clock speed.Studious observers might realise that I'm aiming for minimal code-space usage. This code is pretty compact but I think I can do better.
In fact I think I can reach much faster Baud rates. This code is limited by the waitcnt instruction, which is a little cumbersome when one is trying to wring out every last instruction cycle from a Cog.
By using one or both of a Cog's Counter features (CNTA and CNTB), it might be possible to get something close to 18 MBit of UART speed! This will be at the expense of code size though.
It is interesting to note that Mr Nyquist's observations determine that TX and RX do not necessarily share the same theoretical maximum baud rate. TXing is stateless (effectively) but RXing is stateful because we need to be able to notice edge transitions and compare them to the bit rate we are expecting. Even if I can hammer out TX rates of 18MHz, I'll probably be limited to RX rates of about a quarter of that, maybe less.
Science!