Electronic – STM32F04 UART Transmit with Interrupts

embeddedmicrocontrollerprogrammingstm32stm32f0

I have been prototyping my project with the STM32F103 "Bluepill" and for the final product I want to move to the STM32F042F6 which has a smaller TSSOP-20 footprint. I need to use UART in my communications with the device so I tried to create a simple UART transmit program to check that the UART peripheral was working correctly. Here is my code.

#include "stm32f0xx.h"
#include "stm32f0xx_hal.h"
#include "stm32f0xx_hal_conf.h"

void Startup_Sequence(void);
void Error_Handler(void);
void SystemClock_Config(void);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle);

UART_HandleTypeDef UartHandle;
__IO ITStatus UartReady = RESET;

int main(void)
{
    HAL_Init();
    //SystemInit();
    SystemClock_Config();

    GPIO_InitTypeDef  GPIO_InitStruct;
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

   // Setup LED Pin
   GPIO_InitStruct.Pin = GPIO_PIN_4;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

   // Setup UART Tx Pin
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  // Setup UART Rx pin
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  //Setup UART Instance
  UartHandle.Instance = USART1;
  UartHandle.Init.BaudRate = 9600;
  UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  UartHandle.Init.StopBits = UART_STOPBITS_1;
  UartHandle.Init.Parity = UART_PARITY_NONE;
  UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  UartHandle.Init.Mode = UART_MODE_TX_RX;
  UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
  UartHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

  //Error handling
  if(HAL_UART_Init(&UartHandle) != HAL_OK) {
      Error_Handler();
  }

  Startup_Sequence();

  HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
  HAL_NVIC_EnableIRQ(USART1_IRQn);  

  char hello[6] = "hello\n";

  while(1) {
      if(HAL_UART_Transmit_IT(&UartHandle, (uint8_t *)hello, 6) != HAL_OK) {
          Error_Handler();
      }     
  }
}

void Startup_Sequence(void) {
    int i;
    for (i=1; i<50;i++) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
        HAL_Delay((1.0/i) * 1000);
    }
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
}

void Error_Handler(void) {
    while(1) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
        HAL_Delay(1000);
    }
}

/**
  * Associates the interrupt handler with the UartHandle
 */
void USART1_IRQHandler(void) {
    HAL_UART_IRQHandler(&UartHandle);
}

/**
 * This function is called when transmitting
 * @param UartHandle [Pointer to UartHandle]
 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

/**
 * This function is called when receiving
 * @param UartHandle [Pointer to UartHandle]
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInit;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_ClkInitStruct.ClockType = 
    RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                           |RCC_CLOCKTYPE_PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 
    HAL_OK)
    {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }

    /**Configure the Systick interrupt time 
    */
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

    /* SysTick_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
} 

The UART peripheral initialises correctly, because the Error Handler is not called until after the Startup_Sequence() has completed. So why is the ErrorHandler called when I try to transmit? I have tried to send using the blocking mode, but it just timeouts every time.

EDIT: I have tracked the error down to the initialisation function. Here is the GDB Log https://hastebin.com/xopohaniyu.coffeescript but I can't find anywhere where HAL_OK is not returned.

Is there something wrong my setup of the UART peripheral? Or is there a problem with the System clock? Please advise.

Best Answer

GPIO setup is somewhat more complicated flexible on the F0. Here you should also set GPIO_InitStruct.Alternate = GPIO_AF1_USART1, otherwise it will get some random value, because it is an unitialized automatic variable. Enable the warnings in the compiler, and pay attention to them, they are there for a reason.

HAL_UART_Transmit_IT() is called again before the previous transmit has finished. You should wait until the UartReady flag is set, and reset it before repeating.

Related Topic