So-net無料ブログ作成
  • ブログをはじめる
  • ログイン
前の10件 | -

Arduino core for the ESP32 core panic [ESP32]

esp32_i2c_multitask_test_008.png

本当はこの記事では「ESP32 Arduinoはユーザーが排他制御をあまり意識しなくても使えますよ~、楽ですよ~」ってするつもりだったんです。それがですねぇ、この結末、、、

はじまりはESP32 ArduinoでI2Cに関する検索をしていたらツイッターに、「ESP32 Arduinoは排他制御が入っているのでこの結果はおかしい」的なのを見付けて、「ええ!そうなんですか?」ってソースコード(esp32-hal-i2c.c)を見てみました。
esp32_arduino_core_i2c_001.png

あ、有るのう、、、

ちなみに定義されているCONFIG_DISABLE_HAL_LOCKSは何処に有るのか探してみると、esp32\tools\sdk\sdkconfigの中に
#
# Arduino Configuration
#
CONFIG_ENABLE_ARDUINO_DEPENDS=y
CONFIG_AUTOSTART_ARDUINO=y
CONFIG_DISABLE_HAL_LOCKS=

の様に記述されています。実際にこれが有効なのかどうかは判りませんが、なんとなくCONFIG_DISABLE_HAL_LOCKSの定義には値が設定されていない気がする。
となると
i2c->lock = xSemaphoreCreateMutex();
でI2C用のミューテックスが生成され、排他制御が有効となっていると考えられます。

ちなみにI2C同様にミューテックスが設定されているのは、LEDC、SIGMA-DELTA、SPI、UARTでした。

と言う訳で前回
https://hamayan.blog.so-net.ne.jp/2018-07-11
で実行したプログラムの中から、セマフォに関するコードを抜いて実行してみました。

その結果が冒頭のキャプチャです。
あれぇ???と思っているとArduino core for the ESP32のI2Cの抽象化層がしれっと更新されているので、新しい奴で試してみましたが、やはりカーネルパニックを発生させて再起動します。
片方のタスクの起動時間を100msくらいオフセットしてしまえば、一応は起動直後にカーネルパニックを起こす事は避けられていますが、、、タスク間で同期が必要になりますもんね。

なーんでしょうね?次のバージョンアップに期待ですか。

複数タスクでI2Cを共有する場合、当面はこのやり方の様にユーザーで排他制御を入れた方が安心です。
https://hamayan.blog.so-net.ne.jp/2018-07-11

複数タスクの同時アクセスでカーネルパニックを起こすのがI2Cだけなのか、まだわからない、、、
nice!(0)  コメント(0) 

ESP32 ArduinoでI2Cをマルチタスクで動かす [ESP32]

2018-07-11 16.06.45.jpg

I2C接続された2個のBME280をマルチタスクで動かすデモです。
※この話には続きが多分有る!
※ついさっき、Arduino core for the ESP32のI2Cの抽象化層のコードに修正が入った模様。明日、試す。

ここで書いているバージョンのESP32 Arduinoでは確かにI2Cがまともに動きませんでした。
https://hamayan.blog.so-net.ne.jp/2018-06-13-1
多分それ以前のバージョンも、、、

実はつい先日Arduino core for the ESP32が更新されています、、、
https://github.com/espressif/arduino-esp32
はぁぁぁぁ、、、

以下、試験概要

主にI2Cの読み出しでWire.available()が0のまま先に進まない(詳細は不明)感じ。ただこれマルチタスクでやるとなんとなく現象が出やすいだけで、実際には元々I2Cのドライバーがバグっている様な気がする。と言うかまともなドライバーなら排他制御をすればI2Cが問題になるとは思えない。

I2Cのマルチタスク環境下での確認は以下の要領となります。
1.ESP32を1個用意

2.BME280を2個用意

3.2つのBME280をI2Cアドレスをちょっと変えてESP32とI2C接続

4.loopTaskのsetupでloopTask自身の優先度を最大に設定、、、しません

5.loopTaskのsetupでI2Cの排他制御を行うバイナリーセマフォを生成

6.loopTaskのsetupでI2CとBME280の初期化を行う。

7.loopTaskのsetupでAmbientに接続

8.loopTaskのsetupで2つのBME280のそれぞれにI2Cでアクセスする2つのタスクを生成。優先度は同一で低め。つまりloopTaskも含めて3つのユーザータスクが存在する

9.loopTaskのloopでAmbientに、大域変数に保存された2つのBME280の温度、湿度、気圧を送信、グラフ表示を行う。またAmbientに送信する度にカウントアップする値もグラフに表示して、CPUの連続稼働状態のモニターとする。

10.BME280から温度、湿度、気圧を取得するタスクの中では、セマフォを使って排他制御を行いBME280からAD値を取得、実際の温度や湿度や気圧に換算して大域変数に保存。この保存した値を、loopTaskが参照する。

エラー状況を確認
2018年6月13日に入れたバージョンのシリアル出力はこの様にエラー出力を頻発している。
esp32_i2c_multitask_test_004.png


2018年7月11日バージョンのシリアル出力はこの様にエラー出力をしておらず、安定している。
esp32_i2c_multitask_test_002.png


下の図は、2018年7月11日バージョンでAmbientでグラフ化したもの。
esp32_i2c_test_002.png


ESP32_BME280_Ambient.ino
/****************************************************************************/
/* ESP32 BME280 project for Ambient                                         */
/*                                  Copyright (C) 2018- by hamayan          */
/****************************************************************************/
#define  __DEBUG__
//#define  __RUN_IN_AP_MODE__
#define  __RUN_IN_STA_MODE__

#include  <WiFi.h>
#include  "bme280.h"
#include  "Ambient.h"

extern "C" {
}

/*************************************************************************/
/*  prototype and defines.                                               */
/*************************************************************************/
#define  BME280_DEFAULT_I2C_ADDRESS  0x76
#define  BME280_EXTEND_I2C_ADDRESS   0x77
#define  I2C_HERTZ            100000UL
#define  SCL_PIN              26  /**/
#define  SDA_PIN              25  /**/
#define  ACT_LED_PIN          100 /* そんな物は無かった */

static void connectWifi();
static void networkInformations();
void IRAM_ATTR onTimerEvery1seconds();

/*************************************************************************/
/*  instances and valiables.                                             */
/*************************************************************************/
bme280 bme280_01( BME280_DEFAULT_I2C_ADDRESS );  /* bme280( uint8_t adr ); */
bme280 bme280_02( BME280_EXTEND_I2C_ADDRESS );  /* bme280( uint8_t adr ); */
volatile int pressure01,humidity01,temperature01;
volatile int pressure02,humidity02,temperature02;
volatile int cpuCounter;

WiFiClient client;
Ambient ambient;
unsigned int ambientChannelId = 0123456789;
const char* ambientWriteKey = "abcdefg";
const char* ambientReadKey = "abcdefg";

hw_timer_t *timer1second = NULL;
volatile time_t unixTime;  /*1970年からの通算秒*/
volatile time_t passedTime;  /* from start.  */

/*************************************************************************/
/*  task prototype defines.                                              */
/*************************************************************************/
enum TASK_IDS { TASK_ID_I2C_TEST01 = 0, TASK_ID_I2C_TEST02, TASK_ID_END };
xTaskHandle taskHandle[ TASK_ID_END ];
volatile SemaphoreHandle_t semaI2C;  /* I2Cのセマフォ */

void i2cTestTask01( void *execParam );
void i2cTestTask02( void *execParam );

/*************************************************************************/
/*  Wi-Fi defines.                                                       */
/*************************************************************************/
const char ssidAP[] = "ESP32_I2C_TEST";  // SSID
const char passAP[] = "password";   // password
const IPAddress apIP( 0, 0, 0, 0 );  // access point ip address
const IPAddress subnet( 255, 255, 255, 0 );  // sub net mask
const IPAddress stationIP( 0, 0, 0, 0 );  // station mode static ip address
const IPAddress dnsIP( 0, 0, 0, 0 );  // station mode dns ip address
const IPAddress gwIP( 0, 0, 0, 0 );  // station mode gateway ip address
IPAddress myIpAddress;

