SSブログ
前の10件 | -

STM32FをArduino IDEで開発的なメモの8乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

STM32Duinoでは端子の指定方法が2種類あって、これがややこしいのだが、
一つはPinNumber、もう一つはPinNameとなる。

PinNumberはvariantsフォルダーから辿っていき、それぞれのマイコンタイプ毎に分かれて、例えばSTM32F103VETでは以下のフォルダーの
https://github.com/stm32duino/Arduino_Core_STM32/tree/master/variants/STM32F1xx/F103V(C-D-E)(H-T)
variant_generic.hで定義されている、いわゆる通し番号となっている。

PinNameはこれとはまったく違うフォルダーの中に存在する。
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/PinNames.h

PinNameで参照しているPortAとかPortBとかは以下で定義されている。
https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/stm32/PortNames.h

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

STM32FをArduino IDEで開発的なメモの7乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

アマゾンでHALライブラリの参考書を買ってみた。
と言うか、STM32CubeMXの使い方が書かれている。FreeRTOSやAIの導入まで書かれている。

HALライブラリとかSTM32CubeMXとか、なかなか判らんもんね~~~、助かる。


STM32HAL&SW4入門

STM32HAL&SW4入門

  • 作者: K.Watanabe
  • 出版社/メーカー:
  • 発売日: 2017/06/24
  • メディア: Kindle版



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

STM32FをArduino IDEで開発的なメモの6乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。
https://github.com/stm32duino

STM32DuinoでBlynkをやった話。SPIの設定でちょっと躓いたのでメモ。
使ったのはSTM32F401RCTとW5500を搭載した基板となる。

ライブラリが整備されているので、Blynkのサーバーにアクセスする事はWiznetのW5100か、W5200か、W5500を使っている限り比較的容易にできる。
W5300に関してはまだライブラリが存在していないみたいで、これは自分でドライバーを書くしか無さそう。

以下を参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F4_2102_Blynk_Blink

W5500のインタフェースはSPIですが、W5500のCSを標準のNSSとかに設定していない場合、以下の行を初期化時に付け足しておく必要が有る。

Ethernet.init( W5500_CS );

以上。

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

STM32FをArduino IDEで開発的なメモの5乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。

https://github.com/stm32duino
stm32f103_wave_001.png

STM32duinoでは様々な周辺機能のクラスが有ってプロトタイピングは楽なのですが、機能がサポートされていない物も有る。今回はTimerのPWM出力を使って任意のアナログ波形を生成したいと言うお題。もちろんPWM出力はLPF(Low Pass Filter)で均している。

STM32duinoはHardwareTimerクラスを持っている。折角有るのでこのHardwareTimerクラスを使ってお題をこなしたい。

https://github.com/stm32duino/Arduino_Core_STM32/blob/master/cores/arduino/HardwareTimer.h

を見るとPWM出力のメンバー関数も当然のように用意されているので、こちらを使えば、、、
しかしやりたいのは任意の”波形”であり、一定周期でPWMのDutyを変化させないと、任意の直流電圧波形になってしまう。

一定周期でPWMのDutyを変化させる方法は?
1.コンペアマッチのステータスをずっとモニターして、更新タイミングで新しいコンペアマッチの値をレジスタに代入する?
2.コンペアマッチのステータスの変化を割込みで捉えて、割込みのタイミングで新しいコンペアマッチの値をレジスタに代入する?

1のソフトウエアだけでやるのは如何にもスマートではないのでパス。2の割込みを使うのは現実的だが、まだソフトウエアの負荷が大きく、多数のチャネルでそれを行うのはちょっと忍びない。

3.更新タイミングに、DMAで新しい値を転送してしまおう!やはりこれしか無いかな?

STM32duinoはHALライブラリを使用している。HALライブラリでタイマー関連のライブラリは以下になる。

https://github.com/stm32duino/Arduino_Core_STM32/blob/master/system/Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_hal_tim.h

/* Non-Blocking mode: DMA */
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length);
HAL_StatusTypeDef HAL_TIM_PWM_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel);

上記の様にDMA連動の関数が存在する。
確かにHAL_TIM_PWM_Start_DMAを使えば、PWMの更新値はDMA転送で行われている様子だ。
しかしもう少し進めて、DMAの転送完了割込みを起動したい。

HardwareTimerクラスはメンバー関数にattachInterruptを持つ。しかしこのメンバー関数はBASE Timerの更新とか、コンペアマッチの一致時に使うもので、DMA転送の完了と言う訳ではない。

stm32f1xx_hal_tim.hのHALライブラリで使用されているTIM_HandleTypeDef構造体には

DMA_HandleTypeDef *hdma[7];

が存在し、DMAと連動する7種類の条件が有る。
/** @defgroup DMA_Handle_index TIM DMA Handle Index
  * @{
  */
#define TIM_DMA_ID_UPDATE                ((uint16_t) 0x0000)       /*!< Index of the DMA handle used for Update DMA requests */
#define TIM_DMA_ID_CC1                   ((uint16_t) 0x0001)       /*!< Index of the DMA handle used for Capture/Compare 1 DMA requests */
#define TIM_DMA_ID_CC2                   ((uint16_t) 0x0002)       /*!< Index of the DMA handle used for Capture/Compare 2 DMA requests */
#define TIM_DMA_ID_CC3                   ((uint16_t) 0x0003)       /*!< Index of the DMA handle used for Capture/Compare 3 DMA requests */
#define TIM_DMA_ID_CC4                   ((uint16_t) 0x0004)       /*!< Index of the DMA handle used for Capture/Compare 4 DMA requests */
#define TIM_DMA_ID_COMMUTATION           ((uint16_t) 0x0005)       /*!< Index of the DMA handle used for Commutation DMA requests */
#define TIM_DMA_ID_TRIGGER               ((uint16_t) 0x0006)       /*!< Index of the DMA handle used for Trigger DMA requests */


