GSM Modems in Embedded Systems: AT Commands, Popular Modules, and Practical Examples
GSM/LTE modems enable embedded devices to communicate over cellular networks without WiFi or Ethernet. From remote sensor monitoring to GPS tracking and SMS alerts, these modules provide reliable connectivity in applications where traditional networks aren’t available or practical.
This guide covers popular GSM/LTE modules, how AT command communication works, essential commands with examples, and real-world implementations you can deploy in production.
What is a GSM Modem and When Do You Need One?
A GSM modem (or cellular modem) is a hardware device that connects to cellular networks (2G/3G/4G/5G) to provide:
- SMS messaging (send/receive text messages)
- Voice calls (dial/answer phone calls)
- Data connectivity (TCP/IP, HTTP, MQTT over cellular)
- GPS/GNSS positioning (many modules include GPS)
- Network time synchronization
When to Use GSM Instead of WiFi/Ethernet:
✓ Remote locations without infrastructure (farms, pipelines, weather stations)
✓ Mobile applications (vehicle tracking, asset monitoring)
✓ Backup connectivity when primary network fails
✓ Wide-area coverage (entire countries/continents)
✓ SMS alerting for critical events
Popular GSM/LTE Modules for Embedded Systems
1. SIMCom SIM800 Series (2G GSM/GPRS)
Models: SIM800L, SIM800C, SIM800H
Network: 2G GSM/GPRS (850/900/1800/1900 MHz)
Features: SMS, Voice, GPRS data (up to 85.6 kbps)
Interface: UART (9600-115200 baud)
Power: 3.4-4.4V, peak 2A (transmission bursts)
Cost: $3-8 (very affordable)
Best For: SMS alerts, basic data logging, legacy systems
Note: 2G networks are being phased out in many countries (check local availability)
Common Breakout Boards: SIM800L mini module, SIM800C EVB
2. SIMCom SIM7600 Series (4G LTE Cat-1)
Models: SIM7600E (Europe), SIM7600A (Americas), SIM7600G (Global)
Network: 4G LTE Cat-1, fallback to 3G/2G
Features: LTE data (10 Mbps down, 5 Mbps up), SMS, Voice, GPS/GLONASS
Interface: UART, USB
Power: 3.3-4.3V, peak 2A
Cost: $15-25
Best For: IoT devices requiring reliable LTE connectivity, GPS tracking, moderate data rates
3. Quectel EC25 (4G LTE Cat-4)
Network: 4G LTE Cat-4 (150 Mbps down, 50 Mbps up)
Features: Fast data, SMS, Voice, GNSS
Interface: USB 2.0, UART
Power: 3.3-4.3V
Cost: $20-30
Best For: High-bandwidth applications, video streaming, industrial IoT
4. u-blox SARA-R5 (LTE-M / NB-IoT)
Network: LTE-M, NB-IoT (low-power wide-area)
Features: Ultra-low power, deep sleep modes, PSM/eDRX
Power: 2.75-4.2V, deep sleep <5 µA
Cost: $15-20
Best For: Battery-powered IoT sensors, smart meters, long-term deployments
Comparison Table
| Module | Network | Speed | Power | Use Case |
|---|---|---|---|---|
| SIM800L | 2G GSM/GPRS | 85 kbps | High | SMS alerts, legacy |
| SIM7600 | 4G LTE Cat-1 | 10 Mbps | Medium | IoT, GPS tracking |
| EC25 | 4G LTE Cat-4 | 150 Mbps | High | Video, high data |
| SARA-R5 | LTE-M/NB-IoT | 375 kbps | Very Low | Battery IoT sensors |
AT Command Protocol: How GSM Modems Communicate
GSM modems use the AT command set (Attention Commands) over UART serial interface. Commands follow this structure:
AT+COMMAND=parameter1,parameter2\r\n
Response Format:
OK // Command successful
ERROR // Command failed
+CME ERROR: 123 // Extended error with code
Basic Communication Flow
MCU → Modem: AT\r\n
Modem → MCU: OK\r\n
MCU → Modem: AT+CSQ\r\n // Check signal quality
Modem → MCU: +CSQ: 25,0\r\n // Signal strength: 25 (-87 dBm)
OK\r\n
Essential AT Commands Reference
| Command | Description | Example Response |
|---|---|---|
AT | Test communication | OK |
ATI | Module identification | SIM7600E R14 |
AT+CPIN? | Check SIM card status | +CPIN: READY |
AT+CSQ | Signal quality (0-31) | +CSQ: 25,0 (good) |
AT+CREG? | Network registration | +CREG: 0,1 (registered) |
AT+COPS? | Current operator | +COPS: 0,0,"Vodafone" |
AT+CGMR | Firmware version | Revision:1529B04SIM7600M22 |
AT+CCID | SIM card ICCID | +CCID: 89012345... |
AT+CNUM | Own phone number | +CNUM: "","1234567890" |
Practical Example: MCU to GSM Modem Communication
Hardware Connection (STM32 Example)
STM32 UART2 SIM7600 Module
----------- --------------
TX (PA2) ────────> RX
RX (PA3) <──────── TX
GND ──────────GND
──────────VCC (3.8-4.2V, 2A capable)
Basic AT Command Implementation (C)
#include "stm32f4xx_hal.h"
#include <string.h>
#include <stdio.h>
extern UART_HandleTypeDef huart2; // GSM modem UART
#define GSM_UART &huart2
#define GSM_TIMEOUT 5000 // 5 seconds
#define GSM_BUFFER_SIZE 512
char gsm_rx_buffer[GSM_BUFFER_SIZE];
// Send AT command and wait for response
bool gsm_send_command(const char *cmd, const char *expected_response, uint32_t timeout) {
memset(gsm_rx_buffer, 0, GSM_BUFFER_SIZE);
// Send command with \r\n
char cmd_with_cr[128];
snprintf(cmd_with_cr, sizeof(cmd_with_cr), "%s\r\n", cmd);
HAL_UART_Transmit(GSM_UART, (uint8_t*)cmd_with_cr, strlen(cmd_with_cr), 1000);
// Wait for response
uint32_t start = HAL_GetTick();
uint16_t index = 0;
while (HAL_GetTick() - start < timeout) {
if (HAL_UART_Receive(GSM_UART, (uint8_t*)&gsm_rx_buffer[index], 1, 100) == HAL_OK) {
index++;
if (index >= GSM_BUFFER_SIZE - 1) break;
// Check if expected response received
if (expected_response && strstr(gsm_rx_buffer, expected_response)) {
return true;
}
}
}
return expected_response ? false : true;
}
// Initialize GSM modem
bool gsm_init(void) {
HAL_Delay(3000); // Wait for modem boot
// Test communication
if (!gsm_send_command("AT", "OK", 2000)) {
return false;
}
// Disable command echo
gsm_send_command("ATE0", "OK", 2000);
// Check SIM card
if (!gsm_send_command("AT+CPIN?", "+CPIN: READY", 5000)) {
return false; // SIM card not ready
}
// Wait for network registration
for (int i = 0; i < 30; i++) {
gsm_send_command("AT+CREG?", NULL, 2000);
if (strstr(gsm_rx_buffer, "+CREG: 0,1") ||
strstr(gsm_rx_buffer, "+CREG: 0,5")) {
return true; // Registered on network
}
HAL_Delay(2000);
}
return false; // Network registration failed
}
// Get signal strength (0-31, 99=unknown)
int gsm_get_signal_strength(void) {
if (gsm_send_command("AT+CSQ", "+CSQ:", 2000)) {
int signal, ber;
if (sscanf(gsm_rx_buffer, "+CSQ: %d,%d", &signal, &ber) == 2) {
return signal; // 0-31 (31 = -51dBm or better)
}
}
return -1;
}
Real-World Use Cases with Working Code
Use Case 1: Send SMS Alert
Application: Temperature monitoring system sends SMS when threshold exceeded
// Send SMS message
bool gsm_send_sms(const char *phone_number, const char *message) {
char cmd[128];
// Set SMS text mode
if (!gsm_send_command("AT+CMGF=1", "OK", 2000)) {
return false;
}
// Set recipient number
snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"", phone_number);
if (!gsm_send_command(cmd, ">", 5000)) {
return false;
}
// Send message content + Ctrl+Z (0x1A)
char msg_with_ctrl_z[256];
snprintf(msg_with_ctrl_z, sizeof(msg_with_ctrl_z), "%s%c", message, 0x1A);
HAL_UART_Transmit(GSM_UART, (uint8_t*)msg_with_ctrl_z, strlen(msg_with_ctrl_z), 5000);
// Wait for send confirmation
uint32_t start = HAL_GetTick();
while (HAL_GetTick() - start < 30000) { // 30 sec timeout
if (gsm_send_command("", "+CMGS:", 1000)) {
return true;
}
}
return false;
}
// Example usage
void temperature_monitor_task(void) {
float temperature = read_temperature_sensor();
if (temperature > TEMP_THRESHOLD) {
char message[128];
snprintf(message, sizeof(message),
"ALERT: Temperature %.1f°C exceeds threshold!", temperature);
if (gsm_send_sms("+1234567890", message)) {
// SMS sent successfully
log_event("SMS alert sent");
}
}
}
Use Case 2: HTTP POST Data to Cloud Server
Application: Remote sensor posts data to REST API
// HTTP POST request via GPRS
bool gsm_http_post(const char *url, const char *data, int *http_code) {
// Initialize HTTP service
if (!gsm_send_command("AT+HTTPINIT", "OK", 5000)) {
return false;
}
// Set HTTP parameters
gsm_send_command("AT+HTTPPARA=\"CID\",1", "OK", 2000);
char cmd[256];
snprintf(cmd, sizeof(cmd), "AT+HTTPPARA=\"URL\",\"%s\"", url);
if (!gsm_send_command(cmd, "OK", 2000)) {
gsm_send_command("AT+HTTPTERM", NULL, 2000);
return false;
}
// Set content type
gsm_send_command("AT+HTTPPARA=\"CONTENT\",\"application/json\"", "OK", 2000);
// Prepare POST data
snprintf(cmd, sizeof(cmd), "AT+HTTPDATA=%d,10000", strlen(data));
if (!gsm_send_command(cmd, "DOWNLOAD", 5000)) {
gsm_send_command("AT+HTTPTERM", NULL, 2000);
return false;
}
// Send actual data
HAL_UART_Transmit(GSM_UART, (uint8_t*)data, strlen(data), 5000);
HAL_Delay(500);
// Execute POST request
if (!gsm_send_command("AT+HTTPACTION=1", "OK", 2000)) {
gsm_send_command("AT+HTTPTERM", NULL, 2000);
return false;
}
// Wait for response (async notification: +HTTPACTION: 1,200,1234)
uint32_t start = HAL_GetTick();
while (HAL_GetTick() - start < 30000) {
HAL_Delay(500);
if (strstr(gsm_rx_buffer, "+HTTPACTION:")) {
int method, code, length;
if (sscanf(gsm_rx_buffer, "+HTTPACTION: %d,%d,%d", &method, &code, &length) == 3) {
*http_code = code;
gsm_send_command("AT+HTTPTERM", "OK", 2000);
return (code == 200 || code == 201);
}
}
}
gsm_send_command("AT+HTTPTERM", "OK", 2000);
return false;
}
// Example: Send sensor data to cloud
void send_telemetry(void) {
float temperature = read_temperature();
float humidity = read_humidity();
char json_data[256];
snprintf(json_data, sizeof(json_data),
"{\"device_id\":\"ESP001\",\"temp\":%.1f,\"humidity\":%.1f}",
temperature, humidity);
int http_code;
if (gsm_http_post("http://api.example.com/telemetry", json_data, &http_code)) {
printf("Data sent successfully (HTTP %d)\n", http_code);
}
}
Use Case 3: GPS Tracking Device
Application: Vehicle tracking system using GSM+GPS module
typedef struct {
float latitude;
float longitude;
float altitude;
float speed;
bool valid;
} gps_data_t;
// Get GPS coordinates (SIM7600 example)
bool gsm_get_gps(gps_data_t *gps) {
// Power on GPS
gsm_send_command("AT+CGPS=1", "OK", 2000);
HAL_Delay(2000); // Wait for GPS fix
// Request GPS data
if (!gsm_send_command("AT+CGPSINFO", "+CGPSINFO:", 5000)) {
return false;
}
// Parse NMEA-like response: +CGPSINFO: lat,N,lon,E,date,time,alt,speed,course
// Example: +CGPSINFO: 4807.038,N,01131.000,E,13062026,124100.0,449.6,0.0,0
char lat_str[16], lon_str[16], alt_str[16], speed_str[16];
char ns, ew;
if (sscanf(gsm_rx_buffer, "+CGPSINFO: %[^,],%c,%[^,],%c,%*[^,],%*[^,],%[^,],%[^,]",
lat_str, &ns, lon_str, &ew, alt_str, speed_str) >= 6) {
// Convert to decimal degrees
float lat_deg = atof(lat_str) / 100.0f;
float lon_deg = atof(lon_str) / 100.0f;
gps->latitude = (ns == 'N') ? lat_deg : -lat_deg;
gps->longitude = (ew == 'E') ? lon_deg : -lon_deg;
gps->altitude = atof(alt_str);
gps->speed = atof(speed_str);
gps->valid = (strcmp(lat_str, "") != 0);
return gps->valid;
}
return false;
}
// GPS tracking application
void gps_tracker_task(void) {
gps_data_t gps;
if (gsm_get_gps(&gps)) {
char json[256];
snprintf(json, sizeof(json),
"{\"lat\":%.6f,\"lon\":%.6f,\"alt\":%.1f,\"speed\":%.1f}",
gps.latitude, gps.longitude, gps.altitude, gps.speed);
int http_code;
gsm_http_post("http://tracking.example.com/api/location", json, &http_code);
}
}
Use Case 4: Remote Device Control via SMS
Application: Gate opener controlled by SMS command
typedef struct {
char phone_number[20];
char message[160];
bool new_message;
} sms_message_t;
// Read incoming SMS
bool gsm_read_sms(int index, sms_message_t *sms) {
char cmd[32];
snprintf(cmd, sizeof(cmd), "AT+CMGR=%d", index);
if (!gsm_send_command(cmd, "+CMGR:", 5000)) {
return false;
}
// Parse response: +CMGR: "REC UNREAD","+1234567890",,"26/08/30,12:34:56+00"
// Message content on next line
char *phone_start = strstr(gsm_rx_buffer, "\",\"");
if (phone_start) {
phone_start += 3;
char *phone_end = strchr(phone_start, '\"');
if (phone_end) {
int len = phone_end - phone_start;
strncpy(sms->phone_number, phone_start, len);
sms->phone_number[len] = '\0';
// Message content after second \r\n
char *msg_start = strstr(phone_end, "\r\n");
if (msg_start) {
msg_start += 2;
char *msg_end = strstr(msg_start, "\r\n");
if (msg_end) {
len = msg_end - msg_start;
strncpy(sms->message, msg_start, len);
sms->message[len] = '\0';
sms->new_message = true;
return true;
}
}
}
}
return false;
}
// SMS command handler
void sms_control_task(void) {
// Check for new SMS
gsm_send_command("AT+CMGL=\"ALL\"", NULL, 5000);
// If SMS detected, read it
if (strstr(gsm_rx_buffer, "+CMGL:")) {
sms_message_t sms;
if (gsm_read_sms(1, &sms)) {
// Process command
if (strstr(sms.message, "OPEN") && is_authorized(sms.phone_number)) {
open_gate();
gsm_send_sms(sms.phone_number, "Gate opened");
} else if (strstr(sms.message, "STATUS")) {
char status[100];
get_system_status(status);
gsm_send_sms(sms.phone_number, status);
}
// Delete processed message
gsm_send_command("AT+CMGD=1", "OK", 2000);
}
}
}
Essential Tips and Best Practices
1. Power Supply Requirements
GSM modems draw high peak current during transmission (1-2A bursts):
✓ Use dedicated 3.7V-4.2V LiPo battery or buck converter rated 2A+
✓ Add bulk capacitors (1000-2200 µF) near module power pins
✗ Do NOT power directly from Arduino 5V pin or USB (voltage sag causes resets)
2. Antenna Selection
Poor antenna = poor signal = failed connections:
✓ Use external antenna with SMA connector for best range
✓ Keep antenna away from metal enclosures
✓ For PCB antenna, follow manufacturer layout guidelines exactly
3. SIM Card Activation
// Always check SIM status before attempting network operations
gsm_send_command("AT+CPIN?", "+CPIN: READY", 5000);
// If PIN required:
// gsm_send_command("AT+CPIN=1234", "OK", 5000); // Enter PIN
4. Network Registration Wait
// Network registration can take 5-30 seconds
// Always check registration status before data operations
for (int retry = 0; retry < 30; retry++) {
gsm_send_command("AT+CREG?", NULL, 2000);
if (strstr(gsm_rx_buffer, "+CREG: 0,1")) {
break; // Registered on home network
}
HAL_Delay(2000);
}
5. Error Handling
// Enable verbose error messages
gsm_send_command("AT+CMEE=2", "OK", 2000);
// Now errors return descriptive text:
// ERROR: SIM not inserted
// +CME ERROR: network timeout
6. Watchdog and Recovery
// Implement modem health check
bool modem_alive = gsm_send_command("AT", "OK", 2000);
if (!modem_alive) {
// Hardware reset modem via power or reset pin
modem_hardware_reset();
gsm_init();
}
GSM vs Other IoT Connectivity Options
| Technology | Range | Power | Data Rate | Cost | Best For |
|---|---|---|---|---|---|
| GSM/LTE | Nationwide | High | 10-150 Mbps | Medium | Mobile, remote, wide area |
| WiFi | 50-100m | Medium | 50-300 Mbps | Low | Fixed locations, high data |
| LoRaWAN | 2-15 km | Very Low | 0.3-50 kbps | Low | Sensors, rural IoT |
| NB-IoT | Nationwide | Very Low | 250 kbps | Medium | Battery IoT, smart meters |
| Bluetooth | 10-100m | Low | 1-2 Mbps | Very Low | Wearables, local sensors |
Summary
Key Takeaways:
- GSM modems enable cellular connectivity for embedded devices via AT commands over UART
- Popular choices: SIM800 (2G, legacy), SIM7600 (4G LTE, versatile), SARA-R5 (LTE-M, low power)
- AT commands follow pattern:
AT+COMMAND=param\r\n→ response →OK - Common applications: SMS alerts, HTTP/MQTT data upload, GPS tracking, remote control
- Critical requirements: 2A power supply, proper antenna, SIM card with data plan
- Always implement network registration checks, error handling, and modem watchdog
GSM modems provide reliable wide-area connectivity for IoT and M2M applications where WiFi isn’t practical. Master AT commands, and you can integrate cellular communication into any embedded project.