const char ssidSTA[] = "ssid";  // SSID
const char passSTA[] = "password";   // password
const char ntpServer[] = "ntp.nict.jp";

/*************************************************************************/
/*  setup.                                                               */
/*************************************************************************/
void setup()
{
  Serial.begin( 115200 );
  Serial.println( "ESP32 I2C Test." );

  uint64_t chipid = ESP.getEfuseMac();  //The chip ID is essentially its MAC address(length: 6 bytes).
  Serial.printf( "ESP32 Chip ID = %04X",(uint16_t)(chipid>>32) );  //print High 2 bytes
  Serial.printf( "%08X\n",(uint32_t)chipid );  //print Low 4bytes.

  /* initialize unixTime  */
  struct tm localTime =
    {0,0,0,10,4-1,2018-1900,0,0,0};
  unixTime = mktime( &localTime );

  /* 1second timer interrupt initialize. */
  timer1second = timerBegin( 0, 80, true );
  timerAttachInterrupt( timer1second, &onTimerEvery1seconds, true );
  timerAlarmWrite( timer1second, 1000 * 1000UL, true );
  /* 1second timer interrupt start. */
  timerAlarmEnable( timer1second );

  /* gpio pins configuration, */
  initGPIO();

  /* display mac address. */
  networkInformations();
 
  /* wifi AP open */
  connectWifi();

#if defined( __RUN_IN_STA_MODE__ )
  /* init and get the time from ntp server. */
  Serial.print( "Connecting to NTP server. current time = " );
  connectNTP( ntpServer );
  Serial.print( stringDataAndTime( NULL, NULL ) );
  Serial.println( "  ...done." );
#endif  /* defined( __RUN_IN_STA_MODE__ ) */

  /* configure tasks. */
  /* change the task priority to highest. */
//  UBaseType_t currentPriority = uxTaskPriorityGet( NULL );
//  vTaskPrioritySet( NULL, 24 );

  /* Create binary semaphore */
  semaI2C = xSemaphoreCreateBinary();
  xSemaphoreGive( semaI2C );  /* give one semaphore */

  /* imitialize i2c. */
  Wire.begin( SDA_PIN, SCL_PIN );  // Wire.begin( SDA, SCL );
  Wire.setClock( I2C_HERTZ );  // default = 100kbps

  /* bme280 start with i2c. */
  Serial.print( "initialize BME280_01 " );
  bme280_01.begin();
  int bmeId = bme280_01.read( BME280_ID );
  if( bmeId != BME280_ID_VALUE )
  {
    Serial.print( "ID ERROR : " );
    Serial.println( bmeId, HEX );
    while(1) {}
  }
  Serial.print( "ID = 0x" ); Serial.println( bmeId, HEX );

  Serial.print( "initialize BME280_02 " );
  bme280_02.begin();
  bmeId = bme280_02.read( BME280_ID );
  if( bmeId != BME280_ID_VALUE )
  {
    Serial.print( "ID ERROR : " );
    Serial.println( bmeId, HEX );
    //while(1) {}
  }
  Serial.print( "ID = 0x" ); Serial.println( bmeId, HEX );

  /* connecting to ambient. */
  Serial.print( "connecting to ambient." );
  ambient.begin( ambientChannelId, ambientWriteKey, &client );
  Serial.println( "...done." );

  /* active i2c test task01. priority = 2 */
  xTaskCreatePinnedToCore( i2cTestTask01, "", configMINIMAL_STACK_SIZE * 2, NULL, 2, &taskHandle[ TASK_ID_I2C_TEST01 ], 1 );

  /* active i2c test task02. priority = 2 */
  xTaskCreatePinnedToCore( i2cTestTask02, "", configMINIMAL_STACK_SIZE * 2, NULL, 2, &taskHandle[ TASK_ID_I2C_TEST02 ], 1 );

  /* change the task priority to original. */
//  vTaskPrioritySet( NULL, currentPriority );
//  vTaskDelete( NULL );  /* delete loopTask. */
}

/*************************************************************************/
/*  loop.                                                                */
/*************************************************************************/
void loop()
{
  time_t baseNTPRequestTime = passedTime;
  time_t baseStackMonitorTime = passedTime;
  time_t baseAmbientUpdateTime = passedTime;
  while( 1 )
  {
    vTaskDelay( pdMS_TO_TICKS( 1 * 1000UL ) );

    #if defined( __RUN_IN_STA_MODE__ )
    /* get the time from ntp server. */
    if( (passedTime - baseNTPRequestTime) >= 1 * 3600UL )
    {
      baseNTPRequestTime = passedTime;
      connectNTP( ntpServer );
    }
    #endif  /* defined( __RUN_IN_STA_MODE__ ) */

    /* stack monitor. */
    if( (passedTime - baseStackMonitorTime) >= 10UL )
    {
      baseStackMonitorTime = passedTime;
      stackMonitor();
    }

    /* update data to ambient server. */
    if( (passedTime - baseAmbientUpdateTime) >= 60UL )
    {
      baseAmbientUpdateTime = passedTime;
      ambient.set(1, temperature01 );  //
      ambient.set(2, humidity01 );  //
      ambient.set(3, pressure01 );  //
      ambient.set(4, temperature02 );  //
      ambient.set(5, humidity02 );  //
      ambient.set(6, pressure02 );  //
      ambient.set(7, cpuCounter );  //
      if( ambient.send() == false ) Serial.println( "Transmitting to AMBIENT was error." );
      if( ++cpuCounter >= 50 ) cpuCounter = 0;
    }
  }
}

/*************************************************************************/
/*  stack monitor                                                        */
/*************************************************************************/
static void reportStackSize( TaskHandle_t taskHdl, int count )
{
  unsigned portBASE_TYPE stzckSize = uxTaskGetStackHighWaterMark( taskHdl );
  String msg = "  Task"; msg += String( count ); msg += " remains stack size = "; msg += String( stzckSize );
  Serial.println( msg );
}

static void stackMonitor()
{
  int i;
  for( i = 0; i < sizeof(taskHandle) / sizeof(taskHandle[ 0 ]); i++ )
  {
    reportStackSize( taskHandle[ i ], i );
  }

  TaskHandle_t loopTaskHandle = xTaskGetCurrentTaskHandle();
  reportStackSize( loopTaskHandle, i );

  Serial.print( stringDataAndTime( NULL, NULL ) );
  Serial.print( " ip : " );
  Serial.println( myIpAddress );
}