とまぁ、PWMの更新にDMAを使い、データブロックの転送完了後に何かしらの割込みを発生させることが出来そうな雰囲気は有るのだが、どうすれば良いのか判らなくて嵌まった。

なのでSTM32の初心に帰って自分で割込みをなんとかする事とする。

そもそもDMA転送完了割込みの割込みハンドラ自体が、検索しても割込みベクターが書いてあるファイル(STM32F103VETであれば startup_stm32f103xe.s )の中に、例えばTimer3 channel1のDMA要求の接続先であるDMA1_Channel6の割込みハンドラは、

.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler

と記述されているが、このままではDefault_Handlerに行ってしまう。

つまり、DMA割込みを使いたかったら自前でDMA1_Channel6_IRQHandlerを用意し、NVICの設定を行い、DMAに割込みを許可すれば良い事になる、、、ホンマ?
以下、参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F1_PWM_WAVE_Output_01
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/libraries

上記例ではTC(Transmit Complete)とエラーのみ、割込みを有効化していますが、もちろんHT(Half Transmit)を有効化することは有用です。
例えばADCのデータを連続的に取り込む場合にDMAはよく使います。DMAを循環モードで動かしている場合、取り込み先のメモリーはリングバッファとして扱われますので常時どこかのアドレスに対して書込みが行われています。
プログラム側はどの位置まで書込みが完了したのか把握したい場合、リングバッファの前半と後半に分けてそれぞれ書込み完了のタイミングが判れば、前半終了のHT割込みのタイミングでリングバッファの前半の内容を安全に演算や転送などの処理をできますし、後半の終了のTC割込みのタイミングでリングバッファの後半の内容を安全に演算や転送などの処理をできます。

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

STM32FをArduino IDEで開発的なメモの4乗くらい [STM32F]

色々あって、STM32FでやるArduinoは、以下にしています。

https://github.com/stm32duino

STM32duinoでは、STM32F_CPU_IDENTITYクラスを利用する事で、CPUの情報を色々取得する事ができます。
例えば、
#include <STM32F_CPU_Identity.h>
STM32F_CPU_IDENTITY cpu_id;としておいて、
cpu_id.sysload()でsystick timerの値、
cpu_id.hclk()でhclkの値、
cpu_id.pclk1()とcpu_id.pclk2()でpclk1とpclk2の値、
cpu_id.sysclk()でシステムクロックの値が取得できますん。
また、
uint32_t uid[3];
cpu_id.uID( uid );

で、3つのCPU IDが取得できますん。

そんなわけでCPUのクロック等の情報を取得できたのですが、では実際にArduino環境でSTM32Fの開発を行った場合、システムクロックはどうなっているんでしょうか?
と言うのが今回のお題。

STM32Fの開発に使用した基板はNUCLEOとかではなくオリジナルの基板であることから、Arduino IDEのボードの選択は”STM32F1 series”とし、Board parts numberは"Generic F103VETx"としています。つまりSTM32F103VETを搭載したマイコンボードです。

上記マイコンボードは、HSE用に8MHzのクリスタルを接続してあります。STM32F103VETは最大72MHzで動かすことができます。
しかしSTM32F_CPU_IDENTITYクラスで取得したシステムクロックは64MHzとなりました、、、う~~~ん。

結局ボードにGenericタイプを選んだ時にシステムクロックがどうなるのかと言うと、STM32duinoのツールチェインのvariantsにそれが有りました。例えば、以下の様なPATHにgeneric_clock.cが有りますん。

C:\Users\ユーザー名\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.0.0\variants\STM32F1xx\F103V(C-D-E)(H-T)

generic_clock.cのSystemClock_Config関数でシステムクロックの設定が行われており、標準ではHSIを使用し、HSIが8MHzですから8MHz÷2×16で64MHzの出来上がりです。

ですがSystemClock_Config関数はWEAK修飾子が付いています。
なのでユーザーが独自にSystemClock_Config関数を用意すれば、そちらが優先される事となります。

ユーザーがSystemClock_Config関数を生成するもっとも簡単な方法はSTM32CubeMXを使う事です。グラフィカルな画面でマウスでポチポチしていけばSystemClock_Config関数を生成してくれるので、それを取って来てスケッチに貼り付けるだけでOKです。以下参照してみてください。

https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/F1F4_GET_CPU_ID
https://github.com/hamayanShowa-ele/ArduinoShare/tree/main/libraries

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

ESP32でfreeRTOS まとめ Interface誌でfreeRTOSが特集されたので、、、 [ESP32]

ESP32でfreeRTOS まとめ Interface誌でfreeRTOSが特集されたので、、、一覧にしてみた。
Interfaceのページ
https://interface.cqpub.co.jp/magazine/202104/


