Обсуждаем контроллеры компании Atmel.
Сб дек 11, 2021 16:43:02
ARV, Ваша память всё ещё на высоте
. Просто дописывала ноль до чётного и при компиляции выбрасывала жёлтый варнинг.
Вс дек 12, 2021 07:01:34
Да, так как адресация двухбайтная, компилятор об этом предупреждает, и дописывает недостающий байт нулем. Поэтому, кол во байтов всегда должно быть четным, дописывайте сами недостающий байт.
Пн дек 13, 2021 12:26:56
....Как истинный извращенец пишу на ASM.
...Правильно в програмном флеше.
А вот так другой "извращенец" сделал бы...
Целая куча энергонезависимой памяти с однобайтовой организацией!!!
- Код:
.include "m328pdef.inc"
.ESEG
.org 0
.db 0xFC,0x84,0xDA,0xCE,0xA6,0x6E,0x7E,0xC4,0xFE,0xEE,0x00
.DSEG
.org 0x100
.CSEG
.org 0x00
.def A = r16
.def B = r17
.Macro xchg
push @0
push @1
pop @0
pop @1
.EndMacro
.Macro ldiw
ldi @0L,low(@1)
ldi @0H,High(@1)
.EndMacro
.Macro WaitEEPE ;Ожидание флага готовности EEPE
sbic EECR, EEPE
rjmp PC-1
.EndMacro
.Macro fld ;fld Reg,XYZ
WaitEEPE
out EEARH,@1H
out EEARL,@1L
nop
nop
sbi EECR,EERE
in @0,EEDR
.EndMacro
.Macro flds ;flds Reg,Addr
WaitEEPE
ldi @0,High(@1)
out EEARH,@0
ldi @0,Low(@1)
out EEARL,@0
nop
nop
sbi EECR,EERE
in @0,EEDR
.EndMacro
.Macro fsts ;fsts Addr,Reg
push r0
mov r0,@1
flds @1,@0
cpse r0,@1
rcall writebyte
mov @1,r0
pop r0
.EndMacro
.Macro fst ;fst XYZ,Reg
push r0
fld r0,@0
xchg r0,@1
cpse r0,@1
rcall writebyte
pop r0
.EndMacro
writebyte:
cli
WaitEEPE
out EEDR,r0
sbi EECR,EEMPE
sbi EECR,EEPE
WaitEEPE
sei
ret
Reset:
cli
ldiw X,RAMEND
out SPL,XL
out SPH,XH
.
.
sei
Loop:
;Далее просто вот так читать!
ldiw Z,2
fld A,Z
;или так
flds A,2
;Или просто вот так записать!
ldiw Z,2
ldi A,0x56
fst Z,A
;или так
ldi A,0x56
fsts 0x2,A
rjmp Loop
Одно НО! Макрос не инструкция и всякие пропуски sbrc(s) или sbic(s) или cpse не работают....Табличку искомую можно в обычную оперативку ОЗУ скопировать при старте если требуется быстрый доступ.
Последний раз редактировалось
С.Н. Пн дек 13, 2021 16:51:08, всего редактировалось 4 раз(а).
Пн дек 13, 2021 13:31:17
EEPROM для изменяемых данных. Параметры, настройки и прочее. Если данные константы, значит храним их во Flash памяти.
Пн дек 13, 2021 14:38:52
У ЕЕПРОМки ресурс перезаписи меньше чем у флеша.
Ставить туда чего-то часто перезаписываемого без проверок невыгодно.
Для чтения констант - затраты времени заметно выше, чем при чтении константы из флэша.
Пн дек 13, 2021 16:20:27
У ЕЕПРОМки ресурс перезаписи меньше чем у флеша.
Ставить туда чего-то часто перезаписываемого без проверок невыгодно.
Для чтения констант - затраты времени заметно выше, чем при чтении константы из флэша.
По всем пунктам ЗА!. Поэтому проверка встроена при записи. Про время оговорку сделал.
Замечу, что речь зашла про "часы", "извращенец.... на ассемблере".
Так впадем же в этот "блуд" по полной! У меня есть еще в запасе: "технология" #define ... #ifdef и всякие логические выражения, укорачивающие код; операции с нецелыми константами. Все это превращает программу на ассемблере в водевиль.
Чтобы не было обид - сам я такой же "извращенец" - в смысле "любитель ассемблера", как и автор вопроса про выравнивание данных по словам - Да пусть его часы будут ходить всегда верно и красиво!
Пн дек 13, 2021 21:36:14
aklВ документации все верно...
Однако на практике - уж довольно часто имеем "глюки" с повреждением содержимого интегрированной в кристалл ЕЕПРОМки...
Пт дек 17, 2021 01:49:30
BOB51, ну так или BOD включайте, или после работы с еепромкой положите в регистр EEARL/EEARH адрес неиспользуемой ячейки еепрома
Содержимое обычно портися когда выключается питание. МК в агонии как жидкий терминатор в домне - бросается во все стороны и делает непредсказуемые вещи.
в т. ч. и команду записи или стирания еепрома может инициировать. И запортит ту ячейку, адрес коей лежит в EEAR....
Пт дек 17, 2021 09:46:41
В программе, работающей с EEPROM обязательно использую
- Код:
OUT EECR,ZERO ; на всякий случай
SER R16
OUT EEARH,R16 ;
OUT EEARL,R16 ;задать заведомо некорректный адрес
Касательно камней, у которых EEPROM <=256 типа Mega48 обмен должен быть по корректному адресу.
Спойлер
- Код:
;************************************************
; Запись в EEPROM
; ZH,ZL -адрес
; R_DATA- данные
;************************************************
EEWRITE:
CLR ZH
; SBIC EECR,EEPE
; RJMP EEWRITE
; OUT EEARH,ZH
OUT EEARL,ZL
OUT EEDR,R_DATA
SBI EECR,EEMPE
SBI EECR,EEPE
EEWWAIT:
SBIC EECR,EEPE
RJMP EEWWAIT
OUT EECR,ZERO ;!!!!!!!!!!!!!!
RET
;************************************************
; Чтение из EEPROM
; ZH,ZL-адрес
; R_DATA-данные
;************************************************
EEREAD:
CLR ZH
; SBIC EECR,EEPE
; RJMP EEREAD
; OUT EEARH,ZH
OUT EEARL,ZL
SBI EECR,EERE
IN R_DATA,EEDR
OUT EECR,ZERO ;!!!!!!!!!!!!!!
RET
;************************************************
Пт дек 17, 2021 11:37:00
akl, да можно и корректный адрес задавать. Главное, что б ячейка неиспользуемая была.
Или выделить под такую ячейку явный адрес, или загонять в EEAR значение E2END.
Но это в случае батарейных устройств, где МК спит 99% времени и должен экономить батарейку.
В остальных случаях проще включить в фузах BOD - и агонии МК не будет. Но за это надо платить парой десятков микроамперов.
Ср янв 05, 2022 00:37:15
Скоро сломаю голову. Ошибка где-то на поверхности, но понять не могу.
Работаем с часами DS3231. Работаем по I2C через прерывание. Для начала получаю только секунды, минуты и часы. Старт, отправку адреса часов и регистра, рестарт опускаю. Там всё работает. Сразу к получению данных. Этот вариант работает без вопросов. В оперативке по метке TIMME лежат все нужные данные
Спойлер
//в Temp1 обработанное содержимое регистра TWSR
cpi Temp1, 0x40 // Если 0x40 - Пришли после посылки команды на чтение, просто выкинем
breq Secc // в регистр Ack, сказав, что готовы принимать от часов секунды
cpi Temp1, 0x50 // Если 0x50 - Байт принят, нам надо положить его в ОЗУ микроконтроллера
breq ByteRecive // причем сюда будем много раз входить, поэтому ответ Ack
ByteRecive:
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 0
rjmp Minn
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 1
rjmp Hourr
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 2
rjmp Stop
Secc: ; получение секунд
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000001
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV ; Команда на считывание первого байта - секунды
rjmp Exit
Minn: ; сохранение секунд и получение минут
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME, temp3 ; положили в оперативку секунды
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000010
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV ; Команда на считывание второго байта - минуты
rjmp Exit
Hourr: ; сохранение минут и получение часов
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+1, temp3 ; положили в оперативку минуты
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000100
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание третьего байта - часы
rjmp Exit
Stop: ; сохранение часов и отправка стоп
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+2, temp3 ; положили в оперативку часы
RCALL IIC_STOP ; Отослали стоп
Теперь пробую получать ещё 4 регистра - день недели, дату, месяц, год.
Спойлер
cpi Temp1, 0x40 // Если 0x40 - Пришли после посылки команды на чтение, просто выкинем
breq Secc // в регистр Ack, сказав, что готовы принимать от часов секунды
cpi Temp1, 0x50 // Если 0x50 - Байт принят, нам надо положить его в ОЗУ микроконтроллера
breq ByteRecive // причем сюда будем много раз входить, поэтому ответ Ack
ByteRecive:
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 0
rjmp Minn
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 1
rjmp Hourr
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 2
rjmp Weekk
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 4
rjmp Datee
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 5
rjmp Monthh
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 6
rjmp Yearr
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
sbrc flags, 7
rjmp Stop
Secc: ; получение секунд
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000001
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV ; Команда на считывание первого байта - секунды
rjmp Exit
Minn: ; сохранение секунд и получение минут
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME, temp3 ; положили в оперативку секунды
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000010
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV ; Команда на считывание второго байта - минуты
rjmp Exit
Hourr: ; сохранение минут и получение часов
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+1, temp3 ; положили в оперативку минуты
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00000100
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание третьего байта - часы
rjmp Exit
Weekk: ; сохранение часов и получение дня недели
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+2, temp3 ; положили в оперативку часы
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00010000
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание четвёртого байта - день недели
rjmp Exit
Datee: ; сохранение дня недели и получение даты
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+3, temp3 ; положили в оперативку день недели
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b00100000
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание пятого байта - даты
rjmp Exit
Monthh: ; сохранение даты и получение месяца
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+4, temp3 ; положили в оперативку дату
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b01000000
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание шестого байта - месяца
rjmp Exit
Yearr: ; сохранение месяца и получение года
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+5, temp3 ; положили в оперативку месяц
lds flags, FFLAGS+1 ; извлекаем флаги I2C из оперативки
andi flags, 0b00001000
ori flags, 0b10000000
sts FFLAGS+1, flags ; положили в оперативку флаг I2C
RCALL IIC_RCV2 ; Команда на считывание седьмого байта - года
rjmp Exit
Stop: ; сохранение года, отправка стоп и вывод данных
IN temp3,TWDR ; Забрали из регистра TWIDR
sts TIMME+6, temp3 ; положили в оперативку год
RCALL IIC_STOP ; Отослали стоп
И вот тут засада. Секунды, минуты и часы по прежнему корректные, а вот остальные 4 байта заполнены единицами. Подскажите, где я напартачил?
Ср янв 05, 2022 16:29:36
1 - в симуляторе студии проверьте, в какой момент появляются единицы. I2C в симуляторе не проверить, потому создайте программные закладки.
2 - не обязательно каждый раз считывать данные. Достаточно при включении считать данные, потом опрашивать вывод IRQ кажется, который тикает каждую секунду. Ессно, нужно теперь самому проводить все вычисления. Прибавление секунд, минут, часов. Но так проще.
Ср янв 05, 2022 17:26:39
a1000, вот честно, в такой закрученной "циклической" логике с кучей переходов, базируясь на flags, я до конца не отследил что и как работает.
Сделайте один цикл на 7 итераций и в нем просто читайте 7 байт данных, складывая их в память и инкрементируя указатель.
Чтение по i2c с точки зрения МК - достаточно медленное, но я не думаю, что у вас прям такой реалтаймовый проект, когда не сделать чтение 3231 на ожиданиях.
Плюсом такого цикла будет то, что установка всех режимов, регистров, флагов i2c будет в одном месте. Включая ACK для всех байтов, кроме последнего, и NACK для последнего.
И тогда вы не наступите на те грабли, которые я вижу на первый взгляд.
У вас во втором примере чтение секунд и минут выполняется макросом/подпрограммой IIC_RCV (RCALL IIC_RCV) - судя по всему, это чтение с флагом ACK.
А вот часы вы читаете макросом IIC_RCV2 - это чтение с NACK - последний байт.
После этого 3231 понимает, что от него уже ничего не ждут, и ничего не отдает. вот вам и 0xFF.
Кроме того, вы читаете день недели, число, месяц и год тем же макросом - IIC_RCV2 - без ACK.
Замените везде, кроме последнего байта (год) RCALL IIC_RCV2 на RCALL IIC_RCV
Ср янв 05, 2022 18:29:08
GoldenAndy, вы абсолютно правы. Совсем забыл про NACK, вот и скопировал не глядя. Спасибо за помощь, исправил, всё заработало.
Ср янв 05, 2022 18:48:48
А почему у меня команда ld не работает в студио-симуляторе для tiny2313 ?
Ошибка компиляции,неправильный регистр. Регистр длинный r30,адрес
ячейки туда загружен и такой и сякой.Все равно ошибка.
Ср янв 05, 2022 18:56:24
А адрес озу у Вас где? Всю строку пж покажите.
Ср янв 05, 2022 19:10:25
А почему у меня команда ld не работает в студио-симуляторе для tiny2313 ?
Ошибка компиляции,неправильный регистр. Регистр длинный r30,адрес
ячейки туда загружен и такой и сякой.Все равно ошибка.
Регистровая пара Zh:Zl она же R31:R30
Диапазон адресов для команд LD rd,Z , LDS rdZ+rel касается только ОЗУ (для тини2313 это 0х0000-0x00DF)
Для доступа к таблицам в ПЗУ используется группа команд LPM
Ср янв 05, 2022 20:52:23
Боюсь ошибиться, но по моему, LD работает только с регистровой парой. Попробуйте так
- Код:
ldi r30,0xdf
clr r31
ld r20,Z