2
\$\begingroup\$

I am trying to send and receive data to and from an STM32F1xx. I have got the STM32 to successfully send data back to the computer. I did that using the code below.

__HAL_RCC_USART1_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

//Setup UART RX Pin
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

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;

//Error handling
if(HAL_UART_DeInit(&UartHandle) != HAL_OK) {
    Error_Handler();
}
if(HAL_UART_Init(&UartHandle) != HAL_OK) {
    Error_Handler();
}
char msg[] = "testing\n\r";
while(1) {
  HAL_UART_Transmit(&UartHandle, (uint8_t*)msg, sizeof(msg), 10);
}

The code above works perfectly. I then tried to send data from the computer to the STM32. I tried the below code

 if(HAL_UART_Receive_IT(&UartHandle, (uint8_t*)msg, 5) == HAL_OK) {
          char msg[] = "HAL_OK";
          HAL_UART_Transmit(&UartHandle, (uint8_t*)msg, sizeof(msg), 10);
 } 

and it did not work. No data was sent back to the computer when I sent a byte to the STM32. I did some debugging and the receive function returns HAL_OK once at the start, and then after that returns HAL_BUSY. This makes me think you have to use interrupts, but I am using that with Receive_IT. How do I solve this issue?

\$\endgroup\$
  • \$\begingroup\$ You certainly don't have to use interrupts. Where are you putting that if statement? In the while (1) replacing the original transmit statement? My advice would be to ditch the bloaty, awful HAL and write you code form scratch. You will learn far more about the micro that way and end up with smaller, faster, neater code. \$\endgroup\$ – DiBosco Aug 23 '17 at 15:26
  • \$\begingroup\$ @DiBosco The if statement is in the while(1) loop replacing the transmit statement. \$\endgroup\$ – Tom Eaton Aug 23 '17 at 15:39
  • \$\begingroup\$ Just look up how much code that HAL call ends up using. Compare with the pseudo code of: if ((USART1->SR & DATA_RX_BIT) == DATA_RX_BIT) { Read register & process data} Then think about how much you learn about the processor and its peripheral doing it that way. \$\endgroup\$ – DiBosco Aug 23 '17 at 15:51
  • 1
    \$\begingroup\$ The development speed outweighs the library size in my opinion. \$\endgroup\$ – Tom Eaton Aug 23 '17 at 15:55
  • 1
    \$\begingroup\$ The _IT suffix means that HAL_UART_Receive_IT() is supposed to be used in interrupt mode. But you're not trying to use interrupt mode. Maybe you should use HAL_UART_Receive() instead. \$\endgroup\$ – kkrambo Aug 23 '17 at 16:37
4
\$\begingroup\$

I do not see you enabling the UART interrupt or calling the appropriate IRQ handlers and that could be a problem.

Here is a complete example of an UART Echo application done with HAL that I wrote for the SO STM32 documentation topic. As SO Documentation will be shut down I have quoted the whole example. It was written for an STM32F4 but with HAL it is almost the same for an STM32F1.

Echo application - HAL library

In this example the microcontroller echos back the received bytes to the sender using UART RX interrupt.

#include "stm32f4xx.h"

UART_HandleTypeDef huart2;

/* Single byte to store input */
uint8_t byte;

void SystemClock_Config(void);

/* UART2 Interrupt Service Routine */
void USART2_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart2);
}

/* This callback is called by the HAL_UART_IRQHandler when the given number of bytes are received */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USART2)
  {
    /* Transmit one byte with 100 ms timeout */
    HAL_UART_Transmit(&huart2, &byte, 1, 100);

    /* Receive one byte in interrupt mode */ 
    HAL_UART_Receive_IT(&huart2, &byte, 1);
  }
}

void uart_gpio_init()
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __GPIOA_CLK_ENABLE();

  /**USART2 GPIO Configuration
  PA2     ------> USART2_TX
  PA3     ------> USART2_RX
  */
  GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void uart_init()
{
  __USART2_CLK_ENABLE();

  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart2);

  /* Peripheral interrupt init*/
  HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART2_IRQn);
}

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  uart_gpio_init();
  uart_init();

  HAL_UART_Receive_IT(&huart2, &byte, 1);

  while(1)
  {

  }
}

This example used an STM32F4 Discovery (STM32F407VG), GPIO and alternate function values should be changed according to the STM32 microcontroller in use.

\$\endgroup\$
0
\$\begingroup\$

You shouldn't need to use interrupts, pooling is a valid method for UART communication. Looking at your code the GPIO configuration seems off. The Tx pin is configured as Alternate Function but you didn't defined the function.

Looking at @Bence answer you can see that pins uses af 7 for USART functions. I would suggest adding the following line before calling the first HAL_GPIO_Init:

GPIO_InitStruct.Alternate = GPIO_AFx_USART1;

And change GPIO_InitStruct.MODE for the Rx pin to the following:

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Alternate = GPIO_AFx_USART1;

You'll have to replace "AFx" with the proper alternate function for those pins to work with USART1. You can find that info on the MCU datasheet. Usually on a table after pin description.

When using pins connected to a peripheral instead of simple I/O you need to proper mux the physical. Read a bit about Microcontroller pin muxing.

New contributor
Otávio Borges is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.