1

I've been trying to implement a basic per-byte UART Rx Interrupt on a STM32F4 board using HAL skeleton code generated by STMCubeMX version 4.26.0

Quite simply - I want to receive a character in UART1 via an Rx interrupt and transmit it on UART 6

I have successfully implemented a polled version of what I want to achieve

    uint8_t in_usart1[10];

    HAL_StatusTypeDef usart1_status;

    usart1_status = HAL_UART_Receive(&huart1, in_usart1, 1, 1);

    if (usart1_status != HAL_TIMEOUT)
    {
            HAL_UART_Transmit(&huart6, in_usart1, 1, 100);
    }

I've enabled the UART 1 NVIC interrupt in STMCubeMX and stm32f4xx_it.c contains the IRQ handler which I've added my own user handler to:

void USART1_IRQHandler(void)
{
    /* USER CODE BEGIN USART1_IRQn 0 */

    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */
    HAX_USART1_IRQHandler(&huart1); /* My Handler */
    /* USER CODE END USART1_IRQn 1 */
}

I've seen lot's of commentary about UART_Receive_IT() - but I suspect this is based on older versions of HAL due to UART_Receive_IT() being defined in stm32f4xx_hal_uart.c

My suspicion is that I need to enable to interrupt / clear the interrupt flag as when I debug, USART1_IRQHandler() is NEVER called

Does any one have any code that demonstrates what I am trying to achieve? My google-foo has failed me

EDIT: I've gotten a little closer... In main.c I added (comments are existing code)

  /* USER CODE BEGIN PV */
  uint8_t rx_buffer;
  /* USER CODE END PV */

  ...

  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 10);
  /* USER CODE END 2 */

And then created:

  void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  {
        if (huart->Instance == USART1)
        {
              HAL_UART_Transmit(&huart6, &rx_buffer, 1, 100);
        }
  }

Now the Rx interrupt gets fired - but it's a bit flakey on the USART6 Tx, and the Rx interrupt only gets fired once

2 Answers 2

2

Do not block HAL_UART_RxCpltCallback for a long time! Just set a flag and check it and then send data from the main function.

And rx_buffer is variable so correct call HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);

Sign up to request clarification or add additional context in comments.

Comments

1

For anybody stumbling across this question, the answer is embarrassingly simple. I have two UARTs - One I was using an Rx Interrupt, and the other using DMA.

Turns out the one I thought I had configured for Interrupt was actually configured for DMA and visa-versa...

In STMCubeMX - USART1 (RS485) has DMA Tx and DMA Rx enabled - USART6 (Debug - RS232) has global interrupt enabled

In main.c

/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
/* USER CODE END 2 */

I have a user_main.c which has the following code:

#include <string.h>
#include "stm32f4xx_hal.h"

extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart6;

UART_HandleTypeDef *debug_uart(void)
{
    return &huart6;
}

UART_HandleTypeDef *rs485_uart(void)
{
    return &huart1;
}

#define BUFFER_SIZE 1

uint8_t debug_rx_buffer[BUFFER_SIZE];
uint8_t debug_tx_buffer[BUFFER_SIZE];

uint8_t rs485_rx_buffer[BUFFER_SIZE];
uint8_t rs485_tx_buffer[BUFFER_SIZE];

static void rs485_tx(uint8_t *tx_buffer, uint16_t len)
{
    HAL_UART_Transmit_DMA(rs485_uart(), tx_buffer, len);
}

static void debug_tx(uint8_t *tx_buffer, uint16_t len)
{
    HAL_UART_Transmit(debug_uart(), tx_buffer, len, 1000);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == debug_uart())
    {
        memcpy(rs485_tx_buffer, debug_rx_buffer, BUFFER_SIZE);
        rs485_tx(rs485_tx_buffer, BUFFER_SIZE);

        HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
    }
    else if (huart == rs485_uart())
    {
        memcpy(debug_tx_buffer, rs485_rx_buffer, BUFFER_SIZE);
        debug_tx(debug_tx_buffer, BUFFER_SIZE);

        HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
    }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == debug_uart())
    {
    }
    else if (huart == rs485_uart())
    {
    }
}

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
}

The memcpy()'s may not be strictly required, but they do provide a level of isolation between all the buffers. Technically, there probably should be semaphores providing even more protection...

Note that I DO NOT use HAL_UART_Transmit_IT() for the debug UART - If you want to use HAL_UART_Transmit_IT (i.e. interrupt generated on completion of Tx), you will need to write code that handles transmission of characters from a circular buffer

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.