apeescape2.com
  • メイン
  • 仕事の未来
  • 革新
  • ブランドデザイン
  • 財務プロセス
バックエンド

ESP32オーディオサンプリングの操作

ESP32は、WiFiおよびBluetooth対応の次世代マイクロコントローラーです。これは、上海を拠点とするEspressifの後継者であり、非常に人気があり、愛好家にとっては革命的です。 ESP8266マイクロコントローラー 。

マイクロコントローラーの中でも巨大なESP32の仕様には、台所の流し台以外のすべてが含まれています。これはシステムオンチップ(SoC)製品であり、そのすべての機能を利用するには、実際にはオペレーティングシステムが必要です。

このESP32チュートリアルでは、タイマー割り込みからアナログ-デジタルコンバーター(ADC)をサンプリングする際の特定の問題について説明し、解決します。 ArduinoIDEを使用します。機能セットの点で最悪のIDEの1つであっても、Arduino IDEは少なくともセットアップとESP32開発での使用が簡単であり、さまざまな一般的なハードウェアモジュール用のライブラリの最大のコレクションを備えています。ただし、代わりに多くのネイティブESP-IDFAPIも使用します Arduino パフォーマンス上の理由から。



ESP32オーディオ:タイマーと割り込み

ESP32には、2つのグループに分けられた4つのハードウェアタイマーが含まれています。すべてのタイマーは同じで、16ビットのプリスケーラーと64ビットのカウンターがあります。プリスケール値は、タイマーに入る内部80 MHzクロックからのハードウェアクロック信号をN番目のティックごとに制限するために使用されます。プリスケールの最小値は2です。これは、割り込みが公式に最大40MHzで発生する可能性があることを意味します。これは悪いことではありません。最高のタイマー解像度では、ハンドラーコードは最大6クロックサイクル(240MHzコア/ 40MHz)で実行する必要があるためです。タイマーには、いくつかの関連するプロパティがあります。

  • divider —周波数プリスケール値
  • counter_en —タイマーに関連付けられた64ビットカウンターが有効かどうか(通常はtrue)
  • counter_dir —カウンターがインクリメントされるかデクリメントされるか
  • alarm_en —「アラーム」、つまりカウンターのアクションが有効になっているかどうか
  • auto_reload —アラームがトリガーされたときにカウンターがリセットされるかどうか

重要な個別のタイマーモードのいくつかは次のとおりです。

  • タイマーは無効になっています。 ハードウェアはまったくカチカチ音をたてていません。
  • タイマーは有効ですが、アラームは無効です。 タイマーハードウェアはカチカチ音をたてており、オプションで内部カウンターをインクリメントまたはデクリメントしていますが、他に何も起きていません。
  • タイマーが有効になり、そのアラームも有効になります。 以前と同様ですが、今回は、タイマーカウンターが特定の構成された値に達すると、何らかのアクションが実行されます。カウンターがリセットされるか、割り込みが生成されます。

タイマーのカウンターは任意のコードで読み取ることができますが、ほとんどの場合、定期的に何かを実行することに関心があります。つまり、割り込みを生成するようにタイマーハードウェアを構成し、それを処理するコードを記述します。

割り込みハンドラ関数は、次の割り込みが生成される前に終了する必要があります。これにより、関数が取得できる複雑さの上限が厳しくなります。一般に、割り込みハンドラーは可能な限り最小限の作業を実行する必要があります。

リモートで複雑なことを実現するには、代わりに、割り込みのないコードによってチェックされるフラグを設定する必要があります。単一のピンを単一の値に読み取ったり設定したりするよりも複雑な種類のI / Oは、多くの場合、別のハンドラーにオフロードする方が適切です。

ブートストラップテーマとは

ESP-IDF環境では、FreeRTOS関数vTaskNotifyGiveFromISR()割り込みハンドラー(割り込みサービスルーチン、またはISRとも呼ばれます)に実行する何かがあることをタスクに通知するために使用できます。コードは次のようになります。

