【原创】读取 UNO 的 AVR 熔丝等信息-Arduino中文社区 - Powered by Discuz! Archiver

t3486784401 发表于 2019-3-21 18:25

【原创】读取 UNO 的 AVR 熔丝等信息

本帖最后由 t3486784401 于 2019-3-21 18:25 编辑

UNO 使用 AVR 控制器 M328P,在一些时候需要知道熔丝配置信息(例如确认工作状态)。
正常情况下这些信息需要 ISP 下载器(例如2313那个)来读取,但是 AVR 支持用户程序访问,
这索性用内联汇编写了段读取代码,直接用IDE下进去就能读出了。

至于这些信息怎么用,需要参考 AVR 手册,无非就是晶振选择、掉电检测、BOOT范围等等。
其中 Fuse: 熔丝位,Lock: 锁定位,Sign: 签名位(对应AVR型号),
最后一项 OSCCAL 是芯片校正字,在小规模下可以用作 AVR 的指纹(重复几率 1/256)。

uint8_t ReadINFO(uint8_t idx)
{
    // Read INFO(idx=0~7)
    const uint8_t CmdTable=
    {
      // = SPMCSR
      // = Z-PTR
      _BV(SIGRD)|_BV(SPMEN), 0,   // Signature 1
      _BV(SIGRD)|_BV(SPMEN), 2,   // Signature 2
      _BV(SIGRD)|_BV(SPMEN), 4,   // Signature 3
      _BV(SIGRD)|_BV(SPMEN), 1,   // OSCCal
      _BV(BLBSET)|_BV(SPMEN), 2,// Fuse Extended Byte
      _BV(BLBSET)|_BV(SPMEN), 3,// Fuse High Byte
      _BV(BLBSET)|_BV(SPMEN), 0,// Fuse Low Byte
      _BV(BLBSET)|_BV(SPMEN), 1,// Lock Bits
    };
    uint8_t cmd= CmdTable;
    uint8_t adr= CmdTable;
    uint8_t dat= 0;
    // Save/Restore Z data
    __asm__ __volatile__("push r30\n" "push r31\n");
    // Z=addr, dat=(Z)
    while(SPMCSR&_BV(SPMEN));         // Wait until idle
    __asm__ __volatile__("clr r31\n" "mov r30, %0\n" :"+r"(adr));
    SPMCSR= cmd;
    __asm__ __volatile__("lpm %0, Z" :"=r"(dat));
    // Save/Restore Z data
    __asm__ __volatile__("pop r31\n" "pop r30\n");
    return dat;
}

运行结果:


附上完整代码:

欢迎大家指点或报告 BUG.........
页: [1]
查看完整版本: 【原创】读取 UNO 的 AVR 熔丝等信息