2024-07-29 04:17 PM
void sendAT(char command[], char answer[], int waitForAnswer) { char ATcommand[500]; uint8_t buffer[500] = { 0 }; uint8_t ATisOK = 0; sprintf(ATcommand, "%s\r\n", command); DEBUG_PRINT("Sending AT Command: "); DEBUG_PRINT(ATcommand); while (!ATisOK) { HAL_UART_Transmit(&huart2, (uint8_t*) ATcommand, strlen(ATcommand), 2000); HAL_UART_Receive(&huart2, buffer, sizeof(buffer) - 1, 300); buffer[sizeof(buffer) - 1] = '\0'; HAL_Delay(500); ATisOK = !waitForAnswer; if (strstr((char*) buffer, "OK")) { ATisOK = 1; } DEBUG_PRINT("GSM: "); DEBUG_PRINT((char* ) buffer); HAL_Delay(1000); memset(buffer, 0, sizeof(buffer)); } } char* sendATWithReturn(char command[]) { char ATcommand[500]; uint8_t buffer[300] = { 0 }; char *returnBuffer = malloc(300 * sizeof(char)); if (returnBuffer == NULL) { return NULL; } sprintf(ATcommand, "%s\r\n", command); HAL_UART_Transmit(&huart2, (uint8_t*) ATcommand, strlen(ATcommand), 1000); HAL_UART_Receive(&huart2, buffer, 300, 100); HAL_Delay(500); DEBUG_PRINT("GSM: "); DEBUG_PRINT((char* ) buffer); strncpy(returnBuffer, (char*) buffer, 300); return returnBuffer; }
void modemStart(char *apn, char *user, char *pwd) { sendATWithReturn("AT"); HAL_Delay(1000); sendATWithReturn("AT+CPIN?"); HAL_Delay(1000); sendATWithReturn("AT+CREG?"); HAL_Delay(1000); sendATWithReturn("AT+CGATT?"); HAL_Delay(1000); sendATWithReturn("AT+CSQ"); HAL_Delay(1000); char command[500]; snprintf(command, sizeof(command), "AT+CGDCONT=1,\"IP\",\"%s\"", apn); sendAT(command, "OK", 1); memset(command, 0, sizeof(command)); HAL_Delay(1000); sendAT("AT+CGATT=1", "OK", 0); HAL_Delay(1000); sendATWithReturn("AT+CSTT?"); HAL_Delay(1000); snprintf(command, sizeof(command), "AT+CSTT=\"%s\",\"%s\",\"%s\"", apn, user, pwd); sendAT(command, "OK", 1); memset(command, 0, sizeof(command)); HAL_Delay(1000); sendATWithReturn("AT+CIICR"); HAL_Delay(1000); sendATWithReturn("AT+CIFSR"); HAL_Delay(1000); sendATWithReturn("AT+CIPMUX=1"); /* AT+CPIN?: Verifica o status do PIN do SIM. AT+CREG?: Verifica o status de registro na rede. Sequência de Inicialização: AT+NETCLOSE: Fecha qualquer conexão de rede existente. AT+CGATT=0: Desativa o GPRS. AT+CGATT=1: Ativa o GPRS. AT+CGDCONT: Define o contexto PDP. AT+CSTT: Define o APN, usuário e senha. AT+CIICR: Inicia a conexão sem fio. AT+CIFSR: Obtém o endereço IP. AT+CIPMUX=1: Habilita o modo de múltiplas conexões. */ }
19:37:54.671 -> Serial2: Send AT: 19:37:54.671 -> Sending AT Command: AT 19:37:54.671 -> GSM: AT 19:37:54.671 -> OK 19:37:54.671 -> 19:37:56.282 -> Serial2: GSM: AT 19:37:56.282 -> OK 19:37:56.282 -> 19:37:57.878 -> Serial2: GSM: AT+CPIN? 19:37:57.878 -> +CPIN: READY 19:37:57.878 -> 19:37:57.878 -> OK 19:37:57.878 -> 19:37:59.455 -> Serial2: GSM: AT+CREG? 19:37:59.455 -> +CREG: 0,1 19:37:59.455 -> 19:37:59.455 -> OK 19:37:59.455 -> 19:38:01.060 -> Serial2: GSM: AT+CGATT? 19:38:01.060 -> +CGATT: 1 19:38:01.060 -> 19:38:01.060 -> OK 19:38:01.060 -> 19:38:04.242 -> Serial2: GSM: AT+CSQ 19:38:04.242 -> +CSQ: 18,0 19:38:04.242 -> 19:38:04.242 -> OK 19:38:04.242 -> Sending AT Command: AT+CGDCONT=1,"IP","zap.vivo.com.br" 19:38:04.287 -> GSM: AT+CGDCONT=1,"IP","zap.vivo.com.br" 19:38:04.287 -> OK 19:38:04.287 -> 19:38:06.839 -> Serial2: Sending AT Command: AT+CGATT=1 19:38:06.839 -> GSM: AT+CGATT=1 19:38:06.885 -> OK 19:38:06.885 -> 19:38:11.069 -> Serial2: GSM: AT+CSTT? 19:38:11.069 -> ERROR 19:38:11.069 -> Sending AT Command: AT+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:11.069 -> GSM: A+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:11.069 -> ERROR 19:38:11.069 -> 19:38:12.670 -> Serial2: GSM: A+CSTT="zap.vivo.com.br","vivo","vivo" 19:38:12.670 -> ERROR
Solved! Go to Solution.
2024-07-30 07:19 AM - edited 2024-07-30 07:22 AM
@BarryWhit wrote:Can you share a link to the AT command manual you're using for this module? None of the ones I've found list AT+CSTT as a valid command.
But At+CSTT is a listed command for the much older SIM900 module from the same company, which was used in older shields for arduino.
2024-07-29 04:53 PM
Use the insert code sample to format your code.
2024-07-29 05:04 PM
Learn to use buffers, and interrupts.
The devices operate in Rx/Tx concurrently, not this send-blocking, receive-blocking, arbitrary delays, nonsense.
Cellular modems can have time-outs running into multiple minutes for interactions with the network.
The AT command protocol expects you to wait for a response, AT, ERROR, NO CARRIER, etc and not jam further input until the prior command has completed. It might also send you unsolicited responses like RING, when an inbound call comes in. You need to approach this in a much more stateful manner.
2024-07-29 05:47 PM - edited 2024-07-30 06:44 AM
Apparently with two characters in the password the command is sent correctly, but with more than two the AT loses its T,
You do realize none of us know which GSM modem your using nor its command set, right? which one's "the password" then?
I tested it this way:19:28:09.621 -> Serial2: GSM: AT+CSTT=“zap.vivo.com.br”,“vivo”,"dd”19:28:09.621 -> ERRORNote that AT+CSTT is correct.Doing some more tests, I realized that the error is in the part of sending and receiving the data by Serial, since even the DEBUG_PRINT that occurs before the while click to send the command is correct.[...]After a lot of thought, I realized that the error was due to the fact that the command was going to the module with the T for AT missing (A+CSTT).
What is this "test"? it just looks like you sent a command, and the modem reported an error. How exactly is this a different "test" from the log output you posted?
I don't see any compelling evidence suggesting the issue is a mangled command being transmitted. All you know is that you send the modem a command and it signaled an error. That could be caused by any number of things, including a malformed command, malformed arguments, sending the command when the modem wasn't expecting it, or something else.
Use TX-RX Loopback to verify that everything you send comes back without error. Make the wiring of similar length to your modem connection, though that's unlikely to be the issue unless you're running the wires across the room.
For typical UART data rates, you can use a cheap 10$ USB logic analyzer to see exactly what goes on the line , in terms of both data and timing. They all come with libsigrok based software that does protocol decoding, including UART.
Delorean probably pointed out the issue for you., you need to implement this as a state machine instead of using hardcoded delays (do use response timeouts), you need to decouple RX reception from TX, and you need to condition TX on the modem having responded to the previous command.
2024-07-29 06:04 PM - edited 2024-07-29 06:05 PM
How could I adapt the interrupts in this case? I tried to analyze the module's response via HAL_UART_RxCpltCallback but I couldn't get the answer.
2024-07-29 06:10 PM
You need to show that particular code you've tried to get working but failed to. That way we can see how you're trying to communicate to the GSM module and receiving from it.
2024-07-30 05:48 AM - edited 2024-07-30 06:02 AM
The problem is with the “HAL_UART_RxCpltCallback” function, which is never called.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == huart2.Instance){ DEBUG_PRINT("OLHA A MENSAGEM!\r\n"); HAL_UART_Receive_IT(&huart2, buffer, sizeof(buffer) - 1); gsmState = 2; } } uint16_t sendTick = 0; void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == huart2.Instance){ DEBUG_PRINT("MENSAGEM ENVIADA!\r\n"); gsmState = 1; sendTick = HAL_GetTick(); } } void sendAT(char command[], char answer[], int waitForAnswer) { char ATcommand[200]; uint8_t commandBuffer[200] = { 0 }; uint8_t ATisOK = 0; snprintf(ATcommand, sizeof(ATcommand), "AT%s\r\n", command); memcpy(commandBuffer, (uint8_t*)ATcommand, strlen(ATcommand) + 1); DEBUG_PRINT("Sending AT Command: \r\n"); DEBUG_PRINT(ATcommand); while (!ATisOK) { if(gsmState == 0){ HAL_UART_Transmit_IT(&huart2, commandBuffer, sizeof(commandBuffer)); } if(gsmState == 1){ if(HAL_GetTick() >= sendTick + 2000){ DEBUG_PRINT("TimeOut\r\n"); gsmState = 0; } } if(gsmState == 2){ buffer[sizeof(buffer) - 1] = '\0'; ATisOK = !waitForAnswer; if (strstr((char*) buffer, "OK")) { gsmState = 0; ATisOK = 1; }else{ gsmState = 0; } DEBUG_PRINT("GSM: \r\n"); DEBUG_PRINT((char*) buffer); memset(buffer, 0, sizeof(buffer)); } HAL_Delay(1000); } }
10:01:42.225 -> Serial2: Send AT: 10:01:42.225 -> Sending AT Command: 10:01:42.225 -> AT 10:01:42.225 -> MENSAGEM ENVIADA! 10:01:42.225 -> 10:01:45.221 -> Serial2: TimeOut 10:01:45.221 -> 10:01:46.235 -> Serial2: MENSAGEM ENVIADA! 10:01:46.235 -> 10:01:49.203 -> Serial2: TimeOut 10:01:49.203 -> 10:01:50.205 -> Serial2: MENSAGEM ENVIADA! 10:01:50.205 ->
Sorry, I wrote in a hurry and ended up forgetting important details.
Well, the modem I use is a Simcom a7670sa 4g. I used this modem in my Arduino system, where the TinyGSM library did all the heavy lifting. Based on it, I built this sequence for initializing and connecting to the mobile internet network, and then making HTTP requests.
The tests I'm referring to are as follows: I was suspicious that the problem might be memory, so I reduced the number of characters by removing the apn password from the command and sending it to the module. And so the module received the command correctly, but returned the obvious error since the password was wrong.
I'm using a local operator here in my country, called vivo, in which its APN has the credentials:
zap.vivo.com.br
user: vivo
psw: vivo
When the command has all these credentials it returns the omitted character problem.
I then tested putting in one character at a time, and saw that up to 2 characters the command worked, more than that it gave a problem.
2024-07-30 06:40 AM - edited 2024-07-30 06:48 AM
> I used this modem in my Arduino system
Arduino serial library behaves differently, it does buffering for you.
Other people who answered noted that your STM32 UART code is a bit naïve, so it isn't obvious that one character is missing in TX. Try to sniff the UART lines with external analyzer to capture the actual data. Try to find a library for "AT" device communication that handles concurrent TX and RX and various 'modem' responses.
The 'TX-RX Loopback' proposed by @BarryWhit can be helpful as well. This requires two UARTs: one for the modem, another for a 'terminal' running on a PC. The software should simply send bytes received from the modem to the terminal and v.v. as fast as possible without delays. So you type commands on the terminal and get responses from the modem. Unfortunately the Cube library does not have a ready example for this.
2024-07-30 06:51 AM
Did you call HAL_UART_Receive_IT to initialize the interrupt? I only see where you call it inside the callback but not before hand.
Then did you enable the NVIC?
2024-07-30 06:57 AM
@Pavel A. wrote:Try to find a library for "AT" device communication...
@MatheusMarkies Some examples here:
https://www.avrfreaks.net/s/topic/a5C3l000000UYptEAG/t147703?comment=P-1410260