This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: Interfacing SIM900 GSM module to TM4c (via UART) - Issue with receiving and parsing SMS

Part Number: TM4C123GH6PM

Hello,

I've been trying (with not very much success) to send SMS to my TM4C MCU via a SIMCom SIm900 GSM module.

They are connected through UART2 (PD6 and PD7), sending UART data to the GSM module works without issues, also sending SMS messages...

I managed to put together a program to receive (read) and parse SMS messages, it works but with quite a lot of bugs, it doesn't have a predictable output and it very important in the application where I would like to integrate this.

As I seen so far the content of the RX data is the issue.

I'll paste my initialization functions and sms processing functions here. Maybe someone can help me out with a tip.

UART2 Init Function, that uses UART STDIO from TIVAWARE

void UART2_Init(void){
        uint32_t uart_config_read = 0;
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);  //Enable clock on UART2
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);  //Enable clock on port D  //PD6 and PD7 will be RX and TX to GSM module
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART2));  //wait for UART2 to initialize
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD));  //wait for PortD to initialize
	
	GPIO_PORTD_LOCK_R = 0x4C4F434B;  //Unlock GPIO PD7
	GPIO_PORTD_CR_R |= 0xC0;  //Allow changes to PD6,7
	
	IntDisable(INT_UART2);
	UARTIntDisable(UART2_BASE,UART_INT_RX|UART_INT_TX|UART_INT_RT);  //Disable UART2 Interrupts
	UARTDisable(UART2_BASE);  //Disable UART2 while configuration
	
	GPIOPinConfigure(GPIO_PD6_U2RX);  //PCTL
	GPIOPinConfigure(GPIO_PD7_U2TX);
	GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7);  //DIR, PAD, 
	
	UARTClockSourceSet(UART2_BASE, UART_CLOCK_SYSTEM);  //Set the clock source for UART2
	UARTParityModeSet(UART2_BASE, UART_CONFIG_PAR_NONE);
	UARTFIFOEnable(UART2_BASE);  //Enable the UART FIFO
	UARTStdioConfig(GSM_UART_PORT, GSM_BAUD_RATE, SysCtlClockGet());
	UARTEchoSet(false);
	UARTIntRegister(UART2_BASE,&UARTStdioIntHandler);
	UARTConfigGetExpClk(UART2_BASE, SysCtlClockGet(), &GSM_Baud_Rate_Read, &uart_config_read);  //Get the Baud Rate
}

Initialization function of GSM module:

void PowerOnGSM(void){
	uint8_t lineCount = 0;
	uint16_t i = 0;
	uint8_t uart2_dump[1024] = "";
	
	UARTprintf("AT+CMGF=%u\r\n",1);  //message format text
	SysCtlDelay(Millis2Ticks(100)); //Interrupts are NOT disabled and OS is NOT stoped during delay!	
	lineCount = GSMgetResponse();

	UARTprintf("AT+CSDH=%u\r\n",0);  //do not show complete message header
	SysCtlDelay(Millis2Ticks(100));
	lineCount = GSMgetResponse();
		
	UARTprintf("AT+CNMI=%u%u%u%u%u\r\n",0,0,0,0,1);  //set new message indication mode
	//Messages are stored on GSM module, no indication is provided
	//AT+CMGR=msgNum will read the messages when user triggers GSMprocessMessage(msgNum)
	SysCtlDelay(Millis2Ticks(100));
	lineCount = GSMgetResponse();
}

SMS Processing functions: void GSMprocessMessage(uint8_t msgNum), uint8_t GSMgetResponse(void), bool GSMparseMessage(uint8_t lineCount)

//*****************************************************************************
//
// PROCESS SMS FOR ENVELOPE AND CONTENT 
//
//*****************************************************************************
void GSMprocessMessage(uint8_t msgNum) {	
	bool msgPresent = 0;  // Flag to ignore deleted messages
	int lineCount=0;  // Hold the number of lines

	
	// Request the message and get the lines of the response (includes envelope, nulls, SIM responses)
	UARTprintf("AT+CMGR=%u\r\n",msgNum);  //read request for msgNum
	SysCtlDelay(Millis2Ticks(10));
	
	// Start message retrieval
	lineCount = GSMgetResponse();

	// Make sure there's message content, process for envelope and content
	msgPresent = GSMparseMessage(lineCount);

	// Show the user what we found
	PC_Display_Message("\n\r>>> MESSAGE :",msgNum," ");
	if (msgPresent) {
		PC_Display_Message("> FROM: ",0,msgSender);  //TODO: Try to send a BS to delete the 0
		PC_Display_Message("> AT:",0,msgDate);			
		PC_Display_Message("> ON: ",0,msgTime);
		PC_Display_Message("> TEXT :",0,msgContent);			
	}
	else PC_Display_Message("> NOT PRESENT!",0," ");
}

