2020-12-21 03:40 PM
Here's the essence of what I have at the moment. I wonder why it does not enter DMATxComplete, I have tried with 128 and 30 buffer sizes...
//****** dac.c **********//
DAC_HandleTypeDef hdac1;
DMA_HandleTypeDef hdma_dac_ch1;
DMA_HandleTypeDef hdma_dac_ch2;
/* DAC1 init function */
void MX_DAC1_Init(void)
{
DAC_ChannelConfTypeDef sConfig;
/**DAC Initialization
*/
hdac1.Instance = DAC1;
if (HAL_DAC_Init(&hdac1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**DAC channel OUT1 config
*/
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_80MHZ;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**DAC channel OUT2 config
*/
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T7_TRGO; //T7
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
sConfig.DAC_HighFrequency = DAC_HIGH_FREQUENCY_INTERFACE_MODE_ABOVE_80MHZ;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_DAC_MspInit(DAC_HandleTypeDef* dacHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(dacHandle->Instance==DAC1)
{
/* USER CODE BEGIN DAC1_MspInit 0 */
/* USER CODE END DAC1_MspInit 0 */
/* DAC1 clock enable */
__HAL_RCC_DAC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**DAC1 GPIO Configuration
PA4 ------> DAC1_OUT1
PA5 ------> DAC1_OUT2
*/
GPIO_InitStruct.Pin = DAC_OUT1_Pin | DAC_OUT2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* DAC1 DMA Init */
/* DAC_CH2 Init */
hdma_dac_ch2.Instance = DMA2_Channel5;
hdma_dac_ch2.Init.Request = DMA_REQUEST_DAC1_CH2; //DMA_REQUEST_3;
hdma_dac_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac_ch2.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac_ch2.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_dac_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_dac_ch2.Init.Mode = DMA_CIRCULAR;
hdma_dac_ch2.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_dac_ch2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(dacHandle,DMA_Handle2,hdma_dac_ch2);
/* DAC_CH1 Init */
hdma_dac_ch1.Instance = DMA1_Channel3;
hdma_dac_ch1.Init.Request = DMA_REQUEST_DAC1_CH1; //DMA_REQUEST_6;
hdma_dac_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac_ch1.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dac_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dac_ch1.Init.Mode = DMA_NORMAL;
hdma_dac_ch1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_dac_ch1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(dacHandle,DMA_Handle1,hdma_dac_ch1);
/* USER CODE BEGIN DAC1_MspInit 1 */
/* Enable Transfer Complete on channel 3 */
//DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
/* USER CODE END DAC1_MspInit 1 */
}
}
void Audio_MAL_Play(uint32_t * signal, uint32_t size)
{
if(HAL_DAC_Stop_DMA(&hdac1, DAC_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if(HAL_TIM_Base_Stop(&htim6) != HAL_OK)
{
Error_Handler();
}
/* Disable DMA1 Channel3 */
//HAL_DMA_Abort(DMA1_Channel3);
/* Enable DMA1 Channel3 */
//HAL_DMA_Start(DMA1_Channel3);
if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, signal, size, DAC_ALIGN_12B_R) != HAL_OK) // 12B_L or 12B_R?
{
/* Start DMA Error */
Error_Handler();
}
// Set the timer period to the default
htim6.Instance->ARR = ARR_FILE; // replace with htim7?
if(HAL_TIM_Base_Start(&htim6) != HAL_OK) // replace with htim7
{
Error_Handler();
}
}
void start_DAC_us(uint32_t * signal, uint32_t size)
{
if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, signal, size, DAC_ALIGN_12B_R) != HAL_OK) // 12B_L or 12B_R?
{
/* Start DMA Error */
Error_Handler();
}
// Only playback Sine Wave on DAC Channel 2, DAC Channel 1 will playback AudioTrack
if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, signal, size, DAC_ALIGN_12B_R) != HAL_OK) // input a second signal for DAC channel 2
{
/* Start DMA Error */
Error_Handler();
}
// Set the timer period to the default
htim7.Instance->ARR = ARR_SIN; //Channel2 - Sine Wave
if(HAL_TIM_Base_Start(&htim7) != HAL_OK) // replace with htim7
{
Error_Handler();
}
// Set the timer period to the default
htim6.Instance->ARR = ARR_FILE; //Channel1 - Audio File
if(HAL_TIM_Base_Start(&htim6) != HAL_OK)
{
Error_Handler();
}
}
//****** In function.c **********//
start_DAC_us( (uint32_t *)Sine12bit, SIZE_LUT);
Audio_MAL_Play((uint32_t*)Sine12bit, SIZE_LUT);
BufferSelection = 2;
do
{
if(BufferRead != 0)
{
/* Play sine test */
// Audio_MAL_Play( (uint32_t *)Sine12bit, SIZE_LUT);
// BufferRead = 0;
if(BufferSelection == 2)
{
/* Play buffer 2 */
Audio_MAL_Play((uint32_t*)Sine12bit, SIZE_LUT);
BufferRead = 0;
}
else if (BufferSelection == 1)
{
/* Play buffer 1 */
Audio_MAL_Play((uint32_t*)Sine12bit, SIZE_LUT);
BufferRead = 0;
}
}
}while((FlagBits & FLAG_TOGGLE_US));
-----------------------------------------------------------------------------------
void WavePlayer_DMATxComplete_IRQHandler(void)
{
if(__HAL_DMA_GET_FLAG(&hdma_dac_ch1,DMA_FLAG_TC3))
{
if(BufferSelection == 2)
{
BufferSelection = 1;
BufferRead = 1;
}
else
{
BufferSelection = 2;
BufferRead = 1;
}
__HAL_DMA_CLEAR_FLAG(&hdma_dac_ch1,DMA_FLAG_TC3);
}
}
2020-12-22 10:53 AM
When I set DMA for DAC_Ch1 as a circular buffer it enters WavePlayer_DMATxComplete_IRQHandler constantly. However, when I set the DMA as a "normal" buffer, it only enters it at the beginning. It is supposed to do reset BufferRead = 1, since it does not enter the function it gets stuck without any output at the DAC.
I have added the following code to init the DMA NVIC for interrupts, without further success:
void WavePlayer_Init(void)
{
/********************************* DMA Config *******************************/
/* DMA1 clock enable (to be used with DAC) */
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; //Enable DMA1 Clock //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA channel3 Configuration is managed by Audio_MAL_Play() function */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
/* Enable Transfer Complete on channel 3 */
__HAL_DMA_ENABLE_IT(&hdma_dac_ch1,DMA_IT_TC);
}
How can I debug this? How can I know where the DMA Tx complete fails?
2020-12-22 12:18 PM
> When I set DMA for DAC_Ch1 as a circular buffer it enters WavePlayer_DMATxComplete_IRQHandler constantly.
> However, when I set the DMA as a "normal" buffer, it only enters it at the beginning.
Quite likely, DAC underruns. Read out and check the DMA and DAC registers content, focus on status bits in both.
JW
2020-12-22 03:41 PM
Where can I find the DMA and DAC registers content? I have looked in HAL_DMA_Start_IT() and I am not sure I know where to focus.
2020-12-22 11:56 PM
I said, read out.
The easiest way is to use the register view in debugger.
JW