/*************************************************************************/
/*  bme280Read                                                           */
/*************************************************************************/
static int bme280Read( bme280 *bm, BME280_S32_t *temperature, BME280_U32_t *pressure, BME280_U32_t *humidity )
{
  #define  WAIT_FOR_SEMAPHORE_TIME  (100UL)

  if( xSemaphoreTake( semaI2C, pdMS_TO_TICKS( WAIT_FOR_SEMAPHORE_TIME )  ) == pdFAIL ) return (-1);  // not portMAX_DELAY
  bm->force( 1, 1 );
  xSemaphoreGive( semaI2C );  /* give one semaphore */

  vTaskDelay( pdMS_TO_TICKS( 2UL ) );  /**/

  while( 1 )
  {
    /* 変換が開始されるとbit3が1に、変換が終了してレジスタに書き込まれると、bit3が0になる */
    if( xSemaphoreTake( semaI2C, pdMS_TO_TICKS( WAIT_FOR_SEMAPHORE_TIME )  ) == pdFAIL ) return (-1);  // not portMAX_DELAY
    uint8_t status = bm->readStatus();
    xSemaphoreGive( semaI2C );  /* give one semaphore */
    if( status == 0xFF ) return (-1);
    if( status & 0x08 ) taskYIELD(); /* for Co-operative Scheduling */
    else break;
  }
  taskYIELD(); /* for Co-operative Scheduling */

  BME280_S32_t tempS32;
  if( xSemaphoreTake( semaI2C, pdMS_TO_TICKS( WAIT_FOR_SEMAPHORE_TIME )  ) == pdFAIL ) return (-1);  // not portMAX_DELAY
  tempS32 = bm->readAdc_T();
  xSemaphoreGive( semaI2C );  /* give one semaphore */
  if( tempS32 == (-1) ) return (-1);
  taskYIELD(); /* for Co-operative Scheduling */
  *temperature = (bm->BME280_compensate_T_int32( tempS32 ) + 5L) / 10L;

  if( xSemaphoreTake( semaI2C, pdMS_TO_TICKS( WAIT_FOR_SEMAPHORE_TIME )  ) == pdFAIL ) return (-1);  // not portMAX_DELAY
  tempS32 = bm->readAdc_P();
  xSemaphoreGive( semaI2C );  /* give one semaphore */
  if( tempS32 == (-1) ) return (-1);
  taskYIELD(); /* for Co-operative Scheduling */
  *pressure = (bm->BME280_compensate_P_int64( tempS32 ) + 128UL) / (256UL * 100UL);

  if( xSemaphoreTake( semaI2C, pdMS_TO_TICKS( WAIT_FOR_SEMAPHORE_TIME )  ) == pdFAIL ) return (-1);  // not portMAX_DELAY
  tempS32 = bm->readAdc_H();
  xSemaphoreGive( semaI2C );  /* give one semaphore */
  if( tempS32 == (-1) ) return (-1);
  taskYIELD(); /* for Co-operative Scheduling */
  *humidity = (bm->BME280_compensate_H_int32( tempS32 ) + 512UL) / 1024UL;

  return 0;
}

/*************************************************************************/
/*  i2cTestTask01                                                        */
/*************************************************************************/
void i2cTestTask01( void *execParam )
{
  Serial.println( "i2cTestTask01 start." );
  while( 1 )
  {
    vTaskDelay( pdMS_TO_TICKS( 1000UL ) );  /**/
    BME280_S32_t temperature;
    BME280_U32_t pressure;
    BME280_U32_t humidity;
    if( bme280Read( &bme280_01, &temperature, &pressure, &humidity ) != 0 )
    {
      Serial.println( "i2cTestTask01 does not take a semaphore." );
      continue;
    }

    temperature01 = (int)((temperature + 5) / 10);
    pressure01 = (int)pressure;
    humidity01 = (int)humidity;

    Serial.print( "P01 = " ); Serial.print( pressure, DEC );
    Serial.print( " H01 = " ); Serial.print( humidity, DEC );
    Serial.print( " T01 = " ); Serial.print( temperature, DEC );
    Serial.println();
  }
}

/*************************************************************************/
/*  i2cTestTask02                                                        */
/*************************************************************************/
void i2cTestTask02( void *execParam )
{
  Serial.println( "i2cTestTask02 start." );
  while( 1 )
  {
    vTaskDelay( pdMS_TO_TICKS( 1000UL ) );  /**/
    BME280_S32_t temperature;
    BME280_U32_t pressure;
    BME280_U32_t humidity;
    if( bme280Read( &bme280_02, &temperature, &pressure, &humidity ) != 0 )
    {
      Serial.println( "i2cTestTask02 does not take a semaphore." );
      continue;
    }

    temperature02 = (int)((temperature + 5) / 10);
    pressure02 = (int)pressure;
    humidity02 = (int)humidity;

    Serial.print( "P02 = " ); Serial.print( pressure, DEC );
    Serial.print( " H02 = " ); Serial.print( humidity, DEC );
    Serial.print( " T02 = " ); Serial.print( temperature, DEC );
    Serial.println();
  }
}

/*************************************************************************/
/*  initialize GPIO                                                      */
/*************************************************************************/
static void initGPIO()
{
  pinMode( ACT_LED_PIN, OUTPUT );
  digitalWrite( ACT_LED_PIN, HIGH );  /**/
}

