cancel
Showing results for 
Search instead for 
Did you mean: 

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

YFuku.3
Associate III

< 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 

17 REPLIES 17
YFuku.3
Associate III

>>TJ

I'm new to STM32 .

I think once HAL_TIM_Base_Stop_IT(&htim2) in line 105, and 111 is called, timer is reset. Isn't this correct?

YFuku.3
Associate III

>>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?

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
Up vote any posts that you find helpful, it shows what's working..
Vishnuvardhan
Associate II

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
Associate II

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

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
Associate II

Thank you ill try woth your suggestion

kurta999
Senior