AVR Libc Home Page | ![]() |
AVR Libc Development Pages | ||
Main Page | FAQ | Library Reference | Additional Documentation | Example Projects |
#include <avr/io.h> #include <avr/boot.h>
このモジュール内のマクロはAVRのブートローダ機能をサポートするC言語インタフェースを提供します。これらのマクロはどのフラッシュメモリサイズでも動作できるようデザインされています。
_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())を使います。
#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) |
|
SPM割り込みが有効かチェック. |
|
bootloader lock bitsをセット
boot_lock_bits_set (_BV (BLB12));
|
|
Value: do { \ boot_spm_busy_wait(); \ eeprom_busy_wait(); \ boot_lock_bits_set (lock_bits); \ } while (0) |
|
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; \ })) アドレスパラメータとして以下のものが使えます:
|
|
引数addressで示されたアドレスを含むFLASHページを消去します。
|
|
Value: do { \ boot_spm_busy_wait(); \ eeprom_busy_wait(); \ boot_page_erase (address); \ } while (0) |
|
ブートローダーテンポラリページバッファに、ワード型のデータを書き込みます。
|
|
Value: do { \ boot_spm_busy_wait(); \ eeprom_busy_wait(); \ boot_page_fill(address, data); \ } while (0) |
|
ブートローダーテンポラリページバッファを フラッシュの(address)位置に書き込みます。
|
|
Value: do { \ boot_spm_busy_wait(); \ eeprom_busy_wait(); \ boot_page_write (address); \ } while (0) |
|
RWWセクションbusyチェック (レジスタ SPMCRの、ビット RWWSB ) |
|
Read-While-Write(書き込み中読みだし)メモリセクションを有効にする |
|
Value: do { \ boot_spm_busy_wait(); \ eeprom_busy_wait(); \ boot_rww_enable(); \ } while (0) |
|
SPM書き込みbusyチェック |
|
SPM-busyが解除されるまで待つ |
|
SPM割り込み禁止 |
|
SPM割り込み許可 |
|
|
|
boot_lock_fuse_bits_get関数で拡張ヒューズビットを読み出すためのアドレス値。 |
|
boot_lock_fuse_bits_get関数で上位ヒューズビットを読み出すためのアドレス値。 |
|
boot_lock_fuse_bits_get関数でロックビットを読み出すためのアドレス値。 |
|
boot_lock_fuse_bits_get関数で下位ヒューズビットを読み出すためのアドレス値。 |