AVR Libc Home Page AVRs AVR Libc Development Pages
Main Page FAQ Library Reference Additional Documentation Example Projects

<avr/boot.h>: Bootloader Support Utilities


Detailed Description

    #include <avr/io.h>
    #include <avr/boot.h>
このモジュール内のマクロはAVRのブートローダ機能をサポートするC言語インタフェースを提供します。これらのマクロはどのフラッシュメモリサイズでも動作できるようデザインされています。
Note:
すべてのAVRがブートローダーをサポートされているわけではありません。お使いのプロセッサのデータシートをご参照ください。
Todo:
Maeckからのemail : 小さいデバイス(ATmega64/128以外すべて)では、 __SPM_REG は I/O spaceにありますので、より短い"in","out"命令でアクセス可能です。ブートローダーはサイズ制限が厳しいので、これは重要な最適化になり得ます。(※1.4.3現在、sts命令でアクセスしている模様)


※概要(訳注):

簡単にブートローダープログラムについて書いておきます。詳細はAVRデータシートの解説をお読みください。
大きな流れとして、ブートローダーをサポートしているAVRのフラッシュメモリは、ヒューズビットの設定により、以下の2パートに分けられます。

プログラム場所 書き換え側 状況
NRWW RWW 書き換え可能
NRWW 書き換え可能だが、CPU一時停止、書き込み終了後再開
RWW RWW
NRWW
実質書き換え不能
(書き込み中プログラム消滅、CPUは動き続け暴走)
よって、ブートローダーはNRWW内にあることが望まれます。
ブートローダ外・書き換え領域の一部がNRWWに入ることについては問題ありません。
リセットしたとき、通常、AVRは0番地から実行されますが。RWW領域を消去したりすると割り込みベクタが消滅してしまうので、起動が困難になってしまいます。そのため、ヒューズビット(BOOTRST)の設定により、リセット時ブートセクタ領域からプログラムをスタートさせるようにすることができます。
リセット後ブートセクタから実行し、外部スイッチなどの情報を読み、ブートセクタが要求されればそのまま実行し、そうでなければ0番地に飛びアプリケーションを実行するようなコードを書くことができます。

SPMによる書き込みはISPライタによる書き込みと似ています。32〜128バイト程度のページ単位で消去・書き込みを行えます。
ページアドレス設定・消去(数msecかかる)
SPM動作が終わるまで待つ
while (終わるまで) {
   ページバッファにデータを書き込む(書き込みに時間はかからない)、
}
ページバッファ書き込み(数msecかかる)
SPM動作が終わるまで待つ
各動作は、SPMCRレジスタに行いたい動作を示すビットを書き込み、その後間髪を入れずSPM命令を実行することで行います。
<avr/boot.h>が提供するマクロはこの面倒な手順を容易に使えるマクロ化したものです。
読み出しはLPM命令(WinAVRではpgm_read_byte())を使います。


API Usage Example
以下のコードで典型的なboot APIの使い方を示します。
    #include <inttypes.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>
    
    void boot_program_page (uint32_t page, uint8_t *buf)
    {
        uint16_t i;
        uint8_t sreg;

        // Disable interrupts.

        sreg = SREG;
        cli();
    
        eeprom_busy_wait ();        // eeprom読み書き終了待ち

        boot_page_erase (page);     // 指定ページのメモリ消去
        boot_spm_busy_wait ();      // Wait until the memory is erased.

        for (i=0; i<SPM_PAGESIZE; i+=2)
        {
            // little-endian(下位ビットが後ろ)で2バイトを16bit変数に詰め込む

            uint16_t w = *buf++;
            w += (*buf++) << 8;
        
            boot_page_fill (page + i, w);  // バッファに書き込む
        }

        boot_page_write (page);     // バッファをまとめてフラッシュに書き込む
        boot_spm_busy_wait();       // 書き込みが終わるまで待つ

        // RWWセクションを再度有効にする。
        // この後アプリケーション領域に戻るなら必要になります。

        boot_rww_enable ();

        // 有効な割り込みがあれば、割り込みを有効にする

        SREG = sreg;
    }

