Skip to main content
HARI krishna
Associate III
December 7, 2016
Solved

STM32F030C8 Interface with Quectel M95

  • December 7, 2016
  • 14 replies
  • 3864 views
Posted on December 07, 2016 at 12:59

Hi all,

I am working for a project which is having 5 interfacing modules out of this one module needs to interface quectel M95 GSM modem to stm32f030C8. From PCB side and Hardware all was done working fine modem Responding to AT Commands.USART1 is used for interfacing M95 module. STM32 cube MX tool is used for generate code for TrueStudio.

Here is my problem,when i sent AT command modem responding with OK and reading messages also.For that i am using USART2 to display received message on PC terminal using MAX3232 converter.

If i want read the message which is received , in that received message some part of message is missing.i tried to increase the buffer size & receive length in the HAL_UART_Receive_IT  function but not worked out.

I am using usart1 receive interrupt .Receiving uart message are not exact what we need to receive some of sending characters also received.

uint8_t  uart1_aRxBuffer[150],

send_Buf[100];

HAL_UART_Transmit(&huart1,(uint8_t *)send_Buf,len,1000);

HAL_UART_Receive_IT(&huart1,(uint8_t *)uart1_aRxBuffer,len1);

please help on this it is need to submit to the client ASAP.

#no-hablo-hal
This topic has been closed for replies.
Best answer by aaron239955_stm1_st
Posted on December 15, 2016 at 20:05

The response you are seeing makes perfect sense because your logic is completely confused.

Regardless of the command, this is the way your logic is currently working:

1. You transmit a string (command) to the M95 like AT+GSM.....

2. You delay 2 seconds, during which time the M95 sends a response

