Skip to main content
YFuku.3
Associate III
October 8, 2018
Question

How to send and receive message through UART interrupt or DMA?

  • October 8, 2018
  • 17 replies
  • 9250 views

< What I want to do? >

  • Send string messages(AT command) from STM32 microcontroller to LTE module through UART, receive the reply, and store the received data in a string variable. 
  • I tried HAL_UART_Receive function and it works. However, it doesn't complete the job until duration set in the timeout param passes, even if all the bytes are received. I want CPU to move to next job right after receiving all the bytes.

*My Mother tongue is not English. If what I'm writing here is not understandable, let me know. I will fix sentences properly.

 < Environment >

  • Nucleo-L053R8
  • 3G module(HL8548-G)

https://source.sierrawireless.com/resources/airprime/hardware_specs_user_guides/airprime_hl8548_and_hl8548-g_product_technical_specification/

  • The Nucleo-L053R8 and the 3G module should be connected properly.

 < What I tried? >

  • I looked through discussion on some websites and figured out that taking one byte by one from the buffer by HAL_UART_Receive_IT or HAL_UART_Receive_DMA is needed. Then I implemented the below code. However, it does not work well. I'm struggling for this problem for two weeks. I appreciate it if you give me any advice.
  • Settings: 32MHz, using HAL_UART_Receive_DMA(115200baud, Circular mode, no interrupt), and a timer(prescaler:100-1, counter period:320, interrupt, 1msec interruption), 
  • How the below code works
  1.  Initialize UART, timer, and printf function.
  2. (In Func_3G_Comm func)Send string stored in txBuf by HAL_UART_Transmit.
  3. (In Func_3G_Comm func)Enable HAL_UART_Receive_DMA(&huart1, (uint8_t*)&rxBuf_IT, 1);.
  4. (In Func_3G_Comm func)Enter sleep mode.
  5. (In HAL_UART_RxCpltCallback func)When one byte is received, stop a timer, store it in rxBuf, and start the timer again. 
  6. (In HAL_TIM_PeriodElapsedCallback func)When 1msec passes after the last byte is received, this func is called. This means no byte will be received. Set rxFlag = 1.
  7. (In Func_3G_Comm func)Break for loop by rxFlag = 1. Print string in rxBuf
  • The step 7 does not work. Just "AT" characters show up and only blank later.
  • I don't know using DMA is the good way.

extracts from main.c

#include "main.h"
#include "stm32l0xx_hal.h"
TIM_HandleTypeDef htim2;
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
 
#define txBuf_size 512
#define rxBuf_size 128
 
char txBuf[txBuf_size];
char rxBuf[rxBuf_size];
char superRxBuf[2000];
uint8_t rxFlag = 0;
uint16_t rxIndex = 0;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM2_Init(void);
void Func_3G_Comm(char *Cmd);
 
extern void initialise_monitor_handles(void);
 
int main(void)
{
 initialise_monitor_handles(); // Initialize printf func
 HAL_Init();
 SystemClock_Config();
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_DMA_Init();
 MX_USART1_UART_Init();
 MX_TIM2_Init();
 
 /* Perform the initial configuration in 3G module */
 Func_3G_Comm("AT&K3"); // Set hardware flow control
 Func_3G_Comm("AT+KTCPCLOSE=1"); // Close TCP1 connection
 Func_3G_Comm("AT+KTCPDEL=1"); // Close Delete TCP1 connection
 Func_3G_Comm("AT+GPSSTOP"); // Stop GPS
 Func_3G_Comm("AT+GPSNMEA=01,,0"); // Stop receiving GPS NMEA data
 Func_3G_Comm("AT+CGATT=0"); // PS detachment
 Func_3G_Comm("AT+KCNXCFG=1,\"GPRS\",\"***.com\",\"***.com\",\"***\""); // Configure TCP Connection
 Func_3G_Comm("AT+CGDCONT=4,\"IP\",\"***.com\""); // Configure GPRS
 Func_3G_Comm("AT+KCNXPROFILE=1"); // Configure current profile connection
 Func_3G_Comm("AT+KGNSSAD=1"); // Configure GNSS antenna detection
 Func_3G_Comm("AT+CGATT=1"); // PS attachment
 Func_3G_Comm("AT+KTCPCFG=1,0,\"xxxxxx.com\",16650"); // Configure TCP Connection
 Func_3G_Comm("AT+KCNXUP=1"); // Bring up PDP connection
 Func_3G_Comm("AT+KTCPCNX=1"); // Start TCP connection
 
 while (1)
 {
 }
 
}
 
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
 huart1.Instance = USART1;
 huart1.Init.BaudRate = 115200;
 huart1.Init.WordLength = UART_WORDLENGTH_8B;
 huart1.Init.StopBits = UART_STOPBITS_1;
 huart1.Init.Parity = UART_PARITY_NONE;
 huart1.Init.Mode = UART_MODE_TX_RX;
 huart1.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
 huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
 
 if (HAL_UART_Init(&huart1) != HAL_OK)
 {
 _Error_Handler(__FILE__, __LINE__);
 }
 
}
 
