USIはATtinyにあり、ATmegaにはない機能です。ATmegaには各種シリアル通信の機能がすでに備わっていて比較的簡単に使用できるので、こんなものはいらないんだと思います。ATtinyは小さい回路でいろんな機能を実現するためにこういう実装になったのでしょう。が、それゆえにちょっと自由度があるのがちょっといいね。
AVR319っていうドキュメントを参考にするんだけど、MichrochipのページからIAR(gccじゃないのであくまで参考)のコードを見る方法がわからない。google先生にUSI attiny spiって聞くとここに見つかる。ちなみにAVR.jpの応用記述からAVR319を見に行くと日本語化したドキュメントとZIP圧縮したコードがある。AVR.jpすばらしい。もう10年以上時々見ているけど、変わらず存在していることがすばらしい。
で、データシートとドキュメントを頼りにとりあえずSPIマスターっぽい波形を出力するコードを作成した。あいかわらず説明はない。データシートを読んでください。USIのStrobeにはTimer0を使うことができますが、Arduino化したことでTimer0は使えないのでTimer1でsoftware strobeにします。また、これによりデータセットのタイミングをUSICS0によってrisingにするかfallingにするか選択できます。
#include <avr/iotnx4.h>
#define PIN_DI (0x40)
#define PIN_DO (0x20)
#define PIN_SCL (0x10)
volatile uint8_t txCompleted;
volatile uint8_t rxUSIDR;
volatile uint8_t stat;
ISR(TIM1_COMPA_vect){
USICR|=0x01;/*Toggle Clock Port Pin*/
}
ISR(USI_OVF_vect){
TIMSK1&=~(0x02);/*clear Timer/Counter1 Output Compare A Match Interrupt Enable*/
TCCR1B&=~(0x01);
USISR=0x40;/*Write 1 to clear Counter Overflow Interrupt Flag*/
txCompleted=1;
rxUSIDR=USIDR;
}
uint8_t wrtval[]={0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uint8_t valpos=0;
void setup(void){
stat=0;
DDRA|=(PIN_DO|PIN_SCL);
DDRA&=~(PIN_DI);
PORTA|=(PIN_DI|PIN_SCL);
USICR=0x5A;
TCCR1A=0x00;
OCR1A=0x0020;
TCCR1B=0x08;
}
void loop(void){
if((USISR&0x0F)==0x00){
if(++valpos>8){valpos=0;}
delay(200);
USIDR = wrtval[valpos];
txCompleted=0;
TIFR1|=0x02;
TCCR1B|=0x01;
TIMSK1=0x02;
}
}
USICR=0x5A;をUSICR=0x5E;ってすると、CPHAを1か0か選択できる。CPOLは今0だけど、1にする方法はわからない。そういう時は外部インバーターだわ、、、(逃げ)。いや、USIではできないらしい。しょーがないので、そういう場合はやはりインバーターだわ。
それはさておき、ビット数が8未満のデータを送りたいときどうするか、
USISRをいじってからタイマーをスタートする。USISRの上位4ビットは状態ビットなので、0を書いちゃってもOKだろう。なので、
| 送信ビット数 | USISR |
| 1 | 0x0E |
| 2 | 0x0C |
| 3 | 0x0A |
| 4 | 0x08 |
| 5 | 0x06 |
| 6 | 0x04 |
| 7 | 0x02 |
| 8 | 0x00 |
ってすればよい(たぶん)。
まぁいいかんじ。
いやーしかし暑くてやる気がおきんね。暑くなる前からそんなにやる気があったわけじゃないけど。

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