Skip to main content
Explorer
December 27, 2024
Solved

Problem with DAC+DMA End-of-Transmission Interrupts on STM32L452RET6P

  • December 27, 2024
  • 2 replies
  • 1380 views

 

Spoiler

Hi Friends, I have a problem using the DAC with the DMA. I have configured the DAC's DMA in normal mode and I want it to generate an interrupt at the end of data transmission to let me know that it has sent all the data to the output. The data is modified at the output through Timer 6. This is how the DAC is configured:

static void MX_DAC1_Init(void)
{

 /* USER CODE BEGIN DAC1_Init 0 */

 /* USER CODE END DAC1_Init 0 */

 DAC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN DAC1_Init 1 */

 /* USER CODE END DAC1_Init 1 */

 /** DAC Initialization
 */
 hdac1.Instance = DAC1;
 if (HAL_DAC_Init(&hdac1) != HAL_OK)
 {
 Error_Handler();
 }

 /** 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;
 if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN DAC1_Init 2 */
 /* USER CODE END DAC1_Init 2 */
}

this is how the dma is configured:

void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 if(hdac->Instance==DAC1)
 {
 /* USER CODE BEGIN DAC1_MspInit 0 */

 /* USER CODE END DAC1_MspInit 0 */
 /* Peripheral clock enable */
 __HAL_RCC_DAC1_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();
 /**DAC1 GPIO Configuration
 PA4 ------> DAC1_OUT1
 */
 GPIO_InitStruct.Pin = GPIO_PIN_4;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 /* DAC1 DMA Init */
 /* DAC_CH1 Init */
 hdma_dac_ch1.Instance = DMA1_Channel3;
 hdma_dac_ch1.Init.Request = 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_LOW;
 if (HAL_DMA_Init(&hdma_dac_ch1) != HAL_OK)
 {
 Error_Handler();
 }
 __HAL_LINKDMA(hdac,DMA_Handle1,hdma_dac_ch1);
 /* DAC1 interrupt Init */
 HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
 /* USER CODE BEGIN DAC1_MspInit 1 */
 /* USER CODE END DAC1_MspInit 1 */
 }
}

This is the function that handles end-of-transmission interrupts:

 

void DMA1_Channel3_IRQHandler(void)
{
 /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
 //INTERRUPT DI FINE TRASMISSION DMA
 if (DMA1->ISR & DMA_ISR_TCIF3)
 {
 HAL_DAC_Stop_DMA(&hdac1, DAC_CHANNEL_1);
 DMA1->IFCR = DMA_IFCR_CTCIF3; // Reset del flag TCIF3
 HAL_DMA_IRQHandler(&hdma_dac_ch1);
 }
}

it all seems to work, but it signals the end-of-transmission interrupt when there are still two values ​​of the array to be transmitted. When the array is composed of only two values, there is never an error. Please help me because I can't solve the problem.

 

HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, &DAC_VALUE, LUNGHEZZA, DAC_ALIGN_12B_R);

function to start data transmission.

    This topic has been closed for replies.
    Best answer by waclawek.jan

    Hi @KnarfB ,

    Thanks for the example. 

    This confirms what I wrote above: if the highest level is the last sample, DMA's Transfer Complete comes *one* trigger cycle before the last sample is output. 

    Non-triggered mode of DAC, and DMA triggered by timer rather than by DAC, can be used to achieve what @MBertocchi probably wants to achieve; or, if a signal/interrupt is desired one cycle after the last sample is output (at the falling edge of the above sawtooth signal), the output values table could be rearranged accordingly; or indirectly a timer interrupt could be used.

    JW

    2 replies

    Super User
    December 27, 2024

    > it signals the end-of-transmission interrupt when there are still two values ​​of the array to be transmitted

    Why do you think so? 

    Have you read the DAC chapter in RM?

    JW

    Explorer
    December 28, 2024

    I did some tests using a defined signal to transmit on the DAC and a physical pin that goes high when an interrupt is generated. The array signal that is transmitted on the DAC is composed of 10 different points and when it transmits the eighth value I see that the physical pin goes high...so I think it is not handling the end-of-transmission interrupt correctly. If instead I create an array of only two points when it has transmitted the second point it generates an interrupt and the pin goes high, so it seems to work correctly, but only up to two points.

     

    help me understand what you mean by RM in the DAC chapter.

    Super User
    December 28, 2024

    The Transfer Complete interrupt from DMA comes when DMA transfers the last of data to the target. However, if DAC is set to be triggered from an external trigger (timer), data are written (by DMA) to DAC's Holding register, and are moved (by DAC itself) from it to the actual DAC (Output register) one trigger period later. 

    This is described in the DAC chapter in the Reference Manual (RM).

    I don't know why do you observe two sample lag. I don't use Cube.

    Try a very slow timer period to see this effect more prominently.

    Super User
    December 28, 2024

    Hi @KnarfB ,

    Thanks for the example. 

    This confirms what I wrote above: if the highest level is the last sample, DMA's Transfer Complete comes *one* trigger cycle before the last sample is output. 

    Non-triggered mode of DAC, and DMA triggered by timer rather than by DAC, can be used to achieve what @MBertocchi probably wants to achieve; or, if a signal/interrupt is desired one cycle after the last sample is output (at the falling edge of the above sawtooth signal), the output values table could be rearranged accordingly; or indirectly a timer interrupt could be used.

    JW

    Explorer
    December 28, 2024

    Thank you very much now I understand better, I will try to work and solve this problem to have an interrupt on the falling edge. I thought it was a bug of the STM32L452RE instead I understood that it was working correctly.

    @KnarfB Thanks for the example.