前回からの続きです。NucleoボードをNTS-1のカスタムコントロールパネルとして動作させることに成功しました。前回は中間まとめでしたが、結果的に前回がハードウェア編、今回がソフトウェア編という感じになりました。
前回の最後のところで
どうも、SPIの信号は8bitなのに、クロックがうまく同期していないのかノイズがどこかから載っているのか、Nucleo側のクロックカウントが実際の信号と合っていないようです。Nucleo側を9bitの設定にすると同期できてきますが、当然ながらこれでは正しくデータがやり取りできません。
と書きましたが、結論から書くと「SPIに用いるGPIOピンのクロックを下げる」ことで解決しました。
修正対象のファイルは
C:\Users\YOUR_USER_NAME\AppData\Local\Arduino15\packages\NTS-1 Custom Panels\hardware\stm32\1.0.1\variants\NTS1_REF_CP_REVC\nts1_iface.c
です。このファイルがカスタムパネルのドライバの本体です。
このファイルの268行目の
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
を
gpio.Speed = GPIO_SPEED_FREQ_LOW;
に修正します。
ヒントになったのはSTMicroが出しているエラータの資料の中に、以下のような記載があったことでした。
2.9.5 Corrupted last bit of data and/or CRC, received in master mode with
delayed SCK feedback
(ざっくり省略)
Workaround
The following measures can be adopted, jointly or individually:
• Decrease the APB clock speed.
• Configure the I/O pad of the SCK pin to higher speed.
前述のとおり、どうもSPIのクロックがうまく検出できていないらしい、という感じていたところ、この記述を見て「そうか、GPIOピンの反応速度をいじれるのか・・・」と気づきました。
このGPIO_SPEED_FREQ_HIGH
やGPIO_SPEED_FREQ_LOW
はSTマイクロ提供のHALの中のファイルで以下のように定義されています。
#define GPIO_SPEED_FREQ_LOW (0x00000000U) /*!< range up to 2 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_MEDIUM (0x00000001U) /*!< range 4 MHz to 10 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_HIGH (0x00000003U) /*!< range 10 MHz to 50 MHz, please refer to the product datasheet */
SPIの実際のクロックスピードは1MHzでしたので、LOWでもいいはず・・・ということでLOWに設定したところ、ようやく動作しました。
ちなみに、SPIがクロックをうまく取れていないらしい、と気づいたのは、パネルから本体へ送信するデータが無いときに送るダミーデータ(通常は0xff)を0xF7(0b11110111)に変更して信号を観測したときでした。
このときの信号を観測すると、下図のようになっていました。信号は上からMOSI(音源→パネル)、クロック、MISO(パネル→音源)の順に並んでいます。
SPIの設定はLSB First、データはクロックのrising edgeで取得、となっています。しかし、一番下のMISOの信号はrising edgeで変化してしまっており、送られるデータも左から11101111となるはずが、実際には
1101111 1011111 01111111 11111110
という具合に8ビット送るごとに1ビットずつずれていってしまっています。
私の工作が悪くてノイズが回り込んでいる可能性もありますが、通信要件的にはLOW Speedにしても問題ないはずなので、この修正はプルリクエストを投げておきたいと思います。
最後に、動作している様子のビデオと、このビデオで動かしているスケッチ(Nucleoのユーザボタンを押すと音が鳴る)を載せておきます。
コメント