/*************************************************************************/
/*  ESP32 network parameter informatons.                                 */
/*************************************************************************/
static void networkInformations()
{
  Serial.println();
  Serial.printf("Free Heap Size = %d\r\n", esp_get_free_heap_size());
  Serial.printf("System Free Heap Size = %d\r\n", system_get_free_heap_size());
  Serial.printf("Minimum Free Heap Size = %d\r\n", esp_get_minimum_free_heap_size());
  Serial.println();
  uint8_t mac[6];
  esp_efuse_read_mac( mac );
  Serial.printf("EFuse Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  system_efuse_read_mac( mac );
  Serial.printf("System Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  esp_read_mac( mac, ESP_MAC_WIFI_STA );
  Serial.printf("[Wi-Fi Station] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  esp_read_mac( mac, ESP_MAC_WIFI_SOFTAP );
  Serial.printf("[Wi-Fi SoftAP] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  esp_read_mac( mac, ESP_MAC_BT );
  Serial.printf("[Bluetooth] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  esp_read_mac( mac, ESP_MAC_ETH );
  Serial.printf("[Ethernet] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  Serial.println();
}

/*************************************************************************/
/*  connect Wi-Fi                                                        */
/*************************************************************************/
static void connectWifi()
{
  WiFi.disconnect();
#if defined( __RUN_IN_AP_MODE__ )
  WiFi.mode( WIFI_AP );
  WiFi.softAP( ssidAP, NULL, 6, 0, 4 );  // no pass, ch=6, ssid=broadcast, max connections=4
  vTaskDelay( pdMS_TO_TICKS( 100UL ) );
  WiFi.softAPConfig( apIP, apIP, subnet );

  myIpAddress = WiFi.softAPIP();
  Serial.print( "SSID : " );
  Serial.print( ssidAP );
  Serial.print( " AP IP address : " );
  Serial.println( myIpAddress );
#else  /* defined( __RUN_IN_AP_MODE__ ) */
  unsigned long baseTim = millis();
  WiFi.mode( WIFI_STA );
//  WiFi.config( stationIP,dnsIP,gwIP,subnet );  /**/
  WiFi.begin( ssidSTA, passSTA );
  while( WiFi.status() != WL_CONNECTED )
  {
     Serial.print( "." );
     vTaskDelay( pdMS_TO_TICKS( 100UL ) );
  }
  myIpAddress = WiFi.localIP();
  Serial.print( "\r\nIP number assigned by DHCP is " );
  Serial.print( myIpAddress );
  Serial.print( " association time = " ); Serial.print( millis() - baseTim, DEC ); Serial.println( "ms" );
#endif  /* defined( __RUN_IN_AP_MODE__ ) */
}

/*************************************************************************/
/*  connect ntp server.                                                  */
/*************************************************************************/
static void connectNTP( const char *server )
{
  #define  TZ  (9)
  /* init and get the time from ntp server. */
  configTime( TZ * 3600UL, 0, server );
  struct tm timeinfo;
  if( getLocalTime( &timeinfo ) == true )
  {
    timerAlarmDisable( timer1second );
    setUnixTime( &timeinfo );
    timerAlarmEnable( timer1second );
  }
}

/*************************************************************************/
/*  set unixTime from date and time                                      */
/*************************************************************************/
void setUnixTime( struct tm *tim )
{
  time_t presentTim = mktime( tim );
  unixTime = presentTim;
}

/*************************************************************************/
/*  get date and time string from unixTime                               */
/*************************************************************************/
String stringDataAndTime( char *yyyymmdd, char *hhmm )
{
  struct tm *tim = localtime( (time_t *)&unixTime );
  char buffer[32];
  sprintf( buffer, "%d/%02d/%02d %02d:%02d:%02d", tim->tm_year + 1900, tim->tm_mon + 1, tim->tm_mday,
    tim->tm_hour, tim->tm_min, tim->tm_sec );
  if( yyyymmdd != NULL )
  {
    sprintf( yyyymmdd, "%04d%02d%02d", tim->tm_year + 1900, tim->tm_mon + 1, tim->tm_mday );
  }
  if( hhmm != NULL )
  {
    sprintf( hhmm, "%02d%02d", tim->tm_hour, tim->tm_min );
  }

  return String( buffer );
}

/*************************************************************************/
/*  timer interrupt handler.                                             */
/*************************************************************************/
void IRAM_ATTR onTimerEvery1seconds()
{
  passedTime++;
  unixTime++;
}

/****************************************************************************/
/*                                  Copyright (C) 2018- by hamayan          */
/****************************************************************************/



bme280.cpp
/*********************************************************************************/
/* BME280を使用した温度と湿度と気圧の取得                                        */
/*                                         designed by hamayan since 2015/09/29  */
/*********************************************************************************/
#include  "bme280.h"

/*************************************************************************/
/* 大域変数宣言                                                          */
/*************************************************************************/

/*************************************************************************/
/* プロトタイプ宣言                                                      */
/*************************************************************************/

/*************************************************************************/
/* 端子定義                                                              */
/*************************************************************************/

/*************************************************************************/
/* インスタンス                                                          */
/*************************************************************************/

bme280::bme280( uint8_t adr )
{
  i2cAddress = adr;
}


void bme280::readCalibrationData()
{
  uint8_t buf[26];

  read( BME280_CALIB00, buf, 26 );
  dig_T1 = ((uint16_t)(buf[1]) << 8) | ((uint16_t)(buf[0]) << 0);
  dig_T2 = ((signed short)(buf[3]) << 8) | ((signed short)(buf[2]) << 0);
  dig_T3 = ((signed short)(buf[5]) << 8) | ((signed short)(buf[4]) << 0);
  dig_P1 = ((uint16_t)(buf[7]) << 8) | ((uint16_t)(buf[6]) << 0);
  dig_P2 = ((signed short)(buf[9]) << 8) | ((signed short)(buf[8]) << 0);
  dig_P3 = ((signed short)(buf[11]) << 8) | ((signed short)(buf[10]) << 0);
  dig_P4 = ((signed short)(buf[13]) << 8) | ((signed short)(buf[12]) << 0);
  dig_P5 = ((signed short)(buf[15]) << 8) | ((signed short)(buf[14]) << 0);
  dig_P6 = ((signed short)(buf[17]) << 8) | ((signed short)(buf[16]) << 0);
  dig_P7 = ((signed short)(buf[19]) << 8) | ((signed short)(buf[18]) << 0);
  dig_P8 = ((signed short)(buf[21]) << 8) | ((signed short)(buf[20]) << 0);
  dig_P9 = ((signed short)(buf[23]) << 8) | ((signed short)(buf[21]) << 0);
  dig_H1 = buf[25];

  read( BME280_CALIB26, buf, 7 );
  dig_H2 = ((signed short)(buf[1]) << 8) | ((signed short)(buf[0]) << 0);
  dig_H3 = buf[2];
  dig_H4 = ((signed short)(buf[3]) << 4) | ((signed short)(buf[4] & 0x0f) << 0);
  dig_H5 = ((signed short)(buf[4] & 0xf0) << 4) | ((signed short)(buf[5]) << 0);
  dig_H6 = (signed char)buf[6];
}

BME280_S32_t bme280::readAdc_T()
{
  uint8_t buf[3];

  if( read( BME280_TEMP_MSB, buf, sizeof(buf) ) == (-1) )
  {
    Serial.println( "bme280::readAdc_T read error 01." );
    return (-1);
  }

  return ((BME280_S32_t)buf[0] << 12) | ((BME280_S32_t)buf[1] << 4) | ((BME280_S32_t)buf[2] >> 4);
}

BME280_S32_t bme280::readAdc_P()
{
  uint8_t buf[3];

  if( read( BME280_PRESS_MSB, buf, sizeof(buf) ) == (-1) )
  {
    Serial.println( "bme280::readAdc_P read error 01." );
    return (-1);
  }

  return ((BME280_S32_t)buf[0] << 12) | ((BME280_S32_t)buf[1] << 4) | ((BME280_S32_t)buf[2] >> 4);
}

BME280_S32_t bme280::readAdc_H()
{
  uint8_t buf[2];

  if( read( BME280_HUM_MSB, buf, sizeof(buf) ) == (-1) )
  {
    Serial.println( "bme280::readAdc_H read error 01." );
    return (-1);
  }

  return ((BME280_S32_t)buf[0] << 8) | ((BME280_S32_t)buf[1] << 0);
}


void bme280::readAdc_PTH( BME280_S32_t *p, BME280_S32_t *t, BME280_S32_t *h )
{
  uint8_t buf[8];

  read( BME280_PRESS_MSB, buf, sizeof(buf) );

  *h = ((BME280_S32_t)buf[0] << 8) | ((BME280_S32_t)buf[1] << 0);
  *t = ((BME280_S32_t)buf[2] << 12) | ((BME280_S32_t)buf[3] << 4) | ((BME280_S32_t)buf[4] >> 4);
  *p = ((BME280_S32_t)buf[5] << 12) | ((BME280_S32_t)buf[6] << 4) | ((BME280_S32_t)buf[7] >> 4);
}

void bme280::force( uint8_t pressureOverSample, uint8_t temperatureOverSample )
{
  write( BME280_CTRL_MEAS, ((pressureOverSample & 0x07) << 5) | ((temperatureOverSample & 0x07) << 2) | 1 );
}

uint8_t bme280::readStatus()
{
  uint8_t status = read( BME280_STATUS );

  return status;
}


/*************************************************************************/
/* begin                                                                 */
/*************************************************************************/
void bme280::begin()
{
  write( BME280_RESET, BME280_RESET_VALUE );  /*RESET*/
  delay( 1UL );
  write( BME280_CTRL_MEAS, 0 );  /* set to sleep mode. */
  write( BME280_CONFIG, (4 << 5) | (1 << 2) | 0 );  /*config:stand-by period =500ms,*/
                                      /*iir filter=2 over samples,spi mode=ignore*/
  write( BME280_CTRL_HUM, 1 );  /*ctrl hum*/
//  write( BME280_CTRL_MEAS, (1 << 5) | (1 << 2) | 3 );  /*ctrl meas:temperature over sampling=1,*/
                                      /*pressure over sampling=1,mode=normal*/
  write( BME280_CTRL_MEAS, (1 << 5) | (1 << 2) | 0 );  /*ctrl meas:temperature over sampling=1,*/
                                      /*pressure over sampling=1,mode=sleep*/
  readCalibrationData();
}


void bme280::begin( uint8_t meas, uint8_t hum, uint8_t config )
{
  write( BME280_RESET, BME280_RESET_VALUE );  /*RESET*/
  delay( 1UL );
  write( BME280_CTRL_MEAS, 0 );  /* set to sleep mode. */
  write( BME280_CONFIG, config );  /*config*/
  write( BME280_CTRL_MEAS, meas );  /*ctrl meas*/
  write( BME280_CTRL_HUM, hum );  /*ctrl hum*/

  readCalibrationData();
}


/*************************************************************************/
/* I2C Write                                                             */
/*************************************************************************/
int bme280::write( uint8_t reg, uint8_t dat )
{
  Wire.beginTransmission( i2cAddress );
  Wire.write( reg );
  Wire.write( dat );
  return Wire.endTransmission();
}


/*************************************************************************/
/* I2C block Write                                                       */
/*************************************************************************/
int bme280::write( uint8_t reg, const uint8_t *dat, size_t len )
{
  Wire.beginTransmission( i2cAddress );
  Wire.write( reg );
  Wire.write( dat, len );
  return Wire.endTransmission();
}


/*************************************************************************/
/* byte data read                                                        */
/*************************************************************************/
int bme280::read( uint8_t reg )
{
  Wire.beginTransmission( i2cAddress );
  Wire.write( reg );
  Wire.endTransmission( false ); //endTransmission but keep the connection active

  Wire.requestFrom( (uint8_t)i2cAddress, (uint8_t)1 ); //Ask for bytes, once done, bus is released by default

  unsigned long baseTime = millis();
  while( Wire.available() == 0 ) //Hang out until we get the # of bytes we expect
  {
    if( (millis() - baseTime) > WAIT_FOR_BME280_I2C_TIME ) return (-1);
  }

  return Wire.read() & 0x00ff;
}


/*************************************************************************/
/* any bytes data read                                                   */
/*************************************************************************/
int bme280::read( uint8_t reg, uint8_t data[], size_t len )
{
  Wire.beginTransmission( i2cAddress );
  Wire.write( reg );
  Wire.endTransmission( false ); //endTransmission but keep the connection active

  Wire.requestFrom( (uint8_t)i2cAddress, (uint8_t)len ); //Ask for bytes, once done, bus is released by default

  unsigned long baseTime = millis();
  while( Wire.available() < len ) //Hang out until we get the # of bytes we expect
  {
    if( (millis() - baseTime) > WAIT_FOR_BME280_I2C_TIME ) return (-1);
  }

  for(int i = 0 ; i < len; i++)
    data[i] = Wire.read();    

  return 0;
}




#if 0

// Returns temperature in DegC, double precision. Output value of “51.23” equals 51.23 DegC.
// t_fine carries fine temperature as global value
BME280_S32_t t_fine;

BME280_S32_t bme280::BME280_compensate_T_double(BME280_S32_t adc_T)
{
  BME280_S32_t var1, var2, T;
  
  var1 = (((BME280_S32_t)adc_T)/16384.0 - ((BME280_S32_t)dig_T1)/1024.0) * ((BME280_S32_t)dig_T2);
  var2 = ((((BME280_S32_t)adc_T)/131072.0 - ((BME280_S32_t)dig_T1)/8192.0) *
    (((BME280_S32_t)adc_T)/131072.0 - ((BME280_S32_t)dig_T1)/8192.0)) * ((BME280_S32_t)dig_T3);
  t_fine = (BME280_S32_t)(var1 + var2);
  T = (var1 + var2) / 5120.0;

  return T;
}

// Returns pressure in Pa as double. Output value of “96386.2” equals 96386.2 Pa = 963.862 hPa
BME280_S32_t bme280::BME280_compensate_P_double(BME280_S32_t adc_P)
{
  BME280_S32_t var1, var2, p;
  var1 = ((BME280_S32_t)t_fine/2.0) - 64000.0;
  var2 = var1 * var1 * ((BME280_S32_t)dig_P6) / 32768.0;
  var2 = var2 + var1 * ((BME280_S32_t)dig_P5) * 2.0;
  var2 = (var2/4.0)+(((BME280_S32_t)dig_P4) * 65536.0);
  var1 = (((BME280_S32_t)dig_P3) * var1 * var1 / 524288.0 + ((BME280_S32_t)dig_P2) * var1) / 524288.0;
  var1 = (1.0 + var1 / 32768.0)*((BME280_S32_t)dig_P1);
  if (var1 == 0.0)
  {
    return 0; // avoid exception caused by division by zero
  }
  p = 1048576.0 - (BME280_S32_t)adc_P;
  p = (p - (var2 / 4096.0)) * 6250.0 / var1;
  var1 = ((BME280_S32_t)dig_P9) * p * p / 2147483648.0;
  var2 = p * ((BME280_S32_t)dig_P8) / 32768.0;
  p = p + (var1 + var2 + ((BME280_S32_t)dig_P7)) / 16.0;

  return p;
}

// Returns humidity in %rH as as double. Output value of “46.332” represents 46.332 %rH
BME280_S32_t bme280::bme280_compensate_H_double(BME280_S32_t adc_H)
{
  BME280_S32_t var_H;
  var_H = (((BME280_S32_t)t_fine) - 76800.0);

  var_H = (adc_H - (((BME280_S32_t)dig_H4) * 64.0 + ((BME280_S32_t)dig_H5) / 16384.0 * var_H)) *
  (((BME280_S32_t)dig_H2) / 65536.0 * (1.0 + ((BME280_S32_t)dig_H6) / 67108864.0 * var_H *
  (1.0 + ((BME280_S32_t)dig_H3) / 67108864.0 * var_H)));
  var_H = var_H * (1.0 - ((BME280_S32_t)dig_H1) * var_H / 524288.0);
  if (var_H > 100.0)
    var_H = 100.0;
  else if (var_H < 0.0)
    var_H = 0.0;

  return var_H;
}

#else
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
// t_fine carries fine temperature as global value

BME280_S32_t t_fine;

BME280_S32_t bme280::BME280_compensate_T_int32(BME280_S32_t adc_T)
{
  BME280_S32_t var1, var2, T;

  var1 = ((((adc_T>>3) - ((BME280_S32_t)dig_T1<<1))) * ((BME280_S32_t)dig_T2)) >> 11;
  var2 = (((((adc_T>>4) - ((BME280_S32_t)dig_T1)) * ((adc_T>>4) - ((BME280_S32_t)dig_T1))) >> 12) *
  ((BME280_S32_t)dig_T3)) >> 14;
  t_fine = var1 + var2;
  T = (t_fine * 5 + 128) >> 8;

  return T;
}

// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
// Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
BME280_U32_t bme280::BME280_compensate_P_int64(BME280_S32_t adc_P)
{
  BME280_S64_t var1, var2, p;

  var1 = ((BME280_S64_t)t_fine) - 128000;
  var2 = var1 * var1 * (BME280_S64_t)dig_P6;
  var2 = var2 + ((var1*(BME280_S64_t)dig_P5)<<17);
  var2 = var2 + (((BME280_S64_t)dig_P4)<<35);
  var1 = ((var1 * var1 * (BME280_S64_t)dig_P3)>>8) + ((var1 * (BME280_S64_t)dig_P2)<<12);
  var1 = (((((BME280_S64_t)1)<<47)+var1))*((BME280_S64_t)dig_P1)>>33;
  if (var1 == 0)
  {
    return 0; // avoid exception caused by division by zero
  }
  p = 1048576-adc_P;
  p = (((p<<31)-var2)*3125)/var1;
  var1 = (((BME280_S64_t)dig_P9) * (p>>13) * (p>>13)) >> 25;
  var2 = (((BME280_S64_t)dig_P8) * p) >> 19;
  p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)dig_P7)<<4);

  return (BME280_U32_t)p;
}

// Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
// Output value of “47445” represents 47445/1024 = 46.333 %RH
BME280_U32_t bme280::BME280_compensate_H_int32(BME280_S32_t adc_H)
{
  BME280_S32_t v_x1_u32r;

  v_x1_u32r = (t_fine - ((BME280_S32_t)76800));
  v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - (((BME280_S32_t)dig_H5) * v_x1_u32r)) +
    ((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * (((v_x1_u32r * 
    ((BME280_S32_t)dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) *
    ((BME280_S32_t)dig_H2) + 8192) >> 14));
  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)dig_H1)) >> 4));
  v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
  v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);

  return (BME280_U32_t)(v_x1_u32r >> 12);
}

