Введение
Во всех микроконтроллерах 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
Потом невредно узнать размер бут-области, если разные бутлодыри применяются в разными адресами входа. Или, с целью повышения секретности, часть неизменяемых примитивных функций может находиться в бут-области.
Невредно также узнать делится ли фузом системная тактовая частота, если одна и та же прошивка применяется в экономичном и неэкономичном варианте.
RSS feed for comments to this post