1
votes

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

2 Answers

2
votes

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);

1
votes

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