ATmega328PのSPIペリヘラルを使わずにタイマーでSPIを出してみる。
Timer2のCTCモードでCompareAとCompareBを使って、任意のスピードでSPIを出すのが目標。
で、いきなりこうなる。
#define PIN_CSN (0x04)
#define PIN_MOSI (0x08)
#define PIN_MISO (0x10)
#define PIN_SCK (0x20)
volatile uint8_t txCompleted;
volatile uint8_t trxCount;
volatile uint8_t emutxSPDR;
volatile uint8_t emurxSPDR;
ISR(TIMER2_COMPA_vect){
emurxSPDR=emurxSPDR<<1;
if(PINB&PIN_MISO){
emurxSPDR|=0x01;
}
PORTB|=(PIN_SCK);
trxCount=trxCount+1;
if(trxCount>15){
txCompleted=1;
TCCR2B&=0xF8;
TIMSK2=0x00;
}
}
ISR(TIMER2_COMPB_vect){
uint8_t tempPORTB;
tempPORTB=PORTB;
if(emutxSPDR&0x80){
tempPORTB&=~PIN_SCK;
tempPORTB|=PIN_MOSI;
}else{
tempPORTB&=~PIN_SCK;
tempPORTB&=~PIN_MOSI;
}
PORTB=tempPORTB;
emutxSPDR=emutxSPDR<<1;
trxCount=trxCount+1;
if(trxCount>15){
txCompleted=1;
TCCR2B&=0xF8;
TIMSK2=0x00;
}
}
uint8_t trxCount_ini[]={0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00};
void Timer2CTC_SPI_MasterStart(uint8_t dataLength_in_bit){
trxCount=trxCount_ini[dataLength_in_bit];
DDRB|=(PIN_MOSI|PIN_SCK);
TCCR2A=0x02;
TCCR2B=0x00;
TCNT2=0x00;
TIFR2=0x07;
TIMSK2=0x06;
OCR2B=0x0C;
OCR2A=0x18;
TCCR2B|=0x02;
}
uint8_t txdata[]={0x55,0x50,0xAA,0xAF};
uint8_t byte_pos;
void setup(void){
DDRB|=PIN_CSN;
PORTB|=PIN_CSN;
byte_pos=0;
}
void loop(void){
txCompleted=0;
emutxSPDR=txdata[byte_pos&0x03];
PORTB&=~(PIN_CSN);
Timer2CTC_SPI_MasterStart(8);
while(txCompleted==0){
//
}
PORTB|=(PIN_CSN);
byte_pos++;
delayMicroseconds(60);
}
SPI波形は出せている。
OCR2B=0x0C;
OCR2A=0x18;
の設定で40kHz。これを小さくすれば速いSPIになるんだけど、これ以上小さくすると、時々クロックパルスが抜けちゃいましたorz。だめだな、遅すぎる。割り込みでやっていることをもっと小さくすると速くなるのか?
で、こんなコードでやってみた。ピン上げ下げだけ。
#define PIN_SCK (0x20)
ISR(TIMER2_COMPA_vect){
PORTB|=(PIN_SCK);
}
ISR(TIMER2_COMPB_vect){
PORTB&=~(PIN_SCK);
}
void setup(void){
DDRB|=(PIN_SCK);
TCCR2A=0x02;
TCCR2B=0x00;
TCNT2=0x00;
TIFR2=0x07;
TIMSK2=0x06;
OCR2B=0x08;
OCR2A=0x10;
TCCR2B|=0x02;
}
void loop(void){
}
約60kHzで、2msくらいに一回、パルスがおかしくなる。Timer0が悪さしてるのかな?とにかく、Arduino bootloaderの書かれているATmega328PのTimer2では正確で速いものは作れない。クソッ。

コメントをお書きください