75256
spresense + LTE拡張ボードにて LTE拡張ボード上のアナログピンA4を読み込んだ後  
LTE接続してUDPでデータ送信、その後にlteAccess.shutdown()を行うとエラーで停止してしまいます。  
analogReadをしなければエラー発生せずに正常に動作します。

LTEの接続送受信と アナログ読み込みの順序を入れ替えると１度は正常にLTE接続-送信-シャットダウンを行いますが  
アナログ読み込み後は失敗してしまいます。

LTEを接続したままであればUDP送信は何度でもできるのですが  
送信周期が1時間以上空くことと省電力化のためにLTEをOFFにしておきたいのですが  
なにか対処方法はありますでしょうか？

エラー検証用に抜き出して確認しているコードとエラー内容は以下のようになっています。  
spresense arduino のバージョンは 2.1.0 です。（2.0.2でも同一でした）

```

    #include <LTE.h>
    
    #define LTE_APN       "soracom.io"  // replace your APN
    #define LTE_USER_NAME "sora"        // replace with your username
    #define LTE_PASSWORD  "sora"        // replace with your password
    
    char  host[] = "harvest.soracom.io";
    int   port = 8514;
    LTE           lteAccess;
    LTEUDP        lteUdp;
    int   ad_value = 0;
    
    void setup()
    {
      /* Initialize Serial */
      Serial.begin(115200);
    }
    
    void loop()
    {
      ad_value = analogRead(PIN_A4);
    
      //************************************************************
      // LTE setting
      // If your SIM has PIN, pass it as a parameter of begin() in quotes
      Serial.println("LTE Start");
      while (true) {
        if (lteAccess.begin() == LTE_SEARCHING) {
          if (lteAccess.attach(LTE_APN, LTE_USER_NAME, LTE_PASSWORD, LTE_NET_AUTHTYPE_CHAP, LTE_NET_IPTYPE_V4V6, false) == LTE_CONNECTING) {
            Serial.println("Attempting to connect to network.");
            break;
          }
          Serial.println("An error occurred, shutdown and try again.");
          lteAccess.shutdown();
          sleep(1);
        }
      }
    
      while (LTE_READY != lteAccess.getStatus()) {
        sleep(1);
      }
    
      Serial.println("UDP Send Start");
      if (lteUdp.begin(port)  == 1) {
        if (lteUdp.beginPacket(host, port) == 1) {
          Serial.println("UDP Data make Start");
          char ad_str[10];
          sprintf(ad_str, "ad=%04x", ad_value);
          lteUdp.write(ad_str, 7);
          if (lteUdp.endPacket() == 1) {
            Serial.println("UDP Data Send OK");
            delay(100);
          } else {
            Serial.println("UDP Data Send NG(endPacket)");
          }
        } else {
          Serial.println("UDP Data make NG(beginPacket)");
        }
        lteUdp.stop();
        Serial.println("UDP Send Stop");
      }
    
      lteAccess.shutdown();  
      Serial.println("LTE End");
      //************************************************************
    
      sleep(60);
    }
    
```

