Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SSブログ
English Version

CH32V203で遊ぶ(その2)USART割込みでLiDAR接続 [CH32V]

 前回の記事では SPI インターフェースを使い LCD を制御しました。今回はシリアル通信と割込み機能を試してみたいと思います。

1.今回の目標
 割込みを使ったシリアル受信機能を実装します。更に以前(2020年8月頃)購入した安価な LiDAR のデータを受信し、LCD上に表示することに挑戦してみたいと思います。


2.割込みを使ったシリアル受信の実装
 サンプルを参照して実装は簡単にできました。ヘッダファイルと割込み処理のコードを貼っておきます。説明する部分はあまりありませんが、受信バッファは2のべき乗サイズにしてリングバッファにしています。また、バッファからの読出し時には割込み処理との競合防止のため、受信割込み禁止にしています。

シリアル受信のヘッダファイル
/******************************************* USART interrupt hander Ver 0.01 2024/07/15 by skyriver *******************************************/ /* * usard receive interrupt routine * USART2:Tx(PA2),Rx(PA3) */ #define RiSIO USART2 #define RiPORT GPIOA #define RiSIOTx GPIO_Pin_2 #define RiSIORx GPIO_Pin_3 #define RXBUFSIZE 128 // receive buffer size #define BUFIDXMASK (RXBUFSIZE - 1) void InitSio( void ); uint8_t SioGetc( void ); extern volatile uint8_t RxCnt;


シリアル受信処理
/******************************************* USART interrupt hander Ver 0.01 2024/07/15 by skyriver *******************************************/ #include "debug.h" #include <stdint.h> #include "serial.h" voratile uint8_t RxBuf[ RXBUFSIZE ] = {0}; volatile uint8_t RxCnt = 0, RxWrIdx = 0; volatile uint8_t RxRdIdx = 0; void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); /* * configlate USARTn * return : none */ void InitSio( void ) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // uart name RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // port name /* USART TX Rx */ GPIO_InitStructure.GPIO_Pin = RiSIOTx; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(RiPORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = RiSIORx; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(RiPORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(RiSIO, &USART_InitStructure); USART_ITConfig(RiSIO, USART_IT_RXNE, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; // uart name NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(RiSIO, ENABLE); } /* * Rx interrupt handler */ void USART2_IRQHandler( void ) { if( USART_GetITStatus( RiSIO, USART_IT_RXNE ) != RESET ) { if( RxCnt < (RXBUFSIZE - 1) ) { // not buffer full RxCnt++; RxBuf[RxWrIdx++] = USART_ReceiveData(RiSIO); RxWrIdx &= BUFIDXMASK; } else { USART_ReceiveData(RiSIO); } } } /* * get character from Rx buffer * return -> data */ uint8_t SioGetc( void ) { uint8_t data; while( RxCnt == 0 ) {} USART_ITConfig(RiSIO, USART_IT_RXNE, DISABLE); // disable Rx interrupt data = RxBuf[ RxRdIdx++ ]; RxRdIdx &= BUFIDXMASK; RxCnt--; USART_ITConfig(RiSIO, USART_IT_RXNE, ENABLE); // enable Rx interrupt return( data ); }



3.LiDAR との接続
 旧 Twitter のタイムラインで見かけて AliExpress さんから 2020年8月頃に購入したものです。下の写真は裏側にある基板の部分です。左下の元々あったコネクタのピッチが狭いため、左上のコネクタを瞬間接着剤でプリント基板に接着しています。
 尚、中央部にある裏側への配線は元々あったものです。

手持ちの LiDAR 写真(裏面)


 下の写真が表側で417と書いてあります(この LiDAR の型番?)。

手持ちの LiDAR 写真(表面)


 カバーを外した状態が下の写真です。なぜカバーを外したかというとこの個体は調子が悪かった(特に角度情報)ためです。まぁカバーを外したところで修理できる訳ではないのですが・・

手持ちの LiDAR 写真(カバー外し後)


 LiDAR 側の電源は 5V なので、CH32V203 を入れたブレッドボードは LinkE から 3.3V を給電し、LiDAR には安定化電源から 5V を給電しました。安定化電源の電流値は 400mA 程度でした。LCD は前回からの継続で 320 x 240 dot でカラーの MSP2807 を接続しています。

 LiDAR との接続を下表に示します。LiDAR のシリアル出力は 3.3V のレベルに変換されて出力されているので CH32V203 に直接接続可能です。

CH32V203K8Y6LiDARMSP2807WCH-LinkE
1:3.3V 1:VCC
5:3.3V 1:VCC
7:RA1 8:LED
8:USART2_Tx
9:USART2_Rx LiDAR_Tx
10:RA4 5:DC
11:SPI_CK 7:CLK
12:SPI_MISO
13:SPI_MOSI 6:DIN
16:GND GND 2:GND 8:GND
17:3.3V 1:VCC
19:USART1_Tx 1:RX
20:USART1_Rx
21:RA11 4:RESET
22:RA12 3:CS
23:SWDIO 7:SWDIO
24:SWCLK 6:SWCLK
32:GND GND 2:GND 8:GND


★追記 2024/07/20 {
 オシロで確認した LiDAR のシリアル出力信号波形が下図です。

LiDAR のシリアル波形例
}

 ロジアナで確認した LiDAR の出力も貼っておきます。