portMUX_TYPE DRAM_ATTR timerMux = portMUX_INITIALIZER_UNLOCKED; TaskHandle_t complexHandlerTask; hw_timer_t * adcTimer = NULL; // our timer void complexHandler(void *param) { while (true) { // Sleep until the ISR gives us something to do, or for 1 second uint32_t tcount = ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)); if (check_for_work) { // Do something complex and CPU-intensive } } } void IRAM_ATTR onTimer() { // A mutex protects the handler from reentry (which shouldn't happen, but just in case) portENTER_CRITICAL_ISR(&timerMux); // Do something, e.g. read a pin. if (some_condition) { // Notify complexHandlerTask that the buffer is full. BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(complexHandlerTask, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken) { portYIELD_FROM_ISR(); } } portEXIT_CRITICAL_ISR(&timerMux); } void setup() { xTaskCreate(complexHandler, 'Handler Task', 8192, NULL, 1, &complexHandlerTask); adcTimer = timerBegin(3, 80, true); // 80 MHz / 80 = 1 MHz hardware clock for easy figuring timerAttachInterrupt(adcTimer, &onTimer, true); // Attaches the handler function to the timer timerAlarmWrite(adcTimer, 45, true); // Interrupts when counter == 45, i.e. 22.222 times a second timerAlarmEnable(adcTimer); }

注:この記事全体でコードで使用されている関数は、 ESP-IDF API とで ESP32ArduinoコアGitHubプロジェクト 。

CPUキャッシュとハーバードアーキテクチャ

注意すべき非常に重要なことはIRAM_ATTRですonTimer()の定義の節割り込みハンドラ。これは、CPUコアが命令を実行(およびデータにアクセス)できるのは組み込みRAMからのみであり、プログラムコードとデータが通常格納されているフラッシュストレージからは実行できないためです。これを回避するために、合計520 KiBのRAMの一部がIRAMとして使用されます。これは、フラッシュストレージからコードを透過的にロードするために使用される128KiBのキャッシュです。 ESP32は、コードとデータに別々のバスを使用します( 「ハーバードアーキテクチャ」 )したがって、これらは非常に個別に処理され、メモリプロパティにまで拡張されます。IRAMは特別であり、32ビットアドレス境界でのみアクセスできます。

実際、ESP32メモリは非常に不均一です。そのさまざまな領域がさまざまな目的に使用されます。最大連続領域のサイズは約160KiBであり、ユーザープログラムがアクセスできるすべての「通常の」メモリは合計で約316KiBにすぎません。

フラッシュストレージからのデータの読み込みは遅く、SPIバスアクセスが必要になる可能性があるため、速度に依存するコードはIRAMキャッシュに収まるように注意する必要があり、その一部がによって使用されるため、多くの場合、はるかに小さくなります(100 KiB未満)。オペレーティング・システム。特に、割り込みが発生したときに割り込みハンドラコードがキャッシュにロードされない場合、システムは例外を生成します。割り込みが発生したときにフラッシュストレージから何かをロードすることは、非常に遅く、ロジスティックの悪夢でもあります。 IRAM_ATTR onTimer()の指定子ハンドラーは、コンパイラーとリンカーに、このコードを特別なものとしてマークするように指示します。このコードはIRAMに静的に配置され、スワップアウトされることはありません。

ただし、IRAM_ATTR指定された関数にのみ適用されます。その関数から呼び出された関数は影響を受けません。

タイマー割り込みからのESP32オーディオデータのサンプリング

割り込みからオーディオ信号をサンプリングする通常の方法では、サンプルのメモリバッファを維持し、サンプリングしたデータを入力して、データが利用可能であることをハンドラタスクに通知します。

ESP-IDFは adc1_get_raw() 最初のADCペリフェラルの特定のADCチャネルのデータを測定する機能(2番目のADCチャネルはWiFiによって使用されます)。ただし、タイマーハンドラーコードで使用すると、プログラムが不安定になります。これは、他のIDF関数(特にロックを処理する関数)を多数呼び出す複雑な関数であり、adc1_get_raw()も呼び出さないためです。また、それが呼び出す関数はIRAM_ATTRでマークされていません。割り込みハンドラーは、ADC関数がIRAMからスワップアウトされるのに十分な大きさのコードが実行されるとすぐにクラッシュします。これは、WiFi-TCP / IP-HTTPスタック、またはSPIFFSファイルシステムライブラリである可能性があります。または他の何か。

注:一部のIDF関数は、割り込みハンドラーから呼び出すことができるように特別に作成されています(IRAM_ATTRでマークされています)。 vTaskNotifyGiveFromISR()上記の例の関数はそのような関数の1つです。

