Как прочитать fuse биты AVR из программы

04/09/2013 - 20:47 Павел Бобков

Введение   

   Во всех микроконтроллерах AVR есть конфигурационные fuse биты. Это такие биты, которые задают ряд глобальных настроек микроконтроллера, например, источник тактового сигнала, пороговое напряжение схемы сброса, размер загрузочной области, разрешение сторожевого таймера и т.д. 
   
   Fuse биты хранятся во флэш памяти, поэтому сохраняют свое значение при отсутствии питания. Обычно они устанавливается однократно на этапе первичного программирования прошивки.

   Неправильно установленные fuse биты могут нарушить работу системы. В лучшем случае микроконтроллер будет работать, например, на неправильной частоте, а в худшем мы потеряем возможность программирования микроконтроллера по SPI интерфейсу. Это может произойти или по не знанию, или в результате случайной ошибки. 

   Существует способ, который может предотвратить часть таких ситуаций. Он состоит в том, чтобы заложить в программу микроконтроллера сравнение fuse битов с требуемыми значениями. Что-то вроде самоконтроля. Но для того чтобы их можно было проверять, их нужно сначала прочитать. И сейчас мы разберемся, как это сделать.

   Сразу оговорюсь, пример будет для IAR`a. Просто у меня сейчас нет доступа к Atmel Studio, потому что я не дома.

Чтение fuse и lock битов из программы

   Fuse и lock биты расположены в специальных регистрах в энергонезависимой памяти. Для доступа к этим регистрам нужно выполнить ряд действий:

- загрузить в регистровую пару ZH:ZL адрес,
- установить в управляющем регистре SPMCR биты BLBSET и SPMEN,
- выполнить ассемблерную инструкцию lpm.

   Поскольку мы программируем на Си, в нашем случае задача будет решаться более простым способом, с помощью встроенной функции IAR`a. Она выполнит за нас практически все эти действия. Прототип функции описан в файле intrinsics.h и выглядит следующим образом.


unsigned char __AddrToZByteToSPMCR_LPM(void __flash* addr, unsigned char byte);


   Функция принимает два параметра. Это адрес флэш памяти и байт, загружаемый в регистр SPMCR.
SPMCR – регистр, управляющий операциями записи и чтения флэш памяти. Для чтения fuse битов в этот регистр нужно загрузить число 9.

   Адреса, по которым расположены fuse биты следующие:

fuse low bits            0x0000
fuse high bits           0x0003
fuse extended bits   0x0002
lock bits                  0x0001

   Используя эти данные, можно написать макросы для чтения fuse битов.


/* макросы для чтения fuse битов */
#define _SPM_GET_LOW_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0000U, 0x09U)
#define _SPM_GET_HIGH_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0003U, 0x09U)
#define _SPM_GET_EXTENDED_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0002U, 0x09U)


А для чтения lock битов в файле intrinsic.h уже есть макрос.


#define _SPM_GET_LOCKBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0001, 0x09)

Пример

   Ну и небольшой пример как могла бы выглядеть программа с начальной проверкой fuse битов.


#include <ioavr.h>
#include <intrinsics.h>
#include <stdint.h>

/* макросы для чтения fuse битов */
#define _SPM_GET_LOW_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0000U, 0x09U)
#define _SPM_GET_HIGH_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0003U, 0x09U)
#define _SPM_GET_EXTENDED_FUSEBITS() __AddrToZByteToSPMCR_LPM((void __flash*)0x0002U, 0x09U)

/* структрура для сохранения fuse битов */
typedef struct{
   uint8_t fuseLow; 
   uint8_t fuseHigh; 
   uint8_t fuseExtended; 
   uint8_t lockbits;
} fuseSettings_t;

volatile fuseSettings_t value;

void FUSE_Read(void)
{
   value.fuseLow = _SPM_GET_LOW_FUSEBITS();
   value.fuseHigh = _SPM_GET_HIGH_FUSEBITS(); 
   value.fuseExtended = _SPM_GET_EXTENDED_FUSEBITS();
   value.lockbits = _SPM_GET_LOCKBITS();
}


int main( void )
{
   /*считываем fuse биты*/
   FUSE_Read();

   /*проверяем fuse биты*/
   if (value != ...){

      /*если биты не соответствуют эталону, сигнализируем пользователю*/
        ...
   }

   while(1);
   return 0;

}



Comments   

# Ruzanov Andrey 2013-09-05 03:59
Интересная статья, а возможно записать биты из кода. было бы удобно при ошибке исправить на требуемое значение.
# Pashgan 2013-09-05 12:10
По моему только lock биты можно менять из программы.
# Plotnik 2013-09-05 06:32
Есть хорошая связка-AS 6 и AVR Burn_o_Mat,где можно и проверить,и читать и записать фьюз-биты.А для проверки (кто сомневается в установке фьюз-бит) калькуляторwww.engbedded.com/fusecalc/.
# Pashgan 2013-09-05 11:54
Это любой программатор позволяет делать.
# megannnn98 2013-09-05 08:03
Спасибо за статью. Просьба, по возможности, добавить как это делать на AS6
# Pashgan 2013-09-05 11:54
Хорошо. Главное не забыть, потому что я только через пару недель домой вернусь.
# САБ 2013-09-08 12:01
А я думаю, что надо пользоваться программатором, который читает требуемое значение фузов из файла. Их значение в этом файле один раз проверятеся на этапе отладки и возможность при прошивке случайно их выставить неправильно изчезает, вместе с необходимостью их проверять изнутри прошивки. Так что считаю способность читать фузы из программы без возможноси их исправить самой бесполезной функцией в МК.
# Peter 2013-09-10 08:53
Это Вы зря. Конечно не часто, но узнать тип МК на котором запущено никогда не вредно. Взять хоть атмеги 64 и 128 - вроде всё одинаково но размер ЕПРОМ и биты в ADC разные.
Потом невредно узнать размер бут-области, если разные бутлодыри применяются в разными адресами входа. Или, с целью повышения секретности, часть неизменяемых примитивных функций может находиться в бут-области.
Невредно также узнать делится ли фузом системная тактовая частота, если одна и та же прошивка применяется в экономичном и неэкономичном варианте.
# ESC 2014-03-28 07:44
Автор, сам пробовал??? Контроллер зависает при вызове FUSE_Read() (МК - Atmega128).
# Pashgan 2014-03-28 08:31
Да. Mega16, Mega8535, IAR 5.11 - все читается, ничего не зависает.

У вас недостаточно прав для комментирования.