//*****************************************************************************
//
// STORE A GSM RESPONSE TO ARRAY responseLine[]
//
//*****************************************************************************
uint8_t GSMgetResponse(void) {
bool readResponse = true;       // Keeps the loop open while getting message
int readLine = 0;               // Counts the lines of the message
char *GSMresponse = NULL;       // Use to grab input
char g_cInput[128];      // String input to a UART
	
	PC_Display_Message("> Started message reading", 0," ");
	while(readResponse&&(readLine<10)) {  //TODO, do not hardcode, use macro
		// Grab a line
		//UART2_GetString(g_cInput,sizeof(g_cInput));  //grabs string untill character != CR or LF
		if(UARTRxBytesAvail() > 2) UARTgets(g_cInput,sizeof(g_cInput));
		// Stop after newline
		strcpy(responseLine[readLine],g_cInput/*GSMresponse*/);
		//PC_Display_Message(">>> Line nr: ", readLine, g_cInput);
		//PC_Display_Message(">>> Line nr: ", readLine, responseLine[readLine]);
		// If this line says OK we've got the whole message
		if((strncmp(responseLine[readLine],"OK",2)==0)||
			 (strncmp(responseLine[readLine],"ERROR",5)==0)){
			readResponse = false;
		}
		else readLine++;
	}
	return (readLine+1);
}

//*****************************************************************************
//
// PARSE GSM MESSAGE FOR ENVELOPE AND MESSAGE CONTENT
// Stores message envelope and constant to global variables, OR returns true
// for message present, false for no message
//
//*****************************************************************************
bool GSMparseMessage(uint8_t lineCount) {
uint8_t activeLine = 0;  // Counter for line being processed
char *msgEnvelope = NULL;  // Message envelope holder

	msgContent = NULL; // Clear out the old message
	// Parse the new message
	while (activeLine < lineCount) //lineCount is larger by 1 than responseLine [index]
	{
		PC_Display_Message("Processed line: ",activeLine,responseLine[activeLine]);
		// CASE FOR ENVELOPE (which will look like:)
		// +CMGR: "REC READ","+40712334501","","17/04/12,22:53:48+12"
		if ( strstr(responseLine[activeLine],"+CMGR:") != '\0' )  //if message received
		{
			// Start parsing
			msgEnvelope = responseLine[activeLine];
			PC_Display_Message("> Envelope is: ",0,msgEnvelope);
				
			msgSender = strtok(msgEnvelope,",");  // Go to first comma, skipping status
			msgSender = strtok(NULL,",");  // Grab the number	
			msgSender += 3;  // Skip the prefix from the phone number and qautation marks
			msgSender[10] = '\0';  // Store the number (with null terminator)
			
			msgDate = strtok(NULL,",");  // Go to next comma, skipping phonebook entry
			msgDate = strtok(NULL,",");  // Grab the date
			msgDate += 1;  //remove qautation marks
			msgDate[8] = '\0';  // Store the date (with null terminator)
			
			msgTime = strtok(NULL,",");  // Grab the time
			msgTime[8] = '\0';  // Store the time (with null terminator)
		}

		// CASE FOR MESSAGE CONTENT
		// If we already found the envelope, and the line's not blank...
		else if (( msgEnvelope != NULL) && (responseLine[activeLine] != NULL))
		{
			// ... and we haven't found any content, this is the first line.
			if (msgContent == NULL) {msgContent = responseLine[activeLine];}

			// ... otherwise, add a space and append this line.
			else if ( activeLine+2 <= lineCount ) {  //+2 because of emply line before OK and last line with OK.
				strcat(msgContent, " ");
				strcat(msgContent, responseLine[activeLine]);
			}
		}
		activeLine++; // Proceed to next line
	}
	if (msgEnvelope == NULL) { // If we didn't find an envelope, there's no message
		return false;
	}
	else { 	// Otherwise, return true.
		return true;
	}
}

Global data and defines:

// Data from most recent incoming message stored here
char responseLine[10][160];  // Use to store UART inputs
static char *msgContent =  NULL;  // Message content holder
static char *msgSender =   NULL;  // Message sender
static char *msgDate =     NULL;  // Message date
static char *msgTime =     NULL;  // Message time

#define BAUD_RATE (115200)
#define GSM_BAUD_RATE (115200)
#define GSM_UART_PORT (2)
#define UART2_INT_PRIO (2)

I call GSMprocessMessage(msgNum)  from a GPIO ISR, when I want to read a SMS (specifying the msgNum I want to read).

The program as it is works, but gets a valid result (correct SMS retriaval and parsing) ~ 2 out of 10 times.

If you have any suggestions, tips please let me know.

Regards,

Alex Gaal

  • Hello Alex. Don't worry. Your code is O.K. but do this: connect to the GSM/GPRS module with let's say puTTY over serial*. Send all the needed AT+ commands to the module and wait for the response. Note response times and response messages. Then inside your source create some time depended reading loops and wait for the known answers when AT+ commands are send through your code. If you do it just carefully, then your code will go rock-n'-rolling. SIM900/800 modules and the other known, when triggered over serial have those delay answering problems. You either code proper time waiting and check loops, or you go a step further and you download the module's SDK and you write an applet that loads directly onto the GSM/GPRS module's flash, thus creating your own deterministic serial communication schema. BUT, also have in mind that there is set of AT+ commands that minimize the useless responses from the GSM modules and that alone speed things up very much and also makes the whole communication schema more deterministic.
    *--Note that TTL of GSM module is about 3.5 volt while PC's serial is +/- 12v. You need an RS-232-to-TTL 3.3V converter for directly connecting module with PC' serial.

    Good luck,
    John

    P.S. Instead strncmp use indexof