これを回避するための最もIDFに適した方法は、ADCサンプルを取得する必要があるときに割り込みハンドラーがタスクに通知し、このタスクにサンプリングとバッファー管理を行わせ、場合によっては別のタスクをデータ分析に使用することです(または圧縮または送信、または場合によっては何でも)。残念ながら、これは非常に非効率的です。ハンドラー側(実行する作業があることをタスクに通知する)とタスク側(実行するタスクを取得する)の両方で、オペレーティングシステムとの対話と実行中の数千の命令が関係します。このアプローチは、理論的には正しいものの、CPUを大幅に停止させる可能性があるため、他のタスク用に予備のCPUパワーをほとんど残しません。

IDFソースコードを掘り下げる

ADCからのデータのサンプリングは通常簡単な作業であるため、次の戦略はIDFがどのように行うかを確認し、提供されたAPIを呼び出さずにコードに直接複製することです。 adc1_get_raw()関数はに実装されています rtc_module.c IDFのファイルとそれが行う8つほどのことのうち、実際にADCをサンプリングしているのは1つだけです。これは、adc_convert()の呼び出しによって実行されます。幸いなことに、adc_convert()は、SENSという名前のグローバル構造を介して周辺ハードウェアレジスタを操作することによってADCをサンプリングする単純な関数です。

オリンピックシンボルは、のゲシュタルト原理の例です。

このコードをプログラムで機能するように(そしてadc1_get_raw()の動作を模倣するように)適応させるのは簡単です。次のようになります。

