RaspberryとArduinoの無線通信

nRF24L01-Mirfライブラリ


最近STM32を使う機会が増えています。
UNOの32K Flashはあまりにも小さく、MEGAのボードサイズはあまりにも大きすぎますが、
STM32F103C8ならば、最低でも64K Flash(ほとんどが128K FLASH)で、ボードサイズも小さくて手ごろです。

STM32をArduino環境で開発する場合、コアライブラリが必要になります。
今までこち らのMaple Coreを使っていましたが、最近はこちらの STM32 Coreを使っています。

Maple Coreは実質STM32F103に特化したコアライブラリですが、
STM32 Coreライブラリは、ものすごい勢いでサポートボードが増えていて、
NUCLEOやDiscoveryなど、ST純正のボードだけでなく、STM32F1、F2、F3、F4、F7、G0、G4、H7、L0、L1、 L4を使った
汎用開発ボード(Generic Board)の対応も増えています。
F101のBluePillやBlackPillと同じフォームファクターでF303やF401のボードが安価に入手できます。
そこで、STM32 Coreでこちらのライブラリ を使ってみましたが、何故か動きませんでし た。

左からF101、F101、F303、F401、F411の開発ボード




ArduinoでのSPIライブラリの使い方には以下の2つの書き方が有ります。
こちらがLegacyなコードです。
SPI.begin()
SPI.setClockDivider(divider)
SPI.setDataMode(mode)
SPI.setBitOrder(order)
SPI.transfer(data);

こちらが新しいモダンな書き方です。
SPI.begin()
SPI.beginTransaction(SPISettings(speed, order, mode))
SPI.transfer(data);
SPI.endTransaction()

Arduinoのリファレンスを見るとLeagcyコードは非推奨になっていて、新しいプロジェクトではモダンなコードを使えと書いてあります。
UNOやMEGAではLegacyのコードも問題なく動きますが、Arduino_Core_STM32ではモダンなコードしか動きません。
SPIで通信を行うライブラリの中にArduino_Core_STM32では動かないものが有りますが、これが原因です。

STM32の場合、クロック周波数がモデルごとに異なるので、SPI.setClockDivider(divider)でSPIクロック 分周器(divider)を指定すると、
SPIスピードがモデルごとにまちまちになります。
SPISettingsでスピードを具体的に指定する必要が有ります。

トランザクション付きのSPIをサポートするかどうかはSPIライブラリに依存します。
トランザクション付きのSPIをサポートするライブラリでは、SPI.begin()するとSPI_HAS_TRANSACTIONが定義されま す。
この定義の有無を判断して以下の様にコードを振り分けます。
SPI.begin()
#if defined(SPI_HAS_TRANSACTION)
  SPI.beginTransaction(spiSettings);
#endif
  uint8_t value = SPI.transfer(data);
#if defined(SPI_HAS_TRANSACTION)
  SPI.endTransaction();
#endif



こちらのライブラリソースを見てみましたが、 LinuxやTinyまでサポートしているので、結構コードが難解で、
STM32 Coreの時にどちらのAPIが使われるのかよくわかりません。

こちらのライブラリ は、RF-Nano用に開発されたライブラリですが、非情にコードがシンプルです。
そこで、こちらのラ イブラリをベースに、STM32 Coreでも動くライブラリを作りました。
こちらで 公開しています。
ATmega/STM32/ESP8266のどれでも、同じライブラリを使って、相互に通信することができます。

Mirfというライブラリは非常に古くからあるライブラリで、オリジナルはこちらの様です。
これを改訂したのがこちらで すが、CEピンとCSNピンがライブラリ内部で固定になっています。
RF-Nanoでは違うCEピンとCSNピンを使っているので、これらのピンを引数として指定できるようにしたのがこちらです。

こちらのライブラリが余りにも有名なので、Mirf ライブラリはあまり使われていませんが、
バグも枯れていて非常に優秀なライブラリです。



MirfライブラリをRaspberryPi用にポートしたものが、こちらに公開されています。
試してみましたが、デバイスファイルが"/dev/spidev0.0"、SPI周波数が2Mhz固定で、
さらに、SPIのtransfer関数に初期化漏れがあり、手元のRaspberryでは動きませんでした。
そこで、これらを改訂したライブラリをこちらで公開していま す。

さらに、これをESP-IDFにポートしたものをこちらで公開しています。
これで、RaspberryPi/ATmega/STM32/ESP8266/ESP32が同じライブラリで通信できるようになります。



こちらはSTM32F103ですがボードに直接nRF24L01をマウントすることができます。


マウントするとこの様になります。
下側の8ピンソケットにはESP01を直接マウントすることができます。


CE=PB0 CSN=PB2に繋がっているので、
Nrf24l Mirf = Nrf24l(PB0, PB2);
で動きます。


こちらはSTM32F405ですが、これもボードに直接nRF24L01をマウントすることができます。


マウントするとこの様になります。


ただ、オンボードにW25Q16のSPI FLASHが実装されていて、以下の様にSPI(PB3/PB4/PB5)を共有しています。
NRF24L01 (JP2)
1 GND
2 3V3
3 PB6 NRF_CE
4 PB7 NRF_CS
5 PB3 SPI1_SCK
6 PB5 SPI1_MOSI
7 PB4 SPI1_MISO
8 PB8 NRF_IRQ

SPI Flash W25Q16 (U3)
1 PB0 F_CS
2 PB4 SPI1_MISO
3 WP 3V3
4 GND
5 PB5 SPI1_MOSI
6 PB3 SPI1_SCK
7 HOLD 3V3
8 VCC 3V3

PB0をPullUPするとFLASHが無効になるはずなので、PB0をPullUpしてnRF24L01をマウントしてみました。
CE=PB6 CSN=PB7に繋がっているので、
Nrf24l Mirf = Nrf24l(PB6, PB7);
で動くはずですが、なぜか動きませんでした。

setup()の先頭で以下の様にSPIをRemapして、以下の様に接続したら動きました。
/*
 * Nrf24l Mirf = Nrf24l(PB0, PB1);
 *
 * VCC  3.3V
 * MISO PB14
 * MOSI PB15
 * SCK  PB13
 * CE   PB0
 * CSN  PB1
*/

void setup()
{
  SPI.setMOSI(PB15);
  SPI.setMISO(PB14);
  SPI.setSCLK(PB13);
  SPI.setSSEL(PB12);

以下略