esp_modem/examples: Add an example to synchronise PSM sleep in Sim70XX modem and esp32.

This example enables Power saving mode in Sim70XX modem and tries to synchronise the sleep cycle of the modem with esp32.
When the modem wakes up from PSM sleep it wakes up the esp32. While the modem is awake esp32 is set to light sleep.

Closes: https://github.com/espressif/esp-protocols/issues/54
This commit is contained in:
Abhik Roy
2022-10-18 14:55:34 +05:30
parent 5097065a22
commit 1ca139109a
6 changed files with 360 additions and 0 deletions

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "modem_psm.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,109 @@
menu "Example Configuration"
choice EXAMPLE_MODEM_DEVICE
prompt "Choose supported modem device (DCE)"
default EXAMPLE_MODEM_DEVICE_SIM7080
help
Select modem device connected to the ESP DTE.
config EXAMPLE_MODEM_DEVICE_SIM7070
bool "SIM7070"
help
SIM7070 is Multi-Band CAT M and NB IoT module.
config EXAMPLE_MODEM_DEVICE_SIM7080
bool "SIM7080"
help
SIM7080 is Multi-Band CAT M and NB IoT module.
endchoice
menu "UART Configuration"
config EXAMPLE_MODEM_UART_TX_PIN
int "TXD Pin Number"
default 4
range 0 31
help
Pin number of UART TX.
config EXAMPLE_MODEM_UART_RX_PIN
int "RXD Pin Number"
default 5
range 0 31
help
Pin number of UART RX.
config EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE
int "UART Event Task Stack Size"
range 2000 6000
default 4096
help
Stack size of UART event task.
config EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY
int "UART Event Task Priority"
range 3 22
default 5
help
Priority of UART event task.
config EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE
int "UART Event Queue Size"
range 10 40
default 30
help
Length of UART event queue.
config EXAMPLE_MODEM_UART_TX_BUFFER_SIZE
int "UART TX Buffer Size"
range 256 2048
default 512
help
Buffer size of UART TX buffer.
config EXAMPLE_MODEM_UART_RX_BUFFER_SIZE
int "UART RX Buffer Size"
range 256 2048
default 1024
help
Buffer size of UART RX buffer.
endmenu
config EXAMPLE_MODEM_PWRKEY_PIN
int "PWRKEY Pin Number"
default 18
range 0 31
help
Pin number connected to modem's power key pin.
config EXAMPLE_MODEM_STATUS_PIN
int "STATUS Pin Number"
default 19
range 0 31
help
Pin number connected to modem's status pin.
config EXAMPLE_MODEM_LIGHT_SLEEP_DURATION
int "Light Sleep Duration"
default 10
range 0 15000
help
Duration in seconds, of which the esp32 goes into light sleep while the modem is awake.
config EXAMPLE_MODEM_PPP_APN
string "Set MODEM APN"
default "internet"
help
Set APN (Access Point Name), a logical name to choose data network
config EXAMPLE_MODEM_T3412_PERIODIC_TAU
string "T3412 Requester Periodic TAU"
default "00000100"
help
T3412 timer, i.e the duration of one awake and sleep cycle of the modem in PSM.
config EXAMPLE_MODEM_T3324_ACTIVE_TIME
string "T3324 Requester Active Time"
default "00000001"
help
T3324 timer, i.e the duration for which the modem stays PSM.
endmenu

View File

