LoginSignup
2
1

LoRaモジュールE220-900T22S(JP)のWakeOnRadioを使ってみる

Last updated at Posted at 2024-02-03

はじめに

クレアリンクテクノロジー E220-900T22S(JP)
SEMTEC社LoRaチップ「LLCC68」 搭載LoRaモジュール

このLoRaモジュールにはWOR(Wake on Radio)機能があり省電力なIoTに役立つので使ってみようと思います

WORとは

WOR(Wake on Radio)対応で、省電力待機状態のモジュールをワイヤレスプリアンブル信号によって起こして受信させることができ、それによってデバイスへ割り込みを発生させるなどし、機器全体の省電力制御をワイヤレスで実現することが可能です。

スクリーンショット 2024-02-02 224901.png

E220-900T22S(JP)データシート
https://dragon-torch.tech/wp-content/uploads/2023/12/data_sheet_Rev1.5.pdf

AUXピンがLOWになることでマイコンを起動させます

こちらのライブラリのexampleを参考にSeeed XiaoESP32C3を使ってみました(ピン数は少なめですが1000円以下でコンパクトでセンサー用にばらまくにはおすすめのマイコンボードです)

https://github.com/xreef/LoRa_E32_Series_Library/blob/master/examples/manageWakeUpOfMicrocontroller/esp32_e32_wake_up_from_WOR_deep_sleep/esp32_e32_wake_up_from_WOR_deep_sleep.ino
なおこのLoRa_E32_Series_LibraryはE220-900T22S(JP)に今のところ非対応です

XiaoESP32C3のピン配置

755a3b84-f4b8-41fe-8aec-e1054749151e.png

スクリーンショット 2024-02-03 085147.png

ここでDeepSleepからGPIOWakeupに使えるピンはVDD3P3_RTCによって電力供給されるパッド GPIO0 ~ 5 とあり
このボードではD0~D3の4本のみでこれをLoRaモジュールの AUX ピン用に使います

主に使う関数

(注)EPS32やESP32S3とESP32C3とでいくつか関数の名前や仕様が異なる場合があります 今回はESP32C3についての関数です

LoRaモジュールの設定

  • 送信‐受信でUART Serial Port Rate、Air Data Rate、SF(拡散率)、BW(帯域幅)、周波数CH、WOR サイクルを同じに設定します
    また注意点として

⚫ 周波数チャンネルが 923.5 MHz〜928.0MHz の範囲、すなわち
BW:125kHz で CH:15-37 を選択した場合、
BW:250kHz で CH:14-36 を選択した場合、
および BW:500kHz で CH:13-30 を選択した場合
➢ 送信時間が 400ms 制限の規定があるため、レジスタでの設定値によらずサブパケッ
ト長が 32byte に変更されます。また、プリアンブル送信にかかる時間が制限を超え
てしまうため、WOR モードは利用しないでください。

省電力ゲートウェイ

乾電池駆動のセンサー子機とソーラー電池駆動のLTEゲートウェイを以下のような構成で考えてみました
例えば子機からの送信が数秒/回で送信間隔が1時間のとき親機側は常時受信を待ち受けてる必要がなく大幅に省電力化できます

親機が定期的に子機を起こして終わったらDeepSleep

・NormalMode : 送信:可 受信:可

・WORSendingMode 送信:WORモード 受信:可

・WORReceivingMode 送信:不可 受信:WORモード

・ConfigurationMode 設定変更モード/Deepsleepモード: 送信:不可 受信:不可

sensorWakeUp.ino
#include <Arduino.h>
#define SerialMon Serial
#define SerialLoRa Serial1

// E220-900T22S(JP)へのピンアサイン
#define LoRa_ModeSettingPin_M0 GPIO_NUM_2//D0 
#define LoRa_ModeSettingPin_M1 GPIO_NUM_3//D1
#define LoRa_Rx_ESP_TxPin GPIO_NUM_21//D6
#define LoRa_Tx_ESP_RxPin GPIO_NUM_20//D7
#define LoRa_AUXPin GPIO_NUM_4//D2

// E220-900T22S(JP)のbaud rate
#define LoRa_BaudRate 9600
int16_t senserID = 0x0001;
RTC_DATA_ATTR uint16_t bootCount = 0;
esp_sleep_source_t  wakeup_reason;

