Как прочитать 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;

}



Комментарии   

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

Добавить комментарий

Защитный код
Обновить