int IRAM_ATTR local_adc1_read(int channel) { uint16_t adc_value; SENS.sar_meas_start1.sar1_en_pad = (1 << channel); // only one channel is selected while (SENS.sar_slave_addr1.meas_status != 0); SENS.sar_meas_start1.meas1_start_sar = 0; SENS.sar_meas_start1.meas1_start_sar = 1; while (SENS.sar_meas_start1.meas1_done_sar == 0); adc_value = SENS.sar_meas_start1.meas1_data_sar; return adc_value; }

次のステップは、関連するヘッダーを含めて、SENSを含めることです。変数が使用可能になります:

#include #include

最後に、adc1_get_raw()以降ADCをサンプリングする前にいくつかの構成手順を実行します。ADCがセットアップされた直後に直接呼び出す必要があります。これにより、タイマーが開始される前に、関連する構成を実行できます。

このアプローチの欠点は、他のIDF機能とうまく連携しないことです。 ADC構成をリセットする他の周辺機器、ドライバー、またはランダムなコードが呼び出されるとすぐに、カスタム関数は正しく機能しなくなります。少なくともWiFi、PWM、I2C、およびSPIはADC構成に影響を与えません。何かがそれに影響を与える場合は、adc1_get_raw()への呼び出しADCを再度適切に構成します。

ESP32オーディオサンプリング:最終コード

local_adc_read()で関数が配置されている場合、タイマーハンドラーコードは次のようになります。

#define ADC_SAMPLES_COUNT 1000 int16_t abuf[ADC_SAMPLES_COUNT]; int16_t abufPos = 0; void IRAM_ATTR onTimer() { portENTER_CRITICAL_ISR(&timerMux); abuf[abufPos++] = local_adc1_read(ADC1_CHANNEL_0); if (abufPos >= ADC_SAMPLES_COUNT) { abufPos = 0; // Notify adcTask that the buffer is full. BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(adcTaskHandle, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken) { portYIELD_FROM_ISR(); } } portEXIT_CRITICAL_ISR(&timerMux); }

ここで、adcTaskHandle complexHandlerの構造に従って、バッファを処理するために実装されるFreeRTOSタスクです。最初のコードスニペットの関数。オーディオバッファのローカルコピーを作成し、それを自由に処理できます。たとえば、バッファでFFTアルゴリズムを実行したり、バッファを圧縮してWiFi経由で送信したりできます。

逆説的ですが、Arduino関数はanalogRead()でマークされているため、ESP-IDFAPIの代わりにArduinoAPIを使用すると(つまり、adc1_get_raw()の代わりにIRAM_ATTR)機能します。ただし、それらはより高いレベルの抽象化を提供するため、ESP-IDFのものよりもはるかに低速です。パフォーマンスについて言えば、カスタムADC読み取り機能はESP-IDF機能の約2倍の速度です。

ESP32プロジェクト:OSへまたはOSへではない

ここで行ったこと、つまりオペレーティングシステムのAPIを再実装して、オペレーティングシステムを使用しなかった場合でも発生しない問題を回避することは、オペレーティングシステムを使用することの長所と短所をよく表しています。最初の場所。

小型のマイクロコントローラーは、場合によってはアセンブラーコードで直接プログラムされ、開発者は、プログラムの実行のあらゆる側面、すべての単一CPU命令、およびチップ上のすべての周辺機器のすべての状態を完全に制御できます。プログラムが大きくなり、使用するハードウェアが増えるにつれて、これは当然退屈になる可能性があります。多数の周辺機器、2つのCPUコア、および複雑で不均一なメモリレイアウトを備えた、ESP32などの複雑なマイクロコントローラは、最初からプログラミングするのが困難で面倒です。

すべてのオペレーティングシステムは、そのサービスを使用するコードにいくつかの制限と要件を課していますが、通常、その利点は価値があります。つまり、開発がより速く、より簡単になります。ただし、場合によっては回避でき、埋め込みスペースでは回避する必要があります。

関連: 完全に機能するArduinoウェザーステーションの作り方

基本を理解する

ESP32は何に使用されますか?

ESP32は、IoT製品の作成に使用されるWiFiとBluetoothを備えたマイクロコントローラーです。これは、デュアルコアCPUと、ハードウェア暗号化オフロード、520 KiB RAM、12ビットADCなどの多数の機能を備えた強力なデバイスです。機能セットによって開発がより効果的になる複雑な製品で使用されます。

Espressifを使用しているデバイスは何ですか?

Espressifは、最もよく知られている製品がESP8266およびESP32WiFi対応マイクロコントローラーである会社です。このような製品は、その大規模な機能セットの恩恵を受けることができるIoTデバイスで使用されます。

javascriptは現在の日時を取得します

マイクロコントローラのタイマー割り込みとは何ですか?

タイマーはマイクロコントローラー周辺機器(内部モジュール)であり、内部または外部クロック信号とペアになっており、クロックティックごとに値をインクリメントまたはデクリメントします。タイマーは、特定の数がカウントされた後に割り込みを生成できます。これにより、コードが実行されます。

ESPプログラミングとは何ですか?

ESP32は、IoT製品の作成に使用されるWiFiおよびBluetooth対応のマイクロコントローラーです。これは、デュアルコアCPUと豊富な機能を備えた強力なデバイスです。 ESP32ファームウェアの作成は、通常、FreeRTOS上に実装されているESP-IDFというベンダー提供の開発フレームワークに依存しています。

システムオンチップはどのように機能しますか?

システムオンチップは、単一のチップパッケージ上で、動作中のコンピューターを構築するために使用される多くの(またはすべての)コンポーネントを含むハードウェアを構築するためのアプローチです。正確な仕様はさまざまであり、システムメモリ、グラフィックプロセッサ、I / Oコントローラ、ネットワークコントローラ、フラッシュメモリなどが含まれる場合と含まれない場合があります。

書体分類のニュアンスを理解する

Uiデザイン

書体分類のニュアンスを理解する
マインドズアイ–データ視覚化心理学の考察

マインドズアイ–データ視覚化心理学の考察

Uxデザイン

人気の投稿
Vue3でのオンデマンドの反応性
Vue3でのオンデマンドの反応性
VanillaJSでのReactとJSXのエミュレート
VanillaJSでのReactとJSXのエミュレート
カスタムMagento2ウィジェットを作成する方法
カスタムMagento2ウィジェットを作成する方法
不和ボットの作り方:概要とチュートリアル
不和ボットの作り方:概要とチュートリアル
JavaScriptデザインパターンの包括的なガイド
JavaScriptデザインパターンの包括的なガイド
 
Google BigQueryを使用する意味があるのはいつですか?
Google BigQueryを使用する意味があるのはいつですか?
Pythonビデオストリーミングでポルノを20倍効率化した方法
Pythonビデオストリーミングでポルノを20倍効率化した方法
ディストレストM&A:バーゲン購入の機会の評価
ディストレストM&A:バーゲン購入の機会の評価
スニペットブラウジングパターンのAndroid開発者ガイド
スニペットブラウジングパターンのAndroid開発者ガイド
究極のUXフック– UXにおける予測的、説得力のある、感情的なデザイン
究極のUXフック– UXにおける予測的、説得力のある、感情的なデザイン
人気の投稿
  • 2025年までに、ロボットはすべての家庭用コマーシャルに搭載される予定です
  • Webサイトの例のヒューリスティック評価
  • %c c ++
  • 日食vsメモ帳++
  • c ++ソースファイル
カテゴリー
プロセスとツール ツールとチュートリアル 製品の担当者とチーム ヒントとツール Kpiと分析 ブランドデザイン モバイル 仕事の未来 財務プロセス 投資家と資金調達

© 2021 | 全著作権所有

apeescape2.com