SeeeduinoXIAOのSPIペリヘラルを使わずにタイマーでSPIを出してみる。ボードをインストールすると、Timer3のライブラリが入ってくるらしく、
#include <TimerTC3.h>
とすれば使えるようになるらしい。まずは使ってみる。
#include <TimerTC3.h> #define PORT_SCK PORT_PA07 #define REG_PORT_IOBUS_DIR0 (*(RwReg *)0x60000000U) #define REG_PORT_IOBUS_DIRCLR0 (*(RwReg *)0x60000004U) #define REG_PORT_IOBUS_DIRSET0 (*(RwReg *)0x60000008U) #define REG_PORT_IOBUS_DIRTGL0 (*(RwReg *)0x6000000CU) #define REG_PORT_IOBUS_OUT0 (*(RwReg *)0x60000010U) #define REG_PORT_IOBUS_OUTCLR0 (*(RwReg *)0x60000014U) #define REG_PORT_IOBUS_OUTSET0 (*(RwReg *)0x60000018U) #define REG_PORT_IOBUS_OUTTGL0 (*(RwReg *)0x6000001CU) #define REG_PORT_IOBUS_IN0 (*(RoReg *)0x60000020U) void timerISR(){ REG_PORT_IOBUS_OUTTGL0=PORT_SCK; } void setup(void){ REG_PORT_IOBUS_DIRSET0=(PORT_SCK); REG_PORT_IOBUS_OUTSET0=(PORT_SCK); TimerTc3.initialize(1);// in us TimerTc3.attachInterrupt(timerISR); } void loop(void){ }
1usごとに割り込みが入るはずなので、周期は2usになってほしいんだけど、実際は4usになっている。1usだと何かが間に合わないのか、そもそも設定できないのか。3us設定だとちゃんと6usになります。
では、このTimer3を使ってSPIを撃ってみたいと思います。
いつも通り、いきなりですが、こちらで。
#include <TimerTC3.h> #define PORT_MISO PORT_PA05 #define PORT_MOSI PORT_PA06 #define PORT_SCK PORT_PA07 #define PORT_CSN PORT_PA11 #define REG_PORT_IOBUS_DIR0 (*(RwReg *)0x60000000U) #define REG_PORT_IOBUS_DIRCLR0 (*(RwReg *)0x60000004U) #define REG_PORT_IOBUS_DIRSET0 (*(RwReg *)0x60000008U) #define REG_PORT_IOBUS_DIRTGL0 (*(RwReg *)0x6000000CU) #define REG_PORT_IOBUS_OUT0 (*(RwReg *)0x60000010U) #define REG_PORT_IOBUS_OUTCLR0 (*(RwReg *)0x60000014U) #define REG_PORT_IOBUS_OUTSET0 (*(RwReg *)0x60000018U) #define REG_PORT_IOBUS_OUTTGL0 (*(RwReg *)0x6000001CU) #define REG_PORT_IOBUS_IN0 (*(RoReg *)0x60000020U) volatile uint32_t counter; volatile uint32_t txCompleted; volatile uint8_t txBuf; volatile uint8_t rxBuf; void timerISR(){ if(counter&0x0001){ rxBuf=rxBuf<<1; if(REG_PORT_IOBUS_IN0&PORT_MISO){ rxBuf|0x01; } REG_PORT_IOBUS_OUTSET0=(PORT_SCK); }else{ if(txBuf&0x80){ REG_PORT_IOBUS_OUTSET0=(PORT_MOSI); }else{ REG_PORT_IOBUS_OUTCLR0=(PORT_MOSI); } txBuf=txBuf<<1; REG_PORT_IOBUS_OUTCLR0=(PORT_SCK); } counter=counter+1; if(counter>15){ txCompleted=1; } } uint8_t txdata[]={0x55,0x50,0xAA,0xAF}; uint32_t byte_pos; void setup(void){ REG_PORT_IOBUS_DIRSET0=(PORT_MOSI|PORT_SCK|PORT_CSN); REG_PORT_IOBUS_DIRCLR0=(PORT_MISO); REG_PORT_IOBUS_OUTSET0=(PORT_MOSI|PORT_CSN); REG_PORT_IOBUS_OUTCLR0=(PORT_SCK); byte_pos=0; } void loop(void){ txBuf=txdata[byte_pos&0x00000003]; REG_PORT_IOBUS_OUTCLR0=(PORT_CSN); txCompleted=0; counter=0; TimerTc3.initialize(4); TimerTc3.attachInterrupt(timerISR); while(txCompleted==0){ // } TimerTc3.detachInterrupt(); REG_PORT_IOBUS_OUTSET0=(PORT_CSN); byte_pos++; delayMicroseconds(10); }
はい、できましたー。
安全見て4usタイマーにして125kbit/sとなっています。ATmega328Pと比較すると(たった)3倍速い。レジスタ直叩きだともうちょっと何とかなるのかもしれないが、32bitマイコンのレジスタみるのはしんどいので、今回はここまで。
最近、CばっかりやっているからPythonとかもう全然わからなくなってきた、、、ほんの数か月でいろんなことを忘れてしまう。まぁ初老の中年なのでしょーがない。
そうだ、選挙に行こう。
コメントをお書きください