Реализация шины SMBus на базе микроконтроллера MSP430
Краткое содержание
Данный пример применения описывает программную реализацию шины системного управления (system management bus (SMBus)) на базе микроконтроллера MSP430. Рассмотрены протоколы ведущего (master) устройства, базирующегося на прерываниях ведомого (slave), а также примеры использования ведущего устройства. Шина SMBus является подвидом шины 2C и широко используется в смарт-батареях (smart batteries) и других системных устройствах.
1 Введение
SMbus это двухпроводной синхронный последовательный протокол, являющийся производным от I2C. Так же, как и 2C, он использует линии последовательного тактирования (SCL) и данных (SDA). Для исключения неопределённого состояния на линии используются подтягивающие (pullup) резисторы или источники тока, а устройства, подключенные к шине должны иметь выходы типа «открытый коллектор» либо «открытый сток». Это соответствует монтажному «И» всех устройств, что означает, что каждое из устройств может либо перевести шину в состояние лог. «0», либо освободить её. Так как подключённые к шине устройства могут быть запитаны от различных напряжений, они не должны переводить линию в состояние лог. «1».
Все устройства разделяются на ведущие (master) и ведомые (slave). Ведущее устройство может инициировать передачу и формирует тактовый сигнал. Ведомое принимает либо передаёт данные, но при этом процесс передачи инициируется ведущим. Устройства могут иметь как признаки ведущего и ведомого одновременно, так и быть исключительно одним либо другим. Например, ведомое устройство может в критических случаях становиться ведущим и передавать системе сообщения о неисправности. Алгоритм такого поведения целиком определяется конкретной областью применения.
Каждое устройство на шине имеет уникальный 7-битный адрес. Это позволяет подключать к линии до 128 устройств, однако некоторые адреса являются зарезервированными. Различные коммерчески доступные устройства имеют адреса, присвоенные координационным комитетом SMBus.
При приёме и передаче данных используются семь различных протоколов. Это «Быстрая команда» (Quick Command), «Отправить байт» (Send Byte), «Принять байт» (Receive Byte), «Записать Слово/Байт» (Write Byte/Word), «Прочитать Слово/Байт» (Read Byte/Word), «Запрос состояния» (Process Call), и «Чтение/запись Блока» (Block Read/Write). Каждый протокол имеет собственный конкретный набор действий, но общая схема схожа для всех протоколов.
Передача всегда начинается с символа «Старт» (S). Этот символ передаётся переводом обеих линий в состояние лог. «1», последующим переводом линии SDA в состояние лог. «0» и, наконец, выставлением лог. «0» на шине SCL. После передачи стартовой последовательности, начинается передача 8-ми блоков, завершающаяся подтверждением (ACK). Подтверждение передаётся ведомым устройством путём перевода линии SDA в состояние лог. «0» во время передачи ведущим сигнала SCL. Если линия SDA не была переведена в такое состояние за время импульса на шине SCL, это состояние называется неподтверждением (NACK). Первый 8-битный блок является 7-битным адресом ведомого устройства вкупе с битом, определяющим направление передачи во всех протоколах, за исключением «Быстрой команды». В последнем же данный бит собственно является командой. После передачи адреса и направления, ведущий ожидает подтверждения от ведомого. При этом он формирует одиночный импульс на линии SCL и контролирует перевод ведомым в это время линии SDA в состояние лог. нуля. Если подтверждение не получено, ведущее устройство прекращает передачу и повторяет её позднее. Эта операция также может использоваться для определения присутствия ведомого на шине. После получения подтверждения, передаётся либо получается очередной блок из 8-ми бит, либо передаётся символ останова (P). Этот символ формируется переводом обеих линий в состояние лог. «0», последующим переводом линии SCL в состояние лог. «1» и завершается переводом в лог. «1» линии SDA. Остальные 8-битные блоки могут быть данными, командами либо следующей комбинацией адреса и бита чтения/записи. Точный формат каждого из протоколов можно найти в документе System Management Bus specification на сайте . Ввиду того, что на шине используется подключение устройств по принципу «монтажное «И»», она обладает механизмом арбитража. Если более одного ведущего устройства пытаются передавать данные, первый из них, «отпустивший» шину во время того, как оставшийся удерживает её в состоянии лог. «0» должен отдать арбитраж. Чтобы обеспечить эффективность такого метода, каждое ведущее устройство должно проверять состояние шины каждый раз после перевода её в состояние лог. «1». Если после этого шина удерживается в состоянии лог. «0», ведущее устройство должно прекратить передачу и повторить попытку позднее. В результате такого решения системы арбитража, устройства с меньшими адресами имеют приоритет над устройствами со старшими адресами. Если два ведущих пытаются начать передачу одновременно, тот из них, который передаёт старший адрес, первым освободит линию и потеряет, таким образом, приоритет.
Рабочими частотами шины являются 10 кГц и 100 кГц. Это аналогично шине 2C, за исключением того, что 2C не имеет ограничения скорости снизу, при этом устройства могут занимать шину на неограниченное время. SMBus имеет более жёсткие ограничения, ограничивая минимальную скорость. Несмотря на это, ведомые устройства не обязаны работать с той же частотой, что и ведущие. Единственным ограничением является минимальная скорость их работы в 10 кГц. Возможность работы с разной скоростью реализована следующим образом: если ведомому устройству требуется дополнительное время для завершения операции, оно принуждает ведущего к ожиданию удержанием линии SCL в состоянии лог. «0». Это называется «удлинением тактового сигнала» (clock-low extending). Ведущее устройство должно дождаться, пока ведомое «отпустит» линию SCL, но , если это займёт больше времени, чем разрешено спецификацией, произойдёт тайм-аут. Этим обеспечивается минимальная скорость шины. Дополнительную информацию по протоколу SMBus можно найти на форуме Smart Battery System Implementers Forum (SBS IF). Комитет SBS IF образован представителями фирм Benchmarq Microelectronics Inc., Duracell Inc., Energizer Power Systems, Intel Corporation, Linear Technology Corporation, Maxim Integrated Products, Mitsubishi Electric Corporation, National Semiconductor Corporation, Toshiba Battery Co., и Varta Batterie AG. Комитетом опубликована спецификация SMBus, доступная для скачивания на сайте в формате pdf.
2 Аппаратная часть
На рис. 1 приведен пример подключения шины SMBus. В этом случае MSP430 подключен к смарт-батарее. Батарея питает шину и MSP430, но это не является обязательным, необходимым условием является лишь общая «земля». Подтягивающие (pull up) резисторы обозначены как RP. Для уменьшения потребляемого тока, значения RP выбраны максимально возможными в рамках требований спецификации. Существуют также специальные драйвера шины SMBus, используемые вместо подтягивающих резисторов. Такие устройства обеспечивают максимальный ток на фронте и минимальный при низком уровне на шине.
Рис1. Пример организации шины SMBus
Примечание: Неиспользованный вывод T это термистор. Он используется в блоках Li-Ion батарей для аварийных измерений в случае неисправности модуля батареи или шины SMBus.
|
3 Реализация ведущего устройства шины SMBus
Программа ведущего устройства шины SMBus для MSP430 реализует все существующие типы протоколов. Для экономии регистров, параметры передаются через стек. Максимальная глубина стека 40 байт. Память вне стека не затрагивается, кроме случая операций над блоками. Во время передачи блока его начало передаётся как параметр (блок растёт в сторону верхних адресов памяти). Во время записи блока его размер известен до начала передачи, во время приёма блока его размер передаётся ведомым устройством. При этом следует соблюдать осторожность, чтобы данные из блока не затёрли программную или оперативную память.
Программа состоит из двух основных частей: подпрограмм верхнего уровня и подпрограмм нижнего уровня. Низкоуровневые подпрограммы обрабатывают сдвиг бит, временнЫе характеристики и работу с портами ввода-вывода. Протоколы SMBus, по существу, состоят из нескольких стандартных блоков, которые вызываются и повторяются в определенном порядке. Эти стандартные блоки обрабатываются подпрограммами нижнего уровня. Подпрограммы верхнего уровня обеспечивают пользовательский интерфейс и сохраняют регистры. На каждый протокол приходится одна такая подпрограмма, в них устанавливаются параметры, а затем вызываются подпрограммы нижнего уровня. Для обеспечения требования протокола SMBus к выходам («открытый коллектор»), выводы процессора переключаются со входа на выход и наоборот. В выходных защёлках портов всегда присутствует лог. «0». Это означает, что MSP430 может «освободить» линию переключением вывода на вход, либо «занять» её (т.е. выставить там лог. «0») путём переключения вывода на выход. Выбор требуемых выводов осуществляется «привязкой» их в начале программы к конкретным линиям SDA, SCL и DNC. SDA и SCL соответствуют линиям данных и тактирования шины SMBus. DNC является одновременно линиями SCL и SDA. Соответствующий порт выбирается назначением OUT, DIR и IN. В зависимости от конкретного применения, могут использоваться не все протоколы. Ненужные подпрограммы могут быть «закомментированы», что уменьшит размер кода. Удаление подпрограмм высокого уровня является очевидным, при этом возможно также удаление некоторых неиспользуемых подпрограмм низкого уровня.
Так как SMBus поддерживает несколько ведущих устройств на шине (multimaster) и «горячее включение» (hot-plug), это приводит к появлению ошибок. Их причинами являются занятость шины, отсутствие ведомого устройства, конфликты между несколькими ведущими устройствами и помехи на шине. Программа включает обработку ошибок и флаг ошибки. При обнаружении ошибки передача прекращается, программа выставляет флаг ошибки и возвращается из подпрограммы верхнего уровня. Пользовательская программа должна проверять данный флаг для определения успешного (возвращает 1) или ошибочного (возвращает 0) завершения. Обработка события ошибки осуществляется пользовательской программой.
Основная программа включает в себя подпрограммы верхнего и нижнего уровней и располагается отдельно от пользовательской программы. Место, где должна располагаться пользовательская программа оставлено свободным. Для передачи данных по шине SMBus, просто вызывается соответствующая подпрограмма верхнего уровня.
Примеры передачи параметров приведены в комментариях к каждой подпрограмме. Исходные коды приведены в приложении A. Также в приложениях приводятся демонстрационные программы, иллюстрирующие различные протоколы и примеры работы с смарт-батареей.
4 Примеры реализации программы ведущего устройства шины SMBus
4.1 Поиск устройств на шине
Первый пример довольно прост. В нём производится поиск устройств, присутствующих на шине и отображение адреса последнего найденного устройства. Это весьма удобно во время проверки соединений шины. Первоначально пример был написан для поиска адресов устройств, он наглядно демонстрирует возможность уменьшения размера кода при помощи удаления неиспользуемых подпрограмм.
Ввиду простоты примера, была удалена значительная часть кода. Оставшийся код можно запускать из-под программы монитора отладочного модуля MSP430x33x (EVK part number MSP-EVK430x330).
4.2 Чтение данных смарт-батареи
Этот пример значительно объёмнее первого. В нём используются протоколы «Чтение слова», «Запись слова» и «Чтение блока» для связи со смарт-батареей. В примере считываются температура, напряжение, производитель, химическая разновидность и ёмкость батареи.
Также используется запись значения в регистр «Предупреждение об оставшейся ёмкости» (RemainingCapacityAlarm), записанное значение проверяется. Эти операции производятся циклически, результат отображается на ЖКИ. Пример демонстрирует использование более сложных протоколов и процесс обработки возвращаемых данных. В данной конфигурации программа протоколов SMBus запускается из EPROM отладочного модуля MSP430x33x (EVK part number MSP-EVK430x330), а пользовательская программа запускается из монитора этого модуля.
5 Реализация ведомого устройства шины SMBus
Эта программа представляет пример реализации ведомого устройства шины SMBus и построена на базе прерываний. Назначения при помощи оператора. equ в начале программы позволяют выбрать адрес ведомого устройства, выводы и порты. В программе реализован протокол «Отправка байта» (что для ведомого устройства означает передачу байта к нему от ведущего). В промежутке между прерываниями ведомое устройство может находиться в режиме пониженного потребления либо выполнять другие задачи. Так как прерывание происходит каждый раз при переходе линии SDA из состояния лог. «1» в лог. «0», ведомое устройство при загруженности шины проводит значительную часть времени в подпрограмме обработки прерываний.
Чтобы исключить контроль шины ведомым устройством во время работы с другими ведомыми могут быть использованы внешние элементы, контролирующие шину и формирующие прерывания только при совпадении адреса ведомого устройства. Ещё одним недостатком использования прерываний без дополнительных внешних устройств является время обработки прерывания. Так как оно составляет несколько тактов, при этом существует вероятность пропуска стартовой последовательности. При реализации поллинга вероятность пропустить стартовую посылку снижается, но процессор постоянно занят отслеживанием состояния шины. Выбор оптимального решения зависит от конкретной реализации. Вариант с прерываниями позволяет процессору обслуживать другие задачи во время неактивного состояния шины, но при этом есть вероятность пропустить первую попытку установления связи. Вариант с поллингом не оставляет процессору возможности обрабатывать другие задачи вне зависимости от состояния шины. Потребление также при этом возрастает, так как процессор не может быть переведен в режим пониженного энергопотребления во время неактивного состояния шины.
На базе данного протокола возможна реализация остальных. В нашем примере обрабатываются стартовые и стоповые последовательности, приём 7-битных блоков адреса и 8-битных блоков данных / команд. Использование этих процедур в требуемом порядке позволяет реализовать некоторые другие протоколы.
Регистры не сохраняются в стеке с целью обеспечения требований спецификации в области наиболее быстрой стартовой последовательности. Время между переходом линий SDA и SCL в состояние лог. «0» может составлять всего 4 мс. Если известно, что ведущее устройство выдаёт сигналы с большей длительностью, можно сохранять регистры в стеке в начале процедуры, но это может привести к пропуску стартовой посылки при работе с более быстрым ведущим устройством.
6 Заключение
Необходимость увеличения времени жизни батарей в переносных устройствах привела к разработке батарей со сложным химическим составом и повышению требований к технологиям мониторинга. Шина SMBus предоставляет удобный и чёткий интерфейс для мониторинга смарт-батарей, а сверхнизкое потребление микроконтроллера MSP430 делает его незаменимым для таких систем.
Приложение A Программа ведущего устройства шины SMBus
;*****************************************************************************************
; Программа ведущего устройства шины SMBus, параметры передаются через стек
;*****************************************************************************************
RAM_orig .set 00240h ; Стартовый адрес в ОЗУ
SP_orig .set 005DEh ; Указатель стека
EPROM .set 08850h ; Размещение EPROM
;––– Определения управляющих регистров
WDTCTL .equ 0120h
WDTHold .equ 80h
WDT_wrkey .equ 05A00h
;PORT 0
P0IE .equ 015h
P0DIR .equ 012h
P0IN .equ 010h
P0OUT .equ 011h
; port 2
P2IN .equ 028h
P2OUT .equ 029h
P2IE .equ 02Dh
P2SEL .equ 02Eh
P2DIR .equ 02Ah
SDA .equ 020h
SCL .equ 080h
DNC .equ 0A0h
OUT .equ P2OU
TDIR .equ P2DIR
IN .equ P2IN
LCD1 .equ 031h
LCDM .equ 030h
IE1 .equ 0h
IE2 .equ 01h
IFG1 .equ 02h
IFG2 .equ 03h
block .equ 0550h
alcd .equ 0B500h ; Размещение таблицы символов
; ASCII для ЖКИ
;*****************************************************************************************
; Reset : инициализация процессора
;*****************************************************************************************
.sect ”MAIN”,RAM_orig
RESET
MOV #SP_orig,SP ; Инициализация указателя стека
;*******************************************************************************
; Начало пользовательской программы
;*****************************************************************************************
; Здесь должна быть расположена пользовательская программа
;*****************************************************************************************
; Завершение пользовательской программы
;*****************************************************************************************
.sect ”smbus”, EPROM
;*****************************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально
; для реализации различных протоколов
;*****************************************************************************************
; Протокол «Быстрая команда» 1
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; не используется unused
; не используется unused
; не используется unused
; адрес address старшая область памяти high mem
;
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; SUB #06h, SP ; остальные параметры не используются
; CALL #qcp
; ADD #08h, SP ; вычесть объём параметров
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
qcp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 28(SP), R7 ; получить адрес из стека
CALL #sbit ; отправить стартовую посылку и адрес
;CALL #sendone ; отправить «1» или
CALL #sendzero ; отправить «0»
CALL #ack ; ждём подтверждения (ACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Отправить байт» 2
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; не используется unused
; не используется unused
; данные data
; адрес address старшая область памяти high mem
;
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #055h ; отправляемые данные
; SUB #04h, SP ; остальные параметры не используются
; CALL #sbp
; ADD #08h, SP ; вычесть объём параметров
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
sbp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 28(SP), R7 ; получить адрес из стека
MOV.B 26(SP), R8 ; получить данные из стека
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить байт команды
CALL #ack ; ждём подтверждения (ACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Принять байт» 3
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; данные (data) в ?
; неподтверждение(NACK) из
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; данные data
; не используется unused
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #08h ; код команды
; SUB #04h, SP ; зарезервировать место под принимаемые данные
; CALL #rcbp
; POP R8 ; переместить данные в R8
; ADD #06h, SP ; вычесть объём параметров
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte ; принять байт данных
CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B R14, 22(SP) ; копировать байт данных в стек
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Принять слово» 7
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; данные (data) в ?
; подтверждение(acknowledge) в ?
; данные (data) в ?
; подтверждение(acknowledge) в ?
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; младший байт данных low data byte
; старший байт данных high data byte
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #008h ; код команды “температура батареи”
; PUSH #00h ; зарезервировать байт под принимаемые данные
; PUSH #00h ; зарезервировать байт под принимаемые данные
; CALL #rwp
; POP R10 ; переместить данные в R10
; POP R11 ; переместить данные в R11
; ADD #04h, SP ; освободить место, занимаемое командой и адресом
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rwp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte ; принять младший байт данных
MOV.B R14, 22(SP) ; сохранить младший байт данных в стеке
CALL #sack ; ждём подтверждения (ACK)
CALL #rbyte ; принять старший байт данных
CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B R14, 24(SP) ; сохранить старший байт данных в стеке
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Запись блока» 8
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; счётчик байт (byte count) из
; подтверждение(acknowledge) в ?
; данные (data) из
; подтверждение(acknowledge) в ?
;
; данные (data) в ?
; подтверждение(acknowledge) в ?
;
; данные и ACK повторяются n раз
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; счётчик байт byte count
; указатель блока block pointer
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #0020h ; код команды “температура батареи”
; PUSH #00550h ; указатель на начало блока
; PUSH #00h ; зарезервировать байт под счётчик
; CALL #blkw
; POP R10 ; переместить данные в R10
; ADD #06h, SP
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkw
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
MOV 24(SP), R9 ; стартовый адрес блока
MOV.B #00h, R15 ; циклический байтовый счётчик
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
MOV.B 22(SP), R8 ; копировать счётчик байт
CALL #sbyte ; отправить счётчик байт
CALL #ack ; ждём подтверждения (ACK)
blk_rep MOV.B 0(R9), R8 ; передать данные из блока
CALL #sbyte ; отправить байт данных
CALL #ack ; ждём подтверждения (ACK)
INC R15 ; инкремент счётчика положения блока
INC R9 ; инкремент указателя блока
CMP 22(SP), R15 ; проверка завершения данных
JNZ blk_rep ; повтор до завершения
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Чтение блока» 9
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; запись(W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; старт (start) из
; адрес(address) из
; чтение(R) из
; подтверждение(acknowledge) в ?
; счётчик байт (byte count) в ?
; подтверждение(acknowledge) из
; данные (data) в ?
; подтверждение(acknowledge) из
;
; данные и ACK повторяются n раз
; неподтверждение(NACK) из
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; счётчик байт byte count
; указатель блока block pointer
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #0020h ; код команды “температура батареи”
; PUSH #00550h ; указатель на начало блока
; PUSH #00h ; зарезервировать байт под счётчик
; CALL #blkr
; POP R10 ; переместить счётчик в R10
; ADD #06h, SP
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkr
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B #00h, R15 ; циклический байтовый счётчик
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
MOV 24(SP), R9 ; стартовый адрес блока
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte
MOV.B R14, 22(SP) ; поместить счётчик в стек
CALL #sack ; отправить подтверждение (ACK)
rblk_rep CALL #rbyte ; принять байт данных
MOV.B R14, 0(R9) ; переместить данные из блока
INC R15 ; инкремент счётчика положения блока
INC R9 ; инкремент указателя блока
CMP 22(SP), R15 ; проверка завершения данных
JZ blk_done ; повтор до завершения
CALL #sack ; отправить подтверждение (ACK)
CMP 22(SP), R15 ; проверка завершения данных
JNZ rblk_rep ; повтор до завершения
blk_done CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
;*********************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов
;*********************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit ; «отпустить» обе линии
BIC.B #DNC, DIR
; проверка освобождения шины
MOV #05h, R10 ; счётчик на 50 микросекунд
wait
MOV.B IN, R11 ; копировать состояние входов в R11
AND #DNC, R11 ; маска входов
CMP #DNC, R11 ; если линии SDA или SCL в лог. «0»то шина занята
JNZ busy
DEC R10 ; декремент счётчика
JNZ wait
rsbit BIC.B #DNC, DIR ; дополнительное освобождение линии с целью
; использования этой же подпрограммы для
; команды повторяющегося старта
; отправка стартовой последовательности
BIS.B #SDA, DIR
BIS.B #SCL, DIR
; отправка адреса
MOV.B #07h, R13 ; счётчик на 7 бит адреса
MOV.B R7, R11 ; копировать адрес в R11
ashift RLA.B R11 ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться на 7-й позиции
MOV.B R11, R12 ; скопировать его для возможности маскирования
; без потери данных
AND.B #080h, R12 ; маскировать все биты кроме СЗР
CMP.B #00h, R12 ; сравнить с 0
JNZ one
CALL #sendzero ; отправить «1»
JMP zero
one CALL #sendone ; отправить «0»
zero DEC R13 ; декремент счётчика
JNZ ashift ; если счётчик <7 бит, повторить сдвиг
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy CALL #pbit ; отправить STOP и busy
ADD #02h, SP ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP R13 ; восстановление регистров
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV #008h, R11 ; счётчик на ?50 мкс
MOV #02FFh, R11 ; удлинённый счётчик для батареи PS100Z–200
clkex MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
MOV #05F6h, R11 ; счётчик таймаута для NACK
wack
MOV.B IN, R10 ; проверка шины
DEC R11
JZ sbusy ; таймаут NACK–– отправить бит P и повторить попытку
AND.B #SDA, R10 ; маскировать всё, кроме SDA
JNZ wack ; приём ACK или ожидание таймаута
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
BIS.B #SDA, DIR ; выставить лог. «0» на линии SDA
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
NOP
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
NOP
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка байта (используются также sendzero и sendone)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbyte
; отправка данных
MOV.B #08h, R13 ; счётчик на ?50 мкс
MOV.B R8, R11 ; копировать данные в R11
dshift
MOV.B R11, R12
AND.B #080h, R12 ; маскировать все биты, кроме СЗР
CMP.B #00h, R12 ; сравнить с 0
JNZ on
CALL #sendzero ; отправить «1»
JMP zer
on CALL #sendone ; отправить «0»
zer
RLA.B R11 ; сдвиг влево, отправляемый бит в СЗР
DEC R13 ; декремент счётчика на 8
JNZ dshift
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Приём байта
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbyte
MOV.B #08h, R12 ; счётчик на 8 бит данных
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
rrep
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
MOV #0035h, R13 ; удлинённый счётчик для батареи PS100Z–200
; удлинение тактового сигнала
clkxtn MOV.B IN, R10 ; проверка шины
DEC R13
JZ busy ; выход по таймауту
AND.B #SCL, R10
JZ clkxtn ; ожидание, если SCL не «1»
MOV.B IN, R10 ; проверка шины
RLA.B R11 ; вход = МЗР
AND.B #SDA, R10 ; проверка SDA
JZ inzero
BIS.B #01h, R11 ; установить «1» в МЗР
inzero DEC R12
JNZ rrep ; продолжение для оставшейся части байта
MOV.B R11, R14 ; копирование данных
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка неподтверждения (NACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
nack
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
; ждём установки «1» на линии SCL
clkn MOV.B IN, R10
AND.B #SCL, R10 ; проверка линии SCL
JZ clkn
BIS.B #SCL, DIR ; «отпустить» SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sack ; ждём, пока ведомый «отпустит» линию SDA
MOV #000Fh, R11 ; счётчик на ?50 мкс
swaita MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy
AND.B #SDA, R10 ; проверка SCL
JZ swaita
BIS.B #SDA, DIR ; перевести SDA в «0»
BIC.B #SCL, DIR ; перевести SCL в «1»
MOV #000Fh, R11 ; счётчик на ?50 мкс
swait MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy
AND.B #SCL, R10 ; проверка SCL
JZ swait
BIS.B #SCL, DIR ; перевести SCL в «0»
BIC.B #SDA, DIR ; «отпустить» SDA
RET
;––– очистка ЖКИ
show_clr
MOV #15, r5 ; очистка дисплейной памяти
show_clr1
MOV.b #0, LCD1–1(r5)
DEC r5
JNZ show_clr1
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a .equ 01h
b .equ 02h
c .equ 10h
d .equ 04h
e .equ 80h
f .equ 20h
g .equ 08h
h .equ 40h
;––– Определения символов
LCD_Tab .byte a+b+c+d+e+f ; отображает”0”
.byte b+c ; отображает”1”
.byte a+b+d+e+g ; отображает”2”
.byte a+b+c+d+g ; отображает”3”
.byte b+c+f+g ; отображает”4”
.byte a+c+d+f+g ; отображает”5”
.byte a+c+d+e+f+g ; отображает”6”
.byte a+b+c ; отображает”7”
.byte a+b+c+d+e+f+g ; отображает”8”
.byte a+b+c+d+f+g ; отображает”9”
.byte 0 ; отображает ”:” пустой
.byte g ; отображает”;” –
.byte a+d+e+f ; отображает”<” [
.byte d+g ; отображает”=”
.byte a+b+c+d ; отображает”>” ]
.byte a+b+e+g ; отображает”?”
.byte a+b+d+e+f+g ; отображает”@”
.byte a+b+c+e+f+g ; отображает”A”
.byte c+d+e+f+g ; отображает”B” b
.byte a+d+e+f ; отображает”C”
.byte b+c+d+e+g ; отображает”D” d
.byte a+d+e+f+g ; отображает”E”
.byte a+e+f+g ; отображает”F”
.byte a+b+c+d+f+g ; отображает”G”
.byte b+c+e+f+g ; отображает”H”
.byte b+c ; отображает”I”
.byte b+c+d+e ; отображает”J”
.byte 0 ; отображает”K”
.byte d+e+f ; отображает”L”
.byte a+b+c+e+f ; отображает”M”
.byte c+e+g ; отображает”N” n
.byte c+d+e+g ; отображает”O” o
.byte a+b+e+f+g ; отображает”P”
.byte 0 ; отображает”Q”
.byte e+g ; отображает”R” r
.byte a+c+d+f+g ; отображает”S”
.byte d+e+f+g ; отображает”T” t
.byte c+d+e ; отображает”U” u
.byte 0 ; отображает”V”
.byte 0 ; отображает”W”
.byte 0 ; отображает”X”
.byte b+c+d+f+g ; отображает”Y”
.byte a+b+d+e+g ; отображает”Z” 2
LCD_Tab_End
.even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; .sect ”Int_Vect”,0FFFFh–1 ; без программы монитора
; .word RESET ; POR, внеш. Reset, Watchdog
; .end
.sect ”Int_Vect”,05FFh–1 ; с программой монитора
.word RESET ; POR, внеш. Reset, Watchdog
.end
Приложение B Программа поиска адресов
;****************************************************************************
; Программа поиска адресов
;––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
; Программа сканирует шину SMBus на предмет подключенных устройств.
; Начинает с адреса 0x00 и перебирает все 128 возможных адресов.
; Текущий адрес при сканировании отображается на правой части ЖКИ
; На левой части отображается адрес последнего из найденных устройств. Когда устройство
; найдено, программа приостанавливается, адрес переносится в левую часть ЖКИ, после
; чего выполнение продолжается.
; Наличие устройства на шине проверяется посылкой стартовой последовательности,
; адреса устройства и ожидания подтверждения. Далее тестируется следующий адрес.
;
; Программа поиска адресов является примером удаления неиспользуемых частей кода.
; Т.к. ей не требуются некоторые протоколы, некоторые подпрограммы
; верхнего и нижнего уровней были удалены.
;****************************************************************************
RAM_orig .set 00240h ; Стартовый адрес
SP_orig .set 005DEh ; указатель стека
;––– Определения управляющих регистров
WDTCTL .equ 0120h
WDTHold .equ 80h
WDT_wrkey .equ 05A00h
;PORT 0
P0IE .equ 015h
P0DIR .equ 012h
P0IN .equ 010h
P0OUT .equ 011h
; port 2
P2IN .equ 028h
P2OUT .equ 029h
P2IE .equ 02Dh
P2SEL .equ 02Eh
P2DIR .equ 02Ah
SDA .equ 020h
SCL .equ 080h
DNC .equ 0A0h
OUT .equ P2OUT
DIR .equ P2DIR
IN .equ P2IN
LCD1 .equ 031h
LCDM .equ 030h
IE1 .equ 0h
IE2 .equ 01h
IFG1 .equ 02h
IFG2 .equ 03h
address .equ 0500h ; Адрес в ОЗУ для переменной сканирования
;****************************************************************************
; Reset : Инициализация процессора
;****************************************************************************
.sect ”MAIN”,RAM_orig
RESET
MOV #SP_orig,SP ; Инициализация указателя стека
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
CALL #show_clr
; Сброс адреса
res MOV.B #00FFh, address ; адрес начинается с 0xFF
; Начало цикла перебора адресов
retry
INC.B address ; переход к следующему адресу из 0xFF в 0x00
CMP.B #080h, address ; адрес = 80?
JZ res ; сброс адреса по переполнению
; пауза
MOV #02Fh, R7 ; цикл паузы
dela2 MOV #031Fh, R6
dela DEC R6
JNZ dela
DEC R7
JNZ dela2
; Отображение сканируемого адреса
MOV #0000h, R5 ; очистка (убедиться, что очищается старший байт)
MOV.B address, R5 ; R5 ? младший байт
AND #000Fh, R5 ; маска на старшую тетраду
MOV.B LCD_Tab(R5),LCD1+1
; отобразить младшую тетраду 0–F
MOV.B address, R5 ; R5 ? младший байт
AND #00F0h, R5 ; маска на младшую тетраду
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
MOV.B LCD_Tab(R5), LCD1+2
; отобразить старшую тетраду 0–F
PUSH #00h ; место для кода ошибки
PUSH address ; поместить адрес в стек
SUB #06, SP
CALL #hunt
POP R10 ; вернуть данные в R10
POP R11 ; вернуть данные в R11
ADD #04h, SP ; освободить место для адреса и команд
POP R9 ; вернуть код ошибки
CMP #00h, R9
JZ retry ; повтор при неудаче
MOV #0FFh, R7
dela4 MOV #0B4Fh, R6
dela3 DEC R6
JNZ dela3
DEC R7
JNZ dela4
MOV #0000h, R5 ; очистка (убедиться, что очищается старший байт)
MOV.B address, R5 ; R5 ? младший байт
AND #000Fh, R5 ; маска на старшую тетраду
MOV.B LCD_Tab(R5),LCD1+4
; отобразить младшую тетраду 0–F
MOV.B address, R5 ; R5 ? младший байт
AND 00F0h, R5 ; маска на младшую тетраду
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
MOV.B LCD_Tab(R5), LCD1+5
; отобразить старшую тетраду 0–F
JMP retry ; повтор для следующего адреса
;****************************************************************************
; Завершение пользовательской программы
;****************************************************************************
;****************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально
; для реализации различных протоколов
;****************************************************************************
;****************************************************************************
; Поиск это модифицированная часть протокола «Чтение байта»
;****************************************************************************
hunt PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую последовательность и адрес
CALL #sendzero ; отправить 0 для записи
CALL #ack ; ждём подтверждения (ACK)
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
;****************************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit ; «отпустить» обе линии
BIC.B #DNC, DIR
; проверка освобождения шины
MOV #05h, R10 ; счётчик на 50 микросекунд
wait
MOV.B IN, R11 ; копировать состояние входов в R11
AND #DNC, R11 ; маска входов
CMP #DNC, R11 ; если линии SDA или SCL в лог. «0»то шина занята
JNZ busy
DEC R10 ; декремент счётчика
JNZ wait
rsbit BIC.B #DNC, DIR ; дополнительное освобождение линии с целью
; использования этой же подпрограммы для
; команды повторяющегося старта
; отправка стартовой последовательности
BIS.B #SDA, DIR
BIS.B #SCL, DIR
; отправка адреса
MOV.B #07h, R13 ; счётчик на 7 бит адреса
MOV.B R7, R11 ; копировать адрес в R11
ashift RLA.B R11 ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться на 7-й позиции
MOV.B R11, R12 ; скопировать его для возможности маскирования
; без потери данных
AND.B #080h, R12 ; маскировать все биты кроме СЗР
CMP.B #00h, R12 ; сравнить с 0
JNZ one
CALL #sendzero ; отправить «1»
JMP zero
one CALL #sendone ; отправить «0»
zero DEC R13 ; декремент счётчика
JNZ ashift ; если счётчик <7 бит, повторить сдвиг
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy CALL #pbit ; отправить STOP и busy
ADD #02h, SP ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP R13 ; восстановление регистров
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Обработка занятости системы
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
busy3 ADD #06h, SP ; удаление лишних данных процедур sendone или sendzero
busy ADD #02h, SP ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP R13 ; восстановление регистров
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «1»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendone PUSH R10
PUSH R11
BIC.B #SDA, DIR ; установить лог. «1» на линии SDA
BIC.B #SCL, DIR ; установить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV.B #04h, R11 ; установить число тактов для верного времени
clkext MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy3 ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clkext
; арбитраж: убедиться, что на линии SDA действительно лог. «1», иначе приоритет
; отдаётся другому ведущему устройству
MOV.B IN, R10 ; проверка шины
AND.B #SDA, R10 ; маскировать всё, кроме SDA
JZ busy3
BIS.B #SCL, DIR ; освободить линию SCL
MOV.B IN, R10 ; определение повторяющейся
; стартовой последовательности
AND.B #SDA, R10
JZ busy3
POP R11
POP R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «0»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendzero
PUSH R10
PUSH R11
BIS.B #SDA, DIR ; выставить лог. «0» на линии SDA
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV #04h, R11 ; счётчик времени перехода SCL в «1»
clke MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy3 ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clke
BIS.B #SCL, DIR ; освободить линию SCL
POP R11
POP R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV #008h, R11 ; счётчик на ?50 мкс
MOV #02FFh, R11 ; удлинённый счётчик для батареи PS100Z–200
clkex MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
MOV #05F6h, R11 ; счётчик таймаута для NACK
wack
MOV.B IN, R10 ; проверка шины
DEC R11
JZ sbusy ; таймаут NACK–– отправить бит P и повторить попытку
AND.B #SDA, R10 ; маскировать всё, кроме SDA
JNZ wack ; приём ACK или ожидание таймаута
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
BIS.B #SDA, DIR ; выставить лог. «0» на линии SDA
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
NOP
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
NOP
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
RET
;––– очистка ЖКИ
show_clr
MOV #15, r5 ; очистка дисплейной памяти
show_clr1
MOV.b #0, LCD1–1(r5)
DEC r5
JNZ show_clr1
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a .equ 01h
b .equ 02h
c .equ 10h
d .equ 04h
e .equ 80h
f .equ 20h
g .equ 08h
h .equ 40h
LCD_Tab .byte a+b+c+d+e+f ;отображает ”0”
.byte b+c ; отображает”1”
.byte a+b+d+e+g ; отображает”2”
.byte a+b+c+d+g ; отображает”3”
.byte b+c+f+g ; отображает”4”
.byte a+c+d+f+g ; отображает”5”
.byte a+c+d+e+f+g ; отображает”6”
.byte a+b+c ; отображает”7”
.byte a+b+c+d+e+f+g ; отображает”8”
.byte a+b+c+d+f+g ; отображает”9”
.byte a+b+c+e+f+g ; отображает”A”
.byte c+d+e+f+g ; отображает”B” b
.byte a+d+e+f ; отображает”C”
.byte b+c+d+e+g ; отображает”D” d
.byte a+d+e+f+g ; отображает”E”
.byte a+e+f+g ; отображает”F”
LCD_Tab_End
.even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
.sect ”Int_Vect”,05FFh–1 ; с программой монитора
.word RESET ; POR, внеш. Reset, Watchdog
.end
Приложение C Программа работы со смарт-батареей
;****************************************************************************
; Программа SBData
; ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
; Читает температуру, напряжение, производителя, хим. конфигурацию, ёмкость, и
; предупреждение об оставшейся ёмкости из монитора батареи с шиной SMBus.
; Также производится запись в регистр «Предупреждение об оставшейся ёмкости»
; (RemainingCapacityAlarm).
;
; В данном частном случае применялся батарейный смарт-модуль PowerSmart PS100Z–200
; Другие данные из батареи можно читать, меняя команды.
; Контроллер смарт-батареи PowerSmart поддерживает стандарт SMBus V1.0
; и спецификацию Smart Battery data
; Настоящая конфигурация программы написана для использования с пользовательской
; программой под управлением программы монитора
; на отладочной плате 337 EVK, подпрограммы SMBus находятся в EPROM. Также требуется
; Таблица ASCII символов для ЖКИ
; Здесь использован файл ASCII.txt. На него ссылается указатель alcd.
;****************************************************************************
RAM_orig .set 00240h ; Стартовый адрес
SP_orig .set 005DEh ; указатель стека
EPROM .set 08850h ; Размещение EPROM
;––– Определения управляющих регистров
WDTCTL .equ 0120h
WDTHold .equ 80h
WDT_wrkey .equ 05A00h
;PORT 0
P0IE .equ 015h
P0DIR .equ 012h
P0IN .equ 010h
P0OUT .equ 011h
; port 2
P2IN .equ 028h
P2OUT .equ 029h
P2IE .equ 02Dh
P2SEL .equ 02Eh
P2DIR .equ 02Ah
SDA .equ 020h
SCL .equ 080h
DNC .equ 0A0h
OUT .equ P2OUT
DIR .equ P2DIR
IN .equ P2IN
LCD1 .equ 031h
LCDM .equ 030h
IE1 .equ 0h
IE2 .equ 01h
IFG1 .equ 02h
IFG2 .equ 03h
block .equ 0550h
alcd .equ 0B500h ; Размещение таблицы символов ASCII для ЖКИ
;****************************************************************************
; Reset : Initialize processor
;****************************************************************************
.sect ”MAIN”,RAM_orig
RESET
MOV #SP_orig,SP ; Инициализация указателя стека
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
repeat
CMP.B #0FFh, R8
JNZ skp
INC.B R7 ; инкремент старшего байта значения
; для протокола записи слова
MOV.B #00h, R8
skp
INC.B R8 ; инкремент значения
; для протокола записи слова
skp0
; Чтение температуры
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #008h ; поместить команду чтения
; температуры батареи
PUSH #00h ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #rwp
POP R10 ; поместить данные в R10
POP R11 ; поместить данные в R11
ADD #04h, SP ; освободить место команды и адреса
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp0 ; повтор при неудаче
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
XOR R10, R11 ; объединить 2 байта данных
MOV R11, R12
SUB #0AAAh, R12 ; перевод в градусы Цельсия
CALL #display ; вызов подпрограммы отображения
XOR.B #40h, LCD1+1
; добавить децимальную точку
MOV.B alcd+’T’, LCD1+5
CALL #delay ; вызов подпрограммы задержки
skp1 ; чтение напряжения
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #009h ; поместить в стек команду
; чтения напряжения батареи
PUSH #00h ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #rwp
POP R10 ; поместить данные в R10
POP R11 ; поместить данные в R11
ADD #04h, SP ; освободить место команды и адреса
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp1 ; повтор при неудаче
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
XOR R10, R11 ; объединить 2 байта данных
MOV R11, R12
CALL #display ; вызов подпрограммы отображения
XOR.B #40h, LCD1+3
; добавить децимальную точку
MOV.B alcd+’U’, LCD1+5
CALL #delay ; вызов подпрограммы задержки
skp2 ; чтение названия производителя
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #0020h ; поместить в стек команду
; чтения имени производителя
PUSH #block ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #blkr
POP R10 ; поместить данные в R10
ADD #06h, SP
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp2 ; повтор при неудаче
MOV.B block, R5 ; копировать символ
MOV.B alcd(R5), LCD1+6
; отобразить символ
MOV.B block+1, R5 ; копировать символ
MOV.B alcd(R5), LCD1+5
; отобразить символ
MOV.B block+2, R5 ; копировать символ
MOV.B alcd(R5), LCD1+4
; отобразить символ
MOV.B block+3, R5 ; копировать символ
MOV.B alcd(R5), LCD1+3
; отобразить символ
MOV.B block+4, R5 ; копировать символ
MOV.B alcd(R5), LCD1+2
; отобразить символ
MOV.B block+5, R5 ; копировать символ
MOV.B alcd(R5), LCD1+1
; отобразить символ
MOV.B block+6, R5 ; копировать символ
MOV.B alcd(R5), LCD1+0
; отобразить символ
CALL #delay ; вызов подпрограммы задержки
skp3 ; чтение химической конфигурации
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #0022h ; поместить в стек команду
; чтения химической конфигурации
PUSH #block ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #blkr
POP R10 ; поместить данные в R10
ADD #06h, SP
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp3 ; повтор при неудаче
MOV.B block, R5 ; копировать символ
MOV.B alcd(R5), LCD1+6
; отобразить символ
MOV.B block+1, R5 ; копировать символ
MOV.B alcd(R5), LCD1+5
; отобразить символ
MOV.B block+2, R5 ; копировать символ
MOV.B alcd(R5), LCD1+4
; отобразить символ
MOV.B block+3, R5 ; копировать символ
MOV.B alcd(R5), LCD1+3
; отобразить символ
CALL #delay ; вызов подпрограммы задержки
skp4 ; чтение ёмкости батареи
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #0018h ; поместить в стек команду
; чтения ёмкости батареи
PUSH #00h ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #rwp
POP R10 ; поместить данные в R10
POP R11 ; поместить данные в R11
ADD #04h, SP ; освободить место команды и адреса
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp4 ; повтор при неудаче
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
XOR R10, R11
MOV R11, R12
CALL #display ; вызов подпрограммы отображения
XOR.B #40h, LCD1+3
; добавить децимальную точку
MOV.B alcd+’A’, LCD1+1
MOV.B alcd+’H’, LCD1+0
CALL #delay ; вызов подпрограммы задержки
skp5 ; запись предупреждения об оставшейся ёмкости (RemainingCapacityAlarm)
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #001h ; поместить в стек команду
PUSH R8 ; зарезервировать байт для данных
PUSH R7 ; зарезервировать байт для данных
CALL #wwp
POP R11 ; поместить данные в R11
POP R10 ; поместить данные в R10
ADD #04h, SP ; освободить место команды и адреса
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp5 ; повтор при неудаче
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
XOR R10, R11
MOV R11, R12
CALL #display ; вызов подпрограммы отображения
MOV.B alcd+’S’, LCD1+6
CALL #delay ; вызов подпрограммы задержки
skp6 ; считывание оставшейся ёмкости (RemainingCapacityAlarm)
CALL #show_clr
PUSH #00h ; место для кода ошибки
PUSH #000Bh ; поместить адрес в стек
PUSH #001h ; поместить в стек команду
PUSH #00h ; зарезервировать байт для данных
PUSH #00h ; зарезервировать байт для данных
CALL #rwp
POP R10 ; поместить данные в R10
POP R11 ; поместить данные в R11
ADD #04h, SP ; освободить место команды и адреса
POP R9 ; читать код ошибки
CMP #00h, R9
JZ skp6 ; повтор при неудаче
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
RLA R11
XOR R10, R11
MOV R11, R12
CALL #display ; вызов подпрограммы отображения
MOV.B alcd+’R’, LCD1+6
CALL #delay ; вызов подпрограммы задержки
JMP repeat ; завершение программы, бесконечный цикл
;****************************************************************************
; Окончание пользовательской программы
;****************************************************************************
delay
PUSH R6
PUSH R7
MOV #00DFh, R7 ; вложенный цикл задержки
dela4 MOV #0D40h, R6
dela3 DEC R6
JNZ dela3
DEC R7
JNZ dela4
POP R7
POP R6
RET
display ; подпрограмма отображения
PUSH R5
PUSH R12
PUSH R13
PUSH R14
PUSH R15
MOV #16, R15 ; процедура преобразования hex ? BCD
CLR R14 ; входные значения в R12, выходные в R13 и R14
CLR R13
ls1 RLA R12
DADD R13, R13
DADD R14, R14
DEC R15
JNZ ls1
MOV.B R13, R5 ; поместить 2 младших BCD-разряда в R5
AND #000Fh, R5 ; маскировать всё, кроме младшей тетрады
MOV.B LCD_Tab(R5),LCD1+0
; Отобразить младшую тетраду
MOV.B R13, R5
; поместить 2 младших BCD-разряда в R5
AND #00F0h, R5 ; маскировать всё, кроме старшей тетрады
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
MOV.B LCD_Tab(R5), LCD1+1
; Отобразить старшую тетраду
SWPB R13 ; обмен байтами в R13
MOV.B R13, R5 ; поместить 2 старших BCD-разряда в R5
AND #000Fh, R5 ; маскировать всё, кроме младшей тетрады
MOV.B LCD_Tab(R5),LCD1+2
; Отобразить младшую тетраду
MOV.B R13, R5 ; поместить 2 старших BCD-разряда в R5
AND #00F0h, R5 ; маскировать всё, кроме старшей тетрады
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
MOV.B LCD_Tab(R5), LCD1+3
; Отобразить старшую тетраду
MOV.B R14, R5 ; поместить 2 младших BCD-разряда в R5
AND #000Fh, R5 ; маскировать всё, кроме младшей тетрады
MOV.B LCD_Tab(R5),LCD1+4
; Отобразить младшую тетраду
MOV.B R14, R5 ; поместить 2 младших BCD-разряда в R5
AND #00F0h, R5 ; маскировать всё, кроме старшей тетрады
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
RRA R5 ; сдвиг вправо
MOV.B LCD_Tab(R5), LCD1+5
; Отобразить старшую тетраду
POP R15
POP R14
POP R13
POP R12
POP R5
RET
.sect ”smbus”, EPROM
;****************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально
; для реализации различных протоколов
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Быстрая команда» 1
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-–––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; не используется unused
; не используется unused
; не используется unused
; адрес address старшая область памяти high mem
;
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; SUB #06h, SP ; остальные параметры не используются
; CALL #qcp
; ADD #08h, SP ; вычесть объём параметров
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
qcp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 28(SP), R7 ; получить адрес из стека
CALL #sbit ; отправить стартовую посылку и адрес
;CALL #sendone ; отправить «1» или
CALL #sendzero ; отправить «0»
CALL #ack ; ждём подтверждения (ACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Записать байт» 4
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; данные (data) из
; подтверждение(acknowledge) в ?
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; не используется unused
; данные data
; команда command
; адрес address старшая область памяти high mem
;
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #001h ; поместить команду в стек
; PUSH #055h ; отправляемые данные
; SUB #02h, SP ; остальные параметры не используются
; CALL #wbp
; ADD #08h, SP ; вычесть объём параметров
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
wbp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
MOV.B 24(SP), R8 ; отправка данных
CALL #sbyte ; отправить байт данных
CALL #ack ; ждём подтверждения (ACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Записать слово» 5
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; данные (data) из
; подтверждение(acknowledge) в ?
; данные (data) из
; подтверждение(acknowledge) в ?
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; не используется unused
; данные data
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #001h ; код команды
; PUSH #0AAh ; младший отправляемый байт
; PUSH #055h ; старший отправляемый байт
; CALL #wwp
; ADD #08h, SP ; освободить место, занимаемое параметрами
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wwp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
MOV.B 24(SP), R8 ; данные для записи – младший байт
CALL #sbyte ; отправить младший байт данных
CALL #ack ; ждём подтверждения (ACK)
MOV.B 22(SP), R8 ; данные для записи – старший байт
CALL #sbyte ; отправить старший байт данных
CALL #ack ; ждём подтверждения (ACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Читать байт» 6
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; данные (data) в ?
; неподтверждение(NACK) из
; стоп (stop) из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; младший байт данных data
; не используется unused
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #000Bh ; поместить адрес в стек
; PUSH #008h ; код команды чтения температуры батареи
; PUSH #00h ; зарезервировать байт для данных (не используется)
; PUSH #00h ; зарезервировать байт для данных
; CALL #rbp
; POP R10 ; переместить данные в R10
; ADD #06h, SP ; освободить место команды и адреса
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte ; принять байт данных
CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B R14, 22(SP) ; копировать байт данных в стек
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Читать слово» 7
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; данные (data) в ?
; подтверждение(acknowledge) в ?
; данные (data) в ?
; подтверждение(acknowledge) в ?
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; младший байт данных low data byte
; старший байт данных high data byte
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #008h ; код команды “температура батареи”
; PUSH #00h ; зарезервировать байт под принимаемые данные
; PUSH #00h ; зарезервировать байт под принимаемые данные
; CALL #rwp
; POP R10 ; переместить данные в R10
; POP R11 ; переместить данные в R11
; ADD #04h, SP ; освободить место, занимаемое командой и адресом
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rwp
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte ; принять младший байт данных
MOV.B R14, 22(SP) ; сохранить младший байт данных в стеке
CALL #sack ; ждём подтверждения (ACK)
CALL #rbyte ; принять старший байт данных
CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B R14, 24(SP) ; сохранить старший байт данных в стеке
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Запись блока» 8
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; чтение/запись(R/W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; счётчик байт (byte count) из
; подтверждение(acknowledge) в ?
; данные (data) из
; подтверждение(acknowledge) в ?
;
; данные (data) в ?
; подтверждение(acknowledge) в ?
;
; данные и ACK повторяются n раз
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; счётчик байт byte count
; указатель блока block pointer
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #0020h ; код команды “температура батареи”
; PUSH #00550h ; указатель на начало блока
; PUSH #00h ; зарезервировать байт под счётчик
; CALL #blkw
; POP R10 ; переместить данные в R10
; ADD #06h, SP
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkw
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
MOV 24(SP), R9 ; стартовый адрес блока
MOV.B #00h, R15 ; циклический байтовый счётчик
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
MOV.B 22(SP), R8 ; копировать счётчик байт
CALL #sbyte ; отправить счётчик байт
CALL #ack ; ждём подтверждения (ACK)
blk_rep MOV.B 0(R9), R8 ; передать данные из блока
CALL #sbyte ; отправить байт данных
CALL #ack ; ждём подтверждения (ACK)
INC R15 ; инкремент счётчика положения блока
INC R9 ; инкремент указателя блока
CMP 22(SP), R15 ; проверка завершения данных
JNZ blk_rep ; повтор до завершения
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Чтение блока» 9
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание Шаг Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
; старт (start) из
; адрес(address) из
; запись(W) из
; подтверждение(acknowledge) в ?
; команда (command) из
; подтверждение(acknowledge) в ?
; старт (start) из
; адрес(address) из
; чтение(R) из
; подтверждение(acknowledge) в ?
; счётчик байт (byte count) в ?
; подтверждение(acknowledge) из
; данные (data) в ?
; подтверждение(acknowledge) из
;
; данные и ACK повторяются n раз
; неподтверждение(NACK) из
; стоп (stop) из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки error_flag младшая область памяти low mem
; счётчик байт byte count
; указатель блока block pointer
; команда command
; адрес address старшая область памяти high mem
; –––––––––––––––––
; Пример использования
; ––––––––––––––
; PUSH #00h ; место для кода ошибки
; PUSH #00Bh ; поместить адрес в стек
; PUSH #0020h ; код команды “температура батареи”
; PUSH #00550h ; указатель на начало блока
; PUSH #00h ; зарезервировать байт под счётчик
; CALL #blkr
; POP R10 ; переместить счётчик в R10
; ADD #06h, SP
; POP R9 ; читать из стека код ошибки
; CMP #00h, R9
; JZ error ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkr
PUSH SR
PUSH R7
PUSH R8
PUSH R9
PUSH R14
PUSH R15
PUSH R10
PUSH R11
PUSH R12
PUSH R13
MOV.B #00h, R15 ; циклический байтовый счётчик
MOV.B 26(SP), R8 ; параметр команды
MOV.B 28(SP), R7 ; параметр адреса
MOV 24(SP), R9 ; стартовый адрес блока
CALL #sbit ; отправить стартовую посылку и адрес
CALL #sendzero ; отправить «0» для записи
CALL #ack ; ждём подтверждения (ACK)
CALL #sbyte ; отправить код команды
CALL #ack ; ждём подтверждения (ACK)
CALL #rsbit ; отправить повторяющиеся стартовую посылку и адрес
CALL #sendone ; отправить «1» для чтения
CALL #ack ; ждём подтверждения (ACK)
CALL #rbyte
MOV.B R14, 22(SP) ; поместить счётчик в стек
CALL #sack ; отправить подтверждение (ACK)
rblk_rep CALL #rbyte ; принять байт данных
MOV.B R14, 0(R9) ; переместить данные из блока
INC R15 ; инкремент счётчика положения блока
INC R9 ; инкремент указателя блока
CMP 22(SP), R15 ; проверка завершения данных
JZ blk_done ; повтор до завершения
CALL #sack ; отправить подтверждение (ACK)
CMP 22(SP), R15 ; проверка завершения данных
JNZ rblk_rep ; повтор до завершения
blk_done CALL #nack ; отправить неподтверждение (NACK)
CALL #pbit ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP R13
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
;****************************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit ; «отпустить» обе линии
BIC.B #DNC, DIR
; проверка освобождения шины
MOV #05h, R10 ; счётчик на 50 микросекунд
wait
MOV.B IN, R11 ; копировать состояние входов в R11
AND #DNC, R11 ; маска входов
CMP #DNC, R11 ; если линии SDA или SCL в лог. «0»то шина занята
JNZ busy
DEC R10 ; декремент счётчика
JNZ wait
rsbit BIC.B #DNC, DIR ; дополнительное освобождение линии с целью
; использования этой же подпрограммы для
; команды повторяющегося старта
; отправка стартовой последовательности
BIS.B #SDA, DIR
BIS.B #SCL, DIR
; отправка адреса
MOV.B #07h, R13 ; счётчик на 7 бит адреса
MOV.B R7, R11 ; копировать адрес в R11
ashift RLA.B R11 ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться на 7-й позиции
MOV.B R11, R12 ; скопировать его для возможности маскирования
; без потери данных
AND.B #080h, R12 ; маскировать все биты кроме СЗР
CMP.B #00h, R12 ; сравнить с 0
JNZ one
CALL #sendzero ; отправить «1»
JMP zero
one CALL #sendone ; отправить «0»
zero DEC R13 ; декремент счётчика
JNZ ashift ; если счётчик <7 бит, повторить сдвиг
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy CALL #pbit ; отправить STOP и busy
ADD #02h, SP ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP R13 ; восстановление регистров
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Обработка состояния занятости (busy)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
busy3 ADD #06h, SP ; удалить лишние данные от подпрограмм
; sendone или sendzero
busy ADD #02h, SP ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP R13 ; восстановить регистры
POP R12
POP R11
POP R10
POP R15
POP R14
POP R9
POP R8
POP R7
POP SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «1»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendone PUSH R10
PUSH R11
BIC.B #SDA, DIR ; установить лог. «1» на линии SDA
BIC.B #SCL, DIR ; установить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV.B #04h, R11 ; установить число тактов для верного времени
clkext MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy3 ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clkext
; арбитраж: убедиться, что на линии SDA действительно лог. «1», иначе приоритет
; отдаётся другому ведущему устройству
MOV.B IN, R10 ; проверка шины
AND.B #SDA, R10 ; маскировать всё, кроме SDA
JZ busy3
BIS.B #SCL, DIR ; освободить линию SCL
MOV.B IN, R10 ; определение повторяющейся
; стартовой последовательности
AND.B #SDA, R10
JZ busy3
POP R11
POP R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «0»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendzero
PUSH R10
PUSH R11
BIS.B #SDA, DIR ; выставить лог. «0» на линии SDA
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV #04h, R11 ; счётчик времени перехода SCL в «1»
clke MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy3 ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clke
BIS.B # SCL, DIR ; освободить линию SCL
POP R11
POP R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV #008h, R11 ; счётчик на ?50 мкс
MOV #02FFh, R11 ; удлинённый счётчик для батареи PS100Z–200
clkex MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy ; арбитраж – время истекло
AND.B #SCL, R10 ; проверка линии SCL
JZ clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
MOV #05F6h, R11 ; счётчик таймаута для NACK
wack
MOV.B IN, R10 ; проверка шины
DEC R11
JZ sbusy ; таймаут NACK–– отправить бит P и повторить попытку
AND.B #SDA, R10 ; маскировать всё, кроме SDA
JNZ wack ; приём ACK или ожидание таймаута
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
BIS.B #SDA, DIR ; выставить лог. «0» на линии SDA
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
NOP
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
NOP
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка байта (используются также sendzero и sendone)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbyte
; отправка данных
MOV.B #08h, R13 ; счётчик на ?50 мкс
MOV.B R8, R11 ; копировать данные в R11
dshift
MOV.B R11, R12
AND.B #080h, R12 ; маскировать все биты, кроме СЗР
CMP.B #00h, R12 ; сравнить с 0
JNZ on
CALL #sendzero ; отправить «1»
JMP zer
on CALL #sendone ; отправить «0»
zer
RLA.B R11 ; сдвиг влево, отправляемый бит в СЗР
DEC R13 ; декремент счётчика на 8
JNZ dshift
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Приём байта
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbyte
MOV.B #08h, R12 ; счётчик на 8 бит данных
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
rrep
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
MOV #0035h, R13 ; удлинённый счётчик для батареи PS100Z–200
; удлинение тактового сигнала
clkxtn MOV.B IN, R10 ; проверка шины
DEC R13
JZ busy ; выход по таймауту
AND.B #SCL, R10
JZ clkxtn ; ожидание, если SCL не «1»
MOV.B IN, R10 ; проверка шины
RLA.B R11 ; move over for input as LSB
AND.B #SDA, R10 ; проверка SDA
JZ inzero
BIS.B #01h, R11 ; установить «1» в МЗР
inzero DEC R12
JNZ rrep ; продолжение для оставшейся части байта
MOV.B R11, R14 ; копирование данных
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка неподтверждения (NACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
nack
BIC.B #SDA, DIR ; выставить лог. «1» на линии SDA
BIS.B #SCL, DIR ; выставить лог. «0» на линии SCL
BIC.B #SCL, DIR ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
; ждём установки «1» на линии SCL
clkn MOV.B IN, R10
AND.B #SCL, R10 ; проверка линии SCL
JZ clkn
BIS.B #SCL, DIR ; «отпустить» SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sack ; ждём, пока ведомый «отпустит» линию SDA
MOV #000Fh, R11 ; счётчик на ?50 мкс
swaita MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy
AND.B #SDA, R10 ; проверка SCL
JZ swaita
BIS.B #SDA, DIR ; перевести SDA в «0»
BIC.B #SCL, DIR ; перевести SCL в «1»
MOV #000Fh, R11 ; счётчик на ?50 мкс
swait MOV.B IN, R10 ; проверка шины
DEC R11
JZ busy
AND.B #SCL, R10 ; проверка SCL
JZ swait
BIS.B #SCL, DIR ; перевести SCL в «0»
BIC.B #SDA, DIR ; «отпустить» SDA
RET
;––– очистка ЖКИ
show_clr
MOV #15, r5 ; очистка дисплейной памяти
show_clr1
MOV.b #0, LCD1–1(r5)
DEC r5
JNZ show_clr1
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a .equ 01h
b .equ 02h
c .equ 10h
d .equ 04h
e .equ 80h
f .equ 20h
g .equ 08h
h .equ 40h
;––– Определения символов
LCD_Tab .byte a+b+c+d+e+f ; отображает”0”
.byte b+c ; отображает”1”
.byte a+b+d+e+g ; отображает”2”
.byte a+b+c+d+g ; отображает”3”
.byte b+c+f+g ; отображает”4”
.byte a+c+d+f+g ; отображает”5”
.byte a+c+d+e+f+g ; отображает”6”
.byte a+b+c ; отображает”7”
.byte a+b+c+d+e+f+g ; отображает”8”
.byte a+b+c+d+f+g ; отображает”9”
.byte 0 ; отображает ”:” пустой
.byte g ; отображает”;” –
.byte a+d+e+f ; отображает”<” [
.byte d+g ; отображает”=”
.byte a+b+c+d ; отображает”>” ]
.byte a+b+e+g ; отображает”?”
.byte a+b+d+e+f+g ; отображает”@”
.byte a+b+c+e+f+g ; отображает”A”
.byte c+d+e+f+g ; отображает”B” b
.byte a+d+e+f ; отображает”C”
.byte b+c+d+e+g ; отображает”D” d
.byte a+d+e+f+g ; отображает”E”
.byte a+e+f+g ; отображает”F”
.byte a+b+c+d+f+g ; отображает”G”
.byte b+c+e+f+g ; отображает”H”
.byte b+c ; отображает”I”
.byte b+c+d+e ; отображает”J”
.byte 0 ; отображает”K”
.byte d+e+f ; отображает”L”
.byte a+b+c+e+f ; отображает”M”
.byte c+e+g ; отображает”N” n
.byte c+d+e+g ; отображает”O” o
.byte a+b+e+f+g ; отображает”P”
.byte 0 ; отображает”Q”
.byte e+g ; отображает”R” r
.byte a+c+d+f+g ; отображает”S”
.byte d+e+f+g ; отображает”T” t
.byte c+d+e ; отображает”U” u
.byte 0 ; отображает”V”
.byte 0 ; отображает”W”
.byte 0 ; отображает”X”
.byte b+c+d+f+g ; отображает”Y”
.byte a+b+d+e+g ; отображает”Z” 2
LCD_Tab_End
.even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; .sect ”Int_Vect”,0FFFFh–1 ; без программы монитора
; .word RESET ; POR, внеш. Reset, Watchdog
; .end
.sect ”Int_Vect”,05FFh–1 ; с программой монитора
.word RESET ; POR, внеш. Reset, Watchdog
.end
Приложение C Программа ведомого устройства шины SMBus
;****************************************************************************
; Программа ведомого устройства шины SMBus
;****************************************************************************
USER_END .set 0FFFFh
Device .set 325
;––– Определения управляющих регистров
SRE .equ 0h
IE1 .equ 0h
IE2 .equ 01h
IFG1 .equ 02h
IFG2 .equ 03h
WDTCTL .equ 0120h
WDTHold .equ 80h
WDT_wrkey .equ 05A00h
CPUOFF .set 10h
OSCOFF .set 20h
;Порт PORT 0
P0IE .equ 015h
P0DIR .equ 012h
P0IN .equ 010h
P0OUT .equ 011h
P0IES .equ 014h
P0IFG .equ 013h
;Порт port 2
P2IN .equ 028h
P2OUT .equ 029h
P2IE .equ 02Dh
P2SEL .equ 02Eh
P2DIR .equ 02Ah
LCD1 .equ 031h
LCDM .equ 030h
OUT .equ P0OUT
IN .equ P0IN
DIR .equ P0DIR
SDA .equ 010h
SCL .equ 020h
DNC .equ 030h
; Расположение таблицы
Table .equ 0300h
;****************************************************************************
; Reset : инициализация процессора
;****************************************************************************
.sect ”onreset”,0FFFEh
.word INIT
.sect ”intv”, 0FFE0h
.word rbp
.sect ”MAIN”,0C000h
INIT
.if Device = 325
MOV #03C0h, SP
.endif
.if Device = 337
MOV #05D0h, SP
.endif
MOV #(WDTHold+WDT_wrkey),&WDTCTL
; Остановить сторожевой таймер Watchdog Timer
; Инициализация порта port2
BIC.B #DNC, DIR ; Биты 1 и 0 - входы
BIC.B #DNC, OUT ; установить лог. «1» на линиях SDA и SCL
BIS.B #SDA, P0IE ; разрешить прерывания по P0.4
BIS.B #SDA, P0IES ; прерывание по спаду на P0.4
RESET
nready ; шина не находится в состоянии готовности / нет стартовой посылки
waddr ; возврат сюда, если неверный адрес устройства
MOV.B #000h, error ; сброс флага ошибки
MOV.B #055h, address
; адрес = 55h
MOV.B #09h, data ; данные = 09h
EINT ; общее разрешение прерываний
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
repeat
JMP repeat ; ожидание прерывания
;****************************************************************************
; Завершение пользовательской программы
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; приём байта (здесь обрабатывается прерывание)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
;PUSH R11 ; если известно, что стартовая посылка длительная,
; можно добавить эти строки
;PUSH R12
;PUSH R13
;PUSH R14
BIC.B #SDA, P0IFG ; очистить флаг прерывания
;****************************************************************************
; проверка стартовой последовательности
;****************************************************************************
wait2 MOV.B IN, R11 ; копировать состояние входов в R11
DEC R9
JZ done
AND #DNC, R11 ; маскировать все биты, кроме входов
CMP #SCL, R11 ; убедиться, что на линии SDA лог. «0»
; а на SCL лог. «1»
JNZ wait2 ; если нет - ожидаем
wait3 MOV.B IN, R11 ; копировать состояние входов в R11
DEC R9
JZ done
AND #DNC, R11 ; маскировать все биты, кроме входов
JNZ wait3 ; если нет - ожидаем
;****************************************************************************
; Стартовая последовательность получена
;****************************************************************************
MOV #007h, R13 ; счётчик на 7 адресных бит
MOV #0000h, R12 ; регистр для сохранения адреса
taddr MOV.B IN, R14 ; убедиться, что на линии SCL лог. «0»
DEC R9
JZ done
AND #SCL, R14
JNZ taddr
addr MOV.B IN, R14 ; чтение порта
DEC R9
JZ done
MOV.B R14, R11 ; копировать данные
AND #SCL, R14 ; маскировать все биты, кроме SCL
JZ addr ; ждём лог. «1» на SCL
AND #SDA, R11 ; маскировать все биты, кроме SDA
JZ szero ; если «0» - просто сдвиг
RLA.B R12 ; сдвиг влево
BIS.B #0001h, R12 ; если «1» установить «1» в МЗР и сдвиг
JMP sone
szero
RLA.B R12 ; арифметический сдвиг влево ? 0
sone DEC R13 ; декремент счётчика
JNZ taddr ; повтор, если менее 7 бит
MOV.B address, R13 ; копировать адрес устройства в R13
CMP.B R13, R12 ; и сравнить его с принятым адресом
JNZ waddr ; переход, если адрес неверный
;****************************************************************************
; адрес правильный, продолжаем
;****************************************************************************
; чтение бита R/W (чтение/запись)
rwait2 MOV.B IN, R11 ; ждём лог. «0» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JNZ rwait2
rwait MOV.B IN, R11 ; ждём лог. «1» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JZ rwait
MOV.B IN, R11 ; копировать данные из порта
AND.B #SDA, R11 ; маскировать все биты, кроме SDA
JNZ done ; 0 если запись, переход, если 1 (чтение)
;****************************************************************************
; Отправить бит подтверждения (ACK)
;****************************************************************************
rwait3 MOV.B IN, R11 ; ждём лог. «0» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JNZ rwait3
BIS.B #SDA, DIR ; перевести линию SDA в лог. «0»
rwait4 MOV.B IN, R11 ; ждём лог. «1» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JZ rwait4
rwait5 DEC R9
JZ done
MOV.B IN, R11 ; ждём лог. «0» на SCL
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JNZ rwait5
BIC.B #SDA, DIR ; «отпустить» линию SDA
;****************************************************************************
; готов принять байт
;****************************************************************************
MOV #008h, R13 ; счётчик на 8 бит данных
MOV #0000h, R12 ; регистр для сохранения адреса
tdat MOV.B IN, R14 ; убедиться, что на линии SCL лог. «0»
DEC R9
JZ done
AND #SCL, R14
JNZ tdat
dat MOV.B IN, R14 ; читаем данные из порта
MOV.B R14, R11 ; копируем данные
DEC R9
JZ done
AND #SCL, R14 ; маскировать все биты, кроме SCL
JZ dat ; ждём лог. «1» на SCL
AND #SDA, R11 ; маскировать все биты, кроме SDA
JZ szeroc ; если «0» - просто сдвиг
RLA.B R12
BIS.B #0001h, R12 ; если «1» установить «1» в МЗР и сдвиг
JMP szerob
szeroc RLA.B R12 ; арифметический сдвиг влево
szerob
DEC R13 ; декремент счётчика
JNZ tdat
MOV.B R12, data ; копируем в ОЗУ
;****************************************************************************
; Отправить бит подтверждения (ACK)
;****************************************************************************
rwait6 MOV.B IN, R11 ; ждём лог. «0» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JNZ rwait6
BIS.B #SDA, DIR ; перевести линию SDA в лог. «0»
rwait7 MOV.B IN, R11 ; ждём лог. «1» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JZ rwait7
rwait8 MOV.B IN, R11 ; ждём лог. «0» на SCL
DEC R9
JZ done
AND.B #SCL, R11 ; маскировать все биты, кроме SCL
JNZ rwait8
BIC.B #SDA, DIR ; «отпустить» линию SDA
done
;POP R14 ; если известно, что стартовая посылка длительная,
; можно добавить эти строки
;POP R13
;POP R12
;POP R11
MOV #0FFh, R9
RETI
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; переменные
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
address .equ 0248h ; адрес устройства
data .equ 0242h ; отправляемые данные
datin .equ 0244h ; принимаемые данные
error .equ 0246h ; флаг ошибки
Приложение E Содержание файла ASCII.txt
@B500
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
B7 12 8F 1F 3A 3D BD 13 BF 3F 00 00 00 00 00 00
00 BB BC A5 9E AD A9 3F BA 12 96 00 A4 B3 98 9C
AB 00 88 3D AC 94 00 00 00 3E 8F 00 00 00 00 00
00 BB BC A5 9E AD A9 3F BA 12 96 00 A4 B3 98 9C
AB 00 88 3D AC 94 00 00 00 3E 8F 00
q
Популярный сайт знакомств общения maybe.ru
|