Defines

#define BOOTLOADER_SECTION   __attribute__ ((section (".bootloader")))
#define boot_spm_interrupt_enable()   (__SPM_REG |= (uint8_t)_BV(SPMIE))
#define boot_spm_interrupt_disable()   (__SPM_REG &= (uint8_t)~_BV(SPMIE))
#define boot_is_spm_interrupt()   (__SPM_REG & (uint8_t)_BV(SPMIE))
#define boot_rww_busy()   (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
#define boot_spm_busy()   (__SPM_REG & (uint8_t)_BV(SPMEN))
#define boot_spm_busy_wait()   do{}while(boot_spm_busy())
#define GET_LOW_FUSE_BITS   (0x0000)
#define GET_LOCK_BITS   (0x0001)
#define GET_EXTENDED_FUSE_BITS   (0x0002)
#define GET_HIGH_FUSE_BITS   (0x0003)
#define boot_lock_fuse_bits_get(address)
#define boot_page_fill(address, data)   __boot_page_fill_normal(address, data)
#define boot_page_erase(address)   __boot_page_erase_normal(address)
#define boot_page_write(address)   __boot_page_write_normal(address)
#define boot_rww_enable()   __boot_rww_enable()
#define boot_lock_bits_set(lock_bits)   __boot_lock_bits_set(lock_bits)
#define boot_page_fill_safe(address, data)
#define boot_page_erase_safe(address)
#define boot_page_write_safe(address)
#define boot_rww_enable_safe()
#define boot_lock_bits_set_safe(lock_bits)

Define Documentation

 
#define boot_is_spm_interrupt
 )     (__SPM_REG & (uint8_t)_BV(SPMIE))
 

SPM割り込みが有効かチェック.

#define boot_lock_bits_set lock_bits   )     __boot_lock_bits_set(lock_bits)
 

bootloader lock bitsをセット

Parameters:
lock_bits ブートローダーロックビットにセットしたいビットのビットマスク
Note:
ここでは、 '1にセットされたビット' が該当ビットの値を 0 にします。
※ 1の書き込み=該当ビットを0にする。0の書き込み=該当ビットを変更しない。
たとえば、ブートローダーに対するSPM命令を無効とするには、BLB11を0にするので、こうします。
    boot_lock_bits_set (_BV (BLB12));
Note:
他のロックビットと同様、ブートローダーロックビットは一度セットされるとチップイレース以外の方法でクリアすることはできません。これはブートローダープログラム自身もクリアすることになります。
#define boot_lock_bits_set_safe lock_bits   ) 
 

Value:

do { \
    boot_spm_busy_wait();                       \
    eeprom_busy_wait();                         \
    boot_lock_bits_set (lock_bits);             \
} while (0)
boot_lock_bits_set() と同様ですが、実行前にeepromとspmの操作が完了するのを待ちます。
#define boot_lock_fuse_bits_get address   ) 
 

Value:

(__extension__({                                           \
    uint8_t __result;                                      \
    __asm__ __volatile__                                   \
    (                                                      \
        "ldi r30, %3\n\t"                                  \
        "ldi r31, 0\n\t"                                   \
        "sts %1, %2\n\t"                                   \
        "lpm %0, Z\n\t"                                    \
        : "=r" (__result)                                  \
        : "i" (_SFR_MEM_ADDR(__SPM_REG)),                  \
          "r" ((uint8_t)__BOOT_LOCK_BITS_SET),             \
          "M" (address)                                    \
        : "r0", "r30", "r31"                               \
    );                                                     \
    __result;                                              \
}))
アドレスで示されたロックビットまたはヒューズビットを読み出します。

アドレスパラメータとして以下のものが使えます:
  GET_LOW_FUSE_BITS, GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, GET_HIGH_FUSE_BITS.

Note:
返されるロックビット・ヒューズビット値は物理的な値です。0であるビットはプログラムされたビットを表します。
#define boot_page_erase address   )     __boot_page_erase_normal(address)
 

引数addressで示されたアドレスを含むFLASHページを消去します。

