I2S interfacing with the Prop2
Mark_T
Posts: 1,981
I've been looking at using Smartpins to generate I2S bus signals (initially for a DAC using synchronous serial tx).
My sample code is below, but I suspect there is more than one way to skin this particular cat (so to speak) with all the features
in the P2.
I've assumed that the Prop will be the bus master (so generating all the clocks), which I think is reasonable for most scenarios.
Things I wonder about include:
How best to handle an audio stream on the P2?
Can the streamers talk directly to synchronous serial smart pins?
Would FIFO reads and writes be best?
How to architect a system where an ADC will go through one or more cogs for DSP operations like digital filtering,
volume control, monitoring, and then out to a DAC again?
Is support for multiple ADCs or multiple DACs useful?
5.1 signal processor feasible?
How well would using the Prop2 ADC inputs work for quality audio (for feeding to an I2S DAC perhaps) - good enough
to implement a THD meter?
Can the Prop2 clock PLL scale to 196.608MHz? Would it be stable?
On the P1 things are sufficiently constrained that there are fewer choices/possibilities available.
I presume that synchronous serial RX will work well for ADCs, but so far I've only been looking at the 'scope screen
and getting outputs working. One nice thing is that its trivial to change the speed, so long as CLKS_PER_BIT is
a multiple of 8, since the bit timing is all handled in hardware. I think I managed upto 8x 39.0625kHz sample rate.
I've used 6.144MHz/12.288MHz xtals with Prop1 to run at 98.304MHz (power of two times 48kHz, the commonest I2S rate), but
I wonder if that's really necessary given the more flexible PPL.
[ incidentally I discovered the first bit shifted out in synchronous serial mode doesn't seem to last for the full duration, so the timing
is thrown by about one bit time. After its started it all runs in lockstep with WAITCT1 nicely though ]
My sample code is below, but I suspect there is more than one way to skin this particular cat (so to speak) with all the features
in the P2.
I've assumed that the Prop will be the bus master (so generating all the clocks), which I think is reasonable for most scenarios.
Things I wonder about include:
How best to handle an audio stream on the P2?
Can the streamers talk directly to synchronous serial smart pins?
Would FIFO reads and writes be best?
How to architect a system where an ADC will go through one or more cogs for DSP operations like digital filtering,
volume control, monitoring, and then out to a DAC again?
Is support for multiple ADCs or multiple DACs useful?
5.1 signal processor feasible?
How well would using the Prop2 ADC inputs work for quality audio (for feeding to an I2S DAC perhaps) - good enough
to implement a THD meter?
Can the Prop2 clock PLL scale to 196.608MHz? Would it be stable?
On the P1 things are sufficiently constrained that there are fewer choices/possibilities available.
' Smartpin I2S DAC driver proof of concept, 3 smartpins for MCLK, BCLK, DOUT, plus LRCLK bit-banged ' Mark Tillotson 2019-01-12 CON OSCMODE = $010c3f04 FREQ = 160_000_000 NCO_FREQ =%0000_0000_000_00000_00000000_01_00110_0 SYNC_TX = %0000_1001_000_00000_00000000_01_11100_0 ' sync serial tx using pin+1 as clk DOUT_PIN_NUM = 48 CLOCK_PIN_NUM = DOUT_PIN_NUM + 1 MCLK_PIN_NUM = 50 LRCLK_PIN_NUM = 51 ' must be a multiple of 8 for MCLK = 4*BCLK CLKS_PER_BIT = 64 ' for 39.0625kHz samplerate (1.5MHz bitclk) (would be 48kHz for sysclk = 12.288MHz x 16) ' 40 will give 62.5kSPS at 160MHz sysclk PUB demo | i, a clkset(OSCMODE, FREQ) pausems (1000) ' time for 'scope capture setup cognew (@tx_output) repeat pausems (1) DAT org 0 tx_output wrpin ##NCO_FREQ, #CLOCK_PIN_NUM wxpin ##CLKS_PER_BIT/2, #CLOCK_PIN_NUM ' every 64 cycles (32 instructions), bit clock wypin ##$80000000, #CLOCK_PIN_NUM ' toggle every other wrpin ##NCO_FREQ, #MCLK_PIN_NUM wxpin ##CLKS_PER_BIT/8, #MCLK_PIN_NUM ' every 16 cycles (8 instructions), master clock wypin ##$80000000, #MCLK_PIN_NUM ' toggle every other dirh ##CLOCK_PIN_NUM dirh ##MCLK_PIN_NUM ' start clocks together mov left, ##$80FFF000 ' test pat with bot 8 bits zero mov t, left rev t shl t, #1 dirh lrclk_pin wrpin ##SYNC_TX, dout_pin wxpin ##%011111, dout_pin wypin t, dout_pin GETCT time dirh dout_pin ADDCT1 time, idelay outl lrclk_pin jmp #.skipy ' compensate for truncated first bit shifted by smartpin sync serial mode .loop ' left channel outl lrclk_pin ' drive left/right clock .skipy WAITCT1 ADDCT1 time, delay sub right, #$37 ' testing pattern, 31 bits used, decrementing mov t, right ' preload right rev t shl t, #1 ' I2S justification, top bit is delayed 1 place wypin t, dout_pin WAITCT1 ADDCT1 time, delay ' right channel outh lrclk_pin ' drive left/right clock WAITCT1 ADDCT1 time, delay add left, #$100 ' testing pattern, strictly 24 bits mov t, left ' preload left rev t shl t, #1 wypin t, dout_pin WAITCT1 ADDCT1 time, delay jmp #.loop left long 0 right long 0 lrclk_pin long LRCLK_PIN_NUM dout_pin long DOUT_PIN_NUM delay long 16 * CLKS_PER_BIT idelay long 15 * CLKS_PER_BIT time res 1 t res 1
I presume that synchronous serial RX will work well for ADCs, but so far I've only been looking at the 'scope screen
and getting outputs working. One nice thing is that its trivial to change the speed, so long as CLKS_PER_BIT is
a multiple of 8, since the bit timing is all handled in hardware. I think I managed upto 8x 39.0625kHz sample rate.
I've used 6.144MHz/12.288MHz xtals with Prop1 to run at 98.304MHz (power of two times 48kHz, the commonest I2S rate), but
I wonder if that's really necessary given the more flexible PPL.
[ incidentally I discovered the first bit shifted out in synchronous serial mode doesn't seem to last for the full duration, so the timing
is thrown by about one bit time. After its started it all runs in lockstep with WAITCT1 nicely though ]
Comments
Nice to see interest in this topic!
Some months ago I bought a 6 channel analog amplifier, 6 speakers, 3 I2S modules (two channels per module) and a spdif-to-6-analog-out module (6 ch in DTS/DD mode) for doing exactly these kind of things on the P2. The plan is to have a cogdriver that can take multiple audio input streams, mix them together (pan, gain, sample rate conversion, antialaising) and output to smart pins, I2S or spdif with up to 6 out channels (think 5.1 setup). In spdif mode it is only realistic to have 2 out channels though, since realtime DD/DTS encoding is CPU heavy and complex. Having a pure sound driver/mixer in one cog and doing audio input and DSP in others is the best way to go I think. Then there needs to be some kind of hub mechanism to synchronize data producing cogs with the sounddriver/mixer cog.
not yet tested on a live DAC.
Think it might be time to spin up a 64000 extension/accessory board with I2S ADC + DAC