過去に書いた「ESP32はRTOSができるらしい、、、」で始まるESP32でfreeRTOSを使う、いや使ってみた内容のまとめと言うか、リンク集。
ただし2018年に作成した記事なので、freeRTOSのバージョンが上がっている事から必ずしも現状と一致していないところが有るはず。なので、以下のリンクのドキュメントを参照する必要性はあると思う。
https://www.freertos.org/Documentation/RTOS_book.html

ESP32で使用しているfreeRTOSのバージョンも現在はver.10.2.0となっているようだ。
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/freertos-smp.html

1.はじめに
ESP32はDual Core(SMP)なので、そこにちょっと触れて、タスクの生成手順を解説。
https://hamayan.blog.ss-blog.jp/2018-02-16

2.1の続き
1では1つのタスクの生成を行ったが、今回は複数のタスクの生成を行っている。
https://hamayan.blog.ss-blog.jp/2018-02-17

3.それぞれのタスクが動いているうえで、しかし一つのCore上で動く事のできるタスクは1つしか無い。なのでそこで動くタスクが現在どの様な状態にあるのか?の解説。
RTOSを理解するうえでとても重要な概念となる。
https://hamayan.blog.ss-blog.jp/2018-02-18

4.タスクの生成、停止、終了、削除、優先度と言ったタスク管理機能の解説。
https://hamayan.blog.ss-blog.jp/2018-02-18-1

5.タイムティック、つまり処理の時間単位と、それを使った遅延処理、周期処理について解説。
https://hamayan.blog.ss-blog.jp/2018-02-18-2

6.実行すべきユーザータスクが無い時、何が行われるのか?IDLE状態について解説。
WDTリセットとか省電力のカギかも!
https://hamayan.blog.ss-blog.jp/2018-02-19

7.タスク間通信のデータキューの解説。
タスク間で通信する手順が提供されているのです。この通信方法は複数ありまして、今回はデータキューです。このデータキューを利用すると、タスクの実行制御もできます。
https://hamayan.blog.ss-blog.jp/2018-02-19-1

8.タスク優先度に絡むうっかり話。
メカニズムが判れば面白いと思う!
https://hamayan.blog.ss-blog.jp/2018-02-20

9.WDTリセットの実験。
モヤモヤ、、、
https://hamayan.blog.ss-blog.jp/2018-02-21

10.7のデータキューの続き。
https://hamayan.blog.ss-blog.jp/2018-02-21-1

11.資源に対する排他制御、バイナリーセマフォについて解説。
マルチタスク、いやマルチタスクに限らず割込みも含めて、一つの資源に複数のコンテキストからのアクセスに対する制御を行う。
https://hamayan.blog.ss-blog.jp/2018-02-22

12.11の続き。

13.freeRTOSの多重割込みについて解説。
https://hamayan.blog.ss-blog.jp/2018-02-26

14.11とも関係するが、資源の危険な扱い(クリティカルセクション)に関する解説。
https://hamayan.blog.ss-blog.jp/2018-02-26-1

15.ESP32のdigitalWriteについての実験。
https://hamayan.blog.ss-blog.jp/2018-02-26-2

16.12の続き。カウンティングセマフォについて解説。
https://hamayan.blog.ss-blog.jp/2018-02-26-3

17.16の続き。
https://hamayan.blog.ss-blog.jp/2018-02-28

18.17の続き。
https://hamayan.blog.ss-blog.jp/2018-03-01

19.実は14の続き。
https://hamayan.blog.ss-blog.jp/2018-03-02

20.freeRTOSのクリティカルセクションの扱いについて解説。
割込み禁止、割込み許可。
https://hamayan.blog.ss-blog.jp/2018-03-06

21.20の続き。
ディスパッチ禁止、ディスパッチ許可。
https://hamayan.blog.ss-blog.jp/2018-03-07

22.21の続き。
ミューテックス。
https://hamayan.blog.ss-blog.jp/2018-03-07-1

23.22の続き。
https://hamayan.blog.ss-blog.jp/2018-03-08

24.23の続き。
まだまだ続くよミューテックス。
https://hamayan.blog.ss-blog.jp/2018-03-08-1

25.24の続き。
デッドロック。
https://hamayan.blog.ss-blog.jp/2018-03-08-2

26.Tick割込みからのコールバック。
https://hamayan.blog.ss-blog.jp/2018-03-08-3

27.25の続き。
ゲートキーパータスク!結局解決策はそれかよ、、、良いと思う。
https://hamayan.blog.ss-blog.jp/2018-03-08-4

28.データタイプと命名規則。
freeRTOSのAPIがちょっと読み易くなるかもしれない。
RTOSのAPI名等にやたら長い名前はどうかと思うけれど、今時の開発環境なら問題無いのでしょう。
https://hamayan.blog.ss-blog.jp/2018-03-09

29.28の続き。
https://hamayan.blog.ss-blog.jp/2018-03-09-1

30.タスクの状態参照とスタックサイズ。
https://hamayan.blog.ss-blog.jp/2018-03-09-2

31.メモリ管理。
https://hamayan.blog.ss-blog.jp/2018-03-12

33.ドキュメントの訳と解説作業に疲れたので、AquesTalk pico for ESP32の評価版をマルチタスクで動かす。
https://hamayan.blog.ss-blog.jp/2018-03-26

34.ドキュメントの訳と解説作業に疲れたので、Blynkをマルチタスクで動かす。
https://hamayan.blog.ss-blog.jp/2018-03-27

