【BLEを使う】nRF51822 のUART機能を使う
このUARTというのは Universal Asynchronous Receiver Transmitter の略でシリアル通信装置の一種です。
1バイト8ビットのデータを1本の電線で送るために、時系列にデータを分解して、1ビットづつ出力(送信)または入力(受信)します。
最近のほとんどのマイコンには、UART機能が搭載されていますのでマイコン間のデータ交換や、変換ICを使用しRS232C規格の通信としてパソコンとデータのやり取りをすることも可能です。
マイコンメーカーによってはUART以外に独自の呼び方をするメーカーもあります。
いままでの記事はこちらをご覧ください。
今回はnRF51822のUART機能の使い方を説明します。
今まではBLEで無線送信する方法ばかり説明してきましたが、そのBLEが送信する当のデータは、外部から取り込まないといけません。
UART通信やSPI通信はセンサや外部のマイコンからデータを取り込むための手段であり、それらの使用は必須と言えます。
今回は、nRF51822のUART機能を使用してみます。
・端子配置
nRF51822で面白いと思ったのは、周辺機能に対応する特定の端子がないということです。
例えば、ルネサスのマイコンでは、TX機能を持つのはPORT1.6で、RX機能を持つのはPORT1.7と割り当てられていた場合、それらの機能を使いたい場合はPORT1.6とPORT1.7を使うしかありません。
(多くの場合、別端子に同じ機能が割り当てられていますが、使う端子が決められているという点では同じです。)
一方で、nRF51822の場合、機能に割り当てる端子は自分で設定して決めてやります。
端子番号0から31の中から、使いたい端子を選んで、機能を割り当てます。
例えば後述するレジスタPSELRXDについて
PSELRXD = 16;
と設定すれば、端子P0.16がRX端子となります。
開発キットの場合、この設定によりコネクタP2の29番がRX端子になります。
(nRF51822_Development_Kit_User_Guide_v1.4の 5.1.4より引用)
レジスタの値を変えれば、RX端子も変わります。実際に私はPSELRXD = 20に変更して、実際にRX機能がP0.20になったことを確認しました。
・レジスタ
UARTに関連するレジスタは以下になります。
名称 | 初期値 | 値 |
---|---|---|
RXD | 0x00000000 | 受信したRXデータ |
TXD | 0x00000000 | 転送するTXデータ |
ENABLE | 0x00000000 | 0x00000000:UART禁止 0x00000004:UART許可 |
PSELRTS | 0xFFFFFFFF | 0~31:RTSに使用する端子番号 0xFFFFFFFF:UART使用禁止 |
PSELTXD | 0xFFFFFFFF | 0~31:TXDに使用する端子番号 0xFFFFFFFF:UART使用禁止 |
PSELCTS | 0xFFFFFFFF | 0~31:CTSに使用する端子番号 0xFFFFFFFF:UART使用禁止 |
PSELRXD | 0xFFFFFFFF | 0~31:RXDに使用する端子番号 0xFFFFFFFF:UART使用禁止 |
ERRORSRC | 0x00000000 | bit0 0:Overrunエラー未発生 1:Overrunエラー発生 bit1 0:Parityエラー未発生 1:Parityエラー発生 bit2 0:Framingエラー未発生 1:Framingエラー発生 bit3 0:ブレーク条件未発生 1:ブレーク条件発生 |
CONFIG | 0x00000004 | bit0 0:フロー制御禁止 1:フロー制御許可 bit2:bit1 0x00:Parityなし 0x07?:Parityあり |
BAUDRATE | 0x01980000 | ボーレート |
・初期設定
PSELTXDレジスタとPSELRXDレジスタにより、TX機能とRX機能端子を割り当てるか設定します。
また、TX機能を割り当てた端子を出力端子に設定して、初期値をHigh出力にします。RX機能を割り当てた端子を入力端子に設定します。
CONFIGレジスタでフロー制御やパリティビットを使うかどうかを決めます。
フロー制御を有効にした場合は、PSELRTSレジスタとPSELCTSレジスタにより、RTS機能とCTS機能端子を割り当てるか設定します。
また、RTS機能を割り当てた端子を出力端子に設定して、初期値をHigh出力にします。CTS機能を割り当てた端子を入力端子に設定します。
BAUDRATEレジスタで通信速度を何bpsにするか決めます。
最後にENABLEレジスタをUART許可にすれば、UART初期設定完了です。
・送信
タスク信号STARTTX taskを1にすると送信シーケンスが始まります。
TXDレジスタに書き込むことで送信されます。イベント信号EVENTS_TXDRDYが1になると送信完了です。
EVENTS_TXDRDYを監視して、1になるまで待機してから、EVENTS_TXDRDYを0にクリアします。
STOPTX taskにより送信シーケンスは停止します。
・受信
タスク信号STARTRX taskを1にすると受信シーケンスが始まります。
イベント信号EVENTS_RXDRDYが1になると受信データが在ることを意味します。
EVENTS_RXDRDYを監視して、1になるまで待機してから、RXレジスタのデータを読み込み、EVENTS_RXDRDYを0にクリアします。
STOPRX taskにより受信シーケンスは停止します。
・関数
Noridicが提供するサンプルプログラムは以下になります。
nRF5 SDK guides - Nordic DevZone
・simple_uart_get
1byte受信関数
・simple_uart_get_with_timeout
タイムアウト機能付き1byte受信関数。タイムアウト時間はmsec単位で指定可能。
・simple_uart_put
1byte送信関数
・simple_uart_putstring
文字列送信関数
・simple_uart_config
UART初期設定関数。ボーレート初期設定値38400bps。
・補足
UARTのサンプルプログラムをKeilで開くとnrf_dleay.hにErrorが表示されることがありますが、コンパイルは正常に行えます。特定のバージョンのKeil環境に由来する無視しても問題ない擬似エラーです。
The Keil shows an error when #include "nrf_delay.h" - Nordic Q&A - Nordic DevZone - Nordic DevZone
・実験
Norodicが提供しているuart_exampleを使用してみました。
まずはビルドして書き込みます。このサンプルプログラムはS110ドライバが書き込まれていると書き込みできないので、一度Erase allでS110を消してから、Programで書き込みます。
最初はnRFGoマザーボードでプログラムを走らせ、送信は正常に行えたのですが、受信はうまくいきませんでした。
プログラムの問題ではなく、UARTケーブルとnRFGoマザーボードとパソコンの相性が悪いからだと考え、自作の評価ボードで試したところ正常に送受信できるようになりました。
追記
・受信割り込み
受信による割り込みを発生させたい場合は、UARTの初期設定に以下を追加します。
NRF_UART0->INTENSET |= (UART_INTENSET_RXDRDY_Enabled << UART_INTENSET_RXDRDY_Pos );
NVIC_EnableIRQ(UART0_IRQn);
以上を追加すると、受信時に関数UART0_IRQHandlerが呼び出されます。
例えば、UART0_IRQHandlerにおいて、受信データを変数に格納し、そのデータをそのまま送信する処理をさせてみます。
void UART0_IRQHandler(void) { uint8_t cr = simple_uart_get(); simple_uart_putstring((const uint8_t *)"\n\rYour input is "); simple_uart_put(cr); }
キーボードから文字を入力すると、受信割り込みによりUART0_IRQHandlerの処理が実行されているのが確認できます。