Данные не сохраняются в EEPROM

Я использовал следующий код для доступа к eeprom:

void EEPROM_write(unsigned int uiAddress,unsigned char ucData)
{
   while(EECR & (1<<EEWE))
   {
      //do nothing
   }

   while(SPMCR & (1<<SPMEN));
   EEAR = uiAddress;
   EEDR = ucData;
   EECR |= (1<<EEMWE);
   EECR |= (1<<EEWE);
}

char EEPROM_read(unsigned int uiAddress)
{
   while(EECR & (1<<EEWE))
   {
      //do nothing
   }

   EEAR = uiAddress;
   EECR |=(1<<EERE);
   return EEDR;
}

void EEPROM_write_str(unsigned int uiAddress,unsigned char* string,unsigned int size)
{
   int i;
   for(i=0;i<size;i++)
   {
      EEPROM_write(uiAddress+i,string[i]);
   }
}

void EEPROM_read_str(unsigned int uiAddress,unsigned char* string,unsigned int size)
{
   int i;
   for(i=0;i<size;i++)
   {
      string[i] = EEPROM_read(uiAddress+i);
   }
}

char str[]="hello ";
char str2[20];

int main()
{
   usart_init(12);
   //EEPROM_write_str(0,str,6);
   EEPROM_read_str(0,str2,6);
   usart_puts(str2,6);
}

В приведенном выше коде я сначала прокомментировал EEPROM_read_str и usart_puts,... прошил его, затем прокомментировал функцию EEPROM_write_str и удалил комментарии из двух других и снова прошил. Несмотря на это, данные не сохраняются, а вывод отображается в терминале. yyyyy (hex-FF). В чем проблема? (Здесь USART_puts передает строку, принимая второй аргумент в виде количества символов)


person nalostta    schedule 08.08.2017    source источник
comment
Есть eeprom по адресу 0? Где вы стираете eeprom перед записью?   -  person Lundin    schedule 08.08.2017
comment
@Lundin Это EEPROM по адресу от 0 до 1023, я думаю   -  person nalostta    schedule 08.08.2017
comment
@Lundin AVR-s - это архитектура Hardvare, и все памяти имеют разделенные адресные пространства. У AVR есть возможность сделать это во время записи. Ячейка стирается и пишется за один раз. Он вызывается atmel как атомарная запись eeprom   -  person 0___________    schedule 10.08.2017


Ответы (2)


Рабочий код из моего старого проекта avr. Я не использую их в течение многих лет, поэтому предоставьте как есть, так как я не помню точное значение битов сейчас.

void EEPROM_write(uint8_t addr, uint8_t value) {
    while(EECR & (1 << EEPE)) ;             //wait for write enable bit to clear
    EECR &= ~((1 << EEPM1) | (1 << EEPM0)); // (erase & write in one operation)
    EEARL = addr;                           // set the address
    EEDR = value;                           // set value to be written
    EECR |= (1 << EEMPE);                       // set EEPROM Master Write Enable
    EECR |= (1 << EEPE);                        // set EEPROM Master Write Enable
}

uint8_t EEPROM_read(uint8_t addr) {
    while(EECR & (1 << EEPE)) ;             
    EEARL = addr;                           // set the address
    EECR |= (1 << EERE);
    return EEDR;
}
person 0___________    schedule 08.08.2017
comment
Проблема не в этом .... когда я выполняю операции записи и чтения за один раз, данные возвращаются одинаково, однако сброс контроллера приводит к стиранию данных ... - person nalostta; 08.08.2017
comment
Этот код используется в устройствах, продаваемых десятками тысяч – и он всегда сохранял ценность. Первый байт довольно хитрый - иногда он уничтожается на некоторых сериях uC (разные партии один в порядке, а другой нет), поэтому избегайте первого байта, а также помните о мощности. - person 0___________; 08.08.2017
comment
Тогда попробуй мой чек - person 0___________; 08.08.2017
comment
Первый байт довольно хитрый - иногда он уничтожается, а? Это какая-то известная опечатка? В противном случае это звучит очень подозрительно, я бы заподозрил ошибки синхронизации или предварительного масштабирования eeprom. - person Lundin; 08.08.2017
comment
У меня была эта проблема 5+ лет назад. Та же модель от официального дистрибьютора, только разные партии и на некоторых из них потеряно значение первого байта. Я провел гораздо более глубокое исследование, но сейчас я не помню выводов - поскольку я перестал использовать AVR несколько лет назад - Cortex uC просто стал дешевле, чем AVR, имея гораздо большую вычислительную мощность и лучшую периферию. - person 0___________; 08.08.2017
comment
@PeterJ Я пробовал, компилятор выдает ошибку. Он не распознает EEMPE, EEPE и другие подобные регистры. В одном файле я прочитал, что более новые чипы их поддерживают. Полагаю, мой старше. - person nalostta; 08.08.2017

