'Callback in STM32 isn't called

Trying to make simple PWM transmitter i faced with a problem. I have TIM2 with Channel2 (in PWM Generation mode) on board NUCLEO F042K6 and USART1 connected to the board in Async mode (USART works in DMA).

I wanted to make a PWM transmitter that uses a circular buffer that can be filled with one character or several characters at once. The plan was that when the user enters a character (or several characters), the idle line callback is processed, in which a function is called that stores the data in a cyclic buffer. After saving, the data transferred to the buffer is passed to the function PWM_SendChar(...) to convert the data into bits and transfer them over the PWM line. But the problem is when the program goes into PWM_SendChar(...) the callback HAL_TIM_PWM_PulseFinishedCallback(...) isn't called and program stucks in infinite while loop because variable used as a flag for detecting the end of single pulse (PWM_data_sent_flag) wasn't set to value 1.

However, if I use HAL_UART_Recieve(...) func in while(1) loop (located in main(void)) to recieve a char from user program works fine without stucking in while loop in TIM callback. Ofc, for this method I don't use HAL_UARTEx_RxEventCallback(...) and cycle buffer.

Thats's why I think the problem is in USART idle line detection and please help me solve it.

Code Example


Global variable used for waiting the end of pulse:

volatile uint16_t PWM_data_sent_flag = 0;

PWM timer callback:

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM2) {
        HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_2);
        PWM_data_sent_flag = 1;
    }
}

Callback for USART idle line:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
    if (huart == &huart1) {
//      Function_to_save_input_char_in_cycle_buffer() is called
    }
}

Function used to send char as a PWM signal (emited after Function_to_save_input_char_in_cycle_buffer() completed):

void PWM_SendChar(char ch) {
    for (int i = 0, mv = 7; i <= 7; ++i, --mv) {
        uint8_t bit = (ch & (1 << mv)) ? 1 : 0;

        // PWM_LOW_PERCENT encodes bit with zero value, PWM_HIGH_PERCENT encodes bit with value one
        uint16_t duty_cycle = bit == 0 ? PWM_LOW_PERCENT : PWM_HIGH_PERCENT; 

        // Change TIM2 CCR2 value according to bit's value
        __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2,
                GET_PERCENT_VALUE(TIM2->ARR, duty_cycle));

        HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_2);
       
        // Program comes to this cycle and doesn't leave it
        while (!PWM_data_sent_flag)
            ;
        PWM_data_sent_flag = 0;
    }
}

USART receive to idle launch (half data transmitted callback disabled):

int main(void) {
//  Init code  
//  ...

    if (HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*) ring_buf.buff,
            ARRAY_LEN(ring_buf.buff)) != HAL_OK) {
        Error_Handler();
    }
    // Disable half word transmitted callback
    __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); 

    while(1) {
    }
}

TIM2 settings:

static void MX_TIM2_Init(void) {

    /* USER CODE BEGIN TIM2_Init 0 */

    /* USER CODE END TIM2_Init 0 */

    TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
    TIM_MasterConfigTypeDef sMasterConfig = { 0 };
    TIM_OC_InitTypeDef sConfigOC = { 0 };

    /* USER CODE BEGIN TIM2_Init 1 */

    /* USER CODE END TIM2_Init 1 */
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 48000 - 1;
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 100 - 1;
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
        Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
        Error_Handler();
    }
    if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
        Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig)
            != HAL_OK) {
        Error_Handler();
    }
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2)
            != HAL_OK) {
        Error_Handler();
    }
    /* USER CODE BEGIN TIM2_Init 2 */

    /* USER CODE END TIM2_Init 2 */
    HAL_TIM_MspPostInit(&htim2);

}

USART1 settings:

static void MX_USART1_UART_Init(void) {

    /* USER CODE BEGIN USART1_Init 0 */

    /* USER CODE END USART1_Init 0 */

    /* USER CODE BEGIN USART1_Init 1 */

    /* USER CODE END USART1_Init 1 */
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if (HAL_UART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }
    /* USER CODE BEGIN USART1_Init 2 */

    /* USER CODE END USART1_Init 2 */

}

DMA settings:

static void MX_DMA_Init(void) {

    /* DMA controller clock enable */
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* DMA interrupt init */
    /* DMA1_Channel4_5_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(DMA1_Channel4_5_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel4_5_IRQn);

}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source