Note:
アドレスとはフラッシュ内のバイトアドレスです。ワードアドレスではありません。
#define boot_page_erase_safe address   ) 
 

Value:

do { \
    boot_spm_busy_wait();                       \
    eeprom_busy_wait();                         \
    boot_page_erase (address);                  \
} while (0)
boot_page_erase() と同様ですが、実行前にeepromとspmの操作が完了するのを待ちます。
#define boot_page_fill address,
data   )     __boot_page_fill_normal(address, data)
 

ブートローダーテンポラリページバッファに、ワード型のデータを書き込みます。

Note:
アドレスはバイトアドレスで、データはワード型です。AVRは1度に1ワードをバッファに書き込みます。しかしアドレスはバイト単位です。そのため、アドレスは2ずつインクリメントさせ、、2バイトずつワードフォーマットで送ってください。dataのLSBは下位アドレス、MSBは上位アドレスに書かれます。
#define boot_page_fill_safe address,
data   ) 
 

Value:

do { \
    boot_spm_busy_wait();                       \
    eeprom_busy_wait();                         \
    boot_page_fill(address, data);              \
} while (0)
boot_page_fill() と同様ですが、実行前にeepromとspmの操作が完了するのを待ちます。
#define boot_page_write address   )     __boot_page_write_normal(address)
 

ブートローダーテンポラリページバッファを フラッシュの(address)位置に書き込みます。

Note:
アドレスとはフラッシュ内のバイトアドレスです。ワードアドレスではありません。
#define boot_page_write_safe address   ) 
 

Value:

do { \
    boot_spm_busy_wait();                       \
    eeprom_busy_wait();                         \
    boot_page_write (address);                  \
} while (0)
boot_page_write() と同様ですが、実行前にeepromとspmの操作が完了するのを待ちます。
 
#define boot_rww_busy
 )     (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
 

RWWセクションbusyチェック (レジスタ SPMCRの、ビット RWWSB )

 
#define boot_rww_enable
 )     __boot_rww_enable()
 

Read-While-Write(書き込み中読みだし)メモリセクションを有効にする

 
#define boot_rww_enable_safe
 ) 
 

Value:

do { \
    boot_spm_busy_wait();                       \
    eeprom_busy_wait();                         \
    boot_rww_enable();                          \
} while (0)
boot_rww_enable() と同様ですが、実行前にeepromとspmの操作が完了するのを待ちます。
 
#define boot_spm_busy
 )     (__SPM_REG & (uint8_t)_BV(SPMEN))
 

SPM書き込みbusyチェック

 
#define boot_spm_busy_wait
 )     do{}while(boot_spm_busy())
 

SPM-busyが解除されるまで待つ

 
#define boot_spm_interrupt_disable
 )     (__SPM_REG &= (uint8_t)~_BV(SPMIE))
 

SPM割り込み禁止

 
#define boot_spm_interrupt_enable
 )     (__SPM_REG |= (uint8_t)_BV(SPMIE))
 

SPM割り込み許可

#define BOOTLOADER_SECTION   __attribute__ ((section (".bootloader")))
 
 

".bootloder"と呼ばれる領域に関数や変数を宣言するために用いる。
この領域と領域内のコードはリンク時任意のアドレスにリロケート可能である。(BootLoader NRWW領域など)

#define GET_EXTENDED_FUSE_BITS   (0x0002)
 

boot_lock_fuse_bits_get関数で拡張ヒューズビットを読み出すためのアドレス値。

#define GET_HIGH_FUSE_BITS   (0x0003)
 

boot_lock_fuse_bits_get関数で上位ヒューズビットを読み出すためのアドレス値。

#define GET_LOCK_BITS   (0x0001)
 

boot_lock_fuse_bits_get関数でロックビットを読み出すためのアドレス値。

#define GET_LOW_FUSE_BITS   (0x0000)
 

boot_lock_fuse_bits_get関数で下位ヒューズビットを読み出すためのアドレス値。




Automatically generated by Doxygen 1.4.1 on 23 Jan 2006.