我写信给ATmega328P EEPROM如下:

eeprom_write_byte(address, (U8_T) 0);
void eeprom_write_byte(void* address, U8_T data)
{
    cli();
    /* Wait for previous write to complete */
    while (TRUE == EECR.bits.EEPE) {
    }

    /* Set erase-and-write mode */
    EECR.bits.EEPM0 = FALSE;
    EECR.bits.EEPM1 = FALSE;

    /* Set up write */
    EEAR.byte = (U8_T) address;
    EEDR.byte = data;

    /* Enable master write */
    EECR.bits.EEMPE = TRUE;
    /* Enable write */
    EECR.bits.EEPE = TRUE;
    sei();
}

其中,EECREEAREEDR的链接方式如下:

SECTIONS {
  EEAR          = 0x41;
  EEDR          = 0x40;
  EECR          = 0x3F;
  ... 

EEMPEEEPE肯定必须设置在彼此的4个时钟周期内,对吗?

然后,我从EEPROM中读取如下内容:

U8_T eeprom_read_byte(void* address)
{
    cli();
    /* Wait for previous write to complete */
    while (TRUE == EECR.bits.EEPE) {
    }

    /* Set up read */
    EEAR.byte = (U8_T) address;
    /* Enable read */
    EECR.bits.EERE = TRUE;

    sei();

    return EEDR.byte;
}

但我只能拿回0xFF块钱!erased的价值!数据手册指出,设置为0的EEPM0和EEPM1应擦除并写入.但似乎没有发生任何写作.有什么主意吗?

我try 使用-O2进行编译,但没有结果.另一个帖子告诉我使用-03,但-03 destruct 了我的程序(链接器失败).无论如何,我在航空航天工作,优化是被禁止的,所以它必须在没有它们的情况下工作.

寄存器的定义如下:

/** EEPROM Control Register */
typedef union {
    struct {
        /** EEPROM Read Enable */
        VBOOL_T EERE        : 1;
        /** EEPROM Write Enable */
        VBOOL_T EEPE        : 1;
        /** EEPROM Master Write Enable */
        VBOOL_T EEMPE       : 1;
        /** EEPROM Ready Interrupt Enable */
        VBOOL_T EERIE       : 1;
        /** EEPROM Mode Bits */
        VBOOL_T EEPM0       : 1;
        VBOOL_T EEPM1       : 1;
        VBOOL_T Reserved6   : 1;
        VBOOL_T Reserved7   : 1;
    } bits;
    VU8_T byte;
} EECR_T;
/** EEPROM Control Register */
extern volatile EECR_T EECR;

推荐答案

我没有使用过这一部分,但手册13.6.4描述了该过程:

  1. 等待直到EEPE变为零.
  2. 等待SPMCSR中的SPMEN变为零.
  3. 将新的EEPROM地址写入EEAR(可选).
  4. 将新的EEPROM数据写入EEDR(可选).
  5. 在向EECR中的EEPE写入0的同时,向EEMPE位写入‘1’.
  6. 在设置EEMPE后的四个时钟周期内,将‘1’写入EEPE.
  1. 好的,好的.

  2. 你不能这么做.

  3. 你这样做,但只对ls字节EEARL.也就是说,如果地址大于EEARH偏移量256,则代码将无法工作,因为您没有写入EEARH.或者,如果EEARH中留下了杂散值,程序就会失控.

  4. 好的,好的.

  5. 嗯.您正在使用C中不推荐的位字段功能.我不确定EECR.bits.EERE = TRUE;是否会在汇编器级别上导致字节指令或位指令.在后者的情况下,EEPE不会像手册上说的那样被写为零.

    推荐的做法是永远不要使用位字段,而是一次写入整个寄存器,这样你就可以确保EEPE会被设置.

  6. 是的,在执行EECR.bits.EEPE = TRUE;之前没有4个时钟周期延迟似乎是合理的.但这又一次取决于所有的位场粘性结果.也许在最坏的情况下,某些东西被转换为读入寄存器、修改寄存器、写入寄存器序列.在这种情况下,执行远多于4个时钟周期.

理解正在发生的事情的关键是查看程序的反汇编,看看实际生成了什么.AVR ASM很容易阅读,即使对于像我这样从未使用过它的人也是如此.


与此无关的是,您的驱动程序中还有另一个严重的错误.驱动程序应该nevertouch 全局中断屏蔽cli/sei.特别是不能像下面的代码那样销毁它以前的值.如果您曾经接触过这些寄存器,您需要堆叠CCR并在之后恢复它.

EEPROM驱动器may被允许禁用所有中断,但前提是其通过重置MCU来结束整个写入会话.

通常的做法是通过安全模式进入EEPROM编程,在该模式下,在编程开始之前禁用所有中断.一旦完成,等待WDOG或通过将错误的序列写入其寄存器来重启MCU.

在EEPROM更新后重新开始以前的执行是一种危险的做法,因为程序的所有部分都不一定连续地从EEPROM取值.

C++相关问答推荐

CC crate 示例不会与C函数链接

Ebpf内核代码:permission denied:invalid access to map value

__VA_OPT__(,)是否可以检测后面没有任何内容的尾随逗号?

将整数的.csv文件解析为C语言中的二维数组

如何在不使用其他数组或字符串的情况下交换字符串中的两个单词?

为什么GDB/MI进程的FIFO循环中有read()阻塞

在句子中转换单词的问题

用C++实现余弦函数

C I/O:在Windows控制台上处理键盘输入

编译器如何处理具有更复杂值的枚举?

预处理器宏扩展(ISO/IEC 9899:1999(E)§;6.10.3.5示例3)

Linux分段故障(核心转储)

用C++高效解析HTTP请求的方法

在printf()中用%.*S格式填充长度为0的字符串是否会调用任何UB?如果是,是哪一个?

从文件到链表读取日期

中位数和众数不正确

如何找出C中分配在堆上的数组的大小?

保存有符号整数结果的变量是否会溢出(后增量的副作用),并且此后从未在任何表达式中使用过它,是否会导致 UB?

将数组返回到链表

创建 makefile 来编译位于不同目录中的多个源文件