@ -0,0 +1,202 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/*
* Power Saving Mode(PSM) in Sim70XX modems along with
* Deep sleep and Light Sleep modes in esp32.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"
#include "esp_sleep.h"
#include "driver/rtc_io.h"
#include "esp_modem_api.h"
#include "esp_event.h"
#include "sdkconfig.h"
#define BUF_SIZE 1024
#define TXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_TX_PIN)
#define RXD_PIN ((gpio_num_t)CONFIG_EXAMPLE_MODEM_UART_RX_PIN)
#define GPIO_INPUT_STATUS ((gpio_num_t)CONFIG_EXAMPLE_MODEM_STATUS_PIN)
#define GPIO_OUTPUT_PWRKEY ((gpio_num_t)CONFIG_EXAMPLE_MODEM_PWRKEY_PIN)
#define GPIO_OUTPUT_PIN_SEL (1ULL<<GPIO_OUTPUT_PWRKEY)
#define CHECK_ERR(cmd, success_action) do { \
esp_err_t ret = cmd; \
if (ret == ESP_OK) { \
success_action; \
} else { \
ESP_LOGE(TAG, "Failed with %s", ret == ESP_ERR_TIMEOUT ? "TIMEOUT":"ERROR"); \
} } while (0)
const char *TAG = "modem_psm";
RTC_DATA_ATTR static int boot_count = 0;
void dce_init(esp_modem_dce_t **dce, esp_netif_t **esp_netif)
{
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG();
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
*esp_netif = esp_netif_new(&netif_ppp_config);
assert(*esp_netif);
/* setup UART specific configuration based on kconfig options */
dte_config.uart_config.tx_io_num = CONFIG_EXAMPLE_MODEM_UART_TX_PIN;
dte_config.uart_config.rx_io_num = CONFIG_EXAMPLE_MODEM_UART_RX_PIN;
dte_config.uart_config.rx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE;
dte_config.uart_config.tx_buffer_size = CONFIG_EXAMPLE_MODEM_UART_TX_BUFFER_SIZE;
dte_config.uart_config.event_queue_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_QUEUE_SIZE;
dte_config.task_stack_size = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_STACK_SIZE;
dte_config.task_priority = CONFIG_EXAMPLE_MODEM_UART_EVENT_TASK_PRIORITY;
dte_config.dte_buffer_size = CONFIG_EXAMPLE_MODEM_UART_RX_BUFFER_SIZE / 2;
ESP_LOGI(TAG, "Initializing esp_modem for a generic module...");
*dce = esp_modem_new(&dte_config, &dce_config, *esp_netif);
assert(*dce);
}
void config_pwrkey_gpio(void)
{
gpio_config_t io_conf = {}; //zero-initialize the config structure.
io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt
io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; //bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; //disable pull-down mode
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; //disable pull-up mode
gpio_config(&io_conf); //configure GPIO with the given settings
}
void power_on_modem(esp_modem_dce_t *dce)
{
rtc_gpio_hold_dis(GPIO_OUTPUT_PWRKEY);
/* Power on the modem */
ESP_LOGI(TAG, "Power on the modem");
gpio_set_level(GPIO_OUTPUT_PWRKEY, 1);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_level(GPIO_OUTPUT_PWRKEY, 0);
rtc_gpio_hold_en(GPIO_OUTPUT_PWRKEY);
vTaskDelay(pdMS_TO_TICKS(2000));
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
}
void power_down_modem(esp_modem_dce_t *dce)
{
char data[BUF_SIZE];
ESP_LOGI(TAG, "Power down the modem");
/* Power down the modem by AT command */
CHECK_ERR(esp_modem_at(dce, "AT+CPOWD=1", data, 500), ESP_LOGI(TAG, "OK. %s", data));
}
void run_at(esp_modem_dce_t *dce, uint8_t count)
{
for (int i = 0; i < count; i++) {
CHECK_ERR(esp_modem_sync(dce), ESP_LOGI(TAG, "OK"));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void run_at_ping(esp_modem_dce_t *dce)
{
char data[BUF_SIZE];
int rssi, ber;
CHECK_ERR(esp_modem_get_signal_quality(dce, &rssi, &ber), ESP_LOGI(TAG, "OK. rssi=%d, ber=%d", rssi, ber));
vTaskDelay(pdMS_TO_TICKS(1000));
CHECK_ERR(esp_modem_at(dce, "AT+CPSMS?", data, 500), ESP_LOGI(TAG, "OK. %s", data));
vTaskDelay(pdMS_TO_TICKS(1000));
CHECK_ERR(esp_modem_at(dce, "AT+CPSI?", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Inquiring UE system information
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,1", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Activate the APP network
CHECK_ERR(esp_modem_at(dce, "AT+SNPDPID=0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Select PDP index for PING
CHECK_ERR(esp_modem_at(dce, "AT+SNPING4=\"8.8.8.8\",3,16,1000", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Send IPv4 PING
CHECK_ERR(esp_modem_at(dce, "AT+CNACT=0,0", data, 500), ESP_LOGI(TAG, "OK. %s", data)); // Deactivate the APP network
}
void app_main(void)
{
char *cmd;
char data[BUF_SIZE];
esp_modem_dce_t *dce = NULL;
esp_netif_t *esp_netif = NULL;
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
ESP_LOGI(TAG, "Deep sleep Wake Up Cause: %d\n", wakeup_cause);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
dce_init(&dce, &esp_netif);
switch (wakeup_cause) {
case ESP_SLEEP_WAKEUP_UNDEFINED:
/* Power on the modem */
config_pwrkey_gpio();
power_on_modem(dce);
run_at(dce, 3);
/* Configure Power Saving Mode in the modem */
asprintf(&cmd, "AT+CPSMS=1,,,\"%s\",\"%s\"\r\n", CONFIG_EXAMPLE_MODEM_T3412_PERIODIC_TAU,
CONFIG_EXAMPLE_MODEM_T3324_ACTIVE_TIME);
CHECK_ERR(esp_modem_at(dce, cmd, data, 500), ESP_LOGI(TAG, "OK. %s", data));
free(cmd);
vTaskDelay(pdMS_TO_TICKS(1000));
/* Perform Communication tasks */
run_at_ping(dce);
vTaskDelay(pdMS_TO_TICKS(1000));
break;
case ESP_SLEEP_WAKEUP_EXT0:
run_at(dce, 3);
/* Perform Communication tasks */
run_at_ping(dce);
vTaskDelay(pdMS_TO_TICKS(1000));
break;
default:
ESP_LOGI(TAG, "Not a deep sleep reset: %d\n", wakeup_cause);
}
ESP_LOGI(TAG, "Light sleep before going to Deep sleep\n\n");
/* Enter light sleep mode as long as the modem is awake */
esp_sleep_enable_timer_wakeup(CONFIG_EXAMPLE_MODEM_LIGHT_SLEEP_DURATION * 1000000);
esp_light_sleep_start();
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); // Disabling timer before going to deep sleep.
wakeup_cause = esp_sleep_get_wakeup_cause();
ESP_LOGI(TAG, "Light sleep wakeup cause: %d\n", wakeup_cause);
/* DCE and netif clean-up */
/* In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals are powered off.
* So dce and netif would be lost anyway if they are not explicitly destroyed.
* But since dce is also linked with UART communication with the modem it's better to exit gracefully before going to deep sleep.
*/
esp_modem_destroy(dce);
esp_netif_destroy(esp_netif);
/* Enable wakeup if status pin is high */
esp_sleep_enable_ext0_wakeup(GPIO_INPUT_STATUS, 1);
ESP_LOGI(TAG, "Entering deep sleep: %d\n", boot_count++);
esp_deep_sleep_start();
}