Это из сопутствующих файлов с исходным кодом для AVR103 AVR EEPROM Application Note, окончательной публикации. от производителя устройства.

char EEPROM_GetChar( unsigned int addr )
{
    do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
    EEAR = addr; // Set EEPROM address register.
    EECR = (1<<EERE); // Start EEPROM read operation.
    return EEDR; // Return the byte read from EEPROM.
}


void EEPROM_PutChar( unsigned int addr, char new_value )
{
    char old_value; // Old EEPROM value.
    char diff_mask; // Difference mask, i.e. old value XOR new value.

    unsigned char old_interrupt; // Stores interrupt flag while programming.
    old_interrupt = __save_interrupt(); // Save interrupt flag state.
    __disable_interrupt(); // Ensure atomic operation for the write operation.

    do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
    #ifndef EEPROM_IGNORE_SELFPROG
    do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM.
    #endif

    EEAR = addr; // Set EEPROM address register.
    EECR = (1<<EERE); // Start EEPROM read operation.
    old_value = EEDR; // Get old EEPROM value.
    diff_mask = old_value ^ new_value; // Get bit differences.

    // Check if any bits are changed to '1' in the new value.
    if( diff_mask & new_value ) {
        // Now we know that _some_ bits need to be erased to '1'.

        // Check if any bits in the new value are '0'.
        if( new_value != 0xff ) {
            // Now we know that some bits need to be programmed to '0' also.

            EEDR = new_value; // Set EEPROM data register.
            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode.
            EECR |= (1<<EEPE);  // Start Erase+Write operation.
        } else {
            // Now we know that all bits should be erased.

            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (1<<EEPM0);  // ...and Erase-only mode.
            EECR |= (1<<EEPE);  // Start Erase-only operation.
        }
    } else {
        // Now we know that _no_ bits need to be erased to '1'.

        // Check if any bits are changed from '1' in the old value.
        if( diff_mask ) {
            // Now we know that _some_ bits need to the programmed to '0'.

            EEDR = new_value;   // Set EEPROM data register.
            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (1<<EEPM1);  // ...and Write-only mode.
            EECR |= (1<<EEPE);  // Start Write-only operation.
        }
    }

    __restore_interrupt( old_interrupt ); // Restore interrupt flag state.
}


void main()
{
    char t; // Temporary byte.
    unsigned int addr = 0x10; // EEPROM address to use.

    // Test the EEPROM_GetChar() function.
    t = EEPROM_GetChar( addr );

    // Try erasing the whole byte.
    EEPROM_PutChar( addr, 0xff );

    // Try changing a few bits to '0'.
    EEPROM_PutChar( addr, 0x0f );

    // Try changing bits both ways.
    EEPROM_PutChar( addr, 0xf0 );

    // Try changing nothing.
    EEPROM_PutChar( addr, 0xf0 );

    // Restore old value.
    EEPROM_PutChar( addr, t );

    for(;;); // Loop forever.
}
person TomServo    schedule 10.08.2017
comment
Мой компилятор (atmel studio 7) показывает EEMPE как ошибки... он понимает старые команды (EEMWE) - person nalostta; 10.08.2017
comment
Этот документ был написан давно, и некоторые имена регистров могли немного измениться в более новых частях AVR. Пожалуйста, сверьтесь со спецификацией вашей детали, чтобы узнать текущие имена регистров. Но будьте уверены, алгоритм остался прежним. - person TomServo; 10.08.2017