```

    15:26:47.162 -> LTE Start
    15:26:52.940 -> Attempting to connect to network.
    15:27:01.017 -> UDP Send Start
    15:27:01.202 -> UDP Data make Start
    15:27:01.202 -> UDP Data Send OK
    15:27:01.295 -> UDP Send Stop
    15:27:01.295 -> up_hardfault: PANIC!!! Hard fault: 40000000
    15:27:01.295 -> up_assert: Assertion failed at file:armv7-m/up_hardfault.c line: 148 task: altmdm_xfer_task
    15:27:01.295 -> up_registerdump: R0: 68f10246 00000000 00000010 00000080 0d00e265 00000000 04195404 00000000
    15:27:01.295 -> up_registerdump: R8: 00000000 000186a0 00000002 00000000 00000080 0d050960 0d028271 0d029f24
    15:27:01.342 -> up_registerdump: xPSR: 41000000 BASEPRI: 000000e0 CONTROL: 00000000
    15:27:01.342 -> up_registerdump: EXC_RETURN: ffffffe9
    15:27:01.342 -> up_dumpstate: sp:     0d0357a8
    15:27:01.342 -> up_dumpstate: IRQ stack:
    15:27:01.342 -> up_dumpstate:   base: 0d035800
    15:27:01.342 -> up_dumpstate:   size: 00000800
    15:27:01.342 -> up_dumpstate:   used: 00000148
    15:27:01.342 -> up_stackdump: 0d0357a0: 000005dc 0d00dfe3 000000e0 00000000 00000000 00000080 0d050960 0d028271
    15:27:01.342 -> up_stackdump: 0d0357c0: 0d029f24 0d0357d0 0d00e32f 00000003 00000000 0d00e337 0d00e315 0d01cc5f
    15:27:01.342 -> up_stackdump: 0d0357e0: 000000e0 0d01908d 000000e0 0d05088c 00000000 04195404 00000000 0d00e293
    15:27:01.342 -> up_dumpstate: sp:     0d050960
    15:27:01.389 -> up_dumpstate: User stack:
    15:27:01.389 -> up_dumpstate:   base: 0d050a58
    15:27:01.389 -> up_dumpstate:   size: 000005dc
    15:27:01.389 -> up_dumpstate:   used: 00000240
    15:27:01.389 -> up_stackdump: 0d050960: 00000080 00000000 00000000 00000018 00000000 0d028d5f 0d03f7b0 0d034288
    15:27:01.389 -> up_stackdump: 0d050980: 0d03f7b0 0d050108 0000000c 0d025fcb 00000000 0d025fbf 0d03f7b0 0d00f859
    15:27:01.389 -> up_stackdump: 0d0509a0: 0d050118 0d050094 0d050198 0d00f8a3 0d050050 00000000 0d04fec0 0d010df1
    15:27:01.389 -> up_stackdump: 0d0509c0: 00000001 0d04fec0 0d045f50 0d050050 00000000 0d00adbf 0d000504 00000000
    15:27:01.436 -> up_stackdump: 0d0509e0: 0000000c 00000000 00000000 0000000c 0d04fec0 0d04fec0 0d04f680 0d010b93
    15:27:01.436 -> up_stackdump: 0d050a00: 0000000c 0d00ad45 ffffffff 0d04f5b0 00000000 00000000 00000000 0d0124c7
    15:27:01.436 -> up_stackdump: 0d050a20: 00000000 0d050a5c 00000008 4b4f4b4f 00000101 00000000 00000000 00000000
    15:27:01.436 -> up_stackdump: 0d050a40: 00000000 00000000 00000000 0d00b09f 00000000 00000000 deadbeef 0d050a64
    15:27:01.436 -> up_taskdump: Idle Task: PID=0 Stack Used=0 of 0
    15:27:01.436 -> up_taskdump: hpwork: PID=1 Stack Used=576 of 2028
    15:27:01.483 -> up_taskdump: lpwork: PID=2 Stack Used=352 of 2028
    15:27:01.483 -> up_taskdump: lpwork: PID=3 Stack Used=352 of 2028
    15:27:01.483 -> up_taskdump: lpwork: PID=4 Stack Used=352 of 2028
    15:27:01.483 -> up_taskdump: cxd56_pm_task: PID=6 Stack Used=352 of 996
    15:27:01.483 -> up_taskdump: <pthread>: PID=7 Stack Used=312 of 1020
    15:27:01.483 -> up_taskdump: init: PID=8 Stack Used=1440 of 8172
    15:27:01.483 -> up_taskdump: lte_daemon: PID=9 Stack Used=992 of 4068
    15:27:01.483 -> up_taskdump: thrdpool_no01: PID=10 Stack Used=592 of 2004
    15:27:01.483 -> up_taskdump: thrdpool_no02: PID=11 Stack Used=528 of 980
    15:27:01.483 -> up_taskdump: altmdm_xfer_task: PID=12 Stack Used=576 of 1500
    
```
CC BY-SA 4.0
2021-03-05T07:18:39.567
74425
2021-04-14T01:43:21.453
2021-03-05T18:53:43.670
3068
44213
question
spresense arduino
spresense LTE拡張ボードでLTEとADを使うとLTE.shutdown()でエラーになる
送信周期が1分以上あって他に何の処理もしないのであれば、deepSleep を使うのはどうでしょうか。

#include <LowPower.h> と、setup() に LowPower.begin() を追加して、  
sleep(60) の代わりに LowPower.deepSleep(60) を使います。  
(lteAccess.shutdown() を呼ぶと確かにエラーが発生するのでコメントアウトしています)

私が普段使っているやり方ですが、これが最も省電力になります。参考まで。

