前回まででUSBCDC(コミュニケーションデバイスクラス)でVCP(VirtualCOMPort)の動作は確認できたので今回はこれにMicroShellを使える状態していく作業になります。
CDCのやり方はこの記事みてください。
gsmcustomeffects.hatenablog.com
やることは
- 1文字送受信APIの準備
- 受信バッファサイズの設定
前回まででUSBCDC(コミュニケーションデバイスクラス)でVCP(VirtualCOMPort)の動作は確認できたので今回はこれにMicroShellを使える状態していく作業になります。
CDCのやり方はこの記事みてください。
gsmcustomeffects.hatenablog.com
やることは
ここ最近ARM系のお勉強を頑張っています。
今日はWEAK修飾子についてです。
STを例に話すと割り込み後に呼ばれるコールバックってのがWEAKマクロを使って記述されてます。
定義先に行くと
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* Prevent unused argument(s) compilation warning */ UNUSED(htim); /* NOTE : This function Should not be modified, when the callback is needed, the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file */ }
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //i2c_lcd_writeCommand(ClearDisplay); i2c_lcd_writeCommand(ReturnHome); HAL_Delay(2); xprintf("Count:%d",count); count++; }
のように記述されている。
これをMainで呼び出すとこのように使う。
要は同じ関数が二個あったらWEAKがついてる側が譲るということである。
こうすることで関数の上書き的なことができる。これがないとmain文で定義しなければコンパイルエラーになってしまうのでこうやって回避しているわけである。
ちなみにI2C系のデバイスライブラリ作るときもI2Cの送信APIを上書きで定義できるようにすれば汎用性を持たせられるので便利
__weak void i2c_write(){ //This Section is User function }
void i2c_write(){ HAL_I2C_Master_Transmit(&hi2c1,addri2c,(uint8_t*)data,2,0xFF); }
これでi2c_lcdの制御部分を記述してます。
1文字送信コマンドが2byteなのでこういった回りくどいことしてます。
前回は単一チャンネルの変換を行ったが今回はDMAを使ったものをやって行こうと思う。
ADCは変換終了フラグ(EOC)を見てDRレジスタを見に行くことで変換データを得ることができる。
上記の図のようにシーケンスの終了でもフラグが立つ(EOS)
二つのフラグを見てソフトウエア的に行うこともできるがタイミングがずれるとDRのデータが上書きされてしまう。
それを防ぐ仕組みにオーバーランというものある。
これはデータを保護できるがそのあとの変換値は破棄されてしまうので注意が必要だ
そのため複数チャンネルを変換する場合EOCフラグをトリガとしてDMAでレジスタ→メモリを実現したほうがソフト的な介在がなくなるので楽に処理できる。
マニュアル曰く(RM0316 345ページ)
変換されたチャネルの値は特定のデータレジスタに格納されるので、複数のチャネルの変換には
DMA の使用が便利です。これによって、ADCx_DR レジスタにすでに格納されているデータの損失を防ぐことができます。
DMA モードが有効なとき(ADCx_CFGR レジスタの DMAEN ビットがシングル ADC モードで 1 にセットされている場合、またはデュアル ADC モードで MDMAが0b00 以外に設定されている場合)、
各チャネルの変換後、DMA リクエストが生成されます。これにより、変換データを ADCx_DR レジスタからソフトウェアで選択した場所へ転送することができます。
これにもかかわらず、DMA が DMA 転送リクエストを時間内に処理できなかったためにオーバーランが発生した場合(OVR=1)、ADC は DMA リクエストの生成を停止し、新しい変換に対応するデータ
は DMA によって転送されません。
これは、RAM に転送されるすべてのデータを有効とみなすことができることを意味します。
要するにCH変換ごとにDMAリクエストが生成されるということ。
オーバーランが発生するとDMAがとまる。
OVRMODを適切に処理するか頻繁に止まるようならDMAを時間内に処理できるように変換自体の速度を下げておくなど工夫が必要だ。
DMAのモードには
の2つがあり
ワンショットは一回きりの転送になります
一方サーキュラは連続的にADCのCH変換が終わるたびにDMAリクエストが生成するので連続的なストリームが構成できる。
ここでアドレスのインクリメントにチェックを入れておくといい感じに配列に格納できる。
参考までに動いたコードを示しておく
ADC終了時に呼ばれるコールバック内にprintfを入れてUART出力している。
3日間ぐらいかけてADCやってみたんだけど何だかんだDMAを使ったのが一番簡単だねぇ
DMAといったら結構難しいイメージあったけどCubeMXのおかげでほとんど設定してくれるのでかなり楽ですね。
3日間一緒に検討してくれたリアルテック先生には感謝です。
http://realteck-blog.netlify.com/2017/04/08/f031%E3%81%AEadc%E9%80%A3%E7%B6%9A%E5%A4%89%E6%8F%9B%E3%81%8C/realteck-blog.netlify.com
2017/5/18追記
お恥ずかしいお話なのですがオカダといろいろやってて複数のADCを使うとMainにブレーク立てても帰ってこないと2日間ぐらい悩みました。
んで上記の図のようにこいつのADCには低速チャネルもあるんです。
12ビット精度で変換する場合最低でも14サイクルかかります
高速の場合Cubeで19.5サイクルにすればよいのですが低速の部分も19.5にしてました・・・・・ほんと雑魚wwww
なので皆さんはこんなバカなことで時間とかしちゃだめですよ!
直すとちゃんと動く
追記 2019/3/12
自分の場合上記のコードで動いたのですがshyachiさんより指摘があったので載せときます
/* USER CODE BEGIN 2 */ if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); }
の2つの関数はMX_ADC2_Initにてコールされているので呼ばなくて良さそうです。
特にHAL_ADC_ConfigChannelの方は呼ぶと2ch変換できなくなるケースも有るとか
動かない人はこの辺もお試しください
今回は一番簡単なやつやってみます。
やったことを雑に書くとこんな感じ
今回は一個しか読まないのでこのようにPA4にアサインする
一応UARTも使ってるのでそれも設定する
各種設定はこんな感じ
要所要所説明挟むとこんなもん
設定 | 機能 | 説明 |
---|---|---|
mode | independent mode | 独立モードで動く、その他速度を上げるDualModeがある |
Clock Prescaler | 非同期、1~4分周 | 読んで字のごとくクロック分周器 |
Resolution | 6~12bit | ADCの分解能 |
Data Alignment | 右詰め、左詰め | データの詰め方 |
Scan Coversion | Enable,Disable | 一回のシーケンスですべてのCHを変換するかどうか |
Continuos Conversion Mode | Enable,Disable | 連続変換 |
Dis Continuos Conversion Mode | Enable,Disable | 不連続変換 |
End Of Conversion Selection | シングルごとかシーケンスごとか両方か | 変換終了フラグの有無 データシートEOCフラグの部分読んだほうが図もあってわかりやすい |
Low Power Auto Wait | Enable,Disable | 自動遅延変換モードの有無。ADC オーバーランが発生するリスクのある低周波数のクロックで動作しているアプリケーションのパフォーマンスを最適化する場合に有効 |
設定 | 機能 | 説明 |
---|---|---|
Enable Regular Conversion | Enable,Disable | レギュラー変換の有効化 |
Number of conversion | 変換数 | チャンネル数分設定できる |
External Trigger Conversion Source | ソフトおよびタイマートリガ | 変換トリガソースの設定。 タイマーとかに連動できる |
External Trigger Conversion Edge | 立ち上がりか立下りかソフトか | 外部割り込みの設定 |
RankはCH分だけ個別設定ができる
設定 | 機能 | 説明 |
---|---|---|
Channel | チャンネル数分設定できる | 設定したいCHを入れる |
SamplingTime | 1.5~601.5サイクル | サンプリングタイム |
OffsetNumber | 1~4 | オフセットするCHの選択 |
Offset | 1~4056 | 変換値のオフセット |
一応紹介しておく
POTの2番ピンをA3ピンにつないでいるだけだが
参考までにコードを貼っておく