Using the video generator for SPI, i2s etc

I realized that It might be a good idea to share a piece of code that has been lying on my self for a couple of years now.
It's a video-generator-driven SPI driver. I think it's possible to use the same "trick" for other serial protocols as well. (i2s?)
The thing is that it's actually possible to do some crunching simultanesouly with an byte being transfered using the video generator.
In short it works like described below.
Each byte in a data stream is picked from a table in cog memory (address 0 - 255). Evey position in the table has got an 8bit value and the clock interleaved.
The video generator is then setup in certain way to output a clock signal on one pin and the bit stream on another pin.
I will soon upload something... stay tuned!
It's a video-generator-driven SPI driver. I think it's possible to use the same "trick" for other serial protocols as well. (i2s?)
The thing is that it's actually possible to do some crunching simultanesouly with an byte being transfered using the video generator.
In short it works like described below.
Each byte in a data stream is picked from a table in cog memory (address 0 - 255). Evey position in the table has got an 8bit value and the clock interleaved.
The video generator is then setup in certain way to output a clock signal on one pin and the bit stream on another pin.
I will soon upload something... stay tuned!
Comments
Because then I can't output both clock and data simultaneously without any pasm intervention.
I can simply do
wrByteData waitvid CISO, 0-0 ' Start writing a byte using the video generator (clock + serial data) do something while the video generator is busy writing a byte [B]COMPLETELY[/B] by itself wrNextByte waitvid CISO, 0-0
How long does the video generation technique take to start up and tear-down? - surely the PLL has to stabilise (haven't seen this mentioned in the manual - perhaps its very quick).
Give it some milliseconds to stabilize, but it is one time job.
The PLL is set at startup and isn't touched after that.
It's then up to the code to feed the video generator at a steady rate.
I was able to achieve true 20 Mbit from hub-RAM to SPI-RAM on my C3 without any hickups. when the PLL was aligned to the hub window.
I am pretty sure it's possible to do better than that with some clever unrolling in combination with rdlong. (of course, the SPI-RAM on the C3 can't handle more than 20 Mbit)
It was more than a year ago I did anything on this. First of all I have to locate the code somewhere on my drives.
Then I may have to do some code cleaning.
Thanks,
Ahle2 is talking about using the video generator to output SPI at 20Mhz while freeing the COG to do other work.
C.W.
I've been looking at the code for both FSRW and the FATEngine... and as far as I can tell they only bursts out bytes at 20 Mbit. The real continuous performance from hub RAM to SPI is far less.
I'm talking about a loop of "rdbyte-from-HUB-output-to-SPI-RAM" with a real bandwidth of 20 Mbit witouth any kind of hickup. That's impossible with the technique used in the objects you are talking about, because you can't read data from hub simultanously with an byte being sent.
Since the video generator obviously can't read data, I am not able to boost read performance though.
But I think it's possible to do more than 20 Mbit (hopefully 40 Mbit) for I2S and other "oneway protocols" with my technique. And that's where it's getting interesting.
This
writeSPISpeed movi frqa, #00_0000_0 ' Write out data. shl phsb, #1 ' shl phsb, #1 ' shl phsb, #1 ' shl phsb, #1 ' shl phsb, #1 ' shl phsb, #1 ' shl phsb, #1 '
Can be replaced with
[LEFT][COLOR=#3E3E3E][FONT=Parallax]waitvid CISO, 0-0 ' Writes a byte (both clock and data)[/FONT][/COLOR][/LEFT]
"0-0" can be any byte value and will point to the LUT.
Both clock and data are interleaved in the lookup.
Here's the code to generate the interleaved clk+data LUT from address 0 to 255
'----------------------------------------------------------- 'Pre-calculate spi-byte-data and interleave into the 32 bit LUT '----------------------------------------------------------- programStart mov count1, #255 precalcLoop1 mov tmpVal, count1 movd lutAddress1, count1 mov count2, #8 bitLoop shr tmpVal, #1 wc lutAddress1 rcl 0-0, #4 djnz count2, #bitLoop djnz count1, #precalcLoop1 mov 0, #0 '----------------------------------------------------------- 'Pre-calculate spi-clock-data and interleave into the 32 bit LUT '----------------------------------------------------------- mov count1, #255 precalcLoop2 movd lutAddress2, count1 movd lutAddress3, count1 mov dummy, #0 wz lutAddress2 muxnz 0-0, spiClkLowBits lutAddress3 muxz 0-0, spiClkHighBits djnz count1, #precalcLoop2 mov dummy, #0 wz muxnz 0, spiClkLowBits muxz 0, spiClkHighBits ' ' Further down ' ' spiClkHighBits long _10_00_10_00_10_00_10_00_10_00_10_00_10_00_10 spiClkLowBits long _00_10_00_10_00_10_00_10_00_10_00_10_00_10_00
The video generator is then initialized for 4 color VGA mode on pin group 1 (where the SPI pins are on the C3) and the pixel clock is set to 40 Mhz (since each spi clock equals two "pixels")
I will not provide code for this since it's the standard procedure
For it to work I need to setup the 4 "colors" as seen below.
' CISO stands for "Color In Spi Out" and can be seen as a lookup table to convert ' the 32bit interleaved SPI clk/data, "pixel data", to the corresponding SPI pins on the C3 ' 11 10 01 00 <- Incoming "Color" value ' | | | | CISO long 001010_00001000_00000010_00000000 '<- Outgoing SPI data on pin 8 and pin 10 (serial out and clock)
When everything is setup correctly, a simple
waitvid CISO, X
will send a full byte on the SPI bus.
X is the byte to send.
PCM1795DB seems like a good candidate for my experiments, has anyone tried it?
[h=1][/h]
No, but its got current outputs (needs dual RtR opamp on output), and has an SPI interface - the WM8759 is cheaper, is simpler to solder (SOIC14), can drive headphones directly and doesn't need any SPI programming so takes up fewer Prop pins.
I can almost buy 10 x WM8759 for the same price as one PCM1795DB. I think I will order 6 pcs for some experimentation!
I've got an MPC4922 (two channel 12 bit thru-hole DAC) hooked up via SPI to my SpinStudio board. I can successfully drive audio rate (48khz) through out, but only one channel. Once I get to two, the cog I'm using can't keep up and I have to drop the bitrate below 20khz. I'm doing this all in propgcc (C++ code, lmm mode FWIW.)
Anyways, came across this old post, and was wondering if the WAITVID technique is applicable here. Seems like a lot of the time in my loop is spent iterating the bits in the word to toggle the serial output line; seems like waitvid could be used to send all 16 bits per channel (or 32 bits for both channels?) at once?
Unfortunately I'm also a bit of a propeller newbie (have had this board for years and just learning it now) and PASM is unfamiliar to me, and the video generation hardware even more so.
Any tips on how to set up the video hardware for doing SPI this way? I'd _love_ to be able to push high bitrate audio out this way to the DAC.