I2S (LCD/parallel-mode + DMA) sends output buffer twice?
Posted: Thu Jun 08, 2017 6:42 pm
I seem to be experiencing a bug (or configuration error) that leads to incorrect/duplicate I2S data being transmitted. My DMA buffer is transmitted correctly (e.g. in my case 32 clocks edges == 32 16-bit samples in parallel mode) -- however the buffer is being transmitted twice (64 clock edges total, samples [0..32),[0..32)). This bug appears in the following configurations / memory layouts:
- 16-bit stereo (my preferred configuration)
- 16-bit single-channel
- 32-bit single-channel (simply ignoring the LSB and using the upper 16 bits)
- 32-bit stereo (not able to get this working -- clocks ~5-6 cycles for each new transmission then stops)
I have tried nearly all possible combinations of transmit/FIFO settings (everything I could find in the TRM and a few more undocumented bits), specifically the following relevant bits:
I have been implementing an LED matrix driver, using the I2S1 peripheral in the LCD mode, with tx_stop_en=1, and a periodic timer ISR to restart the transmission with a new DMA buffer.
What is going on here? Is this a real bug, or is this a mis-configuration? I am stopping the out_link.start/conf.tx_start transmission in the I2S isr, and then using out_link.restart with a new buffer address in the timer ISR to begin a new transmission. Maybe I am not resetting properly between transmissions? (or, am resetting something that should NOT be reset)
Please let me know if I should add waveforms or additional code to help understand the issue.
- 16-bit stereo (my preferred configuration)
- 16-bit single-channel
- 32-bit single-channel (simply ignoring the LSB and using the upper 16 bits)
- 32-bit stereo (not able to get this working -- clocks ~5-6 cycles for each new transmission then stops)
I have tried nearly all possible combinations of transmit/FIFO settings (everything I could find in the TRM and a few more undocumented bits), specifically the following relevant bits:
Code: Select all
I2S1.conf2.lcd_en = 1; // (need this for parallel mode)
I2S1.conf1.tx_pcm_bypass = 1; // (doesn't seem to make a difference in parallel mode)
I2S1.conf_chan.tx_chan_mod = 0x0; // (also tried 0x1, 0x2, 0x3 -- not too much changed)
I2S1.fifo_conf.tx_fifo_mod = 0x0; // (also tried 0x1, 0x2, 0x3)
I2S1.conf2.lcd_tx_wrx2_en = 0; // (also tried 1, no change)
I2S1.conf2.lcd_tx_sdx2_en = 0; // (also tried 1, this sends each sample twice as documented: not what I want)
I2S1.fifo_conf.tx_data_num = 32; // (doesn't seem to make a difference most of the time, occasional garbage transmitted if set wrong e.g. [16, 0, 63...])
I2S1.sample_rate_conf.tx_bits_mod = 16; // (tried with 32, requires memory layout change to get the data correct, but still sends the data out twice)
I2S1.sample_rate_conf.tx_bck_div_num = 1; // (also tried with 2)
dma_desc.length = 32 * sizeof(uint16_t); // (buffer size in bytes. I expected 32 clock cycles/samples from this, but got 64. If I set it to 32, then I expect 16 samples but I see 32, the second half are duplicated. This is the weirdness.)
dma_desc.size = 32 * sizeof(uint16_t); // (ditto)
What is going on here? Is this a real bug, or is this a mis-configuration? I am stopping the out_link.start/conf.tx_start transmission in the I2S isr, and then using out_link.restart with a new buffer address in the timer ISR to begin a new transmission. Maybe I am not resetting properly between transmissions? (or, am resetting something that should NOT be reset)
Please let me know if I should add waveforms or additional code to help understand the issue.