Чтение фьюзов на ATmega328P

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не знаю, кому и зачем это может нафиг понадобиться, но на Амперке кому-то приспичило, решил сдублировать здесь. Вдруг и нашим кому пригодится.

Собственно, читаем из программы фьюзы и локбиты. Все пояснения в даташите  на 328P, раздел 26.2.2. Если после это нужно с этими фьюзами работать, можно использовать константы (битовые маски), которые определены в файле iom328p.h. Включать его не надо, он у Вас уже включён.

#define	LFUSE	0
#define	HFUSE	3
#define	EFUSE	2
#define	LOCKB	1

uint8_t readFuse(const uint8_t fuse = 0) {
	uint8_t retval = 0;
	__asm__ __volatile__ (
		"mov zl, %[param] \n"	
		"ldi zh, 0 \n"
		"in	r25, %[reg] \n"
		"ori	r25, %[mask] \n"
		"out	%[reg], r25 \n"
		"lpm	%[retval], Z \n"
	:  [retval] "=r" (retval)
	:  [reg] "I" (_SFR_IO_ADDR(SPMCSR)), [mask] "I" (bit(BLBSET) | bit(SPMEN)), [param] "r" (fuse)
	: "r25", "r30", "r31"
	);
	return retval;
}

void setup(void) {
	Serial.begin(115200);
	Serial.print("Low fuse="); Serial.println(readFuse(LFUSE), HEX);
	Serial.print("High fuse="); Serial.println(readFuse(HFUSE), HEX);
	Serial.print("Extended fuse="); Serial.println(readFuse(EFUSE), HEX);
	Serial.print("Lock bits="); Serial.println(readFuse(LOCKB), HEX);
}

void loop(void) {}
Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Нада было там тока ссылку дать. Пусть сюда ходят.

Green
Offline
Зарегистрирован: 01.10.2015

Как всё накручено... Любит у нас народ изобретать.
 

#include <avr/boot.h>;

void setup()
{
  cli();
  uint8_t lowBits      = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS);
  uint8_t highBits     = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
  uint8_t extendedBits = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS);
  uint8_t lockBits     = boot_lock_fuse_bits_get(GET_LOCK_BITS);
  sei();
  
  Serial.begin(9600);
  Serial.print("Low fuse = ");      Serial.println(lowBits, HEX);
  Serial.print("High fuse = ");     Serial.println(highBits, HEX);
  Serial.print("Extended fuse = "); Serial.println(extendedBits, HEX);
  Serial.print("Lock bits = ");     Serial.println(lockBits, HEX);
}

void loop() 
{
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вот так и думал, что такая функция уже есть где-то готовая :)

Ну, тогда будем считать, что я просто показал как она внутри делается :)

Кстати, там она сделана в виде макроса, а не функции и использует "sts"  вместо моей комбинации "in - ori - out". Т.е. они не только взводят в единицы нужные биты, но и заодно обнуляют все остальные. Я так побоялся делать, но, наверное, можно :)

#define boot_lock_fuse_bits_get(address)                   \
(__extension__({                                           \
    uint8_t __result;                                      \
    __asm__ __volatile__                                   \
    (                                                      \
        "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)),           \
          "z" ((uint16_t)(address))                        \
    );                                                     \
    __result;                                              \
}))

 

Green
Offline
Зарегистрирован: 01.10.2015

Иногда нужно заказчику запудрить мозги... Увидев такой код, лох просто цепенеет.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

А вот искал и, тут решение, в закладочку добавлю

arduinec
Offline
Зарегистрирован: 01.09.2015

SysInfo кроме фьюзов ещё и сигнатуры читает, и по сигнатурам определяет контроллер (#74):
http://arduino.ru/forum/programmirovanie/sysinfo-arduino?page=1#comment-...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Я вот знаете о чём думаю. Вот, что в моём решении, что в решении из boot.h (пост #3) нет никаких cli, а ведь если между записью битов в регистр и командой lpm произойдёт прерывание, то потом lpm бред считает.

Я вот не поставил умышленно, типа мол если есть опасность прерываний ставь снаружи, а лишний раз прерывания закрывать не дело. Но так тввёрдо и не уверен, что прав. Может лучше было поставить. Они там (авторы boot.h) тоже из таких соображений не стали ставить? На самом деле - это ведь залёт, при определённых условиях.

sadman41
Offline
Зарегистрирован: 19.10.2016

При чтении серийника я ставлю запрет. Читал где-то дискуссию давно уже, с тех пор и ставлю...

Green
Offline
Зарегистрирован: 01.10.2015

Это уже по ситуации. Обычно использую save_interrupt()/restore_interrupt() - макросы сохраняющие и восстанавливающие SREG и запрещаю прерывания на время чтения фьюзов/локов.

Green
Offline
Зарегистрирован: 01.10.2015

arduinec пишет:

SysInfo кроме фьюзов ещё и сигнатуры читает, и по сигнатурам определяет контроллер (#74):
http://arduino.ru/forum/programmirovanie/sysinfo-arduino?page=1#comment-...


Ага, только какие то школьные ошибки в сообщениях: "Unrecogized signature".))

arduinec
Offline
Зарегистрирован: 01.09.2015

Green пишет:

arduinec пишет:

SysInfo кроме фьюзов ещё и сигнатуры читает, и по сигнатурам определяет контроллер (#74):
http://arduino.ru/forum/programmirovanie/sysinfo-arduino?page=1#comment-...


Ага, только какие то школьные ошибки в сообщениях: "Unrecogized signature".))

Вот глаз-алмаз - за целый год никто эту опечатку не заметил. Спасибо, исправлю.

vvadim
Offline
Зарегистрирован: 23.05.2012

Green пишет:

Иногда нужно заказчику запудрить мозги... Увидев такой код, лох просто цепенеет.)

и зачем вы обижаете 99% участников форума)))))

Green
Offline
Зарегистрирован: 01.10.2015

Зато правда.)

Green
Offline
Зарегистрирован: 01.10.2015

arduinec пишет:

Вот глаз-алмаз - за целый год никто эту опечатку не заметил. Спасибо, исправлю.

Я бы вообще советовал писать по русски. Тогда у людей не будет никаких вопросов.)