uint8_t conf[] ={0xc0, 0x00, 0x08, 
                senserID >> 8, //ADDH
                senserID & 0xff, //ADDL
                0b01110000, // baud_rate 9600 bps  SF:9 BW:125
                0b11100000, //subpacket_size 32, rssi_ambient_noise_flag on, transmitting_power 13 dBm
                0x09, //own_channel
                0b11000111, //RSSI on ,fix mode,wor_cycle 4000 ms
                0x00, //CRYPT
                0x00};
struct  msgStruct{ 
  char targetAdressH = 0x00;//GateWay adress 0x0000
  char targetAdressL = 0x00;
  char targetChannel = 0x09;
  uint16_t myadress = senserID;
  uint16_t bootcount ;
} msg;


  /**
   * @brief ノーマルモード(M0=0,M1=0)へ移行する
   */
void SwitchToNormalMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 0);
  digitalWrite(LoRa_ModeSettingPin_M1, 0);
  delay(100);
}

  /**
   * @brief WOR受信モード(M0=0,M1=1)へ移行する
   */
  void SwitchToWORReceivingMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 0);
  digitalWrite(LoRa_ModeSettingPin_M1, 1);
  delay(100);
}

  /**
   * @brief コンフィグ/sleepモード(M0=1,M1=1)へ移行する
   */
void SwitchToConfigurationMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 1);
  digitalWrite(LoRa_ModeSettingPin_M1, 1);
  delay(100);
}

void IRAM_ATTR deep_sleep(){
    SwitchToWORReceivingMode();
	delay(100);
    Serial.println();
    gpio_hold_en(LoRa_ModeSettingPin_M0);
    gpio_hold_en(LoRa_ModeSettingPin_M1);
    esp_deep_sleep_enable_gpio_wakeup(BIT(LoRa_AUXPin), ESP_GPIO_WAKEUP_GPIO_LOW);
    gpio_deep_sleep_hold_en();
      //Go to sleep now
    Serial.println("Going to sleep now");
    delay(1000);
    esp_deep_sleep_start();
}
void wakeup_cause_print(esp_sleep_source_t  wakeup_reason) {
  switch (wakeup_reason) {
    case 0: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_UNDEFINED"); break;
    case 1: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_ALL"); break;
    case 2: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_EXT0"); break;
    case 3: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_EXT1"); break;
    case 4: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_TIMER"); break;
    case 5: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_TOUCHPAD"); break;
    case 6: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_ULP"); break;
    case 7: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_GPIO"); break;
    case 8: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_UART"); break;
    case 9: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_WIFI"); break;
    case 10: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_COCPU"); break;
    case 11: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG"); break;
    case 12: Serial.println("Wakeup caused by ESP_SLEEP_WAKEUP_BT"); break;
    default: Serial.println("Wakeup was not caused by deep sleep"); break;
  }
}

void setup() {
  pinMode(LoRa_ModeSettingPin_M0, OUTPUT);
  pinMode(LoRa_ModeSettingPin_M1, OUTPUT);
  SerialMon.begin(9600);
  delay(500);
  // E220-900T22S(JP)へのLoRa初期設定
  SerialLoRa.end(); 
  delay(1000); 
  SerialLoRa.begin(LoRa_BaudRate, SERIAL_8N1, LoRa_Tx_ESP_RxPin,LoRa_Rx_ESP_TxPin);
  wakeup_reason = esp_sleep_get_wakeup_cause();
  wakeup_cause_print(wakeup_reason);
  
  if (ESP_SLEEP_WAKEUP_GPIO  == wakeup_reason) {
    Serial.println("Waked up from external GPIO!");
    gpio_hold_dis(LoRa_ModeSettingPin_M0);
    gpio_hold_dis(LoRa_ModeSettingPin_M1);
    gpio_deep_sleep_hold_dis();
    SwitchToNormalMode();
    delay(100);
  }else{
    Serial.println("Waked up from nomal power on!");
    SerialMon.printf("\n sensorID: %d\n",senserID);
    SwitchToConfigurationMode();
    while(!digitalRead(LoRa_AUXPin)){}
    SerialMon.printf("I send conf\r\n");
    for (size_t i = 0; i < sizeof(conf); i++)
    {
      SerialMon.printf(" %02x",conf[i]);
    }
    SerialLoRa.write((uint8_t *)&conf, sizeof(conf));
    delay(10000);
    deep_sleep();
  }
  Serial.println("Wake and start ");
  SwitchToNormalMode();
  msg.bootcount = bootCount;
  Serial.printf("boot:%d \n" ,msg.bootcount);
  SerialLoRa.flush();
  uint8_t payload[]={msg.targetAdressH, msg.targetAdressL, msg.targetChannel ,
                    msg.myadress & 0xff ,msg.myadress >> 8 ,
                    msg.bootcount & 0xff, msg.bootcount >> 8, 
                    };
  SerialMon.printf("I send data\r\n");
  for (size_t i = 0; i < sizeof(payload); i++)
  {
    SerialMon.printf(" %02x",payload[i]);
  }
  SerialMon.println();
  SerialLoRa.write((uint8_t *)&payload, sizeof(payload));
  SerialLoRa.flush();
  delay(100);
  bootCount++;
  deep_sleep();
}