/* Enable DMA controller clock */
static void MX_DMA_Init(void) 
{
 /* DMA controller clock enable */
 __HAL_RCC_DMA1_CLK_ENABLE();
 
 /* DMA interrupt init */
 /* DMA1_Channel2_3_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
}
 
void Func_3G_Comm(char *Cmd)
{
 memset(txBuf, '\0', txBuf_size);
 memset(rxBuf, '\0', rxBuf_size);
 snprintf(txBuf, txBuf_size, "%s\r\n", Cmd);
 HAL_UART_Transmit(&huart1, (uint8_t *)txBuf, strlen(txBuf), 0xFFFF);
 HAL_UART_Receive_DMA(&huart1, (uint8_t*)&rxBuf_IT, 1);
 HAL_SuspendTick();
 for(rxFlag=0;rxFlag==0;)
 {
 HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
 }
 HAL_ResumeTick();
 HAL_TIM_Base_Stop_IT(&htim2);
 printf("%s\n",rxBuf);
}
 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
 HAL_TIM_Base_Stop_IT(&htim2);
 if(UartHandle->Instance==USART1){
 	rxBuf[rxIndex] = rxBuf_IT;
 	rxIndex++;
 }
 HAL_TIM_Base_Start_IT(&htim2);
 HAL_UART_Receive_DMA(&huart1, (uint8_t*)&rxBuf_IT, 1);
}
 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	 if (htim->Instance == TIM2) {
		 rxFlag = 1;
		 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
	 }
}

extracts from stm32l0xx_it.c

void DMA1_Channel2_3_IRQHandler(void)
{
 HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
 
void TIM2_IRQHandler(void)
{
 HAL_TIM_IRQHandler(&htim2);
}

*modification: Func_3G_Comm => LTE_Comm 

This topic has been closed for replies.

17 replies

YFuku.3
YFuku.3Author
Associate III
October 10, 2018

>>Clive Two.Zero

You're right. I will use interrupt, not DMA.

Does anyone have advice on how to get to know the end of messages on interrupt?

Tesla DeLorean
Guru
October 10, 2018

Depends if the data stream has a defined form or if you have to sense and intermessage gap.​

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Vishnuvardhan
Visitor II
November 15, 2018

I felt, what suggested by "AvaTar" is the appropriate design for this kind of application.

  • ISR
  • Buffer between ISR and main loop
  • State machine in main loop
  • Timeouts if response(s) are not received in stipulated time
  • Retries, if response(s) are not received in stipulated time
skupp
Visitor II
February 26, 2019

HI yusukechief1.5356023809566858E12 ,

As I'm working on same topic, receiving response for AT commands from GSM module through stm32 uart. I'm facing issue since 3 weeks. It will really help full of you could share the code of yours for my reference.. Please help me on this.

mail address:shashishreekuppurmce@gmail.com

Thank you in advance

shashishree

S.Ma
Principal
February 26, 2019

You could receive data from uart by dma in a cyclic buffer, and every 1 msec, by interrupt, you check what was received so far. Or you create rx interrupt on per byte basis and manually fill the buffer, while detecting when a message has been fully received and ready for processing.

skupp
Visitor II
February 26, 2019

Thank you ill try woth your suggestion

kurta999
Senior
February 26, 2019