35.ドキュメントの訳と解説作業に疲れたので、BlynkとAquesTalkをマルチタスクで動かす。
https://hamayan.blog.ss-blog.jp/2018-03-28

36.35の続き。
https://hamayan.blog.ss-blog.jp/2018-03-29

37.36の続き。
https://hamayan.blog.ss-blog.jp/2018-03-31

ESP32のシステムタイマーの値を取得する。
https://hamayan.blog.ss-blog.jp/2019-02-11

おまけ。

ESP32 ArduinoでI2Cをマルチタスクで動かす by freeRTOS
https://hamayan.blog.ss-blog.jp/2018-07-11

上の続き。
https://hamayan.blog.ss-blog.jp/2018-07-12

ESP32のGPIOの割り付けについて調べてみた。
https://hamayan.blog.ss-blog.jp/2018-08-03

Arduino AVRでマルチタスクしてみる not freeRTOS !
https://hamayan.blog.ss-blog.jp/2018-10-20

上の続き。
https://hamayan.blog.ss-blog.jp/2018-10-25

上の続き。
https://hamayan.blog.ss-blog.jp/2018-11-02

ESP32のLEDCについて調べてみた。
https://hamayan.blog.ss-blog.jp/2018-11-16

上の続き。
https://hamayan.blog.ss-blog.jp/2018-11-26

M5Stackとフォント
https://hamayan.blog.ss-blog.jp/2019-03-08

M5Stackとフォント ランレングスへの対応
https://hamayan.blog.ss-blog.jp/2019-03-12

M5Stackとフォント GFXFFへの対応
https://hamayan.blog.ss-blog.jp/2019-03-12-1

M5Stackとフォント 漢字フォントの対応
https://hamayan.blog.ss-blog.jp/2019-03-16

M5Stackとフォント 漢字フォントの表示 UTF8への対応
https://hamayan.blog.ss-blog.jp/2019-03-23


モチベーションが尽きたので、一旦無期限サスペンドタスク。


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) 

今更Git、GitHub [gitHub]

恥ずかしながら、以下の本を読んで今更勉強しています、ええ!。

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

  • 出版社/メーカー: シーアンドアール研究所
  • 発売日: 2017/04/21
  • メディア: 単行本(ソフトカバー)



読んで、いや読みながら自分なりにまとめてています。
https://github.com/hamayanShowa-ele/IntroductionToGit

https://hamayanshowa-ele.github.io/IntroductionToGit/

是非参加してください。本を読んだとしても、実際に自分で運用・管理しないと実感できないのですね。

んが!詳細や挿絵は無しなので上記本を含めてちゃんとした本を買って読んだ方がイイですよ!

あと、こんなん公開しています。
https://github.com/chobichan

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

ESP8266への気付き [ESP32]

esp8266_io0.pngESP8266のIO0って、出力設定しないと暴れているよね!なんで???

Deep Sleep!
ESP.deepSleep( 100 * 1000 * 1000UL , WAKE_RF_DEFAULT );
で省電力に入った場合、指定した時間の間だけ省電力で、その後タイムアウトすると8mAくらい消費している感じ。

Light Sleep!
light sleepモードは1mA程度に抑えられるのは助かる。んが、結構手続きが面倒かも。あと起床する手段が必要だが外部割込みが使える。以下のサイトがよく判る。
http://okiraku-camera.tokyo/blog/?p=4996

以下のリンク先のPDFのサンプルをそのまま使っても、ただしくlight sleep modeに入らないのがムカつくよね。タイムアウトで抜ける処理をやりたいのに、、、
https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf

http://okiraku-camera.tokyo/blog/?p=4996
上記リンクのサンプルを若干アレンジして試してみたのだが、かなりの頻度でlight sleepから抜けてしまう現象が発生していた。またコールバックルーチンがいきなり呼ばれてしまう、、、
割込み入力端子はプルアップ抵抗とスイッチのみ接続し、GNDに落とすトリガーを入れている。
なぜいきなり省電力から抜けるのか結局判らない。ただし対策としてコールバックルーチンの中で端子状態を確認し、GNDレベルでなければ再度light sleepに入る様に対策して、確実に省電力状態に入る様にした。


以下、サンプルコード
/*
 ESP8266 light sleep test. 

  気づき
  1.ESP8266をlight sleepに入れると、タイマー系は全て停止してしまうので、
     sleepに入っていた時間を知る事ができない。
  2.wifi再接続時は13秒とか掛かる事が多い。
  3.なぜか一発でlight sleepに入らない事も多い。
  4.上記は、light sleepに入った途端にコールバックルーチンが呼ばれてしまう様で、ポートで端子状態を確認が必要。
  5.コールバックルーチンの中でdelayとかyieldとか呼ぶと、コアを吐いて死んでしまう。

  参考
  http://okiraku-camera.tokyo/blog/?p=4996
*/
#include  <ESP8266WiFi.h>
extern "C" {
  #include "user_interface.h"
  #include "gpio.h"
}

/**********************************************************/
/* defines                                                */
/**********************************************************/
#define  ASSOC         0
#define  INT_X         2
#define  GPS_POWER_PIN 15

#define  FPM_SLEEP_MAX_TIME       0xFFFFFFF

/**********************************************************/
/* global variables                                       */
/**********************************************************/
bool lightSleepLoop;

