2023-05-09 10:54 PM
Hello,
In my project I need to do two 10kHz feedback loops, and I want to make as much in hardware, so I don't have to waste time communicating with dual channel DAC.
So my bright idea is to use a fast 200ksps 24b DAC for generating analog setpoints. In theory, I should be able to connect PCM DAC to SAI, and use circular DMA to transfer my setpoints to DAC with basically no software interaction. This means I will have an array with two variables aligned to 4 inside memory, and DMA should keep copying data to DAC.
Tested this method with software transfer and all looks great, but having trouble configuring SAI to work with DMA in circular mode
hsai_BlockA1.Instance = SAI1_Block_A;
hsai_BlockA1.Init.Protocol = SAI_FREE_PROTOCOL;
hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX;
hsai_BlockA1.Init.DataSize = SAI_DATASIZE_24;
hsai_BlockA1.Init.FirstBit = SAI_FIRSTBIT_MSB;
hsai_BlockA1.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS;
hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_FULL;
hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_192K;
hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE;
hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;
hsai_BlockA1.Init.PdmInit.Activation = DISABLE;
hsai_BlockA1.Init.PdmInit.MicPairsNbr = 0;
hsai_BlockA1.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;
hsai_BlockA1.FrameInit.FrameLength = 64;
hsai_BlockA1.FrameInit.ActiveFrameLength = 32;
hsai_BlockA1.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
hsai_BlockA1.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
hsai_BlockA1.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
hsai_BlockA1.SlotInit.FirstBitOffset = 0;
hsai_BlockA1.SlotInit.SlotSize = SAI_SLOTSIZE_32B;
hsai_BlockA1.SlotInit.SlotNumber = 2;
hsai_BlockA1.SlotInit.SlotActive = SAI_SLOTACTIVE_ALL;
if (HAL_SAI_Init(&hsai_BlockA1) != HAL_OK)
{
Error_Handler();
}
Based on RM, all I have to do is to set correct addresses, data size, and enable DMA, enable SAI, and it should work, but what I get is immediate TE interrupt (transfer Error) even when SAI is not enabled !
To configure the audio subblock for DMA transfer, set DMAEN bit in the SAI_xCR1 register.
The DMA request is managed directly by the FIFO controller depending on the FIFO
threshold level (for more details refer to Section 56.4.9: Internal FIFOs). DMA transfer
direction is linked to the SAI audio subblock configuration:
• If the audio block operates as a transmitter, the audio block FIFO controller outputs a
DMA request to load the FIFO with data written in the SAI_xDR register.
• If the audio block is operates as a receiver, the DMA request is related to read
operations from the SAI_xDR register.
Follow the sequence below to configure the SAI interface in DMA mode:
1. Configure SAI and FIFO threshold levels to specify when the DMA request is launched.
2. Configure SAI DMA channel.
3. Enable the DMA.
4. Enable the SAI interface.
Note: Before configuring the SAI block, the SAI DMA channel must be disabled.
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_6, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_6, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_6, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_6, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_6, LL_DMA_PDATAALIGN_WORD); LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_6, LL_DMA_MDATAALIGN_WORD);
LL_DMA_SetPeriphRequest(DMA2,LL_DMA_STREAM_6,LL_DMAMUX1_REQ_SAI1_A);
LL_DMA_ConfigTransfer(DMA2, LL_DMA_STREAM_6, LL_DMA_DIRECTION_MEMORY_TO_PERIPH|
LL_DMA_PRIORITY_HIGH |
DMA_SxCR_PFCTRL |
LL_DMA_PERIPH_NOINCREMENT |
LL_DMA_MEMORY_INCREMENT |
LL_DMA_PDATAALIGN_WORD |
LL_DMA_MDATAALIGN_WORD);
LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_6, 256);
LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_6, (uint32_t)&aSRC_Const_Buffer, (uint32_t)0x40015820, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_6);
LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_6);
LL_DMA_EnableFifoMode(DMA2,LL_DMA_STREAM_6);
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
And this is how it looks to start:
LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_6);
MX_SAI1_Init();
SAI1_ACR1 |= SAI_xCR1_DMAEN;
MX_DMA_Init();
LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_6);// (imidiatly generates TE DMA IRQ)
__HAL_SAI_ENABLE(&hsai_BlockA1);
So I have 2 questions:
Hope some one sees my mistake ,
2023-05-10 03:23 AM
Problem was found. Switched to AXI RAM so DMA could reach it.
Or need to use MDMA for that :)