2021-07-19 02:14 PM
Hey Guys,
I'm struggling to figure out how to stream sine waves at a constant frequency for 8 channels. Each channel has its own sine wave frequency. The issue I'm having is how to stream all these at the same time. I created an array for each sine wave frequency. I thought to use DMA, but the issue is that I have to combine two sine waves into one array with different length of samples. So is there a way for the DMA to interleave two arrays of different lengths into one I2S module?
I can't seem to find an answer for this.
I'm happy with just using interrupts (if fast enough) if the DMA will not work. For interrupt function :HAL_I2S_Transmit_IT(), would I be able to use the Tx FIFO from this function to send 2, 16 bit data at once. (left and right sample) for each DAC
Interrupt code would look like the following:
while(1)
{
HAL_I2S_Transmit_IT(&hi2s1, &NorthSpeakerSamples[NS_S], 1); // these two functions would have to be combined to work properly.
HAL_I2S_Transmit_IT(&hi2s1, &SouthSpeakerSamples[SS_S], 1);
HAL_I2S_Transmit_IT(&hi2s2, &EastSpeakerSamples[NS_S], 1);// these two functions would have to be combined to work properly.
HAL_I2S_Transmit_IT(&hi2s2, &WestSpeakerSamples[SS_S], 1);
HAL_I2S_Transmit_IT(&hi2s3, &NorthCoilSamples[NS_S], 1);// these two functions would have to be combined to work properly.
HAL_I2S_Transmit_IT(&hi2s3, &SouthCoilSamples[SS_S], 1);
HAL_I2S_Transmit_IT(&hi2s6, &NorthCoilSamples[NS_S], 1);// these two functions would have to be combined to work properly.
HAL_I2S_Transmit_IT(&hi2s6, &SouthCoilSamples[SS_S], 1);
}
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
//NS_S, SS_S, ES_S, WS_S ; // NorthSpeaker_Sample, South..etc...
// NC_S, SC_S, EC_S, WC_S ; // NorthCoil_Sample, South..etc...
// NS_Snum, SS_Snum, ES_Snum, WS_Snum ; // NorthSpeaker_SampleNumberOfSamples, South..etc...
// NC_Snum, SC_Snum, EC_Snum, WC_Snum ; // NorthCoil_SampleSampleNumberOfSamples, South..etc...
if(hi2s==hi2s1)
{
if (NS_S<NS_Snum) ++NS_S; else NS_S=0;
if (SS_S<SS_Snum) ++SS_S; else SS_S=0;
}
}
2021-07-19 02:29 PM
> So is there a way for the DMA to interleave two arrays of different lengths into one I2S module?
The I2S can only be sending out one stream of data. You'll need to combine the channels somehow. You can do this dynamically on the half- and full-transfer complete callbacks, but it would take some processing power.
The audio DAC datasheet should specify how it expects each channel to come in. You'll need to rearrange them on the STM32 side such that they're sent out in the correct order.
2021-07-19 02:34 PM
Hi TDK,
Thanks for your quick reply.
For the function HAL_I2S_Transmit_IT(), will this function let me send 4 bytes to the SPI/I2S Tx FIFO?
Kevin
2021-07-19 02:51 PM
2021-07-19 02:53 PM
ok great. I thought sending more than one sample would end up in blocking-mode.
Thanks!
2021-07-19 04:56 PM
Let see, If I define a DMA buffer 4096, than for freq. 47.1:
4096 / 47.1 = 86.963906582. Rounding up to get integer number of sinewave periods, I would get
4096/ 87 = 47.08045977 Hz.
Stuffing 43.7Hz into the same array, composing 32-bits words where 16-bits 1 channel & 16-bits for another,
4096/ 43.7 = 93.729977117
4096/ 94 = 43.574468085 Hz
The question is if it acceptable error. If not, DMA buffer should be bigger.
For lower freq. error is also lower. It also possible to manage 4 arrays different sizes, making error approximately the same along freq. scale.
2021-07-19 05:31 PM
yes that part is fine, but how to interleave left and right channels on I2S DAC? 16 bits left, 16 bits right, 16 bits left, 16 bits rights, etc...
2021-07-19 06:08 PM
You synthesize two sinewaves in (uint16_t) pre_buffer1[4096] & (uint16_t) pre_buffer2[4096]. Than combine into (uint16_t) out[8192]:,
uint16_t indxb = 0;
for( int i = 0; i < 4096; i++) {
temp = waves1[i];
out[indxb++] = temp;
temp = waves2[i];
out[indxb++] = temp;
}
This part could be done on a desktop computer, and integrated to stm32 software as const uint16_t Look Up Table (LUT).
2021-07-19 06:14 PM
Yes, but each sine wave has different number of samples for 1 complete cycle. I need both sinewaves to repeat continuously with no hiccups/breaks in it.
2021-07-19 06:26 PM
Look my first replay. 87 and 94 intentionally rounded to integers numbers, making exact number of periods per 4096 samples. Number of samples per period of sinewave is not important, it's like DDS.
Having 87 and 94 periods sharp would allow smooth transition from the end of buffer to start again in circular mode DMA. No glitches.