```

    #include <LTE.h>
    #include <LowPower.h> // ★追加
    
    #define LTE_APN       "soracom.io"  // replace your APN
    #define LTE_USER_NAME "sora"        // replace with your username
    #define LTE_PASSWORD  "sora"        // replace with your password
    
    char  host[] = "harvest.soracom.io";
    int   port = 8514;
    LTE           lteAccess;
    LTEUDP        lteUdp;
    int   ad_value = 0;
    
    void setup()
    {
      /* Initialize Serial */
      Serial.begin(115200);
    
      LowPower.begin(); // ★追加
    }
    
    void loop()
    {
      //************************************************************
      // LTE setting
      // If your SIM has PIN, pass it as a parameter of begin() in quotes
      Serial.println("LTE Start");
      while (true) {
        if (lteAccess.begin() == LTE_SEARCHING) {
          if (lteAccess.attach(LTE_APN, LTE_USER_NAME, LTE_PASSWORD, LTE_NET_AUTHTYPE_CHAP, LTE_NET_IPTYPE_V4V6, false) == LTE_CONNECTING) {
            Serial.println("Attempting to connect to network.");
            break;
          }
          Serial.println("An error occurred, shutdown and try again.");
          lteAccess.shutdown();
          sleep(1);
        }
      }
    
      while (LTE_READY != lteAccess.getStatus()) {
        sleep(1);
      }
    
      ad_value = analogRead(PIN_A4);
    
      Serial.println("UDP Send Start");
      if (lteUdp.begin(port)  == 1) {
        if (lteUdp.beginPacket(host, port) == 1) {
          Serial.println("UDP Data make Start");
          char ad_str[10];
          sprintf(ad_str, "ad=%04x", ad_value);
          lteUdp.write(ad_str, 7);
          if (lteUdp.endPacket() == 1) {
            Serial.println("UDP Data Send OK");
            delay(100);
          } else {
            Serial.println("UDP Data Send NG(endPacket)");
          }
        } else {
          Serial.println("UDP Data make NG(beginPacket)");
        }
        lteUdp.stop();
        Serial.println("UDP Send Stop");
      }
    
      //lteAccess.shutdown(); // ★削除
      Serial.println("LTE End");
      //************************************************************
    
      LowPower.deepSleep(60); // ★sleep(60)から置き換え
    }
    
    
```
CC BY-SA 4.0
2021-03-08T05:43:13.673
74513
2021-03-08T05:43:13.673
31378
74425
answer
LTEを定期的に、かつ時間を置いて使う場合eRDXというLTEの省電力機能を使うのはいかがでしょう。  
Arduinoのリファレンスにはないのですが、SDKの以下のAPIはArduinoでも使えるようです。

[5.13.5.7.
モデムを省電力設定にする](https://developer.sony.com/develop/spresense/docs/sdk_developer_guide_ja.html#_%E3%83%A2%E3%83%87%E3%83%A0%E3%82%92%E7%9C%81%E9%9B%BB%E5%8A%9B%E8%A8%AD%E5%AE%9A%E3%81%AB%E3%81%99%E3%82%8B)

  1. [lte_set_edrx_sync](https://developer.sony.com/develop/spresense/developer-tools/api-reference/api-references-spresense-sdk/group__lte.html#gab6317fba4d99cc9ab225e50da969ed43)  
Modemに対してeDRXのパラメータを設定するAPI

  2. [lte_get_current_edrx_sync](https://developer.sony.com/develop/spresense/developer-tools/api-reference/api-references-spresense-sdk/group__lte.html#ga14718e197077eed95127b008dca0ee1f)  
ModemとNetworkのネゴシエーション結果を取得するAPI

```

    #include "lte/lte_api.h"
        
    void setup()
    {
      lte_edrx_setting_t settings = {
          .act_type = LTE_EDRX_ACTTYPE_WBS1,  /* Cat.M */
          .enable = LTE_ENABLE,               /* eDRX 有効化 */
          .edrx_cycle = LTE_EDRX_CYC_65536,   /* 655.36秒間隔でModem起床 */
          .ptw_val = LTE_EDRX_PTW_256         /* Modem起床時2.56秒起き続ける */
      };
        
      /* lteAccess.begin() 等の処理をここで行う */
        
      ret = lte_set_edrx_sync(&settings;);
      if (ret)
        {
          printf("Error to set a eDRX parameter. ret = %d\n", ret);
        }
    
      /* lteAccess.attach() 等の処理をここで行って接続を完了させる */
    
      ret = lte_get_current_edrx_sync(&settings;);
      if (ret)
        {
          printf("Failed to get eDRX settings. ret = %d\n", ret);
        }
      else
        {
          /* eDRX の設定結果が確認できる */
          printf("eDRX act_type = %d\n", settings.act_type);
          printf("eDRX enable = %d\n", settings.enable);
          printf("eDRX edrx_cycle = %d\n", settings.edrx_cycle);
          printf("eDRX ptw_val = %d\n", settings.ptw_val);
        }
    }
    
```
CC BY-SA 4.0
2021-03-15T07:05:56.957
74681
2021-03-15T07:05:56.957
32034
74425
answer
ソニーのSPRESENSEサポート担当です。

analogRead()を呼び出した後にLTE begin(), shutdown()を呼び出すと  
analogReadから使用さるADCのリソースが解放されてしまい  
それが原因でエラーを引き起こしていました。

修正版を開発ブランチにアップしました。  
<https://github.com/SPRESENSE/spresense-arduino-compatible/releases>  
SPRESENSE beta release (2021/04/10)  
sonydevworld/spresense-nuttx@23dc3f5 arch: cxd56xx: Fix multiple open and
close ADC driver

開発ブランチのArduinoパッケージを使用する方法はこちらを参考にしてください。  
[https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_プレリリース_spresense_arduino_board_package_パッケージのインストール](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_%E3%83%97%E3%83%AC%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9_spresense_arduino_board_package_%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

ご指摘ありがとうございました。  
本修正は来月予定の正式リリースに反映される予定です。

今後ともSPRESENSEをどうぞよろしくお願いいたします。  
SPRESENSEサポートチーム
CC BY-SA 4.0
2021-04-14T01:43:21.453
75256
2021-04-14T01:43:21.453
29520
74425
answer