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


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

ModuleNetworkSpeedPowerUse Case
SIM800L2G GSM/GPRS85 kbpsHighSMS alerts, legacy
SIM76004G LTE Cat-110 MbpsMediumIoT, GPS tracking
EC254G LTE Cat-4150 MbpsHighVideo, high data
SARA-R5LTE-M/NB-IoT375 kbpsVery LowBattery 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

CommandDescriptionExample Response
ATTest communicationOK
ATIModule identificationSIM7600E R14
AT+CPIN?Check SIM card status+CPIN: READY
AT+CSQSignal quality (0-31)+CSQ: 25,0 (good)
AT+CREG?Network registration+CREG: 0,1 (registered)
AT+COPS?Current operator+COPS: 0,0,"Vodafone"
AT+CGMRFirmware versionRevision:1529B04SIM7600M22
AT+CCIDSIM card ICCID+CCID: 89012345...
AT+CNUMOwn 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

TechnologyRangePowerData RateCostBest For
GSM/LTENationwideHigh10-150 MbpsMediumMobile, remote, wide area
WiFi50-100mMedium50-300 MbpsLowFixed locations, high data
LoRaWAN2-15 kmVery Low0.3-50 kbpsLowSensors, rural IoT
NB-IoTNationwideVery Low250 kbpsMediumBattery IoT, smart meters
Bluetooth10-100mLow1-2 MbpsVery LowWearables, 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.