void loop() {}

gateway.ino
#include <Arduino.h>
#define SerialMon Serial
#define SerialLoRa Serial1
// E220-900T22S(JP)へのピンアサイン
//(略)
int16_t gatewayAddress = 0x0000;
uint8_t conf[] ={0xc0, 0x00, 0x08, 
                gatewayAddress >> 8, //ADDH
                gatewayAddress & 0xff, //ADDL
                0b01110000, // baud_rate 9600 bps  SF:9 BW:125
                0b11100000, //subpacket_size 32, rssi_ambient_noise_flag on, transmitting_power 13 dBm
                0x09, //own_channel
                0b11000111, //RSSI on ,fix mode,wor_cycle 4000 ms
                0x00, //CRYPT
                0x00};
struct  msgStruct{ 
  char targetAdressH = 0xFF;//broadcast adress 0xFFFF
  char targetAdressL = 0xFF;
  char targetChannel = 0x09;
  uint16_t sensorAdress ;
  uint16_t bootcount ;
} msg;

  /**
   * @brief ノーマルモード(M0=0,M1=0)へ移行する
   */
void SwitchToNormalMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 0);
  digitalWrite(LoRa_ModeSettingPin_M1, 0);
  delay(100);
}

  /**
   * @brief WOR送信モード(M0=1,M1=0)へ移行する
   */
  void SwitchToWORSendingMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 1);
  digitalWrite(LoRa_ModeSettingPin_M1, 0);
  delay(100);
}

  /**
   * @brief コンフィグ/sleepモード(M0=1,M1=1)へ移行する
   */
void SwitchToConfigurationMode(void){
  digitalWrite(LoRa_ModeSettingPin_M0, 1);
  digitalWrite(LoRa_ModeSettingPin_M1, 1);
  delay(100);
}

void setup(){
  pinMode(LoRa_ModeSettingPin_M0, OUTPUT);
  pinMode(LoRa_ModeSettingPin_M1, OUTPUT);
  SerialMon.begin(9600);
  delay(500);
  SerialLoRa.end(); 
  delay(1000); 
  SerialLoRa.begin(LoRa_BaudRate, SERIAL_8N1, LoRa_Tx_ESP_RxPin,LoRa_Rx_ESP_TxPin);                
  // E220-900T22S(JP)へのLoRa初期設定
  SwitchToConfigurationMode();
  SerialMon.printf("I send conf\r\n");
  for (size_t i = 0; i < sizeof(conf); i++)
  {
    SerialMon.printf(" %02x",conf[i]);
  }
  SerialLoRa.write((uint8_t *)&conf, sizeof(conf));
  SwitchToWORSendingMode();
  SerialLoRa.flush();
  //この送信は子機を起こすためでメッセージ内容は受信されない
  uint8_t payload[]={msg.targetAdressH, msg.targetAdressL, msg.targetChannel ,0x00}; 
  SerialMon.printf("I send data\r\n");
  for (size_t i = 0; i < sizeof(payload); i++)
  {
    SerialMon.printf(" %02x",payload[i]);
  }
  SerialMon.println();
  SerialLoRa.write((uint8_t *)&payload, sizeof(payload));
  SerialLoRa.flush();
  delay(100);
  SwitchToNormalMode(void);
}

void loop(){
 //センサーから受信してどこかに送信したりの処理

 //子機からの送信が全て終わったらDeepSpeep
 
}
  

WORでラズパイを起動させる

ラズベリーパイはGPIO3ピンをLOWにすると起動するようになっています。そこでこのLoRaモジュールを使って遠隔で起動することが出来ます
自動起動のプログラムで終了後シャットダウンさせるようにすれば必要なときだけ動かすような用途に利用できます

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1