#endif


/*********************************************************************************/
/* end of file                                                                   */
/*                                         designed by hamayan since 2015/09/29  */
/*********************************************************************************/


bme280.h
/****************************************************************************/
/* BME280 header                                                            */
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/
#ifndef bme280_h
#define bme280_h

#include  <Arduino.h>
#include  <Wire.h>

extern "C" {
}

/* ESP32 Arduinoのドライバーがまともなら無限待ちでもいいかもしれないけれど、イマイチ信用できないのでタイムアウトを設定 */
#define  WAIT_FOR_BME280_I2C_TIME (10UL)


#define  BME280_ID_VALUE      0x60
#define  BME280_RESET_VALUE   0xB6

#define  BME280_HUM_LSB       0xFE
#define  BME280_HUM_MSB       0xFD
#define  BME280_TEMP_XLSB     0xFC
#define  BME280_TEMP_LSB      0xFB
#define  BME280_TEMP_MSB      0xFA
#define  BME280_PRESS_XLSB    0xF9
#define  BME280_PRESS_LSB     0xF8
#define  BME280_PRESS_MSB     0xF7
#define  BME280_CONFIG        0xF5
#define  BME280_CTRL_MEAS     0xF4
#define  BME280_STATUS        0xF3
#define  BME280_CTRL_HUM      0xF2
#define  BME280_CALIB26       (0xE1 + 0)
#define  BME280_CALIB27       (0xE1 + 1)
#define  BME280_CALIB28       (0xE1 + 2)
#define  BME280_CALIB29       (0xE1 + 3)
#define  BME280_CALIB30       (0xE1 + 4)
#define  BME280_CALIB31       (0xE1 + 5)
#define  BME280_CALIB32       (0xE1 + 6)
#define  BME280_CALIB33       (0xE1 + 7)
#define  BME280_CALIB34       (0xE1 + 8)
#define  BME280_CALIB35       (0xE1 + 9)
#define  BME280_CALIB36       (0xE1 + 10)
#define  BME280_CALIB37       (0xE1 + 11)
#define  BME280_CALIB38       (0xE1 + 12)
#define  BME280_CALIB39       (0xE1 + 13)
#define  BME280_CALIB40       (0xE1 + 14)
#define  BME280_CALIB41       (0xE1 + 15)
#define  BME280_RESET         0xE0
#define  BME280_ID            0xD0
#define  BME280_CALIB00       (0x88 + 0)
#define  BME280_CALIB01       (0x88 + 1)
#define  BME280_CALIB02       (0x88 + 2)
#define  BME280_CALIB03       (0x88 + 3)
#define  BME280_CALIB04       (0x88 + 4)
#define  BME280_CALIB05       (0x88 + 5)
#define  BME280_CALIB06       (0x88 + 6)
#define  BME280_CALIB07       (0x88 + 7)
#define  BME280_CALIB08       (0x88 + 8)
#define  BME280_CALIB09       (0x88 + 9)
#define  BME280_CALIB10       (0x88 + 10)
#define  BME280_CALIB11       (0x88 + 11)
#define  BME280_CALIB12       (0x88 + 12)
#define  BME280_CALIB13       (0x88 + 13)
#define  BME280_CALIB14       (0x88 + 14)
#define  BME280_CALIB15       (0x88 + 15)
#define  BME280_CALIB16       (0x88 + 16)
#define  BME280_CALIB17       (0x88 + 17)
#define  BME280_CALIB18       (0x88 + 18)
#define  BME280_CALIB19       (0x88 + 19)
#define  BME280_CALIB20       (0x88 + 20)
#define  BME280_CALIB21       (0x88 + 21)
#define  BME280_CALIB22       (0x88 + 22)
#define  BME280_CALIB23       (0x88 + 23)
#define  BME280_CALIB24       (0x88 + 24)
#define  BME280_CALIB25       (0x88 + 25)

