# STM32F04 UART Transmit with Interrupts

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;

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;

//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) {
}

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

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.

• Why are you needlessly doing floating point math in your delay calculation? Just divide 1000 by the integer divisor. More generally, a problem with your code is that it's unclear what is copied from some source and what is original. Probably you should try to get some existing piece of code to work unmodified before you attempt modifications, so that you'll have a better idea of where subsequent problems might originate. Also make sure that your build is purely for the STM32F0 series, and doesn't include any files belonging to the fairly different STM32F1 series you previously used. – Chris Stratton Oct 9 '17 at 19:23
• Finally, breakpoint the error handler and then do a backtrace to see how it got there - your debug log doesn't include the actual failure, so isn't very useful. – Chris Stratton Oct 9 '17 at 19:25

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.