Enchan1207 / avr-serial

Asynchronous serial communication interface (UART) library for AVR microcontroller

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

非同期シリアル送信

Enchan1207 opened this issue · comments

ちょっと色々やればいけそう?

これで一応非同期にはなったんだけど、どうやら 割り込みベクタUSART_UDRE_vect(送信バッファ空き)が レベル割り込みっぽい んだよな

When the data register empty interrupt enable (UDRIEn) bit in UCSRnB is written to one, the USART data register empty interrupt will be executed as long as UDREn is set (provided that global interrupts are enabled). UDREn is cleared by writing UDRn. When interrupt-driven data transmission is used, the data register empty interrupt routine must either write new data to UDRn in order to clear UDREn or disable the data register empty interrupt, otherwise a new interrupt will occur once the interrupt routine terminates.

(ATmega328P [DATASHEET] p.151より引用)

UCSRnB のデータ レジスタ エンプティ割り込みイネーブル (UDRIEn) ビットに 1 が書き込まれると、UDREn がセットされている限り、USART データ レジスタ エンプティ割り込みが実行されます (グローバル割り込みがイネーブルされている場合)。 UDRn を書き込むと、UDREn はクリアされます。 割り込み駆動のデータ送信が使用される場合、データ レジスタの空の割り込みルーチンは、UDREn をクリアするために新しいデータを UDRn に書き込むか、データ レジスタの空の割り込みを無効にする必要があります。そうしないと、割り込みルーチンが終了すると新しい割り込みが発生します。

つまり、仮にこういうコードを書くとすると:

ISR(USART_UDRE_vect) {
    // 何もせずLEDを点灯
    bit_set(PORTB, LED_BUILTIN);

    // ガバ待機
    volatile uint16_t i = 0xFFFF;
    while (true) {
        i--;
        if (i == 0) {
            break;
        }
    }

    // 消灯
    bit_reset(PORTB, LED_BUILTIN);
    // ガバ待機
    i = 0xFFFF;
    while (true) {
        i--;
        if (i == 0) {
            break;
        }
    }
}

UDRへのアクセスが発生しないのでUDREnはクリアされない -> UDREnがセットされたまま -> UDREエンプティ割り込みが発火、USART_UDRE_vect ベクタが呼ばれる

を繰り返すので、実質的なLチカとなる

つまり、送信可能なデータがないときはUDREエンプティ割り込みごとdisableしなければならない

とりあえずこの辺の設計に気をつけつつ HardwareSerial にならって USART クラスを作ってみますか

…でも命名的には Serial の方がベターなのかなあ ([A-Z]+がクラス名になるのはどうなんだ?)

ただこのissueの内容ではないので一旦close