2020-06-07 02:25 PM
Hi :)
I am trying to play audio from an SD card to the built-in DAC of my Nucleo-F446RE.
I am using DMA, and one buffer of 10240 size, which I want to update continuously using the Transfer Complete / Half Complete callbacks.
The code is quite simple, I simply use the callback to update one half of the buffer while the DMA sends the other half.
#define BUF_SIZE 10240
#define BUF_HALFSIZE (BUF_SIZE/2)
uint8_t llfta_buf[BUF_SIZE];
uint8_t rlfta_buf[BUF_SIZE];
volatile uint8_t updateCh1Part1 = 0, updateCh1Part2 = 0, updateCh2Part1 = 0, updateCh2Part2 = 0;
[...]
int main(void) {
[...]
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)llfta_buf, BUF_SIZE, DAC_ALIGN_8B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t*)rlfta_buf, BUF_SIZE, DAC_ALIGN_8B_R);
HAL_TIM_Base_Start(&htim6);
while (1)
{
UINT readBytes;
if (updateCh1Part1) {
updateCh1Part1 = 0;
f_read(&SDFileLFTALeft, llfta_buf, BUF_HALFSIZE, &readBytes);
}
if (updateCh1Part2) {
updateCh1Part2 = 0;
f_read(&SDFileLFTALeft, llfta_buf+BUF_HALFSIZE, BUF_HALFSIZE, &readBytes);
}
if (updateCh2Part1) {
updateCh2Part1 = 0;
f_read(&SDFileLFTARight, rlfta_buf, BUF_HALFSIZE, &readBytes);
}
if (updateCh2Part2) {
updateCh2Part2 = 0;
f_read(&SDFileLFTARight, rlfta_buf+BUF_HALFSIZE, BUF_HALFSIZE, &readBytes);
}
}
}
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef* hdac)
{
updateCh1Part2 = 1;
}
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef* hdac)
{
updateCh1Part1 = 1;
}
void HAL_DAC_ConvCpltCallbackCh2(DAC_HandleTypeDef* hdac)
{
updateCh2Part2 = 1;
}
void HAL_DAC_ConvHalfCpltCallbackCh2(DAC_HandleTypeDef* hdac)
{
updateCh2Part1 = 1;
}
I can see in the debugger that the actual buffer gets updated, as it should, but the DAC keeps sending the values that were in the buffer in the first place.
Is that maybe not the wau it was meant to be done? I can see in this document (https://www.stmicroelectronics.com.cn/resource/en/application_note/cd00259245-audio-and-waveform-generation-using-the-dac-in-stm32-microcontrollers-stmicroelectronics.pdf), page 21 that they deactivate and reactivate the DMA each time the buffer is updated, but this will create some pops/cracks in the audio, would it not?
Thanks!
Simon
2020-06-07 02:33 PM
Can't see anything wrong. DMAs set to circular, I presume (you might want read out and check/post content of the DMA registers).
> DAC keeps sending the values that were in the buffer in the first place.
A repeating waveform, full-, or half-buffer long?
You might want to initialize the buffers with something easily recognizable (and easily programmable), e.g. a sawtooth.
Isn't the SD read too lengthy at times?
JW
2020-06-07 03:53 PM
> I can see in the debugger that the actual buffer gets updated, as it should, but the DAC keeps sending the values that were in the buffer in the first place.
That doesn't add up. Are you sure the DMA is pulling bytes from the same place they're being updated? DMA doesn't have a memory that would make sending the same data possible if that data no longer exists.
2020-06-07 04:40 PM
Thanks guys! at least I know the DMA should work with the way I am doing it :)
Yes the DMA is in circular mode. Good point about the speed of the SD reads, two reads of half the buffer (since ch1&2 will update at the same time) takes less than 50ms, and half a buffer is 10240/2 samples playing @48kHz that is around 107ms.
I did some ore digging and I think I found the issue - the channel 1 is working perfectly fine (unlucky me I was only looking at Channel 2 on the scope), but for the callbacks for channel 2 are not. I noticed this before in the HAL library (or the code generated by CubeMX), it seems there is a difference between the two channels? In the stm32f4xx_hal_dac.c file it mentions the ConvCpltCallbackCh2 and ConvHalfCpltCallbackCh2 fonctions at the top comment header, but these two functions are actually never declared, unlike the Ch1 functions.
Instead it seems I should use the HAL_DACEx_ConvCpltCallbackCh2 functions from the stm32f4xx_hal_dac_ex.c file? Not sure if this is meant to be that way or it is an error in the lib.
But anyways - all sorted for now, thank you very much chaps!
2020-06-07 04:53 PM
Yes, it seems like the code comments should refer to HAL_DACEx_ConvCpltCallbackCh2 and not HAL_DAC_ConvCpltCallbackCh2, which doesn't exist. The library is otherwise consistent.