3. you THEN enable the UART to receive data, using interrupts (and I still don't see your interrupt handling code)

4. the result of (2) above is that the response from the M95 happens while you are sitting in a 2 second delay.  As a result you get whatever was received by the hardware before it overflowed because you are not emptying the Rx buffer as characters are coming in.  So you get the first 2 characters '+C' which is the beginning of '+CPMS....' but since nobody is looking at the receiver, after the first two characters are buffered in the hardware peripheral (in the Rx register and the CPU interface register) it drops all subsequent characters on the floor.  The whole message was sent back by the M95 while you are sitting in a delay loop and ignoring what is coming back for 2 seconds.  So when you finally enable the Receiver with your HAL call it gives you the two characters it had stuck in the peripheral's registers.

What you need to do is enable the Receiver BEFORE you send a command so that you get back anything that the M95 sends you.  Including the command you sent if you have Echo enabled.  YOU need to figure out what to expect back based on whether echo is on or not, etc etc etc, and throw out any extraneous information and extract the useful response.  You can't use delays to hope that the bad stiff gets ignored and you'll get the good stuff because you don't know how long it will be before the M95 responds.

By waiting 2 seconds to look at the receiver after sending a command, you are ignoring the response from the M95.

And as a side note, setting a receive buffer 5 characters bigger than the size of the buffer you were passed is dangerous at best.  (assuming this will even know what the size is since what is passed to the function is pointer to an arbitrary array)

If you would like me to write the code for you, let me know.

14 replies

aaron239955_stm1_st
Senior
December 7, 2016
Posted on December 07, 2016 at 20:11

It's a little hard to understand what your problem is.  It sound like you are receiving some of the characters you sent out, which causes you a problem?  You show that you are using the Rx channel in Interrupt mode but you do not talk about or show the code you use to respond to the received character interrupt.  I will assume you have the capability to correctly buffer what is being received back from your external device.

The first thing I would suspect is that the device you are communicating with is in ECHO mode, so that every character you send to it, is sent back to you on your Rx line.  This is useful when you are using a terminal emulator program on a PC to talk to the device, not necessarily helpful when you are connecting with your microcontroller.  If you have an AT command to turn off ECHO , like ATE=0, you might send this first.  And then clear your receive buffers.

Next, by using the non-interrupt call to Txmit your message, the program will block until all of the characters are transferred to the UART before moving on to the next statement that starts the Rx channel.  With that the case, and if echo is on, what I would expect is the following:

  1. The Rx channel of the uart actually receives the first character echoed by your external device and is held in a register in the UART, but not transferred since the interrupt Rx has not yet been enabled. 
  2. Not sure but a second character might be received and held due to the double-buffer nature of the UART.
  3. All other characters sent out will be dropped because the UART is 'full:
  4. Last character sent may get received because the HAL_UART_Transmit() call returns when the last character is sent to the buffer but this happens before the last (and maybe the next to last) character has been sent out of the UART.  Depending on the timing and how fast your ISR empties the Rx buffer, it may get one or two of the last echoed characters before it starts receiving the actual response from the peripheral.

There are a number of ways to deal with the situation.  One is to run the Tx in interrupt mode, which will let you immediately enable the receiver and get back all of the echoed characters and throw out what you know to expect.  Also you could just enable the receiver before you send the message and it will have the same effect.  Alternately you can turn off echo on the peripheral as mentioned above.

In any case, you need to make sure you flush the receiver in some controlled way to ensure you only return meaning ful outputs from the device.

Tesla DeLorean
Guru
December 7, 2016
Posted on December 07, 2016 at 21:11

You'll need to manage or suppress the echo back from the modem, and resync depending on the OK, ERROR, NO CARRIER, etc responses the modem might provide. Arbitrary delays should also be avoided, network interaction may take several minutes to complete, and sending characters before completion might result in a command being aborted.

Turn Echo Off

ATE0

Turn Echo On

ATE1

With the HAL stuff make sure you are not creating some blocking code within a call-back (via IRQ Handler). Review how much data was received or transmitted, and if the request timed-out.

#no%20hablo%20hal

‌

>>

please help on this it is need to submit to the client ASAP.

Nobody here cares, your client isn't paying us.

http://www.catb.org/~esr/faqs/smart-questions.html#urgent

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Seb
ST Employee
December 10, 2016
Posted on December 10, 2016 at 18:19

If the second UART is only for debug, try to program the baudrate of the debug uart to be higher than the one going to the Quectel device. Then do not use buffer. When a byte is received from Quectel, directly write the DR of the debug UART TX. Good luck!

HARI krishna
Associate III
December 15, 2016
Posted on December 15, 2016 at 13:53

This is the source code what is running for GSM COM,

UART1 for Quectel M95,UART2 is for Hyper terminal.UART not receiving full reply message.

uint8_t test_commands()

{

send_cmnd((char *)''AT\r'',''OK'');

send_cmnd((char *)''ATE0\r'',''OK'');

send_cmnd((char *)''AT+CPMS=\''SM\'',\''SM\'',\''SM\''\r'',(''+CPMS: SM,0,50,SM,0,50,SM,0,50''));

send_cmnd((char *)''AT+CMGF=1\r'',''OK'');

send_cmnd((char *)''AT+CNMI=2,0,0,0,0\r'',''OK'');

send_cmnd((char *)''AT+CMEE=1\r'',''OK'');

send_cmnd((char *)''AT+CSCS=\''GSM\''\r'',''OK'');

return 0;

}

void send_cmnd(char *AT_cmd_string,char *response_string)

{

char send_Buf[50]={0};//added

sprintf(send_Buf,AT_cmd_string);

uint8_t len = strlen(AT_cmd_string);

printf(''\r\nGSM Tx: %s\r\n'',(int8_t*)AT_cmd_string);

if(len)

{

HAL_UART_Transmit_IT(&huart1,(uint8_t *)send_Buf,len);

}

HAL_Delay(2000);

reponse_read(response_string);

}

void reponse_read(char *response_string)

{

uint8_t len1;

len1=sizeof(response_string);

HAL_UART_Receive_IT(&huart1,(uint8_t *)uart1_aRxBuffer,(len1+5));

HAL_Delay(500);

printf(''\r\n UART1 Rx:%s\r'',uart1_aRxBuffer);

len1=0;

}

And the hyper terminal  Displays below :

0690X00000603KzQAI.jpg

At the red mark we are expecting  result : 

''+CPMS: SM,0,50,SM,0,50,SM,0,50'' but not sucesses

Is UART1 & UART2 use the same buffer for writing & reading?

aaron239955_stm1_st
Senior
December 15, 2016
Posted on December 15, 2016 at 20:05

The response you are seeing makes perfect sense because your logic is completely confused.

Regardless of the command, this is the way your logic is currently working:

1. You transmit a string (command) to the M95 like AT+GSM.....

2. You delay 2 seconds, during which time the M95 sends a response

3. you THEN enable the UART to receive data, using interrupts (and I still don't see your interrupt handling code)

4. the result of (2) above is that the response from the M95 happens while you are sitting in a 2 second delay.  As a result you get whatever was received by the hardware before it overflowed because you are not emptying the Rx buffer as characters are coming in.  So you get the first 2 characters '+C' which is the beginning of '+CPMS....' but since nobody is looking at the receiver, after the first two characters are buffered in the hardware peripheral (in the Rx register and the CPU interface register) it drops all subsequent characters on the floor.  The whole message was sent back by the M95 while you are sitting in a delay loop and ignoring what is coming back for 2 seconds.  So when you finally enable the Receiver with your HAL call it gives you the two characters it had stuck in the peripheral's registers.

What you need to do is enable the Receiver BEFORE you send a command so that you get back anything that the M95 sends you.  Including the command you sent if you have Echo enabled.  YOU need to figure out what to expect back based on whether echo is on or not, etc etc etc, and throw out any extraneous information and extract the useful response.  You can't use delays to hope that the bad stiff gets ignored and you'll get the good stuff because you don't know how long it will be before the M95 responds.

By waiting 2 seconds to look at the receiver after sending a command, you are ignoring the response from the M95.

And as a side note, setting a receive buffer 5 characters bigger than the size of the buffer you were passed is dangerous at best.  (assuming this will even know what the size is since what is passed to the function is pointer to an arbitrary array)

If you would like me to write the code for you, let me know.

HARI krishna
Associate III
December 16, 2016
Posted on December 16, 2016 at 07:28

Thanks for your helpful reply,below is the interrupt handle code for UART receiving ,even after removing increment buffer size same result was seen from the device.

/**

* @brief Receive an amount of data in interrupt mode.

* @param huart: UART handle.

* @param pData: pointer to data buffer.

* @param Size: amount of data to be received.

* @retval HAL status

*/

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

{

if((huart->State == HAL_UART_STATE_READY) || (huart->State == HAL_UART_STATE_BUSY_TX))

{

if((pData == NULL ) || (Size == 0))

{

return HAL_ERROR;

}

/* Process Locked */

__HAL_LOCK(huart);

huart->pRxBuffPtr = pData;

huart->RxXferSize = Size;

huart->RxXferCount = Size;

/* Computation of UART mask to apply to RDR register */

UART_MASK_COMPUTATION(huart);

huart->ErrorCode = HAL_UART_ERROR_NONE;

/* Check if a transmit process is ongoing or not */

if(huart->State == HAL_UART_STATE_BUSY_TX)

{

huart->State = HAL_UART_STATE_BUSY_TX_RX;

}

else

{

huart->State = HAL_UART_STATE_BUSY_RX;

}

/* Enable the UART Parity Error Interrupt */

__HAL_UART_ENABLE_IT(huart, UART_IT_PE);

/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */

__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

/* Process Unlocked */

__HAL_UNLOCK(huart);

/* Enable the UART Data Register not empty Interrupt */

__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

return HAL_OK;

}

else

{

return HAL_BUSY;

}

}

if possible please send me the code for this interface.

HARI krishna
Associate III
December 15, 2016
Posted on December 15, 2016 at 14:06

For the Above code is there any changes needed for receiving uart data from quectel M95.

Is there any problem with receiving data on uart2 and printing it on uart1 with ms delay?

By using these responses i need to check weather modem initialized correctly or not. 

please help me on this issue.

Seb
ST Employee
December 15, 2016
Posted on December 15, 2016 at 14:27

I'm guessing how long does it take to send 'UART1 RX:' and how many bytes I may received in this time?

Try this: inside the interrupt of receiving a byte from Quectel, directly send and write the debug UART the same byte, and make sure the debug UART baud rate is higher (so you don't need extra buffering). When you write your 'GSM....' string, 

send_cmnd((char *)'AT+CPMS=\'SM\',\'SM\',\'SM\'\r',('+CPMS: SM,0,50,SM,0,50,SM,0,50')); anticipate and add immediately the UART1 Rx: string before sending. Then it might work better. Let us know.

HARI krishna
Associate III
December 16, 2016
Posted on December 16, 2016 at 11:51

Using the Above application stm32 need to read the text messages which are stored in the SIM card.

In these messages are some are lengthy(120 characters) for this how to define a receive buffer?

what is the maximum byte buffer size that uart can receive ?

Can i use 

HAL_UART_Receive_IT(&huart1,(uint8_t *)uart1_aRxBuffer,150);?

is there any problem for using lengthy receive buffer?

Seb
ST Employee
December 16, 2016
Posted on December 16, 2016 at 12:50

The RAM size is the limit. In the interrupt for UART RX, fill up a buffer (as big as you need) from receive data string. Once you get the end of string (line feed/return detect) , set a RAM flag which will be polled by the main loop to grab the message and analyse it.

aaron239955_stm1_st
Senior
December 16, 2016
Posted on December 16, 2016 at 17:23

Here is some code that should at least follow a logical process where you can get responses from the M It uses the Interrupt version of the UART receive HAL call, however it limits the size to 1 character. This way you get an interrupt on every character and you can manage the receive buffer yourself.

The callback that is called on each character is near the bottom, and that builds the receive buffer. the routine above it can be used to remove one character from the buffer at a time, and the get_response routine keeps filling the buffer until an 'OK' is received and then returns the length of the message to the calling program. If it does not get this response within the time specified in the 'WaitResponse' value, it returns a -1 as the length as an error indication. You may need to enhance this function if you would like to handle non-'OK' responses from the chip. Also, it does not handle or pass characters received after the 'OK' sequence like line termination characters ' ' or ' '.

Good luck

#define WaitResponse 1000
#define BufferSize 256;
//globals to manage receive buffers
int RxIndex = 0;
char InBuffer[BufferSize];


void send_cmnd(char *AT_cmd_string){
int err;
response_string[0] = 0; // set up condition for 'response_format() function'
HAL_UART_Receive_IT(&huart1, (uint8_t*)InBuffer, 1 );// Start RxInt with first char
printf('

GSM Tx: %s

',(int8_t*)AT_cmd_string); // your debug message
HAL_UART_Transmit_IT(&huart1, AT_cmd_string, strlen(AT_cmd_string));//Send command to M95
err = get_response();
if(err > 0)
printf('

 UART1 Rx:%s
',response_string);
}

int get_response(void){
int i=0, len=0, done = 0, ticktime;
ticktime = HAL_GetTick();// get start tick time
ticktime += WaitResponse; // set time when we give up
ticktime %= 0x1000000; //timer is only 24 bits, so wrap if timer would wrap
// Check for 'OK' to terminate response
while((done==0) && (Hal_GetTick() != ticktime)){
UART1_getchar(); // wait for the next character
len++;
if((InBuffer[len-1] == 'K') && (len>1)){
if(returnBuffer[len-2] == 'O') // got 'OK'
done == 1;
}
}
if(done == 0) // timeout occurred
return -1; //return error value
else {
returnBuffer[len++] = 0;//NULL terminate string
return len;
}

/*
*This routine returns a 1 when a new character has been returned by the
* UART. If no new chars, 
* returns 0
*/
int UART1_kbhit(UART_HandleTypeDef *huart){
//if (huart->RxXferCount == indx)
if(RxIndex == 0)
return 0;
else return 1;
}

/*
* This routine stalls until a character has been recieved by the UART
* and then returns it
*/
char UART1_getchar(void){
__HAL_UART1_EXTI_DISABLE_IT()// hold off interrupt until index updated
while(!UART1_kbhit());
if(RxIndex > 0)
RxIndex --;
__HAL_UART1_EXTI_ENABLE_IT()
return RxBuffer[RxIndex];
}

/*
*This routine is a callback defined by the HAL which is called when the receive
*operation has completed. Since we are setting the receive interrupt function to
*only get once character, this is called when each character comes in so that
*the user program can manage the input buffer. All it does in increment the index
*pointer for the buffer and re-start the interrupt-based receive function.
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart){
RxIndex++;
if(RxIndex == BufferSize) // if overrun buffer, wrap
RxIndex = 0;
HAL_UART_Receive_IT(&huart1, RxBuffer[RxIndex],1);
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

HARI krishna
Associate III
December 19, 2016
Posted on December 19, 2016 at 08:19

Thanks for quick reply, 

The Above code has errors if  we paste same in Debugger,

Any how some what i managed to compile but the code was stopped working on this function

UART1_kbhit

();

My old code was some what improved it working fine with modem replies .

but how to read modem SIM Messages those are very lengthy. For reading one message it is working fine but at the same time second message is not reading simply executing SIM read command.This is done by

HAL_UART_Receive_IT(&huart1,(uint8_t *)uart1_aRxBuffer,120);

can i do like this?

AT+CMGR=1;

** some text Message Reply**

AT+CMGR=2;

Simply OK

But when i delete first message second one is reading.help me on this issue.

HARI krishna
Associate III
December 19, 2016
Posted on December 19, 2016 at 08:49

For the while(!UART1_kbhit()); in function
char UART1_getchar(void) is not getting exit from loop.