/**********************************************************/
/* setup.                                                 */
/**********************************************************/
void setup()
{
  Serial.begin( 115200 );
  delay( 20UL );
  Serial.println();
  Serial.println( "ESP8266 light sleep test." );

  /* GPIOの初期化。消費電力を抑える目的でもある */
  pinMode( ASSOC, OUTPUT ); digitalWrite( ASSOC, LOW ); /* active high */
  pinMode( INT_X, INPUT_PULLUP ); /* active low input */
  pinMode( GPS_POWER_PIN, OUTPUT ); digitalWrite( GPS_POWER_PIN, LOW ); /* active high */

  /* enter light sleep mode. */
  enterLightSleep( FPM_SLEEP_MAX_TIME );
}

/**********************************************************/
/* loop.                                                  */
/**********************************************************/
void loop()
{
  delay( 500 );
  digitalWrite( ASSOC, (digitalRead( ASSOC ) == LOW) ? HIGH : LOW );
}

/**********************************************************/
/* call back routine from wake up.                        */
/**********************************************************/
void fpm_wakup_cb( void )
{
  if( digitalRead( INT_X ) == LOW && digitalRead( INT_X ) == LOW && digitalRead( INT_X ) == LOW )
    lightSleepLoop = false;
  Serial.write( 'c' );
}
 
/**********************************************************/
/* enter the light sleep mode.                            */
/**********************************************************/
void enterLightSleep( uint32_t period )
{
  WiFi.mode( WIFI_OFF );
  wifi_set_opmode_current( NULL_MODE ); 
  wifi_fpm_set_sleep_type( LIGHT_SLEEP_T ); 
  wifi_fpm_open();
  gpio_pin_wakeup_enable( INT_X, GPIO_PIN_INTR_LOLEVEL );  /* or GPIO_PIN_INTR_HILEVEL */
  wifi_fpm_set_wakeup_cb( fpm_wakup_cb ); // Set wakeup callback
  lightSleepLoop = true;
  do
  {
    wifi_fpm_do_sleep( period ); // sleep until gpio activity.
    delay( 50UL );
    Serial.write( '*' );
  } while( lightSleepLoop );
  gpio_pin_wakeup_disable();
  wifi_fpm_close(); // disable force sleep function
}

light sleep時のタイマー
うすうすはそうじゃないか?とは思っていたが、しかしwifi_fpm_do_sleepの引数はμs単位の時間を指定できる事もあり、何度かタイムアウトで省電力から抜けないか?と試したが、少なくともESP-WROOM-02ではできなかった。
light sleep時はタイマー自体が止まってしまうようで、他のマイコンでよくある低消費電力モードに入ってもRCオシレータは動いている!という事は無いのかもしれない。
この為、ESP8266単体で省電力に入っていた時間を知る事はできないのかもしれない。復帰した時にNTPなどに接続すればイイのだが、、、イチイチそんな目的の為にNTPに接続するのもねぇ!
※micros()で省電力に入る直前、直後の時間を出力しても、省電力の時間分進んでいる事は無かった。

3.3Vレギュレータ!
ESP8266とは関係無い?が、3.3Vレギュレータはこれを使った。
無負荷時電流が小さいのが助かる。
http://akizukidenshi.com/catalog/g/gI-11299/


ESP8266_TOUT_ADC.pngTOUT!
TOUTを使って電圧測定をしてみた。その前に、TOUTのADCは10bitのADCであり、入力範囲は0V~1Vであるらしい。
プロットさせてみたのが左のグラフ。簡易的にデータを取った為かどうか判らないが、直線ではない。でも小数点以下1桁くらいの精度の電圧測定なら十分な気もする。これって、内部で補正されているんだっけ?
※Vinは分圧してからTOUTに接続している。



ソフトウエアシリアルのバッファサイズを変更する!
なんであんなケチケチバッファを割り当てているねん?

SoftwareSerial gpsSerial( GPS_TXD, GPS_RXD ); // RX, TX
gpsSerial.begin( 9600, SWSERIAL_8N1, GPS_TXD, GPS_RXD, false , 4096, 4096 );
// 最後から二番目はバッファサイズ、最後は割込み時のバッファサイズ。大きなデータを受信する時は大きめに!

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

Arduinoライブラリでテレビジョンを制御 家庭でできるIoT! 5パルス目 [ESP32]

