2024-01-08 07:26 AM - last edited on 2024-01-23 04:50 AM by Imen.D
Hello,
I have this code
// Initialiser le bloc A
fresult= HAL_SAI_Init(&hsai_BlockA1);
if (fresult != HAL_OK)
{
return HAL_ERROR;
}
// Initialiser le bloc B
fresult= HAL_SAI_Init(&hsai_BlockB1);
if (fresult != HAL_OK)
{
return HAL_ERROR;
}
// Transmission
fresult = HAL_SAI_Transmit(&hsai_BlockB1, (uint8_t *)playbuf, (sizeof(playbuf))/4, 0xFF);
if (fresult != HAL_OK)
{
return HAL_ERROR;
}
// Reception
fresult = HAL_SAI_Receive(&hsai_BlockA1, (uint8_t *)playbuf_RX, (sizeof(playbuf_RX))/4, 0xFF);
if (fresult != HAL_OK)
{
return HAL_ERROR;
}
I am not receiving some of the data, do you know where I can find the documentation to implement SAI blocking mode? thanks in advance.
In my reception array I have only a part of data, and yet my TX table is well initialized like this :
2024-01-10 01:57 AM
Yes you're right, but when I don't know where to start then it seems a little confusing. Thank you for this verification method.
2024-01-16 04:50 AM
Hi,
I tried to set up the circular buffer. Here is my code :
while (1)
{
/* USER CODE END WHILE */
Reset_playbuf_RX();
HAL_Delay(1);
if (dataReadyFlag)
{
processData();
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
To be sure that my RX table is cleared with each call, I reset it all to 0. In my callback I set a flag to 1 and then I proceed with the transfer.
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
dataReadyFlag=1;
}
void processData ()
{for (int32_t n=0; n<8192; n++)
{playbuf_RX[n]=playbuf[n];}
HAL_Delay(1);
}
void Reset_playbuf_RX()
{static int32_t j;
for (j=0;j<8192;j++)
{playbuf_RX[j]=0;}
HAL_Delay(1);
}
But something is wrong, in my playbuf_RX array is never reset to 0 yet I enter it in the void Reset_playbuf_RX function.
Probably it runs continuously via the DMA and I don't have control of the playbuf_RX?
fresult = HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t *)playbuf_RX, (sizeof(playbuf_RX))/4);
if (fresult != HAL_OK)
{return HAL_ERROR;}
When I look at my LRCLK :
And on the TX signal, I have signals that run continuously
How to recover the transmitted signals ? I certainly forgot some functions but what ? Thank you for your advice
2024-01-16 07:06 AM
1) So TX is running continuously? If yes, great!
Now better check that with both LRCK and TX data at the scope, with trigger on LRCK, just to make sure...
2) Your code:
a) dataReadyFlag is set at HALF complete. Why?
b) dataReadyFlag is reset where?
c) I wonder why you ever see playbuf_RX[] not = 0, because your while loop makes no sense.
What your while loop does:
- START: reset playbuf_RX[] = 0
- wait 1 ms
- if dataReadyFlag is set in HALF complete, then you copy playbuf (the DAC buffer?) into playbuf_RX, basically overwriting what the DMA put in there
- and then, 1 ms later you go to START and reset playbuf_RX again
This makes NO sense at all and you're really molesting the DMA buffer by constantly resetting and copying - or I just don't get it.
Here's my suggestion:
1) set dataReadyFlag in RX full complete callback, not in half complete
2) in while loop start only with this, reset the flag, count, toggle an LED
uint32_t cntRxTest = 0;
while(1)
{
if( dataReadyFlag != 0 )
{
dataReadyFlag = 0;
cntRxTest++;
toggle_LED;
}
}
If that is working, maybe reset the playbuf_RX to zero within the if statement.
Maybe make the buffer smaller so that the resetting is done within one sample duration.
2024-01-17 12:21 AM - edited 2024-01-17 03:41 AM
Hi,
Thank you for your comments
I don't understand where the DMA data is stored ? In my configuration SAI1_A (the slave : CODEC)
Peripheral : SAI_RX
Memory : ? Where and how to read this datas when the Flag RX =1 (HAL_SAI_RxCpltCallback, I make a mistake here).
For the Delay (1), it's just being able to make a breakpoint and see if the playbuf_RX table is indeed reset to 0 for the next acquisition, and it's probably not a good method because I'm 'really molesting the DMA buffer' but how to make sure if the data is transmitted correctly when Flag =1 (RxCpltCallback) ? you may lose a frame of data but then you will have a complete frame, right ?
I have 2 signals (blue : data (probe x10). yellow : LRCLK)
2024-01-17 04:13 AM
> I don't understand where the DMA data is stored ?
You should at least read the HAL source function descriptions.
Then you would find for HAL_SAI_Receive_DMA
HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t *)playbuf_RX, (sizeof(playbuf_RX))/4);
playbuf_RX (= memory) is the data buffer you hand over to the DMA, and that's where DMA writes the data it gets from the SAI RX peripheral.
That's why I said it does not make sense to constantly "work" on this buffer.
Scope:
Your scope does NOT show LRCK ( = FS in STM lingo), but probably SCLK ( = CK or so, the bit clock).
LRCK frequency equals the sampling rate, and within one half period you should see one data sample.
If you have 3 channels, then simply add LRCK, and trigger on that.
2024-01-17 07:49 AM
For the scope you're right about FS (yellow) Data (blue) now I have this :
Now I understand better what DMA and memory are. A confusion on my part however, I think that we need a way to check that what we have received corresponds to the transmission. Maybe a pointer to this playbuf_RX array so as not to slow down DMA reception ?
2024-01-17 08:10 AM
Scope: now that looks better!
I guess that there's some up-counting going on, because only the LSBs are changing.
LRCK ~= 36 kHz - is that what you expected from your SAI TX settings?
At 36 kHz, one sampling period is about 27 µs. Check how many buffers you could read or reset within that time, depends on your CPU clock. As a rule of thumb, take factor 4 for each for loop iteration.
To get more "time" to read the buffer, you could now use both the HALF and the complete interrupts:
- at HALF you set half flag within ISR
- in the loop check half flag, if set copy 1st half of the buffer
- at complete set another flag within ISR
- in the loop check complete flag, if set copy 2nd half of the buffer
A pointer is basically an address, so if you want to check what's the content of that address, it doesn't really make a difference concerning the buffer access.
2024-01-18 02:18 AM
Hi,
Thank you very much for this very useful information (at least for me). I think after my configuration the LRCL is correct (Real Audio Frequency ?) :
I don't know how long it will take to read the receive memory but for this loop for example :
void Reset_playbuf_RX()
{static int32_t j;
for (j=0;j<8192;j++)
{playbuf_RX[j]=0;}
}
I think my CPU clock is 32.768 kHz about 30 µs.
2 instructions x 8192 x 27 µs = 0.44 s x 4 (factor) = 1.7s. I think the best method is to do is to read 2 halfs buffers, I'll modify the configuration via '.ioc' to do it. I'll see how to deal with interruptions.
2024-01-18 03:12 AM
> I think my CPU clock is 32.768 kHz about 30 µs.
Hopefully not!
Maybe find some basic tutorial about STM32 / clock setup.
What you show is the LSE, which stands for Low Speed External clock, that should only / mostly be used for a real time clock (RTC).
Your CPU clock should at least be in the MHz range, which STM32 type + board are you using?
CPU clock source should be somewhere from HSI (not good for audio due to jitter) or HSE.
So again, at HALF complete interrupt:
- set half flag within ISR
- in the loop check half flag, if set:
- copy 1st half of playbuf_RX to checkbuf_RX, or simply compare to the TX buffer
- reset 1st half of playbuf_RX
at full complete interrupt same with 2nd half of buffer
2024-01-18 05:27 AM
Hi,
After reading some information about the clock I understand a little better. My CPU clock is 16 MHz
For the moment my objective is just communication by SAI, after of course I need to optimize my electronic board. I have an evaluation board : STM32L552E-EV with STM32L552ZET6QU microcontroller. I understand the 'HALF complete interrupt' after your explanation and I'll implement with this method. You're right, I've to reduce the size of my array just to see at first, for example an array of 100 values.