Многие модели AVR раннего времени выпуска, как и другие микроконтроллеры семейства MCS-51, производимые фирмой Atmel, имели один существенный недостаток. Их память EEPROM была очень не надежной. Без каких-либо на то оснований ее содержимое могло изменится до неузнаваемости; имелись проблемы, при записи данных. В дальнейшем технология производства была улучшена и положение вещей со временем, конечно, изменилось. Но, не смотря на это, ошибки при работе с EEPROM все-таки иногда случаются. Практика показывает, что наиболее распространенными причинами повреждения памяти являются импульсные помехи и сбои в цепях питания. Кроме того разрушение EEPROM может произойти на этапе программирования (даже если команды касаются только работы с fuse-битами или FLASH-памятью программ). Таким образом, для повышения достоверности хранимой в EEPROM информации иногда могут понадобиться дополнительные программные средства.
Проще всего это сделать, если отвести сохраняемой переменной несколько ячеек энергонезависимой памяти. Вероятность того, что все ячейки повредятся одновременно намного меньше. Хранить одно значение по двум адресам имеет смысл тогда, когда необходимо выявить только саму ошибку, но никак не восстановить утерянные данные. Дублирование по трем и более адресам EEPROM уже дает возможность найти и устранить проблему, когда один или несколько байтов случайно претерпели изменения. Подпрограммы, приведенные ниже, производят восстановление 8-разрядной величины, для хранения которой отведено 4 б памяти EEPROM. При считывании, сначала, проверяется условие равенства всех байтов памяти. Если значение хотя бы одного из них отличается от остальных, то данные были повреждены. В этом случае производится по парное сравнение между собой содержимого всех ячеек (всего 6 операций сравнения). В случае равенства хотя бы одной пары число, размещенное в этих двух ячейках, считается уцелевшим. Иначе данные не подлежат восстановлению.
.def data = R16 ;регистр c байтом данных .def eadrl = R24 ;регистр с младший байтом адреса EEPROM .def eadrh = R25 ;регистр со старшим байтом адреса EEPROM . ldi data,0x55 ;записываем число 0x55 в ldi eadrh,high(_var) ;переменную _var из EEPROM-памяти ldi eadrl,low(_var) ;продублированную в 4-х байтах rcall ee_write_check . ldi eadrh,high(_var) ;считываем переменную _var из ldi eadrl,low(_var) ;EEPROM-памяти rcall ee_read_check . .eseg .org 0 _var: .byte 4 ;4 зарезервированных ячейки в EEPROM-памяти ; Подпрограмм записи переменной в EEPROM-память ; R16 – регистр с байтом для записи на входе из подпрограммы ; R25:R24 – регистровая пара для передачи адреса переменной ; EEPROM-памяти при входе в подпрограмму ; R17 – регистр для промежуточных операций ee_write_check: ldi R17,4 ;инициализируем счетчик записанных байт wc1: sbic EECR,EEWE ;ожидаем пока запись не будет закончена rjmp wc1 out EEARH,R25 ;передаем адрес по которому out EEARL,R24 ;будет записано число out EEDR,R16 ;передаем число sbi EECR,EEMWE ;разрешаем запись sbi EECR,EEWE ;начинаем запись байта в EEPROM adiw R24,1 ;увеличиваем адрес на 1 dec R17 ;производим запись числа во все 4 ячейки brne wc1 ret ; Подпрограмм чтения переменной из EEPROM-памяти ; R16 – регистр с прочитанным байтом на выходе из подпрограммы ; R25:R24 – регистровая пара для передачи адреса переменной ; EEPROM-памяти при входе в подпрограмму ; R17,R18,R19 – регистры для промежуточных операций ; На выходе во Флаге T находится признак ошибки. Если T=0, то ; данные успешно считаны, если T=1, то данные повреждены и не ; подлежат восстановлению ee_read_check: set ;при входе устанавливаем флаг ошибки rcall read_byte ;считываем 1-ый байт блока памяти in R16,EEDR ;EEPROM и размещаем его в R16 rcall read_byte ;считываем 2-ой байт блока памяти in R17,EEDR ;EEPROM и размещаем его в R17 rcall read_byte ;считываем 3-ий байт блока памяти in R18,EEDR ;EEPROM и размещаем его в R18 rcall read_byte ;считываем 4-ый байт блока памяти in R19,EEDR ;EEPROM и размещаем его в R19 sbiw R24,4 ;восстанавливаем адрес push R16 ;сохраняем регистр с 1-ым байтом and R16,R17 ;сравниваем четыре байта and R16,R18 and R16,R19 pop R16 ;восстанавливаем регистр с 1-ым байтом brne rc1 ;если все они равны между собой, то clt ;очищаем флаг ошибки и выходим из ret ;подпрограммы с байтом в R16 rc1: cp R16,R17 ;сравниваем 1-ый и 2-ой байты brne rc2 ;если они не равны то продолжаем сравнение push R16 rjmp rc7 rc2: cp R16,R18 ;сравниваем 1-ый и 3-ий байты brne rc3 ;если они не равны то продолжаем сравнение push R16 rjmp rc7 rc3: cp R16,R19 ;сравниваем 1-ый и 4-ый байты brne rc4 ;если они не равны то продолжаем сравнение push R16 rjmp rc7 rc4: cp R17,R18 ;сравниваем 2-ой и 3-ий байты brne rc5 ;если они не равны то продолжаем сравнение push R17 rjmp rc7 rc5: cp R17,R19 ;сравниваем 2-ой и 4-ый байты brne rc6 ;если они не равны то продолжаем сравнение push R17 rjmp rc7 rc6: cpse R18,R19 ;сравниваем 3-ий и 4-ый байты и если ret ;они не равны, то данные утеряны push R18 rc7: pop R16 ;если найдена хотя бы одна одинаковая пара rcall ee_write_check ;чисел, то восстанавливаем их в памяти clt ;и очищаем флаг ошибки на выходе ret read_byte: sbic EECR,EEWE ;ожидаем пока запись не будет закончена rjmp read_byte out EEARH,R25 ;передаем адрес числа для чтения out EEARL,R24 adiw R24,1 ;увеличиваем адрес на 1 sbi EECR,EERE ;разрешаем чтение ret
Перейти к следующей части: Перенос программы между разными моделями
Комментарии (2) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
......
push R16 ;сохраняем регистр с 1-ым байтом
and R16,R17 ;сравниваем четыре байта
and R16,R18
and R16,R19
pop R16 ;восстанавливаем регистр с 1-ым байтом
brne rc1 ;если все они равны между собой, то
clt ;очищаем флаг ошибки и выходим из
ret ;подпрограммы с байтом в R16
.....
Флаг Z должен подняться, если все 4 байта равны?
Но с командой and Rr,Rr при равенстве байтов этого не происходит.
Проверку на равенство всех 4-х байтов я сделал так:
mov r2,r16
eor r16,r17
mov r16,r2
eor r16,r18
mov r16,r2
eor r16,r19
mov r16,r2
brne cp_1;
clt
ret
Вот так работает:
cp r16,r17
brne cp_1
cp r17,r18
brne cp_1
cp r18,r19
brne cp_1;
clt;
ret