LiDAR の出力サンプル


 ヘッダの値が 0x55,0xaa,0x03,0x08 であることを頼りにネットで探したところ、Github の camsense-X1 のページにこのタイプの LiDAR が出力する package のフォーマットと処理方法に関する情報があったので参考にさせて頂きました。package 内のデータのフォーマットは次のようになるとのことです。

/* package format (36 bytes)
 *
 * <0x55><0xAA><0x03><0x08>
 * <speedL><speedH>
 * <startAngleL><startAngleH>
 * <distance0L><distance0H><quality0>
 * <distance1L><distance1H><quality1>
 * <distance2L><distance2H><quality2>
 * <distance3L><distance3H><quality3>
 * <distance4L><distance4H><quality4>
 * <distance5L><distance5H><quality5>
 * <distance6L><distance6H><quality6>
 * <distance7L><distance7H><quality7>
 * <endAngleL><endAngleH>
 * <unknown><unknown> could be a CRC
 */


 LiDAR からのシリアルデータは 115200bps で 36 バイト構成の package データ( 8個の測定データが含まれる)が立て続けに来る(1回転で50 package 程度)ので全データの処理は難しいことから、割込み処理は package を受信したら受信フラグをたて、package 解析&表示処理側で package の処理が終了したら 受信フラグを消すようにしました。このように解析中に受信したデータは捨てることで欠損のない package データを処理できるようにしています。



4.LiDAR 接続での問題点
 LiDAR の出力情報を受信し、LCDに表示する処理を作る上で次の問題が発生しました。
  1. 三角関数の未定義エラー
  2. 処理時間
  3. LiDAR の不調

 4-1.三角関数の未定義エラー
 「undefined reference to 'sin'」というエラーが発生し、しかもソース上のエラー指摘行が sin を使用していない行です。math.h をインクルード済みでこの中で宣言されていますがエラーがでます。ソースファイルの先頭部でプロトタイプ宣言しても状況変わらず・・
 下図のオプション設定を追加することでエラーが解消されました。reference が無いというエラーなのでリンク時のエラーだったんですね。

三角関数未定義エラーの対処設定


 4-2.処理時間
 処理に時間が掛かり LiDAR からの多くの package を読み飛ばしてしまっていました。処理中のロジアナ波形例を下図に示します。上述したように割込み処理で package の全データを受信してから受信フラグを立てるので、下図のマーカーペア0が package 内のデータの取り出し+1つのポイント描画の時間で、マーカーペア1が1つのポイント描画の時間なのでデータ取り出し処理の時間はその差分の 1ms 程です。package には最大で有効データが8個存在します。下図の例では5package につき一つの package を処理していることになります。
 尚、マーカーペア1が package 受信に要する時間です。

LiDAR からのpackageデータ処理中のロジアナ波形例


 仮に整数のみで処理した場合(三角関数はテーブル引き)の想定ロジアナ波形が下図になります。下図から package 2~3個中1個を処理できるようになりそうです。MounRiver Studioでは最適化オプションがディフォルトではサイズ優先(-Os)になっていますが、速度優先(-Ofast)に変更してもあまり変わりませんでした。まずは整数化せずに進めることにします。

LiDAR からのpackageデータ処理中のロジアナ波形(整数のみで処理した想定の場合)


 4-3.LiDAR の不調
 この LiDAR の不調が今回最も頭を悩ました問題です。特に角度情報が更新されずに全て 0xa000 になったりして非常に不安定です。ロジアナで採取した波形から連続した package データを並べたものが下図のサンプルです。
 サンプル2を見ると Flag 部分のビットパターンより、距離データが ( DistanceL, DistanceH, Flag ) ではなく、( DistanceL, Flag, DistanceH ) なのではないかと思えてきますが、その並びで処理してもきれいな表示にはなりませんでした。

packageデータサンプル1

packageデータサンプル2


 現状での LiDAR データの LCD 表示例は下図になります。LiDAR は机の上に置いている状態なので周りにはモニタディスプレイや半田ごて等、雑多な物がある状態です。LiDAR が不安定なので時と場合より表示状態が変化します。

LiDAR データ表示例



5.まとめ
 CH32V203 での割込みによるシリアル受信の実装は早々にできたのですが、4年前に購入した格安の LiDAR の不調で悩みました。
 CH32V の割込み処理もサンプルを参照しながら割合簡単に実装できることが判りました。最終的には LiDAR のデータを奇麗に描けなかったので別の格安 LiDAR で再挑戦してみたい気もします。


★追記 2024/07/20
 データ抽出処理部のバグを修正しました。まだ LiDAR が不安定になる場合がありますが、調子の良い時にはかなりきれいに描画できるようになりました。
 ¥120のマイコンでもほぼリアルタイムに表示できるのが嬉しいですね。


LiDAR データ表示例(改善版)




[TOP] [ 前へ ] 連載記事一覧 [ 次へ ]

nice!(0)  コメント(1) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 1

SamuelShi

素晴らしい文章です。あなたのプロジェクトに助けが必要ですか?PCBWayは無料でモデルを作るスポンサープログラムを持っています。必要でしたらメールをください:marketing06@pcbway.com
by SamuelShi (2024-08-08 17:04) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。