- •I справочный материал ц
- •Подразумевается, что читатель знаком с показательной формой записи действи- етльных чисел.
- •Int a[5]; // массив a[] из 5-и элементов типа int
- •Int a1, a2, a3, a4, a5; // 5 отдельных переменных типа int
- •Void boot_program_page (uint32_t page, uint8_t *buf){
- •Int main(void){
- •Isr_noblock
- •Isr_naked
- •Isr_alias()
- •Isr_aliasof()
- •Isr_block
&
Врезка. Пример
функции самозаписи памяти программ.
#include
<inttypes.h> #include <avr/interrupt.h> #include
<avr/pgmspace.h>
uint16_t
i;
uint8_t
sreg;
//
запрещаем прерывания
sreg
= SREG;
cli();
eeprom_busy_wait();
// ожидаем, завершения предыдущей
записи
boot_page_erase
(page);// стираем указанную страницу
boot_spm_busy_wait();
// ожидаем завершения стирания
//
цикл заполнения страницы памяти
for
(i=0; i<SPM_PAGESIZE; i+=2){
//
заполняем словами «в обратном порядке»
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; }Void boot_program_page (uint32_t page, uint8_t *buf){
Пример: BOOTLOADER_SECTION void funcl(void); - функция func1() будет размещена в области памяти микроконтроллера, отведенной для загрузчика.
GET_LOW_FUSE_BITS
GET_LOW_FUSE_BITS - константа, задающая адрес чтения младшего байта fuse- битов микроконтроллера для применения в boot_lock_fuse_bits_get()
GET_LOCK_BITS
GET_LOCK_BITS - константа, задающая адрес чтения байта lock-битов микроконтроллера для применения в boot_lock_fuse_bits_get()
GET_EXTENDED_FUSE_BITS
GET_EXTENDED_FUSE_BITS - константа, задающая адрес чтения байта расширенных fuse-битов микроконтроллера для применения в boot_lock_fuse_bits_get()
GET_HIGH_FUSE_BITS
GET_HIGH_FUSE_BITS - константа, задающая адрес чтения старшего байта fuse-битов микроконтроллера для применения в boot_lock_fuse_bits_get()
Макросы-функции, определенные в модуле
Так как большинство макросов выполнены в виде макросов-функций, далее они будут рассмотрены без упоминания того, что это не функции на самом деле.
boot_spm_interrupt_enable()
boot_spm_interrupt_enable()
Описание: разрешает прерывания после исполнения инструкции записи в память программ.
boot_spm_interrupt_disable()
boot_spm_interrupt_disable()
Описание: запрещает прерывания после исполнения инструкции записи в память программ.
boot_is_spm_interrupt()
boot_is_spm_interrupt()
Описание: проверяет, разрешены ли прерывания после исполнения инструкции записи в память программ.
boot_rww_busy()
boot_rww_busy()
Описание: проверяет, занята ли секция RWW памяти программ.
boot_spm_busy()
boot_spm_busy()
Описание: проверяет, завершена ли инструкция записи в память программ.
boot_spm_busy_wait()
boot_spm_busy_wait()
Описание: ожидает, пока не завершится инструкция записи в память программ.
boot_lock_fuse_bits_get()
boot_lock_fuse_bits_get(address)
Описание: возвращает считанный байт fuse-битов или lock-битов микроконтроллера в зависимости от значения address, которое может принимать одно из следующих значений: GET_LOW_FUSE_BITS, GET_EXTENDED_FUSE_BITS, GET_HIGH_FUSE_BITS или
GET_LOCK_BITS.
Примечание: возвращается физически реальное значение соответствующего байта, т.е. запрограммированные биты являются нулями, а незапрограммированные биты - единицами.
boot_signature_byte_get()
boot_signature_byte_get(addr)
Описание: возвращает байт из области сигнатуры микроконтроллера. Для микроконтроллеров, поддерживающих калибровочные байты встроенных RC-гене- раторов, этот макрос так же может возвращать и эти значения. Значение addr может находиться в пределах от 0 до 0x1F - см. документацию на примененный микроконтроллер.
boot_page_fill()
boot_page_fill(address, data) Описание: записывает во временный буфер страницы по указанному адресу address заданные данные data.
Примечание: address - это адрес байта, data - это 16-битное значение (слово). AVR адресуют память побайтно, но за один раз записывают слово! Правильное использование макроса заключается в том, чтобы от обращения к обращению увеличивать значение address на 2, а в data помещать сразу по 2 байта, как единое слово.
boot_page_erase()
boot_page_erase(address) Описание: выполняет стирание страницы памяти программ.
Примечание: address - это адрес байта, а не слова.
boot_page_write()
boot_page_write(address) Описание: выполняет запись буфера в указанную address страницу памяти программ.
Примечание: address - это адрес байта, а не слова.
boot_rww_enable()
boot_rww_enable()
Описание: включает доступ к RWW- секции памяти программ.
boot_lock_bits_set()
boot_lock_bits_set(lock_bits) Описание: устанавливает биты защиты загрузчика (BLB-биты). Примечания:
Параметр lock_bits в данном макросе должен содержать единицы в тех позициях, которые должны быть запрограммированы, т.е. записаны в ноль.
Макрос устанавливает только BLB- биты защиты.
Как и любые биты защиты, единожды установленные BLB-биты могут быть стерты только при полном стирании памяти микроконтроллера.
boot_page_fill_safe()
boot_page_fill_safe(address, data) Описание: выполняет то же действие, что и boot_page_fill(), но перед этим дожидается завершения ранее начатой операции самопрограммирования.
boot_page_erase_safe()
boot_page_erase_safe(address) Описание: выполняет то же действие, что и boot_page_erase(), но перед этим дожидается завершения ранее начатой операции самопрограммирования.
boot_page_write_safe()
boot_page_write_safe(address) Описание: выполняет то же действие, что и boot_page_write(), но перед этим дожидается завершения ранее начатой операции самопрограммирования.
boot_rww_enable_safe()
boot_rww_enable_safe()
Описание: выполняет то же действие, что и boot_rww_enable(), но перед этим дожидается завершения ранее начатой операции самопрограммирования.
boot_lock_bits_set_safe()
boot_lock_bits_set_safe(lock_bits)
Описание: выполняет то же действие, что и boot_lock_bits_set(), но перед этим дожидается завершения ранее начатой операции самопрограммирования.
avr/eeprom.h - Поддержка
EEPROM AVR
Этот модуль содержит ряд простых функций и макросов, реализующих основные операции для работы со встроенным EEPROM микроконтроллеров AVR. Все функции действуют по принципу «ожидания», т.е. достаточно длительные. Если требуется реализация работы по прерываниям для максимально эффективного кода, она должна быть реализована пользователем самостоятельно.
Все функции выполняют проверку готовности EEPROM для очередного обращения, но они не контролируют состояние автомата записи в память программ (т.е. самопрограммирования). Если ваша программа содержит код самопрограммирования, вы должны самостоятельно реализовать проверку завершения любой операции самопрограммирования перед обращением к EEPROM.
Так как функции используют фиксированные регистры для работы, они не реен- терабельны, т.е. если эти функции вызываются и из обычного цикла программы и из обработчиков прерываний, следует запрещать глобально прерывания перед обращениям к этим функциям из основной программы.
Определения модуля
Модуль вводит ряд определений (констант и макросов), часть из которых позволяет упростить совместимость исходного текста со средой разработки IAR.
_EEPUT()
_EEPUT(addr, val)
Описание: макрос, осуществляющий запись байта val в EEPROM по адреса addr. Введен для совместимости с IAR.
_EEGET()
_EEGET(var, addr)
Описание: макрос, осуществляющий чтение байта из EEPROM по адресу addr. Введен для совместимости с IAR.
EEMEM
EEMEM
Описание: атрибут, указывающий на то, что переменная должна размещаться в EEPROM. Пример использования: EEMEM int k; - переменная k должна быть размещена в EEPROM.
eeprom_is_ready()
eeprom_is_ready()
Описание: макрос, возвращающий не нулевое значение, если EEPROM готова для очередного обращения, 0 - в противном случае.
eeprom_busy_wait()
eeprom_busy_wait()
Описание: макрос, выполняющий цикл ожидания завершения операции записи в EEPROM.
Функции модуля
Большинство функций реализованы как static inline-функции или макросы-функции.
eeprom_read_byte()
uint8_t eeprom_read_byte (const uint8_t
*p)
Параметры:
const uint8_t *p - указатель на байт в EEPROM
Возвращаемое значение: считанный из EEPROM байт.
Описание: функция выполняет считывание байта по указанному адресу из EEPROM.
eeprom_read_word()
uint16_t eeprom_read_word (const uint16_t *p)
Параметры:
const uint16_t *p - указатель на слово в EEPROM
Возвращаемое значение: считанное из EEPROM слово.
Описание: функция выполняет считывание 16-битного значения из EEPROM.
eeprom_read_dword()
uint32_t eeprom_read_dword (const uint32_t *p)
Параметры:
const uint32_t *p - указатель на двойное слово в EEPROM
Возвращаемое значение: считанное из EEPROM двойное слово.
Описание: функция выполняет считывание 32-битного числа из EEPROM.
eeprom_read_block()
void eeprom_read_block (void *dst, const void *src, size_t n) Параметры:
void *dst - указатель на начало области в ОЗУ
const void *src - указатель на начало области EEPROM
size_t n - количество байт Возвращаемое значение: нет. Описание: функция выполняет считывание n байтов из EEPROM по адресу src и размещает их в ОЗУ, начиная с адреса dest.
eeprom_write_byte()
void eeprom_write_byte (uint8_t *p, uint8_t value)
Параметры:
uint8_t *p - указатель на ячейку в EEPROM
uint8_t value - записываемый байт Возвращаемое значение: нет. Описание: функция выполняет запись байта value в EEPROM по адресу p.
eeprom_write_word()
void eeprom_write_word (uint16_t *p, uint16_t value)
uint16_t *p - указатель на ячейку в EEPROM
uint16_t value - записываемое слово Возвращаемое значение: нет. Описание: функция выполняет запись 16-битного числа value в EEPROM по адресу p.
eeprom_write_dword()
void eeprom_write_dword (uint32_t *p, uint32_t value)
uint32 *p - указатель на ячейку в EEPROM
uint32 value - записываемое двойное слово
Возвращаемое значение: нет. Описание: функция выполняет запись 32-битного числа value в EEPROM по адресу p.
eeprom_write_block()
void eeprom_write_block (const void *src, void *dst, size_t n) Параметры:
void *src - указатель на начало области ОЗУ
void *dst - указатель на начало области в EEPROM
size_t n - количество байт Возвращаемое значение: нет. Описание: функция осуществляет запись n байт из области ОЗУ src в область EEPROM dest.
Следует признать, что модуль eeprom.h от релиза к релизу WinAVR претерпевает существенные модификации, в частности, неоднократно менялись местами параметры функций блочного чтения- записи, что, разумеется, порождает определенные сложности с совместимостью ранее разработанного кода и новой версии компилятора. Поэтому рекомендуется тщательно изучить документацию на свежий релиз WinAVR, т.к. в нем могут быть сюрпризы.
Из числа приятных сюрпризов, появившихся с версии WinAVR 20100110, можно назвать появление «бережных» функций записи EEPROM eeprom_update_xxxx(), где xxxx - это суффикс byte, word, dword или block. Параметры этих функций такие же, как у соответствующих eeprom_write_xxxx(), а отличие в том, что новые функции перед тем, как записать новое значение в ячейку EEPROM, проверяют ее текущее значение и, если оба значения одинаковы, то запись в ячейку не производится. Так как ресурс записей EEPROM AVR ограничен 100000 записей, использование новых функций позволяет увеличить живучесть EEPROM без принятия каких-то особых мер.
Рекомендуется использовать эти функции всегда.
avr/fuse.h - Поддержка
fuse-битов AVR
Модуль позволяет разместить в особой секции ELF-файла информацию о состоянии fuse-битов, которую может извлекать программное обеспечение программатора для установки fuse-битов при программировании микроконтроллера. Размещение этой информации в ELF-файле осуществляется при компоновке программы. К сожалению, в HEX-формате сведения о состоянии fuse-битов размещены быть не могут.
Данный модуль - универсальный, т.е. ориентирован на весь спектр поддерживаемых микроконтроллеров. Необходимо обязательно подключать к проекту модуль io.h, в котором определяются глобальные параметры, используемые затем в модуле fuse.h. Сам модуль fuse.h подключается в этом случае автоматически, поэтому нужды в явном его подключении нет.
В зависимости от типа примененного микроконтроллера fuse-биты могут располагаться в младшем, старшем или расширенном fuse-байте. Для каждого отдельно взятого fuse-бита вводятся константы-маски, соответствующие наименованию fuse-бита, например, FUSE_SPIEN, FUSE_RSTDSBL и т.д.34. Если необходимо установить несколько fuse-битов в одном байте, нужно объединять их при помощи битовой операции AND, т.е. так: (FUSE_SPIEN & FUSE_RSTDISBL & ....).
Для каждого из fuse-байтов конкретного микроконтроллера определены значения fuse-битов по умолчанию, которые следует применять, если изменять их не требуется: LFUSE_DEFAULT для младшего байта, HFUSE_DEFAULT для старшего и EFUSE_DEFAULT для расширенного.
Модуль определяет всего одну глобальную переменную-структуру FUSES, к заданию начальных значений для которой и сводится вся работа с fuse-битами. Данная переменная в зависимости от микроконтроллера может быть разного типа: если микроконтроллер содержит всего один fuse-байт, то эта переменная является просто переменной типа int8_t; если микроконтроллер имеет 2 fuse-байта, то FUSES представляет собой структуру с 2-я полями low и high соответственно типа int8_t каждое; для микроконтроллеров с тремя fuse-байтами
FUSES представляет собой структуру с тремя полями типа int8_t - low, high и extended.
Наконец, если МК содержит более 3-х fuse- байтов, FUSES определена как массив байтов соответствующей длины.
Следует учитывать, что компоновщик использует только значения переменной FUSES, которые были указаны на этапе начальной инициализации, и игнорирует все изменения, которые могли быть сделаны в ходе выполнения программы.
Пример использования см. на врезке.
Важно, что всегда необходимо инициализировать все поля структуры FUSES.
Суть рассматриваемого модуля заключена в том, что получаемый в результате компиляции elf-файл содержит абсолютно всю информацию, необходимую для правильного программирования микроконтроллера. Остается только решить вопрос, какое именно программное обеспечение в состоянии воспользоваться этой информацией. В какой-то мере эту задачу может решить утилита avrdude, входящая в состав WinAVR, однако, только в связке с другой утилитой avr-objcopy. Avrdude - это универсальный программатор, поддерживающий огромное количество схем для прошивки микроконтроллеров AVR, а утилита avr-objcopy позволяет извлекать из elf-файла информационные блоки о flash, eeprom и fuse-битах (из соответствующих секций) и сохранять их в виде hex-файлов, которые уже могут использоваться avrdude для прошивки. К сожалению, обе эти утилиты имеют немалое количество опций запуска, поэтому в рамках данного изложения не рассматриваются (это планируется сделать позже).
avr/interrupt.h - Прерывания
Общие сведения
При обработке прерываний происходит конфликт между декларируемой Си независимостью от аппаратуры, и жесткой привязке векторов прерываний к этой самой аппаратуре. Таким образом, любая реализация обработки прерываний на Си становится уникальной для конкретной среды программирования.