#if 0
typedef  double  BME280_S32_t;
#else
typedef  signed long  BME280_S32_t;
#endif
typedef  unsigned long     BME280_U32_t;
typedef  signed long long  BME280_S64_t;

class bme280 {
private:
  uint8_t i2cAddress;

  uint16_t dig_T1;
  signed short   dig_T2,dig_T3;

  uint16_t dig_P1;
  signed short   dig_P2,dig_P3,dig_P4,dig_P5,dig_P6,dig_P7,dig_P8,dig_P9;

  uint8_t dig_H1;
  signed short  dig_H2;
  uint8_t dig_H3;
  signed short  dig_H4,dig_H5;
  signed char   dig_H6;

  void readCalibrationData();

public:
  bme280( uint8_t adr );
  void begin();
  void begin( uint8_t meas, uint8_t hum, uint8_t config );
  int  write( uint8_t reg, uint8_t dat );
  int  write( uint8_t addr, const uint8_t *dat, unsigned int len );
  int  read( uint8_t reg );
  int  read( uint8_t reg, uint8_t data[], size_t len );

  BME280_S32_t readAdc_T();
  BME280_S32_t readAdc_P();
  BME280_S32_t readAdc_H();
  void readAdc_PTH( BME280_S32_t *p, BME280_S32_t *t, BME280_S32_t *h );
  void force( uint8_t pressureOverSample, uint8_t temperatureOverSample );
  uint8_t readStatus();

#if 0
  BME280_S32_t BME280_compensate_T_double(BME280_S32_t adc_T);
  BME280_S32_t BME280_compensate_P_double(BME280_S32_t adc_P);
  BME280_S32_t bme280_compensate_H_double(BME280_S32_t adc_H);
#else
  BME280_S32_t BME280_compensate_T_int32(BME280_S32_t adc_T);
  BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P);
  BME280_U32_t BME280_compensate_H_int32(BME280_S32_t adc_H);
#endif
};


#endif  /*bme280_H*/

/****************************************************************************/
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/


※実は自分で排他制御を用意する必要が無かった???次号でI2Cの排他制御に突っ込んでみる!

※I2Cを共有するのは同一優先度のタスク間なので、ここは排他制御で一番お手軽なバイナリーセマフォを使用。優先度が同一または隣接まではバイナリーセマフォで充分だと思うが、2つ以上優先度が離れている場合はミューテックスとか別の手段も検討する必要があります。

と言う訳で、githubから最新版を落としてインストールしてください。


ESP32、、、参考になる日本語の読み物、ないよね~

nice!(0)  コメント(0) 

大きな配列を取ると怒られるぅ~~~ [ESP32]

またもやM5Stackである。

