Всех приветствую!
Существует очень много различных датчиков, микросхем ПЗУ с электрическим стиранием, индикаторов ЖКИ, модулей часов и т.д. с интерфейсом I2C, с которыми хотелось бы поработать, или просто "пощупать" их в работе. Для этого нужна программная поддержка. Штатно на Орионе её нет. Каждый первый скажет:"Возьми Arduino и не мучайся!". Взял. Но так неинтересно.
Приобрёл я вот такой модуль с микросхемой ПЗУ AT24C04 объёмом 512 байт.
Схема данного модуля:
Как видно, на плате модуля присутствуют все необходимые элементы обвязки, поэтому нам не придётся городить всё это у себя.
Схема подключения модуля к порту /F600h следующая:
Подключение модуля к Ориону в железе:
Из-за особенностей перепрограммирования КР580ВВ55 приходится отказываться от двух-проводного режима работы и использовать три линии для подключения к порту. Нужен диод для развязки. Подойдёт любой. И при этом КР580ВВ55 программируется один раз в начале работы.
Теперь напишем протокол обмена данными.
Требования: ОС DSDOS, ASSM 2.7 + DSDOS SDK, текстовый редактор ED$.
Для работы с интерфейсом I2C нам понадобятся несколько основных процедур: инициализация, старт, стоп, отправка байта и приём байта, а также несколько вспомагательных.
Перво-наперво напишем процедуру инициализации порта и шины I2C:
PT_SDA_IN: EQU 0F602h
PT_I2C: EQU 0F603h
CHIP_ADDRESS: DB 0A0h
INIT_I2C:
MVI A,93h
STA PT_I2C
MVI A,0C0h
STA PT_SDA_IN
RET
Теперь напишем процедуры старт, стоп и строб сигнала SCL:
I2C_START:
MVI A,0Eh
STA PT_I2C
NOP
MVI A,0Ch
STA PT_I2C
RET
I2C_STOP:
MVI A,0Dh
STA PT_I2C
NOP
MVI A,0Fh
STA PT_I2C
RET
I2C_PULSE:
PUSH PSW
MVI A,0Dh
STA PT_I2C
NOP
MVI A,0Ch
STA PT_I2C
POP PSW
RET
Далее следуют процедуры отправки и приёма байта:
I2C_TRANSMIT:
;вх. [C] передаваемый байт
;вых.[A]=0 - OK
MVI B,8
TLOOP:
MOV A,C
ANI 80h
STA PT_I2C-1
CALL I2C_PULSE
MOV A,C
RAL
MOV C,A
DCR B
JNZ TLOOP
CALL SDA_1
LDA PT_SDA_IN ;READ ACK FROM SLAVE
ANI 1
CALL I2C_PULSE
CALL SDA_0
RET
I2C_RECIEVE:
;вых.[C] принятый байт
CALL SDA_1
LXI B,0800h
RLOOP:
MOV A,C
RAL
MOV C,A
LDA PT_SDA_IN ;READ BIT
ANI 1
ADD C
MOV C,A
CALL I2C_PULSE
DCR B
JNZ RLOOP
CALL SDA_1
CALL I2C_PULSE ;NACK FROM MASTER
RET
Осталось написать обслуживающие подпрограммы:
SDA_0:
PUSH PSW
MVI A,0Eh
STA PT_I2C
POP PSW
RET
SDA_1:
PUSH PSW
MVI A,0Fh
STA PT_I2C
POP PSW
RET
I2C_DELAY_5MS:
PUSH B
LXI B,500
LOOP_DELAY:
DCX B
MOV A,B
ORA C
JNZ LOOP_DELAY
POP B
RET
I2C_ERROR:
CALL I2C_STOP
MVI A,2
LXI H,I2C_T_ERRMSG
CALL 0F000h
MVI A,1
CALL 0F000h
RET
I2C_T_ERRMSG:
DB 13
DB 'Ошибка отправки данных ',7
DB 0
Всё это оборачиваем в библиотеку 24C16.L, которую можно будет скачать в конце статьи по прилагаемой ссылке.
А теперь самое интересное: работа с микросхемой!
Если написание протокола отправки/приёма байта не вызывает никаких вопросов (в даташитах всё подробно описано), то работа именно с памятью вызывает некоторые "затруднения". Дело в том, что организация памяти в этих микросхемах страничная и прежде чем что-то записать или прочитать, нужно сперва "выдернуть страницу" из желаемого адреса и указать её в адресе устройства. Ведь по протоколу мы можем указать только один байт адреса, а у нас их два, т.к. микросхемы типом начиная от 04, адресуются двумя байтами. Поэтому нам понадобятся еще две подпрограммы: запись по указанному адресу и чтение. И их также поместим в библиотеку. Это уже будут наши самые рабочие процедуры обмена данными с микросхемой:
WRITE_I2C:
;вх. [HL] адрес
; [A] данные;
PUSH H
PUSH PSW
MOV A,H
RAL
MOV H,A
LDA CHIP_ADDRESS
ADD H
MOV H,A
CALL I2C_START
MOV C,H
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
MOV C,L
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
POP PSW
MOV C,A
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
CALL I2C_STOP
POP H
RET
READ_I2C:
;вх. [HL] адрес
;вых. [A] данные;
PUSH H
MOV A,H
RAL
MOV H,A
LDA CHIP_ADDRESS
ADD H
MOV H,A
CALL I2C_START
MOV C,H
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
MOV C,L
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
CALL I2C_STOP
CALL I2C_START
INR H
MOV C,H
CALL I2C_TRANSMIT
ORA A
JNZ I2C_ERROR
CALL I2C_RECIEVE
CALL I2C_STOP
MOV A,C
POP H
RET
Комментариев практически нет, но они есть в исходных текстах по прилагаемой ссылке.
Итак, библиотека написана. Теперь можно обмениваться с микросхемой данными, не думая ни об адресации чипа, ни о страницах. Задаём адрес и либо пишем, либо читаем.
Теперь напишем две небольших тестовых программы, которые будут пользоваться нашей библиотекой. Одна показывает дамп ПЗУ, вторая пишет и читает указанный байт по выбранному адресу. Тексты этих программ я приводить не буду, они есть в прилагаемом архиве, покажу только результаты их работы.
Предварительно с помощью стороннего программатора я записал в ПЗУ AT24С04 первые 512 байт МОНИТОРа-1 от Ориона. Всё-таки с существующей информацией легче работать, чем с кодами FFh.
Программа V2$.
Показывает дамп ПЗУ. Чтобы исключить скроллинг, показано 511 байт вместо 512.
Обратим внимание на первый адрес. Его код С3. Теперь с помощью другой программы под названием V3$ изменим этот байт на FFh.
Укажем в исходном тексте адрес и байт:
Запустим программу V3$. Видим результат работы.
По алгоритму это слева направо: пишем FFh - читаем FFh. Работа прошла успешно. Теперь удостоверимся, что это действительно так. Запустим программу V2$.
И мы видим, что первый байт действительно перезаписался с С3 на FF.
Библиотека работает! 👍
В случае какой-то неправильной работы выводится соответствующее сообщение.
Поизучав даташиты, выяснилось, что данная библиотека может поддерживать ПЗУ от AT24C01 до AT24C16. Выше - нет. Для более ёмкостных ПЗУ нужны свои библиотеки. Впрочем, данная легко под это модифицируется.
На этом всё! Безбагового Вам программирования! 👻
Все материалы по статье можно скачать здесь https://disk.yandex.ru/d/uOEGd-l0vMRTgg
До новых встреч!