· 

SPIをTimer3で(Seeeduino XIAO)

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とかもう全然わからなくなってきた、、、ほんの数か月でいろんなことを忘れてしまう。まぁ初老の中年なのでしょーがない。

 

そうだ、選挙に行こう。