uint16_t bitMap[ (80 * 3 * 60 * 3) ];
こんな風に配列を取ると、リンカーに「オーバーフローだクソ野郎」って怒られるようになってしまった。
、、、region `dram0_0_seg' overflowed by 2744 bytes、、、

色々試すと、配列のサイズが40000を超えたあたりでエラーになっている。人によって違うだろうけれど。
リンカースクリプトのdram0_0_segのサイズ設定がしょぼいからだろうけれど、どこを直すと良いのか判らん。

とりあえずHEAP領域から確保すれば怒られない。まだ動かしていないけれど。
uint16_t *bitMap;
bitMap = new uint16_t[ 80 * 3 * 60 * 3 ];

大きな配列を取れないのは、320×240ピクセルで16bitカラーのLCDを持つ装置としては、「どうなんだそれ?」って感じだが。

無理矢理「解決」にされていて、草!
https://www.esp32.com/viewtopic.php?t=1831

どうでもイイが、Arduinoの環境設定のボードマネージャーに、
http://www.M5Stack.com/download/package_m5stack_index.json
は、もう書かなくてもイイらしい。どうせ書いても変なファイルを引っ張ってくるだけだし。

nice!(0)  コメント(0) 

部品を実装してみただけ [ESP32]

2018-07-05 13.02.26.jpg

とりあえず部品を実装してみた。

LEPTONのBREAKOUT BOARDを載せているが、このBREAKOUT BOARDではなくソケットやレギュレータを実装してFLIRのONEとか3.0を使える予定。

実装してみて気付いたんだけど、スルーホール部品を使うと、下のバッテリーアダプターのリポ電池に足が干渉して、ちょっとやばい www

とりあえずM5Stack用の拡張基板自体はうまく行ったみたいなので、オリジナルの拡張基板を作りたい人は、連絡くれればkicadのプロジェクトをまっるっとあげるので、基板外形などを参考にしてね。

nice!(1)  コメント(0) 

何かのプロトタイプ基板があまりにもあれなので、、、 [ESP32]

m5stackThermo_002.png

なにかのプロトタイプ基板が、接続コネクタから信号線が引き出されておらず、あまりにも使い勝手が悪いので、作った。

もう、うにばーさるにゴニョゴニョなんてやってられねーな。
nice!(0)  コメント(0) 

ESP32 for arduino のライブラリの更新と、AquesTalk-ESP、、、 [ESP32]

また更新かよ!2018年7月11日

ESP32 Arduinoライブラリ更新作業メモ

ESP32 for Arduinoのライブラリが新しくなっている事に気付いたので、更新をしたいのだが、GitHubからzipファイルをダウンロードして、まるっとコピーしてしまうと、AquesTalk-ESP関連の変更がいろいろ無効になってしまう。

面倒だなぁ、、、

やっている事は、
1.¥tools¥sdk¥libにlibaquestalk.aを追加
2.¥tools¥sdk¥include¥aquestalkにaquestalk.hを追加
3.esp32の下にplatform.local.txtを作成し、中身は以下とする
compiler.c.extra_flags="-I{compiler.sdk.path}/include/aquestalk"
compiler.cpp.extra_flags="-I{compiler.sdk.path}/include/aquestalk"
compiler.c.elf.libs=-lgcc -lopenssl -lbtdm_app -lfatfs -lwps -lcoexist -lwear_levelling -lhal -lnewlib -ldriver -lbootloader_support -lpp -lsmartconfig -ljsmn -lwpa -lethernet -lphy -lapp_trace -lconsole -lulp -lwpa_supplicant -lfreertos -lbt -lmicro-ecc -lcxx -lxtensa-debug-module -lmdns -lvfs -lsoc -lcore -lsdmmc -lcoap -ltcpip_adapter -lc_nano -lrtc -lspi_flash -lwpa2 -lesp32 -lapp_update -lnghttp -lspiffs -lespnow -lnvs_flash -lesp_adc_cal -llog -lexpat -lm -lc -lheap -lmbedtls -llwip -lnet80211 -lpthread -ljson  -lstdc++ -laquestalk

以上

1.AquesTalk関連ファイルを保存しておいて、、、
2.旧ライブラリファイル群をフォルダーから削除し、、、
3.新ライブラリファイル群を削除したフォルダーにコピーし、、、
4.toolsのget.exeを行い、、、
5.AquesTalk関連ファイルを差し戻す。

参照
https://github.com/espressif/arduino-esp32
http://blog-yama.a-quest.com/?eid=970188

ちゃんと動くかどうかは、まだ確認していない。

と思ったら、、、なんかインクルードファイルの検索パスが変わっていないかぁ、、、
従来
#include <FreeRTOS.h>
で良かったものがエラーになって、以下の様にしないとコンパイルできない、、、
#include <freertos\FreeRTOS.h>
くそぅ、、、

EEPROM.cppの180行目辺りからこんな代入しているから、
  uint8_t value;
  return EEPROMClass::readAll (address, value);

コンパイラにすっごく怒られているんだけれど、、、しょうがないので初期値を与えてエラー回避。

今回の更新で、WiFi.configがまともに動くようになったのは良かった。

nice!(0)  コメント(0) 

ESP32 for arduino のmain.cppの変更? [ESP32]

main.cppのloopTaskの中から、micros()が削除されたね。

Use esp_timer_get_time as time source for micros and mills

だそうだ。

従来micro秒の更新は、loopTaskの中のmicros()で行っていたので、loopTaskに処理が回らないと更新がままならなかったが、それは解消したと言う事かなぁ。
nice!(1)  コメント(0) 

ESP32でマルチタスクを行う為の、とりあえずここまで判った事。 37タスク目 [ESP32]

ESP32_AquesTalk_Test_02.png

別ネタ

ESP32もBlynkとAquesTalkで行こう!

AquesTalk-ESPでGoogle Home Miniに話掛けられるか?

https://youtu.be/klkQz3_6klg

www、エイプリールフールネタじゃないよ!

ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/23
  • メディア: Kindle版



図解 μITRONによる組込みシステム入門(第2版)

図解 μITRONによる組込みシステム入門(第2版)

  • 作者: 武井 正彦
  • 出版社/メーカー: 森北出版
  • 発売日: 2018/02/17
  • メディア: 単行本(ソフトカバー)



μITRON4.0標準ガイドブック

μITRON4.0標準ガイドブック

  • 作者:
  • 出版社/メーカー: パーソナルメディア
  • 発売日: 2001/11/01
  • メディア: 単行本(ソフトカバー)



リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

  • 作者: 高田 広章
  • 出版社/メーカー: CQ出版
  • 発売日: 2004/02
  • メディア: 単行本



nice!(0)  コメント(0) 

ESP32でマルチタスクを行う為の、とりあえずここまで判った事。 36タスク目 [ESP32]

ESP32_aquesTalk_speaker.jpg

別ネタ

ESP32もBlynkとAquesTalkで行こう!
なにかの資料
ESP32_aquesTalk_speaker.png

元々はPWM波形をアンプする回路なので、前段のフィルターのカットオフも10kHzくらいに設定。

ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/23
  • メディア: Kindle版



図解 μITRONによる組込みシステム入門(第2版)

図解 μITRONによる組込みシステム入門(第2版)

  • 作者: 武井 正彦
  • 出版社/メーカー: 森北出版
  • 発売日: 2018/02/17
  • メディア: 単行本(ソフトカバー)



μITRON4.0標準ガイドブック

μITRON4.0標準ガイドブック

  • 作者:
  • 出版社/メーカー: パーソナルメディア
  • 発売日: 2001/11/01
  • メディア: 単行本(ソフトカバー)



リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

  • 作者: 高田 広章
  • 出版社/メーカー: CQ出版
  • 発売日: 2004/02
  • メディア: 単行本



nice!(0)  コメント(0) 

ESP32でマルチタスクを行う為の、とりあえずここまで判った事。 35タスク目 [ESP32]

Screenshot_2018-03-29-00-31-54.png

別ネタ

ESP32もBlynkとAquesTalkで行こう!

Blynk、はじめに
https://www.blynk.cc/getting-started/

Blynk、サンプルコードジェネレーター
https://examples.blynk.cc/?board=ESP32&shield=ESP32%20WiFi&example=GettingStarted%2FVirtualPinWrite

ゆっくりしていってぬ!
※ソースコードに変更有。Blynkタスクの優先度を1に、タスクdelayをコメントアウト。
※Blynkのターミナルも追加して、任意の言葉を発声できる様に変更。
/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************

  You’ll need:
   - Blynk App (download from AppStore or Google Play)
   - ESP32 board
   - Decide how to connect to Blynk
     (USB, Ethernet, Wi-Fi, Bluetooth, ...)

  There is a bunch of great example sketches included to show you how to get
  started. Think of them as LEGO bricks  and combine them as you wish.
  For example, take the Ethernet Shield sketch and combine it with the
  Servo example, or choose a USB sketch and add a code from SendData
  example.
 *************************************************************/
// hello_aquestalk.ino - AquesTalk pico for ESP32 サンプルプログラム

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include "driver/i2s.h"
#include "aquestalk.h"

/*************************************************************************/
/*  instances and valiables.                                             */
/*************************************************************************/
IPAddress myIP; // self IP address
static unsigned long monitorPrintTim;
volatile xQueueHandle que;

/*************************************************************************/
/*  task prototype defines.                                              */
/*************************************************************************/
xTaskHandle taskHandle[ 2 ];
void blynkTask( void *execParam );
void aquesTalkTask( void *execParam );

/*************************************************************************/
/*  Wi-Fi defines.                                                       */
/*************************************************************************/
const char ssid[] = "ap ssid";
const char pass[] = "ap password";

/*************************************************************************/
/*  blynk defines.                                                       */
/*************************************************************************/
const char auth[] = "your blynk token";

/*************************************************************************/
/*  setup.                                                               */
/*************************************************************************/
void setup()
{
  // Debug console
  Serial.begin( 115200 );
  Serial.print( "FreeRTOS Test. " ); Serial.printf( "ESP32 Chip Revision: %d\r\n\r\n" , ESP.getChipRevision() );

  WiFi.disconnect();
  WiFi.begin( ssid, pass );
  while( WiFi.status() != WL_CONNECTED )
  {
     Serial.print( "." );
     vTaskDelay( pdMS_TO_TICKS( 100UL ) );
  }
  myIP = WiFi.localIP();
  Serial.print( "\r\nIP number assigned by DHCP is " );
  Serial.println( myIP );

  // Create data queue.
  que = xQueueCreate( 10, sizeof(char *) );

  /* active the blynk demoTask. */
  xTaskCreatePinnedToCore(
    blynkTask, "",
    configMINIMAL_STACK_SIZE * 4,
    NULL, 1, &taskHandle[ 0 ], 1 );

  /* active the aquesTalk task. */
  xTaskCreatePinnedToCore(
    aquesTalkTask, "",
    (configMINIMAL_STACK_SIZE * 2) + (sizeof(uint32_t) * AQ_SIZE_WORKBUF),
    NULL, 2, &taskHandle[1], 1 );
}

/*************************************************************************/
/*  loop.                                                                */
/*************************************************************************/
void loop()
{
  /* stack monitor. */
  if( (millis() - monitorPrintTim) >= (10 * 1000UL) )
  {
    monitorPrintTim = millis();
    stackMonitor();
  }
}

/*************************************************************************/
/*  stack monitor                                                        */
/*************************************************************************/
static void reportStackSize( TaskHandle_t taskHdl, int count )
{
  unsigned portBASE_TYPE stzckSize = uxTaskGetStackHighWaterMark( taskHdl );
  String msg = "  Task" + String( count ) + " remains stack size = " + String( stzckSize );
  Serial.println( msg );
}

static void stackMonitor()
{
  int i;
  for( i = 0; i < sizeof(taskHandle) / sizeof(taskHandle[ 0 ]); i++ )
  {
    reportStackSize( taskHandle[ i ], i );
  }

  TaskHandle_t loopTaskHandle = xTaskGetCurrentTaskHandle();
  reportStackSize( loopTaskHandle, i );
  Serial.println();
}

/*************************************************************************/
/*  blynk task.                                                          */
/*************************************************************************/
void blynkTask( void *execParam )
{
  Blynk.config( auth );
  while( 1 )
  {
    Blynk.run();
//    vTaskDelay( pdMS_TO_TICKS( 10 ) );
  }
}

// Attach virtual serial terminal to Virtual Pin V4
WidgetTerminal terminal(V4);

/*************************************************************************/
/*  blynk virtual pin 0 function.                                        */
/*************************************************************************/
BLYNK_WRITE( V0 )
{ 
  static const char *talk = "konnnichiwa.";
  int value = param.asInt();
  if( value )
  {
    xQueueSendToBack( que, (const void *)&talk, 0 );
    terminal.println( talk );
    terminal.flush();
  }
}

/*************************************************************************/
/*  blynk virtual pin 1 function.                                        */
/*************************************************************************/
BLYNK_WRITE( V1 )
{ 
  static const char *talk = "korewa;te'_sutode_su.";
  int value = param.asInt();
  if( value )
  {
    xQueueSendToBack( que, (const void *)&talk, 0 );
    terminal.println( talk );
    terminal.flush();
  }
}

/*************************************************************************/
/*  blynk virtual pin 2 function.                                        */
/*************************************************************************/
BLYNK_WRITE( V2 )
{ 
  static const char *talk = "sa'nngatsu/<NUMK VAL=17 COUNTER=nichi> <NUMK VAL=12 COUNTER=ji>/<NUMK VAL=23 COUNTER=funn>.";
  int value = param.asInt();
  if( value )
  {
    xQueueSendToBack( que, (const void *)&talk, 0 );
    terminal.println( talk );
    terminal.flush();
  }
}

/*************************************************************************/
/*  blynk virtual pin 3 function.                                        */
/*************************************************************************/
BLYNK_WRITE( V3 )
{ 
  static const char *talk = "yukkuri_siteittene?";
  int value = param.asInt();
  if( value )
  {
    xQueueSendToBack( que, (const void *)&talk, 0 );
    terminal.println( talk );
    terminal.flush();
  }
}

/*************************************************************************/
/*  blynk virtual pin 4 function.                                        */
/*************************************************************************/
BLYNK_WRITE( V4 )
{ 
  char *talk = (char *)param.getBuffer();
  int length = param.getLength();
  xQueueSendToBack( que, (const void *)&talk, 0 );
  terminal.write( talk, length );
  terminal.println();
  terminal.flush();
}

/*************************************************************************/
/*  aquesTalkTask                                                        */
/*************************************************************************/
void aquesTalkTask( void *execParam )
{
  #define LEN_FRAME 32
  uint32_t workbuf [ AQ_SIZE_WORKBUF ];

  Serial.println( "Initialize AquesTalk" );
  int iret = CAqTkPicoF_Init(workbuf, LEN_FRAME, NULL);  // CAqTkPicoF_Init(workbuf, LEN_FRAME, "licence code");
  if(iret) Serial.println("ERR:CAqTkPicoF_Init");

  DAC_Create();
  Serial.println("D/A start");

  while( 1 )
  {
    char *talk;
    xQueueReceive( que, (void *)&talk, portMAX_DELAY );
    Play( talk );
  }
  DAC_Release();
  Serial.println("D/A stop");
  // vTaskDelete( NULL );  /* delete aquesTalkTask. if you want. */
}


// 一文の音声出力(同期型)
void Play( const char *koe )
{
  Serial.print( "Play:" );
  Serial.println( koe );

  int iret = CAqTkPicoF_SetKoe( (const uint8_t*)koe, 100, 0xffffU );
  if( iret )  Serial.println( "ERR:CAqTkPicoF_SetKoe" );

  for(;;)
  {
    int16_t wav[ LEN_FRAME ];
    uint16_t len;
    iret = CAqTkPicoF_SyntheFrame( wav, &len );
    if( iret ) break; // EOD
    
    DAC_Write( (int)len, wav );
  }
}

////////////////////////////////
//i2s configuration 
const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config =
{
  .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
  .sample_rate = 24000,
  .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
  .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
  .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB,
  .intr_alloc_flags = 0,
  .dma_buf_count = 4,
  .dma_buf_len = 384,
  .use_apll = 0
};

void DAC_Create()
{
  AqResample_Reset();

  i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
  i2s_set_pin((i2s_port_t)i2s_num, NULL);
}

void DAC_Release()
{
  i2s_driver_uninstall((i2s_port_t)i2s_num); //stop & destroy i2s driver 
}

// upsampling & write to I2S
int DAC_Write( int len, int16_t *wav )
{
  int i = 0;
  for( i = 0; i < len; i++ )
  {
    // upsampling x3
    int16_t wav3[ 3 ];
    AqResample_Conv( wav[ i ], wav3 );
    // write to I2S DMA buffer
    for(int k = 0; k < 3; k++ )
    {
      uint16_t sample[ 2 ];
      uint16_t us = ((uint16_t)wav3[ k ])^0x8000U;  // signed -> unsigned data 内蔵DA Only
      sample[ 0 ] = sample[ 1 ] = us; // mono -> stereo
      int iret = i2s_push_sample((i2s_port_t)i2s_num, (const char *)sample, 100);
      if( iret < 0 ) return iret; // -1:ESP_FAIL
      if( iret == 0 ) break;  //  0:TIMEOUT
    }
  }
  return i;
}



ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門 H8マイコンとHOSで始める組み込み開発

  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/23
  • メディア: Kindle版



図解 μITRONによる組込みシステム入門(第2版)

図解 μITRONによる組込みシステム入門(第2版)

  • 作者: 武井 正彦
  • 出版社/メーカー: 森北出版
  • 発売日: 2018/02/17
  • メディア: 単行本(ソフトカバー)



μITRON4.0標準ガイドブック

μITRON4.0標準ガイドブック

  • 作者:
  • 出版社/メーカー: パーソナルメディア
  • 発売日: 2001/11/01
  • メディア: 単行本(ソフトカバー)



リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

リアルタイムOSと組み込み技術の基礎―実践μITRONプログラミング (TECHI (Vol.17))

  • 作者: 高田 広章
  • 出版社/メーカー: CQ出版
  • 発売日: 2004/02
  • メディア: 単行本



nice!(0)  コメント(0) 
前の10件 | -