2019-12-13 09.13.34.png2019-12-13 09.13.27.png前回( https://hamayan.blog.ss-blog.jp/2019-12-09-1 )作成したリモコンのコードを受信するプログラムを使って、テレビジョン(AQUOS)の幾つかのリモコンコードをサンプリングしました。その内容を使ってBlynkでリモコンを実現します。
もうお判りでしょうが、AQUOSライブラリを作成するにあたってHeatpumpIR Classを使って赤外線ドライバー部分はお手軽に実現しています。
テレビはNHKとテレ東くらいしか観ないので、Blynkのパネルの一番下に一発選局ボタンを付けておきました(笑)。
もうちょい機能を追加すれば、テレビのリモコン無くしても安心ですね!

aquos.h
/****************************************************************************/
/* お家のAQUOSをなんとかするヘッダー                                            */
/*                         Copyright (C) 2014 hamayan All Rights Reserved.  */
/****************************************************************************/
#ifndef aquos_h
#define aquos_h

#include  <Arduino.h>
#include  <HeatpumpIR.h>

extern "C" {
//  #include  <mul_tsk.h>
}

/****************************************************************************/
/* なにかの定義                                                             */
/****************************************************************************/
#define  AEHA_T_PERIOD  425UL  //
#define  AEHA_REPEAT_PERIOD  100UL  //

typedef struct  /*AQUOSのフォーマットはAEHAタイプ*/
{
  uint8_t customerCode[2];
  uint8_t data[4];
} AQUOS_CODE;


class aquos : public HeatpumpIR
{
private:
  int antenaSelect;
  int channelSelect;
  uint32_t startTim;
  void send( IRSender& IR, const uint8_t *code, size_t size );

public:
  aquos();
  void onOff( IRSender& IR );
  void ch( IRSender& IR, int value );
  void chUpDown( IRSender& IR, int value );
  void volume( IRSender& IR, int value );
  void antena( IRSender& IR );
  void decide( IRSender& IR );
  void back( IRSender& IR );
  void program( IRSender& IR );
  void recorderList( IRSender& IR );
  void selectorSwitch( IRSender& IR, int upDown, int rightLeft );
  void favorite( IRSender& IR, int sel );
  char type( void );
};


#endif  /*aquos_h*/

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


aquos.cpp
/*********************************************************************************/
/* お家のAQUOSをなんとかするソース                                                   */
/*                                         designed by hamayan since 2015/05/28  */
/*********************************************************************************/
#include  "aquos.h"

#if !defined( _MULTITASK_H_ )
#define  dly_tsk(tim)  delay(tim)
#define  rot_rdq()
#define  loc_cpu()     interrupts()
#define  unl_cpu()     noInterrupts()
#endif /*_MULTITASK_H_ */

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

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

/*************************************************************************/
/* インスタンス                                                          */
/*************************************************************************/
aquos::aquos()
{
  antenaSelect = 0;
  channelSelect = 1;
}

/*************************************************************************/
/* send                                                                  */
/*************************************************************************/
void aquos::send( IRSender& IR, const uint8_t *code, size_t size )
{
  uint8_t tempUC[ size ];
  memcpy( tempUC, code, size );

  // 40 kHz PWM frequency
  IR.setFrequency( 38 );

  //リピートでメソッドが呼ばれた時、強制的に間隔を開ける
  while( (millis() - startTim) < AEHA_REPEAT_PERIOD ) delay( 10 );
  // start time
  startTim = millis();

  // Header
  IR.mark( 8 * AEHA_T_PERIOD );  //frame ppm on
  IR.space( 4 * AEHA_T_PERIOD );  //frame ppm off

  // Data
  for( unsigned int i = 0; i < size; i++ )
  {
    IR.sendIRbyte( tempUC[i], AEHA_T_PERIOD, AEHA_T_PERIOD, 3 * AEHA_T_PERIOD );  // data,426us,425us,1275us
    // pulse on period, pulse off period at ZERO, pulse off period at 1
  }

  // End mark
  IR.mark( AEHA_T_PERIOD );
  IR.space( 0 );
}

/*************************************************************************/
/* 番組表                                                                */
/*************************************************************************/
static const uint8_t TVPROGRAMLIST[]   = {0xaa,0x5a,0x8f,0x12,0x60,0xf2};

void aquos::program( IRSender& IR )
{
  send( IR, TVPROGRAMLIST, sizeof( TVPROGRAMLIST ) );
}

/*************************************************************************/
/* 電源の入り切。だが実際にはテレビがそれに追従してはいない。            */
/*************************************************************************/
static const uint8_t TVOnOff[] = {0xaa,0x5a,0x8f,0x12,0x16,0xd1};

void aquos::onOff( IRSender& IR )
{
  send( IR, TVOnOff, sizeof( TVOnOff ) );
}

/*************************************************************************/
/* 決定ボタン                                                            */
/*************************************************************************/
static const uint8_t DECIDE[] = {0xaa,0x5a,0x8f,0x12,0x52,0xd1};

void aquos::decide( IRSender& IR )
{
  send( IR, DECIDE, sizeof( DECIDE ) );
}

/*************************************************************************/
/* 戻るボタン                                                            */
/*************************************************************************/
static const uint8_t BACK[] = {0xaa,0x5a,0x8f,0x12,0xe4,0x01};

void aquos::back( IRSender& IR )
{
  send( IR, BACK, sizeof( BACK ) );
}

/*************************************************************************/
/* 録画リスト                                                            */
/*************************************************************************/
static const uint8_t RECORDERLIST[]   = {0xaa,0x5a,0x8f,0x12,0xad,0x3f};

void aquos::recorderList( IRSender& IR )
{
  send( IR, RECORDERLIST, sizeof( RECORDERLIST ) );
}

/*************************************************************************/
/* 選択用スイッチ                                                        */
/*************************************************************************/
static const uint8_t SELECTORSWITCH[][6] =
{
  {0xaa,0x5a,0x8f,0x12,0x57,0x81},  /*up*/
  {0xaa,0x5a,0x8f,0x12,0x20,0x81},  /*down*/
  {0xaa,0x5a,0x8f,0x12,0xd8,0xf1},  /*right*/
  {0xaa,0x5a,0x8f,0x12,0xd7,0x01},  /*left*/
};

void aquos::selectorSwitch( IRSender& IR, int upDown, int rightLeft )
{
  if( upDown >= 1 )
    send( IR, SELECTORSWITCH[0], sizeof( SELECTORSWITCH[0] ) );
  else if( upDown <= -1 )
    send( IR, SELECTORSWITCH[1], sizeof( SELECTORSWITCH[1] ) );

  dly_tsk( 100UL );

  if( rightLeft >= 1 )
    send( IR, SELECTORSWITCH[2], sizeof( SELECTORSWITCH[2] ) );
  else if( rightLeft <= -1 )
    send( IR, SELECTORSWITCH[3], sizeof( SELECTORSWITCH[3] ) );
}

/*************************************************************************/
/* チャネルの切り替え                                                    */
/*************************************************************************/
static const uint8_t TVCH[][6] =
{
  {0xaa,0x5a,0x8f,0x12,0x4e,0x32},  /*ch1*/
  {0xaa,0x5a,0x8f,0x12,0x4f,0x22},  /*ch2*/
  {0xaa,0x5a,0x8f,0x12,0x50,0xc2},  /*ch3*/
  {0xaa,0x5a,0x8f,0x12,0x51,0xd2},  /*ch4*/
  {0xaa,0x5a,0x8f,0x12,0x52,0xe2},  /*ch5*/
  {0xaa,0x5a,0x8f,0x12,0x53,0xf2},  /*ch6*/
  {0xaa,0x5a,0x8f,0x12,0x54,0x82},  /*ch7*/
  {0xaa,0x5a,0x8f,0x12,0x55,0x92},  /*ch8*/
  {0xaa,0x5a,0x8f,0x12,0x56,0xa2},  /*ch9*/
  {0xaa,0x5a,0x8f,0x12,0x57,0xb2},  /*ch10*/
  {0xaa,0x5a,0x8f,0x12,0x58,0x42},  /*ch11*/
  {0xaa,0x5a,0x8f,0x12,0x59,0x52},  /*ch12*/
};

void aquos::ch( IRSender& IR, int value )
{
  if( value >= 1 && value <= 12 )
  {
    send( IR, TVCH[value - 1], sizeof( TVCH[0] ) );
    channelSelect = value;
  }
}

/*************************************************************************/
/* チャネルの上下                                                        */
/*************************************************************************/
static const uint8_t TVSEL[][6] =
{
  {0xaa,0x5a,0x8f,0x12,0x11,0xa1},  /*decide up*/
  {0xaa,0x5a,0x8f,0x12,0x12,0x91},  /*decide down*/
};

void aquos::chUpDown( IRSender& IR, int value )
{
  if( value > 0 )  //up
  {
    send( IR, TVSEL[0], sizeof( TVSEL[0] ) );
    channelSelect++;
  }
  else if( value < 0 )  //down
  {
    send( IR, TVSEL[1], sizeof( TVSEL[1] ) );
    channelSelect--;
  }
}

/*************************************************************************/
/* チューナー(アンテナ)の切り替え                                        */
/*************************************************************************/
static const uint8_t TVANTENA[][6] =
{
  {0xaa,0x5a,0x8f,0x12,0x89,0x82},  /*地デジ*/
  {0xaa,0x5a,0x8f,0x12,0x8a,0xb2},  /*BS*/
  {0xaa,0x5a,0x8f,0x12,0x8b,0xa2},  /*CS*/
};

void aquos::antena( IRSender& IR )
{
  if( ++antenaSelect > 1 ) antenaSelect = 0;
  
  send( IR, TVANTENA[antenaSelect], sizeof( TVANTENA[0] ) );
}

/*************************************************************************/
/* ボリュームの上下                                                      */
/*************************************************************************/
static const uint8_t TVVOLUME[][6] =
{
  {0xaa,0x5a,0x8f,0x12,0x14,0xf1},  /*volume up*/
  {0xaa,0x5a,0x8f,0x12,0x15,0xe1},  /*volume down*/
};

void aquos::volume( IRSender& IR, int value )
{
  if( value < 0 )
  {
    send( IR, TVVOLUME[1], sizeof( TVVOLUME[1] ) );
  }
  else if( value > 0 )
  {
    send( IR, TVVOLUME[0], sizeof( TVVOLUME[0] ) );
  }
}

/*************************************************************************/
/* お気に入り番組登録                                       */
/*************************************************************************/
void aquos::favorite( IRSender& IR, int value )
{
  if( value == 0 )  /* nhk sougou. */
  {
    antenaSelect = 0;
    channelSelect = 1;
  }
  else if( value == 1 )  /* nhk bs premium. */
  {
    antenaSelect = 1;
    channelSelect = 3;
  }
  else if( value == 2 )  /* tokyo televison. */
  {
    antenaSelect = 0;
    channelSelect = 7;
  }
  else if( value == 3 )  /* bs tokyo televison. */
  {
    antenaSelect = 1;
    channelSelect = 7;
  }
  else return;

  send( IR, TVANTENA[antenaSelect], sizeof( TVANTENA[0] ) );
  send( IR, TVCH[channelSelect - 1], sizeof( TVCH[0] ) );
}

/*************************************************************************/
/* リモコンフォーマットを答える                                          */
/*************************************************************************/
char aquos::type( void )
{
  return 'A';  /*AEHAのA!*/
}


/*********************************************************************************/
/* end of file                                                                   */
/*                                         designed by hamayan since 2015/05/28  */
/*********************************************************************************/


スケッチの追加部分のみ
aquos  *tv = new aquos();

/*************************************************************************/
/*  blynk virtual pin 6 function as TV power on or off.                  */
/*************************************************************************/
BLYNK_WRITE( V6 )
{ 
  tv->onOff( irSender );
}

/*************************************************************************/
/*  blynk virtual pin 7 function as TV program list on or off.           */
/*************************************************************************/
BLYNK_WRITE( V7 )
{ 
  tv->program( irSender );
}

/*************************************************************************/
/*  blynk virtual pin 8 function as TV record list on or off.            */
/*************************************************************************/
BLYNK_WRITE( V8 )
{ 
  tv->recorderList( irSender );
}

/*************************************************************************/
/*  blynk virtual pin 9 function as TV antena(tuner) change.            */
/*************************************************************************/
BLYNK_WRITE( V9 )
{ 
  tv->antena( irSender );
}

/*************************************************************************/
/*  blynk virtual pin 10 function as channel NHK SOUGOU.                 */
/*************************************************************************/
BLYNK_WRITE( V10 )
{ 
  tv->favorite( irSender, 0 );
}

/*************************************************************************/
/*  blynk virtual pin 11 function as channel NHK BS PREMIUM.             */
/*************************************************************************/
BLYNK_WRITE( V11 )
{ 
  tv->favorite( irSender, 1 );
}

/*************************************************************************/
/*  blynk virtual pin 12 function as channel TOKYO TELEVISION.           */
/*************************************************************************/
BLYNK_WRITE( V12 )
{ 
  tv->favorite( irSender, 2 );
}

/*************************************************************************/
/*  blynk virtual pin 13 function as channel BS TOKYO TELEVISION.        */
/*************************************************************************/
BLYNK_WRITE( V13 )
{ 
  tv->favorite( irSender, 3 );
}

/*************************************************************************/
/*  blynk virtual pin 14 function as cursor move.                        */
/*************************************************************************/
BLYNK_WRITE( V14 )
{ 
  int rightLeft = param[0].asInt();
  int upDown    = param[1].asInt();
  tv->selectorSwitch( irSender, upDown, rightLeft );
}

/*************************************************************************/
/*  blynk virtual pin 15 function as channel up.                         */
/*************************************************************************/
BLYNK_WRITE( V15 )
{ 
  int channel = param.asInt();
  tv->chUpDown( irSender, channel );
}

/*************************************************************************/
/*  blynk virtual pin 16 function as channel down.                       */
/*************************************************************************/
BLYNK_WRITE( V16 )
{ 
  int channel = param.asInt();
  tv->chUpDown( irSender, channel );
}

/*************************************************************************/
/*  blynk virtual pin 17 function as volume up.                          */
/*************************************************************************/
BLYNK_WRITE( V17 )
{ 
  int volume = param.asInt();
  tv->volume( irSender, volume );
}

/*************************************************************************/
/*  blynk virtual pin 18 function as volume down.                        */
/*************************************************************************/
BLYNK_WRITE( V18 )
{ 
  int volume = param.asInt();
  tv->volume( irSender, volume );
}

/*************************************************************************/
/*  blynk virtual pin 19 function as decide button.                      */
/*************************************************************************/
BLYNK_WRITE( V19 )
{ 
  tv->decide( irSender );
}

/*************************************************************************/
/*  blynk virtual pin 20 function as back button.                        */
/*************************************************************************/
BLYNK_WRITE( V20 )
{ 
  tv->back( irSender );
}



ESP-WROOM-02開発ボード

ESP-WROOM-02開発ボード

  • 出版社/メーカー: スイッチサイエンス(Switch Science)
  • メディア: おもちゃ&ホビー









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

TDK-Lamda製DC/DC電源 RDS50-11-5の中身 [電子工作]

TDK-Lamda製DC/DC電源 RDS50-11-5がノイズ試験で飛んだ!らしいので、折角なので中身を見てみた。

RDS50-11-5の製品ページ
https://product.tdk.com/ja/search/power/switching-power/dc-dc-converter/info?part_no=RDS50-110-5

2019-12-12 10.08.08.jpg一番右のシリコンが付いているモジュールは、同期スイッチのモジュールか?そこそこ大きなヒートシンクが付いていた。
あちこちに貫通ビアを使って、パターンの強化を行っている。
端子台右となりの青いのはヒューズ。DC450V 3.15A仕様。
青いヒューズの下はバリスター。
基板中央と右下のノーマルモードノイズ用のフイルムコンデンサは、ポリミイドテープで結構がっちり保護されている。何対策?
コモンモード用の磁器コンデンサは、入力端子台直後と、スイッチングモジュール直前、スイッチングモジュール直後に入っている。
スイッチングモジュールの左隣の白いのは温度ヒューズだと思う。
温度ヒューズの左隣はコモンモードノイズフィルター。コモンモードノイズフィルターの二次側に逆接防止用のダイオードが入っている。
温度ヒューズの下はFET、おそらく何かあった時に電源を切るのだと思う。
コモンモードノイズフィルターの上のトランスは、フィードバック回路用の電源を作るためのもの。
トランスの左隣は出力センス回路の入力フィルターの様だ。


2019-12-12 10.08.43.jpg半田面側はこんな感じ。右側がスイッチング回路。黄土色はフィードバック用のフォトカプラ。
部品面、半田面共にコーティングがされている。基板上の貫通している穴はすべてマスキングしてコーティングの液体が流れないようにした形跡有り。


2019-12-12 10.13.24.jpgこんな端子台有るんだ!特注?
基板の下側のシャーシは、全面的にマイラフィルムを貼っている。




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

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。