1. はじめに
本装置はセンサー情報を集めてCANデータにして上位装置に通知するものである。
世の中にはVectorのツールでもよく知られているものだが、Vectorのツールは高額であり、それほど高度なことをしない限り自作ツールでも問題ない。
むしろ今回処理プロセッサにInfineon(旧Cypress)のPSoCを使用することでセンサーの種類や奇特なIFにも柔軟に対応することが可能となる。
2. 装置概要
今回は普通はCANの情報ないセンサー情報を別途取得し、測定したデータをCANプフォーマットに変換を行い、上位システムに通知する装置例を示す。
項目 | 内容 | 備考 |
---|---|---|
PSoCボード内部諸元 | ||
メインCPU | CY8C3866AXI-040 (Cypress) | 8051 100pinQFP ROM/RAM内蔵 メモリ: ROM:64kbyte,RAM:8kbyte 動作クロック:外部30.0MHz/内部60MHz |
A/D変換部 | 16ch(マルチプレクス入力) 変換時間:246.6us/channel 16ch H/Wシーケン測定周期: 3.972msec/period 入力:シングルエンド0~2.048V 量子化ビット:ΔΣ12bit 入力インピーダンス:10MΩ以上 | DMA転送によりCPUの負荷軽減 A/D変換動作は固定周期 変換データは8タップの移動平均処理する。 座席位置、ドア開閉検出で使用 |
平均化処理 | 移動平均タップ数8 | AD変換データの移動平均処理 |
システムタイマー | 10msec | 測定タイマーの基準時間として使用 |
外部IF部 | ||
UART | TX:1ch 9600bps N81 RX:5ch 9600bps N81 | 距離センサー TW10S-UARTを使用 |
ADポート | 16ch | 1sensor portで3つのADを割り当てる。 |
USB | USB:CDC 2ch,HID 1ch | USB複合デバイス HID:CAN, CDC1:コンソール出力 |
CAN | ~1Mbps | Default:500kbps |
キャラクタLCD | ST7032I I2C IF | センサー測定結果・ステータス情報など表示 |
タクトSW | 2個 | 1つはセンサー情報の表示切替で使用 |
ステータスLED | 2個 | 使い方はT.B.D |
3. CANインターフェース仕様
3.1 CANデータの送信周期
データ取得周期と通知周期は以下の表3-1に従う。送信周期が0.7秒というのはレーザー距離計の測定応答時間を考慮した値となっている。レーザー距離計以外は特に大きな制約はない。
送信方式 | 送信周期 | 更新時間 | データ内容 | CAN ID |
---|---|---|---|---|
定周期 | 700ms | 100ms | ADデータ 16ch | 700h~703h |
定周期 | 700ms | 700ms | 距離データ | 704h~706h |
3.2 PSoC内の送信メールBOXの設定
PSoCのCANペリフェラルは送信メールボックス8個、受信メールボックス16個から構成されている。本装置においては測定したセンサー情報をCANで送信することから8個のメールボックスで以下のような割り当て送出することにした。
symbol | Mail BOX# | CAN ID | DLC | 内容 |
---|---|---|---|---|
CH0003AD | 2 | 700(h) | 8 | ch0~ch3のA/Dデータ |
CH0407AD | 3 | 701(h) | 8 | ch4~ch7のA/Dデータ |
CH0811AD | 4 | 702(h) | 8 | ch8~ch11のA/Dデータ |
CH1215AD | 5 | 703(h) | 8 | ch12~ch15のA/Dデータ |
LADIS12 | 6 | 704(h) | 8 | レーザー距離計 port1~port2 |
LADIS34 | 7 | 705(h) | 8 | レーザー距離計 port3~port4 |
LADIS5 | 8 | 706(h) | 3 | レーザー距離計 port5 |
4. システムクロック設定
5. ADコンバータ
5.1 AD変換のH/Wシーケンス化
使用したPSoCは8051コアの CY8C3866AXI なので、CPUパフォーマンスはそれほど高くない。一方、AD入力は16chかつUART受信割り込みを5ch同時に動作させるため、なるべくCPUを介さずに動作するようにするため、ADコンバータのH/Wシーケンス処理化を検討してみる。
5.2 A/D変換部動作概要
16ch分のA/D変換は全てH/Wシーケンスで行う。
H/WロジックによりA/D入力のマルチプレクスを行い、SOC(start of conversion)トリガにてA/D変換を行い、その終了のEOC(end of conversion)の信号をDMAのトリガとしてメモリに転送される。DMAにて8チャネル分のデータ転送を行った後、割り込み信号によりCPUで各チャネルを移動平均バッファへと転送する。
なお、上記の一連のA/D変換からメモリへのデータ転送はCPUの処理とは非同期で常に行われている。
16channel分のA/D取り込みから各チャネルの移動平均バッファへの転送は2系統のDMAを使用しDouble Buffer経由で移動平均バッファに転送する。1系統約7.944msecでパイプライン処理するため、16chnnel AD処理はその半分の約3.97msecでおこなう。
5.3 A/D変換モジュール設定内容
変換レート(40960sps)に設定にするとA/D変換のH/Wシーケンサーによる1周期(16ch)の変換時間は内部RAMにDAM転送する時間を含めて約429usecであり、A/D変換16ch分の測定結果を内部メモリから移動平均バッファに転送するのに391usec要する。
つまり、他の処理で使用できるCPU処理リソースは429-391≒38usecしかない。
PSoC3はCPUが8051@60MHzでありこの時点でCPU動作率が91%となっているのでやりすぎ!
従って、この変換レートを40960sps⇒4096spsに変更する
5.4 動作タイミグの確認(実測)
上記にタイミグからわかるようにサンプリングを4096spsにした方がCPUの処理時間をマージンを見て確保することができる。
5.5 移動平均バッファの動作概念
H/Wシーケンスで取得したチャネルごとのADデータはDMA割り込み時にローカルの移動平均バッファへ転送する。また、移動平均ライブラリは2,4,8,16,32タップのいづれかの数で平均処理できるようになっている。ADデータの取り出しは入力とは非同期に行われ、必要な時に直近過去の設定したタップ数の移動平均値を取得する。
A/Dの内部サンプル周期は16channelあたり3.97msecは変わらない。
移動平均したデータを設定された外部転送周期で転送を行う。
PSoC3の評価ボード上で実測したところ16channel,32byteのデータを移動平均処理するのに385usec要しているので約83kbyte/secくらいの処理となる。
<<Buffer AのDMA割込みハンドラの中の処理>> /************************************************************************ * Function Name: ADI1_ISR * finish 16 channel measurement -> Transfer DMA1 end -> Occured isr! ********************************************************************/ CY_ISR(ADI1_ISR){ int i; DebugOut_Write(1); Control_RegDma_Write(0); for(i = 0; i < NUMCHAN; i++){ MovingAverage_input(padavech[i], ADresult1[i]); } DebugOut_Write(0); }
Buffer AのDMA割込みハンドラの中の処理
主にAD buffメモリからローカルの移動平均処理バッファにコピーしているだけ。自作したMovingAverage_input()関数が重いのかもしれないが、CPUが8051だと結構処理時間がかかるという感じ。
6. レーザ距離センサー
6.1 UARTブロック
このブロックはレーザー距離センサー(TW10S-UART)用のもので測定値要求コマンドは”UART_1”ブロックがまとめて各距離センサーモジュール向けにブロードキャストを行う。これはUART_2~UART_5のTXブロックを省略することでH/W使用リソースをなるべくコンパクトにするためである。
一方、TXをまとめるのは多少のピンリソースは消費されるが、基板上で一つにまとめるより今後拡張や用途に応じて柔軟に対応できるからです。各センサーの測定結果はそれぞれにUART RXで受け、ブロック毎の受信割込みでデータ受信する。GPIOは各Sensor Portに対する予備的な信号線であり、今回は使用しない。UARTのデータサンプルクロックはボーレートの8倍を入力することにする。今回の距離センサーの通信レートは9600bps(N8)である。
今回使用するレーザー距離計モジュールはUART IFであり、測定開始のコマンドの後、測定したデータが送られてくる。開始コマンドは同じなので5個のUARTブロックの中で一つだけTX部を持つこととし、それを各デバイスにワイヤードでブロードキャストするような感じ。TXを一つだけのブロックにすことでUDB(User Digital Block)の使用するリソースをなるべく節約する目的もある。
受信はそれぞれに「受信割り込みハンドラ」を設け、個別に距離測定管理する。
通常この規模のマイコンで複数(5個)のUARTペリフェラルはなく、PSoCならでは特徴を活かした構成が容易に可能となる。
受信したデータは下記の処理を行い距離に変換する。
6.2 レーザ距離センサー処理
/**************************** TW10S-UARTの受信データから距離への変換 ※Ring_buffライブラリを使用 引数: TRINGBUF *prx 受信リングバッファポインタ 戻り値:int_16 distance 距離データ (mm) ********************************/ int16 TW10S_distanceCalc(TRINGBUF *prx, uint8 *stat){ int16 i,dat[4]; while(RingBuf_LeftValue(prx) > 7){ /* 受信データ数が9byte以上だったら有効データありと判断してworkbuffdrにコピーする*/ if(RingBuf_WatchBuf(prx, 0) == 0x01 && RingBuf_WatchBuf(prx, 1) == 0x03 && RingBuf_WatchBuf(prx, 2) == 0x04){ for(i = 0; i < 3; i++) RingBuf_GetBuf(prx); /* 3つリードポインタを進める */ dat[0] = RingBuf_GetBuf(prx); dat[1] = RingBuf_GetBuf(prx); dat[2] = RingBuf_GetBuf(prx); dat[3] = RingBuf_GetBuf(prx); if(dat[0] >= 0xfc) { /* 異常データー時はステータスエラーを返す 距離データは0 */ *stat = dat[0]; return 0; }else{ /* 正常距離データ */ *stat = 0; return (dat[0] << 24) + (dat[1] << 16) + (dat[2] << 8) +(dat[3]); } }else { RingBuf_GetBuf(prx); /* ヘッダが出てくるまでリードポインタを進める */ } } *stat = 0xfb; /* データが十分ない */ return 0; }
6.3 レーザー距離センサーモジュール(TW10S-UART)
6.3.1 概要仕様
インターフェース: 3.3v-5v/ttl232 3線式シリアルインターフェース
(シングルチップuart/usart/sciインターフェース。rs232インターフェースを直接接続しないでください。)
ボーレート 🙁 4800、9600、19200、38400、57600、115200) オプション、デフォルトは9600
電源電圧: 3.3v;
稼働中: <180ma;
測定範囲: 0.04〜40m (モジュールの前面に基づく)
測定速度: 最大5Hz、つまり1秒以内に5つのデータを測定できます。
測定精度: ± 2ミリメートル + 510 (-5) d、dは測定距離; 動作温度: -10 ~ 50 ℃。 保管温度: -30 ~ 70 ℃ 製品サイズ: 6031*14mm (長さ * 幅 * 高さ);
6.3.2 インターフェース仕様
このレーザー距離計をAliexpressで購入したが、インターフェース仕様書は十分ではなく、ネット上で必要な動作が行えればいいのだが、動作モードに3つほどあり、データ更新周期をなるべく短く従ったのだが、最高0.7秒程度だった。ネットの情報から以下のようIF仕様のようだ。
- 準備
各レンジングの前に、enピンを高レベル (3.3v〜5v) に設定すると、センサーが起動してハードウェアを初期化します。センサーは引き続き以下を発行します。
01 03 02 00 00 B8 44
測定が完了すると、センサーは低電力モードになります。
- 入力レジスタ (関数コード0x03) を読み取ります
(このコマンドを発行する前に、センサーが続行されるのを待ちます)
例:
読む測定距離
説明アドレスコード関数コード開始アドレスレジスタ数crc
送信: 0x01 0x03 0x00 0x0f 0x00 0x02 0xf4 0x08
通常の応答 (測定距離57.505m):
説明[アドレスコード][関数コード][バイト数][レジスタ1値(2byte)][レジスタ2値(2byte)][crc]
通常応答: 0x01 0x03 0x04 0x00 0x00 0xe0 0xa1 0x72 0x4b
注 (この指示の距離は4バイト、0x00 0x00 0xe0 0xa1、距離は0x0000e0a1、10進数で57505mmに変換)
- エラーコード(エラーコード:0x83)
開始アドレスが間違っている場合、レスポンスは次のようになります。
説明[アドレスコード][エラーコード][例外コード][crc]
エラーレスポンス: 0x01 0x83 0x02 0xc0 0xf1 (間違った開始アドレス)
エラーが発生した場合、レジスタ1と2がエラーコードを表します。 具体的なタイプは次のとおりです。
0xff000000 計算エラー、再測定
0xfe000000反射光が弱いか、測定時間が長すぎるため、反射面がより簡単に反射される必要があります。
まな板で、白紙、など。
0xfd000000ターゲットが反射しすぎているため、強い光を当てないでください
0xfc000000測定範囲を超えています。機器の範囲内で測定してください
CRCが後尾についているが、生成多項式が詳細不明。とりあえず無視してもいいかと思われる。
OCTET | 正常 | 間違った開始アドレス | 計算エラー 再測定 | 反射光が弱いか、測定時間が長すぎる | ターゲットが反射しすぎている | 範囲を超えています |
---|---|---|---|---|---|---|
1(アドレスコード) | 0x01 | 0x01 | 0x01 | 0x01 | 0x01 | 0x01 |
2(関数コード) | 0x03 | 0x83 | 0x03 | 0x03 | 0x03 | 0x03 |
3(バイト数) | 0x04 | 0x02 | 0x04 | 0x04 | 0x04 | 0x04 |
4(レジスタ1H) | 測定値(X3) | 0xc0 | 0xff | 0xfe | 0xfd | 0xfc |
5(レジスタ1L) | 測定値(X2) | 0xf1 | 0x00 | 0x00 | 0x00 | 0x00 |
6(レジスタ2H) | 測定値(X1) | CRC(上位8)? | 0x00 | 0x00 | 0x00 | 0x00 |
7(レジスタ2L) | 測定値(X0) | CRC(下位8)? | 0x00 | 0x00 | 0x00 | 0x00 |
8 | CRC(上位8) | CRC(上位8) | CRC(上位8) | CRC(上位8) | CRC(上位8) | |
9 | CRC(下位8) | CRC(下位8) | CRC(下位8) | CRC(下位8) | CRC(下位8) |