ADSP-BF538: контроллеры интерфейса TWI (I2C) |
![]() |
Добавил(а) microsin | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
В процессоре ADSP-BF538 имеется два контроллера двухпроводного интерфейса (two-wire interface, TWI), которые позволяют осуществлять аппаратную поддержку обмена с устройствами стандарта Inter IC (I2C), как это было определено стандартом Philips I2C Bus Specification версии 2.1, разработанном в январе 2000 г. Каждый из этих аппаратных интерфейсов TWI полностью совместим с широко распространенным стандартом шины I2C. Аппаратура TWI была разработана с поддержкой функционала высокого уровня, что дает поддержку конфигураций multimaster (несколько главных устройств на одной шине) и multislave (несколько подчиненных устройств на шине, самая стандартная конфигурация системы I2C). Чтобы сохранить процессорное время, контроллеры TWI можно настроить на инициирование передач с прерываниями только на обслуживание буфера FIFO при чтении и записи данных. Опционально можно настроить прерывания, связанные с протоколом I2C. Каждый из контроллеров TWI осуществляет обмен 8-битными данными в соответствии с протоколом шины I2C. Стандарт Philips I2C Bus Specification версии 2.1 охватывает много вариантов I2C. Контроллеры TWI включают следующие из этих возможностей: • Одновременное функционирование в режимах master (главное устройство на шине) и slave (подчиненное устройство на шине) в системах с несколькими устройствами. Таблица 20-1 показывает выводы контроллеров TWI. Два двунаправленных вывода у каждого из контроллеров предназначены для подключения к шине I2C. Физически интерфейс очень прост, и кроме верхних подтягивающих резисторов, не требуется больше никаких внешних соединений или логических схем. Таблица 20-1. Ножки контроллеров TWI корпуса BC-316 (CSP_BGA) процессора ADSP-BF538.
[Архитектура] Рис. 20-1 показывает общую архитектуру контроллеров TWI. Периферийный интерфейс поддерживает передачи 16-битных данных, и используется для обращения к регистрам TWI и его буферам FIFO при операциях чтения и записи по шине I2C. Рис. 20-1. Блок-схема контроллера TWI. Блок регистров содержит все биты управления и состояния, и отражает то, что может быть записано или прочитано, как это определено программной моделью. Биты состояния могут обновляться своими функциональными блоками. Буфер сконфигурирован как однобайтный с глубиной 2 ячейки буфер передачи FIFO и однобайтный с глубиной 2 ячейки буфер приема FIFO. Регистр сдвига передачи последовательно выдвигает данные из чипа. Вывод может быть сконфигурирован для генерации подтверждений, или это может быть отменено вручную. Регистр сдвига приема принимает данные, поступающие снаружи. Ширина этого регистра 1 байт, и принятые данные могут быть переданы либо в буфер FIFO, либо использоваться в сравнении адреса. Блок сравнения адреса поддерживает сравнение адреса в событии модуля контроллера TWI, когда к нему обращаются как к slave-устройству (подчиненное устройство на шине I2C). Блок прескалера должен быть запрограммирован для генерации опорной частоты 10 МГц по отношению к системной тактовой частоте. Эта опорная частота используется для фильтрации данных и событий времени, интервалы которых определены электрическими параметрами даташита (см. стандарт Philips), а также для генерации тактов SCL. Модуль генерации тактов используется для формирования внешнего сигнала SCL, когда TWI работает в режиме master. В этом модуле находится вся необходимая логика для синхронизации конфигурации тактов системы multimaster, и для растягивания лог. 0 тактов, когда устройство сконфигурировано в режиме slave. [Описание регистров] В каждом из контроллеров TWI имеется 16 регистров, описанных во врезках ниже. Буква x в именах регистров заменяется на 0 или 1 в зависимости от того, к какому из двух интерфейсов TWI регистр относится. В системе программирования VisualDSP++ имена регистров Blackfin определены в соответствующих заголовочных файлах, находящихся в каталоге Blackfin\include. Например, определения адресов регистров и указателей на них для процессора ADSP-BF538 находятся в файлах defBF538.h и cdefBF538.h. [Заголовочный файл defBF538.h] /* Two-Wire Interface 0 (0xFFC01400 - 0xFFC014FF) */
#define TWI0_CLKDIV 0xFFC01400 /* Serial Clock Divider Register */ #define TWI0_CONTROL 0xFFC01404 /* TWI0 Master Internal Time Reference Register */ #define TWI0_SLAVE_CTRL 0xFFC01408 /* Slave Mode Control Register */ #define TWI0_SLAVE_STAT 0xFFC0140C /* Slave Mode Status Register */ #define TWI0_SLAVE_ADDR 0xFFC01410 /* Slave Mode Address Register */ #define TWI0_MASTER_CTRL 0xFFC01414 /* Master Mode Control Register */ #define TWI0_MASTER_STAT 0xFFC01418 /* Master Mode Status Register */ #define TWI0_MASTER_ADDR 0xFFC0141C /* Master Mode Address Register */ #define TWI0_INT_STAT 0xFFC01420 /* TWI0 Master Interrupt Register */ #define TWI0_INT_MASK 0xFFC01424 /* TWI0 Master Interrupt Mask Register */ #define TWI0_FIFO_CTRL 0xFFC01428 /* FIFO Control Register */ #define TWI0_FIFO_STAT 0xFFC0142C /* FIFO Status Register */ #define TWI0_XMT_DATA8 0xFFC01480 /* FIFO Transmit Data Single Byte Register */ #define TWI0_XMT_DATA16 0xFFC01484 /* FIFO Transmit Data Double Byte Register */ #define TWI0_RCV_DATA8 0xFFC01488 /* FIFO Receive Data Single Byte Register */ #define TWI0_RCV_DATA16 0xFFC0148C /* FIFO Receive Data Double Byte Register */ /* Two-Wire Interface 1 (0xFFC02200 - 0xFFC022FF) */
#define TWI1_CLKDIV 0xFFC02200 /* Serial Clock Divider Register */ #define TWI1_CONTROL 0xFFC02204 /* TWI1 Master Internal Time Reference Register */ #define TWI1_SLAVE_CTRL 0xFFC02208 /* Slave Mode Control Register */ #define TWI1_SLAVE_STAT 0xFFC0220C /* Slave Mode Status Register */ #define TWI1_SLAVE_ADDR 0xFFC02210 /* Slave Mode Address Register */ #define TWI1_MASTER_CTRL 0xFFC02214 /* Master Mode Control Register */ #define TWI1_MASTER_STAT 0xFFC02218 /* Master Mode Status Register */ #define TWI1_MASTER_ADDR 0xFFC0221C /* Master Mode Address Register */ #define TWI1_INT_STAT 0xFFC02220 /* TWI1 Master Interrupt Register */ #define TWI1_INT_MASK 0xFFC02224 /* TWI1 Master Interrupt Mask Register */ #define TWI1_FIFO_CTRL 0xFFC02228 /* FIFO Control Register */ #define TWI1_FIFO_STAT 0xFFC0222C /* FIFO Status Register */ #define TWI1_XMT_DATA8 0xFFC02280 /* FIFO Transmit Data Single Byte Register */ #define TWI1_XMT_DATA16 0xFFC02284 /* FIFO Transmit Data Double Byte Register */ #define TWI1_RCV_DATA8 0xFFC02288 /* FIFO Receive Data Single Byte Register */ #define TWI1_RCV_DATA16 0xFFC0228C /* FIFO Receive Data Double Byte Register */ [Заголовочный файл cdefBF538.h] /* Two-Wire Interface 0 */
#define pTWI0_CLKDIV ((volatile unsigned short *)TWI0_CLKDIV)
#define pTWI0_CONTROL ((volatile unsigned short *)TWI0_CONTROL)
#define pTWI0_SLAVE_CTRL ((volatile unsigned short *)TWI0_SLAVE_CTRL)
#define pTWI0_SLAVE_STAT ((volatile unsigned short *)TWI0_SLAVE_STAT)
#define pTWI0_SLAVE_ADDR ((volatile unsigned short *)TWI0_SLAVE_ADDR)
#define pTWI0_MASTER_CTRL ((volatile unsigned short *)TWI0_MASTER_CTRL)
#define pTWI0_MASTER_STAT ((volatile unsigned short *)TWI0_MASTER_STAT)
#define pTWI0_MASTER_ADDR ((volatile unsigned short *)TWI0_MASTER_ADDR)
#define pTWI0_INT_STAT ((volatile unsigned short *)TWI0_INT_STAT)
#define pTWI0_INT_MASK ((volatile unsigned short *)TWI0_INT_MASK)
#define pTWI0_FIFO_CTRL ((volatile unsigned short *)TWI0_FIFO_CTRL)
#define pTWI0_FIFO_STAT ((volatile unsigned short *)TWI0_FIFO_STAT)
#define pTWI0_XMT_DATA8 ((volatile unsigned short *)TWI0_XMT_DATA8)
#define pTWI0_XMT_DATA16 ((volatile unsigned short *)TWI0_XMT_DATA16)
#define pTWI0_RCV_DATA8 ((volatile unsigned short *)TWI0_RCV_DATA8)
#define pTWI0_RCV_DATA16 ((volatile unsigned short *)TWI0_RCV_DATA16)
/* Two-Wire Interface 1 */
#define pTWI1_CLKDIV ((volatile unsigned short *)TWI1_CLKDIV)
#define pTWI1_CONTROL ((volatile unsigned short *)TWI1_CONTROL)
#define pTWI1_SLAVE_CTRL ((volatile unsigned short *)TWI1_SLAVE_CTRL)
#define pTWI1_SLAVE_STAT ((volatile unsigned short *)TWI1_SLAVE_STAT)
#define pTWI1_SLAVE_ADDR ((volatile unsigned short *)TWI1_SLAVE_ADDR)
#define pTWI1_MASTER_CTRL ((volatile unsigned short *)TWI1_MASTER_CTRL)
#define pTWI1_MASTER_STAT ((volatile unsigned short *)TWI1_MASTER_STAT)
#define pTWI1_MASTER_ADDR ((volatile unsigned short *)TWI1_MASTER_ADDR)
#define pTWI1_INT_STAT ((volatile unsigned short *)TWI1_INT_STAT)
#define pTWI1_INT_MASK ((volatile unsigned short *)TWI1_INT_MASK)
#define pTWI1_FIFO_CTRL ((volatile unsigned short *)TWI1_FIFO_CTRL)
#define pTWI1_FIFO_STAT ((volatile unsigned short *)TWI1_FIFO_STAT)
#define pTWI1_XMT_DATA8 ((volatile unsigned short *)TWI1_XMT_DATA8)
#define pTWI1_XMT_DATA16 ((volatile unsigned short *)TWI1_XMT_DATA16)
#define pTWI1_RCV_DATA8 ((volatile unsigned short *)TWI1_RCV_DATA8)
#define pTWI1_RCV_DATA16 ((volatile unsigned short *)TWI1_RCV_DATA16)
Регистр управления TWI (TWIx_CONTROL), показанный на рис. 20-2, используется для разрешения работы модуля TWI, а также для установки взаимосвязи между системной тактовой частотой (SCLK) и внутренним формированием интервалов времени событий контроллера TWI. Внутренняя опорная частота TWI выводится из SCLK с помощью значения программирования прескалера. Рис. 20-2. TWI Control Register. Описание бит регистра TWIx_CONTROL: • SCCB Compatibility (SCCB). Режим совместимости SCCB это опция, и обычно она не должна использоваться на шине I2C. Функция совместимости SCCB допустима только в ситуациях, когда управляется шина стандарта SCCB в режиме master. Передач режима slave следует избегать, когда эта функция разрешена, потому что контроллер TWI в режиме slave всегда генерирует положительное подтверждение (ACK). 1: передачи Master совместимы с SCCB. Этим мастером игнорируются все slave-устройства, которые выставляют биты подтверждения. • TWI Enable (TWIx_ENA). Этот бит должен быть установлен в режиме slave или в режиме master. Рекомендуется устанавливать этот бит в момент времени, когда инициализировано и стабилизировалось время PRESCALE. Это будет гарантировать корректное функционирование логики детектирования занятости шины (bus busy detection). 1: разрешена внутренняя опорная частота. Обеспечивается работа режимов slave и master. • Prescale (PRESCALE). Количество периодов системных тактов (SCLK), используемых для генерации внутренней опорной частоты TWI. Значение PRESCALE должно быть установлено таким образом, чтобы формировались опорные интервалы времени с частотой 10 МГц. Значение PRESCALE представлено как 7-разрядное двоичное значение. Не всегда есть возможность точно установить частоту TWI 10 МГц. В таких случаях можно безопасно округлить вверх величину PRESCALE, чтобы установить его на следующее большее целое значение. Например, если частота SCLK равна 133 МГц, величина PRESCALE вычисляется как 133 МГц / 10 МГц = 13.3. В этом случае значение PRESCALE = 14 будет удовлетворять всем требованиям интервалов времени. В режиме master значения регистра делителя тактовой частоты SCL (TWIx_CLKDIV) используются для формирования длительностей лог. 1 и лог. 0 тактов SCL (см. рис. 20-3). Частоты тактов могут меняться от 400 кГц до менее чем 20 кГц. Разрешающая способность интервалов генерируемых тактов составляет 100 нс (определяется внутренней опорной частой TWI 10 МГц). CLKDIV = период TWIx SCL / период 10 МГц Например, для частоты SCL 400 кГц (период = 1/400 кГц = 2500 нс) и внутренней опорной частоты 10 МГц (период = 100 нс): CLKDIV = 2500 нс / 100 нс = 25 Чтобы получить скважность частоты SCL 30%, нужно установить CLKLOW = 17 и CLKHI = 8. Обратите внимание, что CLKLOW и CLKHI в сумме дают CLKDIV (CLKLOW + CLKHI = 17 + 8 = 25). Рис. 20-3. TWI Clock Divider Register. • Clock High (CLKHI). В этом поле задается количество периодов внутренней опорной частоты 10 МГц, в течение которых SCL остается в лог. 1 перед переходом в лог. 0. Подразумевается, что TWI работает в системе с одним мастером шины. CLKHI представлено как 8-битная двоичная величина. • Clock Low (CLKLO). В этом поле задается количество периодов внутренней опорной частоты 10 МГц, в течение которых SCL удерживается в лог. 0 (удержание в лог. 0 это способ сигнализации устройства slave, которым он сообщает о своей неготовности). CLKLO представлено как 8-битная двоичная величина. Регистр управления режимом подчиненного устройства TWI (TWIx_SLAVE_CTRL), показанный на рис. 20-4, управляет логикой, связанной с режимом работы slave. Настройки в этом регистре не влияют на режим работы master, и не должны быть модифицированы для управления функционалом режима master. Рис. 20-4. TWI Slave Mode Control Register. Биты регистра TWIx_SLAVE_CTRL: • General Call Enable (GEN). Детектирование адреса общего вызова доступно только когда разрешен режим slave. 1: разрешено детектирование адреса общего вызова, при этом принимается транзакция общего вызова (general call). Обновятся все биты источников прерываний, связанных с передачами. • NAK (NAK). 1: на принимаемые транзакции данных slave будут генерировать data NAK (отсутствие подтверждения, not acknowledge). Slave-устройство все еще считается адресованным. • Slave Transmit Data Valid (STDVAL). 1: данные доступны для slave-передачи в передающем FIFO. • Slave Enable (SEN). 1: Разрешен режим slave. Разрешено одновременно и конкурентно использовать режимы slave и master. Регистр адреса подчиненного устройства (TWIx_SLAVE_ADDR), показанный на рис. 20-5, хранит адрес, который распознается на шине в разрешенном режиме slave. Контроллер TWI сравнивает значение этого регистра с принятым адресом во время фазы адресации I2C. Рис. 20-5. TWI Slave Mode Address Register. Во время и при окончании передач режима slave регистр состояния подчиненного режима (TWIx_SLAVE_STAT) содержит информацию по текущей передаче (см. рис. 20-6). Биты состояния режима slave не связаны с генерацией прерываний. Работа в режиме master не влияет на биты TWIx_SLAVE_STAT. Рис. 20-6. TWI Slave Mode Status Register. Биты регистра TWIx_SLAVE_STAT: • General Call (GCALL). Этот бит очистится самостоятельно, если запрещен режим slave (SEN = 0). 1: в момент адресации был детектирован адрес общего вызова (general call). • Slave Transfer Direction (SDIR). Этот бит очистится самостоятельно, если запрещен режим slave (SEN = 0). 1: в момент адресации было определено направление slave-передачи (бит R/W адреса устройства в лог. 0). Регистр управления режимом главного устройства (TWIx_MASTER_CTRL) управляет логикой, связанной с режимом работы master (см. рис. 20-7.) Биты в этих регистрах не влияют на режим работы slave, и они не должны модифицироваться для управлением функционала режима slave. Рис. 20-7. TWI Master Mode Control Register. Биты регистра TWIx_MASTER_CTRL: • Serial Clock Override (SCLOVR). Этот бит можно использовать, когда требуется прямое управление линией тактов. Обычный режим работы master и slave не должен требовать отмены работы тактов. 1: выход последовательных тактов переводится в активный 0, отменяя работу всей другой логики. Это состояние будет сохраняться до очистки бита SCLOVR. Растяжка уровня лог. 0 может использоваться slave-устройством для сигнализации о своей занятости. • Serial Data (SDA) Override (SDAOVR). Этот бит можно использовать, когда требуется прямое управление линией данных. Обычный режим работы master и slave не должен требовать отмены работы данных. 1: выход последовательных данных переводится в активный лог. 0, отменяя работу всей другой логики. Это состояние будет сохраняться до очистки бита SDAOVR. • Data Transfer Count (DCNT). Показывает количество байт данных для передачи. DCNT декрементируется по мере передачи каждого слова данных (байта) DCNT. Когда DCNT достигает 0, генерируется сигнал Stop. Установка DCNT в 0xFF запрещает этот счетчик. В этом режиме передачи данные будут продолжать передаваться, пока не запустится завершение путем установки бита STOP. • Repeat Start (RSTART). 1: выдать повторный сигнал старт (repeat start condition) в момент завершения текущей передачи (DCNT = 0), и начать новую передачу. Текущая транзакция завершается с обновлением соответствующих бит состояния и прерываний. Если во время предыдущей передачи возникла ошибка, repeat start не происходит. При отсутствии любых ошибок бит разрешения режима главного устройства (master enable, MEN) не очистится сам при repeat start. • Issue Stop Condition (STOP). 1: Передача завершится при первой возможности, избегая любых состояний ошибки (как если бы счетчик передачи досчитал до конца) и в этот момент обновится регистр состояния прерываний (TWIx_INT_STAT). • Fast Mode (FAST). 1: используется быстрый режим (скорость до 400 кбит/сек). • Master Transfer Direction (MDIR). 1: инициированная транзакция - прием master. • Master Mode Enable (MEN). Этот бит очистится сам при завершении передачи (после того как декремент счетчика DCNT достигнет 0), включая ситуации, когда передача завершилась из-за ошибки. 1: разрешен функционал режима master. Если шина I2C свободна (находится в состоянии ожидания, когда оба сигнала SCL и SDA в лог. 1), сгенерируется сигнал Start. Во время фазы адресации контроллер TWI, когда он разрешен в режиме master, передает содержимое регистра адреса (TWIx_MASTER_ADDR), показанного на рис. 20-8. При программировании этих регистров опускают бит чтения/записи (бит R/W, который передается последним в фазе адресации I2C). Таким образом, только 7 бит, составляющих старшую часть фазы адреса, должны быть записаны в TWIx_MASTER_ADDR. Например, если адрес slave-устройства b#1010000X, где X соответствует биту R/W, регистр TWIx_MASTER_ADDR программируется значением b#1010000, что соответствует 0x50. Когда на шину отправляется адрес устройства, контроллер TWI сам добавляет бит чтения/записи, основываясь на состоянии бита MDIR регистра управления режимом master TWIx_MASTER_CTRL. Рис. 20-8. TWI Master Mode Address Register. Регистр состояния режима master TWIx_MASTER_STAT, показанный на рис. 20-9, содержит информацию о передачах режима главного устройства и об их завершении. Биты состояния режима master не связаны напрямую с генерацией прерываний, однако предоставляют информацию по текущей транзакции. Функционирование в режиме slave никак не влияет на биты состояния режима master. Рис. 20-9. TWI Master Mode Status Register. Биты регистра TWIx_MASTER_STAT: • Bus Busy (BUSBUSY). Показывает текущее состояние шины I2C - занята она или свободна. Это показывает состояние для всех устройств на шине, не только для этого отдельного устройства. При сигнале Start установка значения этого регистра задерживается из-за наличия фильтрации по входу. При сигнале Stop очистка этого регистра происходит после интервала tBUF. 1: шина занята. Определено активное состояние тактов или данных. • Serial Clock Sense (SCLSEN). Этот бит состояния может использоваться, когда требуется непосредственное чтение уровня линии тактов (SCL). Обновление значения регистра задерживается из-за входного фильтра (номинально на 50 нс). Обычно в режимах master и slave не требуется использовать эту функцию. 1: на линии тактов определен активный 0. Источник активного драйвера нуля не известен, и он может быть как внутренним, так и внешним. • Serial Data Sense (SDASEN). Этот бит состояния может использоваться, когда требуется непосредственное чтение уровня линии данных (SDA). Обновление значения регистра задерживается из-за входного фильтра (номинально на 50 нс). Обычно в режимах master и slave не требуется использовать эту функцию. 1: на линии данных определен активный 0. Источник активного драйвера нуля не известен, и он может быть как внутренним, так и внешним. • Buffer Write Error (BUFWRERR). 1: текущая master-транзакция была оборвана из-за ошибки записи в принимающий буфер. Принимающий буфер и принимающий регистр сдвига оба одновременно заполнены. Этот бит имеет тип W1C ("для очистки нужно записать 1"). • Buffer Read Error (BUFRDERR). 1: текущая master-транзакция была оборвана из-за ошибки чтения передающего буфера. В момент времени, когда требовались данные, буфер передающего регистра сдвига был пуст. Этот бит имеет тип W1C ("для очистки нужно записать 1"). • Data Not Acknowledged (DNAK). 1: текущая master-транзакция была оборвана из-за того, что был детектирован сигнал NAK при передаче данных. Этот бит имеет тип W1C ("для очистки нужно записать 1"). • Address Not Acknowledged (ANAK). 1: текущая master-транзакция была оборвана из-за того, что был детектирован сигнал NAK во время фазы адреса устройства. Этот бит имеет тип W1C ("для очистки нужно записать 1"). • Lost Arbitration (LOSTARB). 1: текущая транзакция была оборвана из-за потери арбитража при конкуренции с другим устройством master на шине. Этот бит имеет тип W1C ("для очистки нужно записать 1"). • Master Transfer in Progress (MPROG). 1: идет процесс master-транзакции. Биты регистра управления FIFO TWIx_FIFO_CTRL влияют только на FIFO, и не привязаны ни к какой другой операции режима master или slave (см. рис. 20-10). Рис. 20-10. TWI FIFO Control Register. Биты регистра TWIx_FIFO_CTRL: • Receive Buffer Interrupt Length (RCVINTLEN). Этот бит определяет частоту, с которой генерируются прерывания приемного буфера. Прерывания могут генерироваться на каждом принятом байте, или после приема двух байт. 1: флаг прерывания приема (RCVSERV) установится, когда поле RCVSTAT в регистре TWIx_FIFO_STAT покажет наличие двух байт в FIFO (FIFO заполнен, 11). • Transmit Buffer Interrupt Length (XMTINTLEN). Этот бит определяет частоту, с которой генерируются прерывания буфера передачи. Прерывания могут генерироваться на каждом передаваемом байте, или после двух переданных байт. 1: флаг прерывания передачи (XMTSERV) установится, когда поле XMTSTAT в регистре TWIx_FIFO_STAT покажет, что FIFO передачи пуст (00). • Receive Buffer Flush (RCVFLUSH). 1: сбрасывает (Flush) содержимое буфера приема и обновляет биты состояния RCVSTAT, чтобы показать пустоту этого буфера. Это состояние сохраняется до тех пор, пока бит RCVFLUSH не будет очищен. Во время активного прима буфер приема в этом состоянии отвечает логике приема так, как если бы он был полон. • Transmit Buffer Flush (XMTFLUSH). 1: сбрасывает (Flush) содержимое буфера передачи, и обновляет биты состояния XMTSTAT для индикации, что буфер пуст. Это состояние сохраняется, пока бит XMTFLUSH не будет очищен. Во время активной передачи в таком состоянии буфер передачи отвечает логике так, как если бы буфер передачи был пуст. Поля в регистре состояния FIFO (TWIx_FIFO_STAT), показанного на рис. 20-11, отражают состояние содержимого приема и передачи буферов FIFO. Буферы FIFO не разделяют данные master и данные slave. Путем использования предоставленных бит состояния и управления FIFO может обслуживаться таким образом, чтобы можно было реализовать одновременное функционирование режимов master и slave. Рис. 20-11. TWI FIFO Status Register. Биты регистра TWIx_FIFO_STAT (все биты этого регистра доступны только на чтение, RO): • Receive FIFO Status (RCVSTAT). Поле RCVSTAT доступно только для чтения. Оно показывает количество достоверных байт данных в буфере приема FIFO. Состояние RCVSTAT обновляется с каждым чтением буфера FIFO с помощью шины данных периферии, или при доступе на запись со стороны регистра сдвига приема. Допускается наличие одновременного доступа. 11: FIFO заполнен и содержит 2 байта данных. Допускается одиночное или двойное чтение байта при обращении к периферийному устройству FIFO. • Transmit FIFO Status (XMTSTAT). Поле XMTSTAT доступно только на чтение. Оно показывает количество достоверных байт данных в буфере передачи FIFO. Состояние XMTSTAT с каждой записью FIFO через шину периферийного устройства или с каждым чтением со стороны регистра сдвига передачи. Допускается наличие одновременного доступа. 11: FIFO передачи заполнен и содержит 2 байта данных. Регистр маски прерываний TWIx_INT_ENABLE, показанный на рис. 20-12, разрешает источники прерываний для активации выхода генерации прерывания TWI. Каждый бит маски соответствует одному биту источника прерывания в регистре состояния прерываний TWI (TWIx_INT_STAT). Чтение и запись регистров маски прерываний TWI не влияет на содержимое регистра состояния прерываний TWI. Рис. 20-12. TWI Interrupt Mask Register. Биты регистра TWIx_INT_ENABLE описаны ниже. Для всех бит этого регистра: если бит в лог. 0, то соответствующее прерывание запрещено. • Receive FIFO Service Mask (RCVSERVM). Если бит RCVINTLEN в регистре TWIx_FIFO_CTRL сброшен в 0, то поле состояния RCVSTAT регистра TWIx_FIFO_STAT обновится на значение 01 или 11. Если RCVINTLEN в 1, то RCVSTAT обновится при RCVSTAT 10 или 11. Всякий раз при обновлении RCVSTAT установится бит RCVSERV в регистре состояния прерываний. Бит маски RCVSERVM определяет, будет ли сгенерировано прерывание при установке бита RCVSERV. 0: запрещена генерация прерывания при установке бита RCVSERV в регистре состояния прерываний TWI. • Transmit FIFO Service Mask (XMTSERVM). Если бит XMTINTLEN в регистре TWIx_FIFO_CTRL сброшен в 0, то бит XMTSERV в регистре состояния прерываний установится всякий раз, когда поле XMTSTAT в регистре TWIx_FIFO_STAT обновится до значения 01 или 00. Если XMTINTLEN равен 1, то бит XMTSERV в регистре состояния прерываний установится всякий раз когда поле XMTSTAT обновится до состояния 00. Бит маски XMTSERVM определяет, будет ли сгенерировано прерывание при установке бита XMTSERV. 0: запрещена генерация прерывания при установке бита XMTSERV в регистре состояния прерываний TWI. • Master Transfer Error Mask (MERRM). 0: запрещена генерация прерывания при установке бита MERR в регистре состояния прерываний TWI. • Master Transfer Complete Mask (MCOMPM). 0: запрещена генерация прерывания при установке бита MCOMP регистра состояния прерываний TWI. • Slave Overflow Mask (SOVFM). 0: запрещена генерация прерывания при установке бита SOVF регистра состояния прерываний TWI. • Slave Transfer Error Mask (SERRM). 0: запрещена генерация прерывания при установке бита SERR регистра состояния прерываний TWI. • Slave Transfer Complete Mask (SCOMPM). 0: запрещена генерация прерывания при установке бита SCOMP регистра состояния прерываний TWI. • Slave Transfer Initiated Mask (SINITM). 0: запрещена генерация прерывания при установке бита SINIT регистра состояния прерываний TWI. Регистр состояния прерываний TWI (TWIx_INT_STAT), показанный на рис. 20-13, содержит информацию о функциональной области TWI, которая возможно требует немедленного обслуживания. Многие из этих бит работают как индикатор дополнительного чтения и обслуживания различных регистров состояния. После обслуживания источника прерывания, связанного с определенным битом, пользователь должен очистить этот бит источника прерывания. Рис. 20-13. TWI Interrupt Status Register. Биты регистра TWIx_INT_STAT описаны ниже. Все биты этого регистра это так называемые sticky-биты, т. е. они устанавливаются автоматически, а очищаются только операцией записи лог. 1 (Write-1-clear, W1C): • Receive FIFO Service (RCVSERV). Если бит RCVINTLEN в регистре TWIx_FIFO_CTRL сброшен в 0, то бит RCVSERV установится каждый раз, когда поле RCVSTAT в регистре TWIx_FIFO_STAT обновится до значения 01 или 11. Если бит RCVINTLEN установлен в 1, то бит RCVSERV установится всякий раз, когда поле RCVSTAT обновится до значения 10 или 11. 1: в буфере FIFO приема есть 1 или 2 байта, где содержатся принятые данные (оттуда можно прочитать эти данные). • Transmit FIFO Service (XMTSERV). Если бит XMTINTLEN в регистре TWIx_FIFO_CTRL сброшен в 0, то бит XMTSERV установится всякий раз, когда поле XMTSTAT в регистре TWIx_FIFO_STAT обновится либо в 01, либо в 00. Если бит XMTINTLEN установлен в 1, то бит XMTSERV установится всякий раз, когда поле XMTSTAT обновится в значение 00. 1: в буфере FIFO передачи есть одна или две свободные 8-битные ячейки, в которые можно записать передаваемые данные. • Master Transfer Error (MERR). 1: произошла ошибка master. Условия возникновения ошибки показаны регистром состояния master (TWIx_MASTER_STAT). • Master Transfer Complete (MCOMP). 1: была завершена инициированная транзакция master. При отсутствии repeat start шина I2C освобождается. • Slave Overflow (SOVF). 1: бит завершения slave-транзакции (SCOMP) был установлен в момент подтверждения последующей транзакции на фазе адреса. Транзакция продолжилась, однако могут быть сложности в отделении одной транзакции от другой. • Slave Transfer Error (SERR). 1: произошла ошибка slave. Произошла выдача повторного сигнала Start или выдача сигнала Stop во время фазы приема данных транзакции. • Slave Transfer Complete (SCOMP). 1: транзакция завершена, и был детектирован либо сигнал Stop, либо сигнал повторного Start. • Slave Transfer Initiated (SINIT). 1: slave обнаружил совпадение адреса, и была инициирована транзакция. Регистр FIFO передачи для одного байта TWIx_XMT_DATA8, показанный на рис. 20-14, хранит 8-разрядное значение данных, записанное в буфер FIFO. Передаваемые данные вводятся в соответствующий буфер передачи в порядке "первым пришел, первым вышел" (first-in first-out, сокращенно FIFO). Хотя записи в шину периферии 16-битные, доступ на запись в регистр TWIx_XMT_DATA8 добавляет только один передаваемый байт в буфер FIFO. Для каждого такого доступа обновится поле состояния передачи (XMTSTAT) в регистре TWIx_FIFO_STAT. Если доступ был выполнен, когда буфер FIFO заполнен, то запись игнорируется, и существующие в буфере FIFO данные остаются не измененными. Все биты регистра TWIx_XMT_DATA8 предназначены только для записи (WO), попытка чтения этого регистра вернет 0x0000. Рис. 20-14. TWI FIFO Transmit Data Single Byte Register. Двухбайтный регистр TWI FIFO передачи (TWIx_XMT_DATA16), показанный на рис. 20-15, хранит 16-битное значение данных, записанное в буфер FIFO. Чтобы снизить частоту возникновения прерываний и время доступа к шине периферии, может быть выполнена двухбайтный доступ к передаваемым данным. Можно записать два байта данных, что эффективно заполняет весь FIFO за один доступ к шине. Все биты в регистре TWIx_XMT_DATA16 предназначены только для чтения (WO). Попытка чтения TWIx_XMT_DATA16 вернет 0x0000. Рис. 20-15. TWI FIFO Transmit Data Double Byte Register. Данные записываются в порядке байт little endian [2], показанном на рис. 20-16. Здесь байт 0 (B0) это первый байт, который будет передан, и байт 1 (B1) это второй передаваемый байт. С каждым таким доступом обновляется поле состояния передачи (XMTSTAT) в регистре TWIx_FIFO_STAT. Если доступ осуществляется, когда буфер FIFO не опустошился, то запись игнорируется, и существующие в буфере FIFO данные и их состояние не изменяется.
Рис. 20-16. Little Endian Byte Order. Однобайтный регистр буфера приема TWI FIFO (TWIx_RCV_DATA8), показанный на рис. 20-17, хранит 8-битное значение данных, которое может быть прочитано из буфера FIFO. Принимаемые данные читаются из соответствующего буфера приема в порядке "первый пришел, первый вышел" (first-in first-out, сокращенно FIFO). Хотя шина периферии имеет разрядность 16 бит, доступ на чтение к TWIx_RCV_DATA8 переместит только 1 байт данных из буфера FIFO. С каждым таким доступом обновится поле состояния приема (RCVSTAT) в регистре TWIx_FIFO_STAT. Если доступ выполнялся, когда буфер FIFO приема пуст, то прочитанные данные не достоверны, и биты состояния FIFO будут все так же показывать его пустоту. Все биты регистра TWIx_RCV_DATA8 предназначены только для чтения (RO). Рис. 20-17. TWI FIFO Receive Data Single Byte Register. Двухбайтный регистр данных TWI FIFO приема (TWIx_RCV_DATA16), показанный на рис. 20-18, хранит 16-битное значение данных, которое может быть прочитано из буфера FIFO. Чтобы снизить частоту возникновения прерываний и время доступа к периферийной шине, можно осуществлять двухбайтный доступ к принимаемым данным. Можно прочитать 2 байта, эффективно опустошая буфер FIFO за один доступ к шине. Данные читаются в порядке байт little endian [2], как показано на рис. 20-19. Здесь байт 0 (B0) это первый принятый байт, и байт 1 (B1) это второй принятый байт. С каждым таким доступом обновится поле состояние приема (RCVSTAT) в регистре TWIx_FIFO_STAT, показывая пустоту буфера приема FIFO. Если доступ осуществлялся, когда буфер FIFO не был заполнен, то прочитанные данные недостоверны, и существующие в буфере FIFO данные и их состояние остаются неизменными. Все биты регистра TWIx_RCV_DATA16 предназначены только для чтения (RO). Рис. 20-18. TWI FIFO Receive Data Double Byte Register.
Рис. 20-19. Little Endian Byte Order. [Механика транзакций данных] Контроллеры TWI следуют протоколу транзакций Philips I2C Bus Specification версии 2.1, опубликованному в январе 2000 года. Одиночная полная транзакция показана на рис. 20-20.
Рис. 20-20. Базовая передача данных. S = сигнал START Чтобы лучше понимать отображение регистров контроллера TWI на базовую передачу данных, рис. 20-21 показывает ту же самую транзакцию, как на рисунке 20-20, с соответствующими именами бит контроллера TWI. На этой иллюстрации контроллер TWI успешно передает 1 байт данных. Устройство slave подтверждает (ACK) и адрес, и данные.
Рис. 20-21. Базовая передача данных с использованием бит контроллера TWI. [Генерация тактов и синхронизация] Реализация контроллера TWI выдает такты только в режиме работы master, и только тогда, когда была инициирована транзакция. Если арбитраж на шине потерян, выход SCK немедленно переходит в третье состояние. Если несколько выходов тактов одновременно управляют сигналом SCK шины I2C, то контроллер синхронизирует свои такты с другими источниками тактов. Это показано на рис. 20-22. Рис. 20-22. Синхронизация тактов SCK контроллера TWI. Выход SCK контроллера TWI следует следующим правилам: • Как только завершился отсчет периода лог. 1 тактов (CLKHI), выход SCK подтягивается к лог. 0, начинается отсчет периода лог. 0 выхода тактов (CLKLOW). [Арбитраж на шине] Контроллеры TWI инициируют передачу в режиме master (MEN) только когда шина в состоянии ожидания (idle), что означает не занятость шины другими устройствами master. Если шина находится в состоянии ожидания, и два устройства masters одновременно инициировали передачу, начнется арбитраж по шине. Это показано на рис. 20-23. Рис. 20-23. Арбитраж шины I2C, как его отрабатывает контроллер TWI. Контроллеры TWI отслеживают уровень на сигнале данных шины SDA, когда сигнал тактов SCL находится в лог. 1. Если контроллером TWI было определено, что SDA находится в активном лог. 0, когда его логика данных требует вывода лог. 1 на SDA, то контроллер TWI теряет арбитраж и прекращает генерацию сигналов тактов и данных (переводит свои драйверы SCL и SDA в третье состояние). Обратите внимание, что арбитраж выполняется не только на перепадах SCK, но и по всему протяжению лог. 1 на SCK. [Сигналы Start и Stop] Сигналы Start и Stop соответствуют изменению уровня SDA, когда SCK находится в лог. 1. Контроллер TWI генерирует (в режиме master) и распознает (в режиме slave) эти сигналы. Обычно сигналы Start и Stop происходят в начале и на завершении транзакции за исключением случаев "комбинированных" транзакций, когда появляется повторный сигнал Start (repeated start), как показано на рис. 20-24. Рис. 20-24. Сигналы Start и Stop протокола I2C. Специальные случаи сигналов Start и Stop для контроллера TWI: • Контроллер TWI адресован как slave-приемник. Если master выдал сигнал Stop во время фазы данных транзакции, контроллер TWI завершает эту транзакцию (SCOMP). [Поддержка адреса общего вызова (General Call)] Контроллеры TWI всегда декодируют и подтверждают адрес общего вызова, если это разрешено в режиме slave (SEN) и если разрешен общий вызов (GEN). Адресация общего вызова (0x00) показывается битом GCALL, который установится, и по принципу функционирования контроллера TWI в режиме slave-приемника. Если данные, связанные с транзакцией, получили отрицательное подтверждение, то установится бит NAK. Если контроллер TWI выдал general call в режиме master-передатчика, соответствующий адрес и направление транзакции может быть установлены с загрузкой данных FIFO передачи. Байт, следующий за адресом общего вызова, обычно определяет, какие действия должны быть предприняты подчиненными устройствами в ответ на этот вызов. Команда во втором байте интерпретируется на основе значения в её младшем бите (LSB). Для slave-устройства TWI это не применимо, и байты, принятые после общего вызова, считаются данными. [Fast Mode] Быстрый режим (Fast Mode) в сущности использует ту же механику, как и стандартный режим скорости. Это происходит в соответствие с электрическими спецификациями. Когда разрешен быстрый режим (FAST), будут изменены следующие интервалы времени, чтобы они удовлетворяли электрическим требованиям. • Время нарастания последовательных данных перед вычислением арбитража (tr). [Примеры программирования] Ниже показаны примеры, как делать общую настройку, как работать в режиме slave и в режиме master, а также даны пояснения по запуску повторных сигналов Start (repeated start). Общая настройка. Общая настройка заключается к записи определенных значений в регистры, это нужно сделать как для работы в режиме master, так и для работы в режиме slave. Общая настройка должна быть выполнена перед тем, как будут установлены биты разрешения работы master и/или slave. Запрограммируйте регистры TWIx_CONTROL, чтобы разрешить работу контроллера TWI, и установите значение прескалера. Запрограммируйте значение прескалера так, чтобы его двоичное значение соответствовало fSCLK / 10 МГц. Все значения должны быть округлены вверх до следующего целого числа. Должен быть установлен бит TWIx_ENA. Обратите внимание, что как только контроллер TWI разрешен, может быть определена занятость шины. Это состояние должно быть очищено после того, как пройдет интервал времени tBUF - подразумевая, что не была детектирована другая активность шины. Режим slave. Когда разрешен режим подчиненного устройства, поддерживаются транзакции как приема, так и передачи. Невозможно разрешить только одно направление данных и не подтвердить положительно (NAK) другое. Это отражается следующей настройкой. 1. Запрограммируйте TWIx_SLAVE_ADDR. Для этого используется подходящее 7-разрядное значение, которое должно совпасть при обращении к устройству во время фазы адреса транзакции. 2. Запрограммируйте TWIx_XMT_DATA8 или TWIx_XMT_DATA16. Это начальные значения данных, которые будут переданы, когда произойдет slave-адресация и потребуется отправка данных. Это необязательный шаг. Если не будут записаны данные, и произойдет slave-адресация с необходимостью передачи данных, такты (SCL) будут растягиваться и будет сгенерировано прерывание, пока данные не будут записаны в FIFO передачи. 3. Запрограммируйте TWIx_INT_ENABLE. Установите биты маски разрешения прерываний, связанные с нужными источниками прерывания. Например, программирование 0x000F приведет к генерации прерывания при событиях совпадения адреса, при корректном завершении slave-транзакции, при ошибке slave-транзакции, при начале следующей транзакции, когда предыдущая транзакция не была обслужена. 4. Запрограммируйте TWIx_SLAVE_CTRL. Это явно подготовит и разрешит работу режима slave-устройства. Как пример, программирование значения 0x0005 разрешит режим работы slave, потребует 7-битной адресации и покажет, что данные в буфере FIFO передачи предназначены для передачи в режиме slave. Таблица 20-2 показывает, как может осуществляться взаимодействие между контроллером TWI и процессором при использовании этого примера программирования. Таблица 20-2. Взаимодействие процессора и контроллера TWI в процессе настройки Slave Mode.
Настройка тактов в режиме master. Работа режима главного устройства устанавливается и реализуется на базе транзакций. В следующих секциях даны примеры пошагового программирования для приема и передачи. Настройка тактирования в режиме master одинаковая как для приема, так и для передачи. Запрограммируйте TWIx_CLKDIV. Это определит длительности интервалов лог. 1 и лог. 0 сигнала тактов SCK. Передача в режиме master. Для передачи в режиме одиночного мастера шины выполните следующие шаги: 1. Запрограммируйте TWIx_MASTER_ADDR. Это определит адрес, который будет передан на фазе адресации транзакции. 2. Запрограммируйте TWIx_XMT_DATA8 или TWIx_XMT_DATA16. Это определит начальные передаваемые данные. Считается ошибкой завершить фазу адреса транзакции и не предоставить данные у буфере FIFO передачи. 3. Запрограммируйте TWIx_FIFO_CTRL. Покажите, когда должно произойти прерывание - после передачи каждого байта (8 бит) или когда будут переданы два байта (16 бит). 4. Запрограммируйте TWIx_INT_ENABLE. Установите биты разрешения в маске, соответствующие желаемым источникам прерывания. Например, программирование значения 0x0030 приведет к генерации прерывания, если завершилась master-транзакция, и если произошла ошибка master-транзакции. 5. Запрограммируйте TWIx_MASTER_CTRL. Это непосредственно подготовит и разрешит работу в режиме master. Например, программирование значения 0x0201 разрешит работу режима master, сгенерирует 7-битный адрес, установит направление транзакции на master-передачу, будет использовать тайминг стандартного режима и передаст 8 байт данных перед генерацией сигнала Stop. Таблица 20-3 показывает, как может выглядеть взаимодействие между контроллером TWI и процессором при использовании этого примера программирования. Таблица 20-3. Взаимодействие процессора и контроллера TWI в процессе настройки master-передачи.
Прием в режиме master. Для приема в режиме одиночного мастера шины выполните следующие шаги: 1. Запрограммируйте TWIx_MASTER_ADDR. Это определит адрес, который будет передан на фазе адресации транзакции. 2. Запрограммируйте TWIx_FIFO_CTRL. Покажите, когда должно произойти прерывание - после приема каждого байта (8 бит) или когда будут приняты два байта (16 бит). 3. Запрограммируйте TWIx_INT_ENABLE. Установите биты разрешения в маске, соответствующие желаемым источникам прерывания. Например, программирование значения 0x0030 приведет к генерации прерывания, если завершилась master-транзакция, и если произошла ошибка master-транзакции. 4. Program TWIx_MASTER_CTRL. Запрограммируйте TWIx_MASTER_CTRL. Это непосредственно подготовит и разрешит работу в режиме master. Например, программирование значения 0x0205 разрешит работу режима master, сгенерирует 7-битный адрес, установит направление транзакции на master-прием, будет использовать тайминг стандартного режима и примет 8 байт данных перед генерацией сигнала Stop. После того, как биты TWI_DCNT при декрементировании дойдут до нуля, master TWI отправит NAK, чтобы показать slave-передатчику, что шина I2C должна быть освобождена. Это позволит master послать сигнал STOP для завершения транзакции. Таблица 20-4 показывает, как может выглядеть взаимодействие между контроллером TWI и процессором при использовании этого примера программирования. Таблица 20-4. Взаимодействие процессора и контроллера TWI в процессе настройки master-приема.
[Сигнал Repeated Start] Сигнал repeated start (повторный старт) это просто отсутствие сигнала Stop между двумя транзакциями, и поскольку каждая транзакция начинается сигналом Start, получается так называемый повторный старт Repeated Start. При этом эти две передачи могут быть любого направления. Например, осуществляется прием сразу после передачи, или передача после приема. В последующих секциях содержится информация, которая поможет программисту написать соответствующий код обработчика прерывания. Последовательность Repeated Start при передаче/приеме. На рис. 20-25 показана передача данных, за которой сразу идет последовательность приема данных. Рис. 20-25. Transmit/Receive Data Repeated Start (затененная область показывает активность на шине slave-устройства). Задачи, выполняемые в каждом прерывании: • Прерывание XMTSERV. Это прерывание было сгенерировано из-за доступа к FIFO. Поскольку это был последний байт в этой транзакции, FIFO_STATUS указал бы на опустошение FIFO передачи. При чтении счетчик DCNT обнулился бы. Установите бит RSTART, чтобы показать repeated start, и установите бит MDIR, который должен соответствовать прием данных для последующей транзакции. • Прерывание MCOMP. Это прерывание было сгенерировано, потому что были переданы все данные (DCNT = 0). Если не было ошибок, будет инициирован сигнал Start. Очистите бит RSTART и запрограммируйте DCNT желаемым количеством принимаемых байт. • Прерывание RCVSERV. Это прерывание было сгенерировано из-за того, что поступил байт в буфер FIFO приема. Здесь требуется только простая обработка данных. • Прерывание MCOMP. Это сигнализирует о завершении транзакции. Последовательность Repeated Start при приеме/передаче. На рис. 20-26 показан прием данных, за которой сразу идет последовательность передачи данных. Рис. 20-26. Receive/Transmit Data Repeated Start (затененная область показывает активность на шине slave-устройства). Задачи, выполняемые в каждом прерывании: • Прерывание RCVSERV. Это прерывание возникает из-за поступления байта данных в буфер FIFO приема. Установите бит RSTART, чтобы показать repeated start, и очистите бит MDIR, чтобы последующая транзакция была передачей данных. • Прерывание MCOMP. Это прерывание произошло из-за завершения транзакции приема данных. Если при этом не было ошибок, будет инициирован сигнал Start. Очистите бит RSTART, и запрограммируйте DCNT желаемым количеством байт, которое должно быть передано. • Прерывание XMTSERV. Это прерывание генерируется по причине доступа к FIFO. Здесь всего лишь нужно обработать все данные, как это необходимо - в данном случае предоставить для FIFO дополнительные передаваемые данные, если это необходимо. • Прерывание MCOMP. Это сигнализирует о завершении транзакции. Нет никаких ограничений по времени, чтобы произошли вышеперечисленные события; пользователь может запрограммировать биты так, как это необходимо. См. далее "Растягивание тактов при сигнале Repeated Start", где объясняется, как контроллер растягивает такты при транзакциях с повторными сигналами Start. [Растягивание тактов] Растягивание тактов это добавленный функционал контроллера TWI, когда он работает в режиме master. Это новое поведение задействует самостоятельное удлинение тактов I2C, когда происходит ожидание обслуживания прерывания. Растягивание осуществляется автоматически (аппаратно), и не требует никаких программных действий со стороны ядра процессора. Контроллер TWI в качестве мастера шины I2C поддерживает 3 режима растягивания тактов: • Растягивание тактов при недогрузке FIFO. Примечание: растягивание тактов в данном контексте это увеличение длительности лог. 0 сигнала SCK, которое сигнализирует о занятости шины и о том, что устройство master требует от slave-устройства ожидания для подготовки/выполнения каких-то своих внутренних операций. Растягивание тактов при недогрузке FIFO. При передаче в режиме master генерируется прерывание, когда буфер FIFO опустошился. В это время начинает передаваться новый байт. Если прерывание XMTSERV не обработано, то растягивается завершающая подтверждения транзакции. Растягивание тактов продолжается, пока в буфер FIFO передачи не будут записаны новые данные (путем записи в регистр TWI_XMT_DATA8 или TWI_XMT_DATA16). Для того, чтобы освободить такты и продолжит передачу, никаких других действий не требуется. Это поведение продолжается, пока не завершится вся передача (DCNT = 0). Завершение передачи показывается битом MCOMP, как иллюстрировано на рис. 20-27 и описано в таблице 20-5. Рис. 20-27. Растягивание тактов при недогрузке FIFO. Таблица 20-5. Случай недогрузки FIFO.
Растягивание тактов при переполнении FIFO. Во время приема в режиме master прерывание генерируется в момент, когда буфер FIFO приема становится заполненным. При этом на фазе подтверждения последнего принятого байта начинается растягивание тактов. Не делается попыток инициировать прием дополнительного байта. Растягивание тактов продолжается, пока ранее принятые данные не будут прочитаны из буфера FIFO (через регистры TWI_RCV_DATA8, TWI_RCV_DATA16). Для освобождения тактов и продолжения приема не требуется никаких других действий. Это поведение продолжается, пока не будут полностью приняты все данные (DCNT = 0). Тогда прием завершается (MCOMP), как показано на рис. 20-28 и описано в таблице 20-6. Рис. 20-28. Растягивание тактов при переполнении FIFO. Таблица 20-6. Случай переполнения FIFO.
Растягивание тактов при сигнале Repeated Start. Функция повторного старта в протоколе I2C требует перехода между двумя соседними транзакциями. С помощью растягивания тактов задача управления этим переходом упрощается, и она одинаковая для всех типов транзакций. Как только завершена начальная master-транзакция TWI (приема или передачи), во время фазы repeated start (которая происходит между транзакциями) такты начинают растягиваться. Конкурентно с этим событием начальная транзакция приведет к генерации прерывания завершения транзакции (MCOMP), которое сигнализирует о завершении начальной транзакции (DCNT = 0). Эта начальная транзакция обрабатывается без каких-либо специальных установок бит или таймингов. Здесь применяется вышеописанная логика растягивания тактов. Нет никаких системных ограничений по времени на последующую транзакцию (приема или передач), чтобы она была настроена и активирована. Эта последовательность может быть повторена любое необходимое количество раз. Процесс показан на рис. 20-29 и описан в таблице 20-7. Рис. 20-29. Растягивание тактов при Repeated Start. Таблица 20-7. Случай Repeated Start.
Ниже во врезках приведено несколько примеров работы с TWI без использования драйвера, напрямую. Ниже приведен код подпрограмм для чтения/записи микросхем EEPROM AT24C64D [4]. Чтение и запись осуществляются без использования прерываний, путем циклического опроса регистров контроллера TWI0. Этот код использовался в драйвере Flash Programmer для утилиты программирования VisualDSP++ [5]. static void twi_clear_all_stat (void) { /* Очищает все биты состояния */ *pTWI0_MASTER_STAT = *pTWI0_MASTER_STAT; ssync(); /* Очищает все флаги прерываний, ожидающих обработки */ *pTWI0_INT_STAT = *pTWI0_INT_STAT; ssync(); /* Сброс буферов передачи и приема */ *pTWI0_FIFO_CTRL = ( XMTFLUSH | RCVFLUSH ); ssync(); } /*****************************************************************************
Сбрасывает интерфейс TWI.
******************************************************************************/
void twi_reset(void) { /* Сброс контроллера TWI */ *pTWI0_CONTROL = TWI_RESET_VAL; ssync(); twi_clear_all_stat(); } static void twiout (u8 byte, u16 ctrl) { *pTWI0_XMT_DATA8 = byte; ssync(); if (ctrl) { *pTWI0_MASTER_CTRL = ctrl; ssync(); } // Ожидание опустошения FIFO передачи: while (*pTWI0_FIFO_STAT != XMT_EMPTY) { ssync(); } } /*****************************************************************************
Выполняет запись в режиме master без использования прерываний.
******************************************************************************/
void twi_mastermode_write(u16 memaddr, u8 *pTwiDataPointer, u16 uwCount) { u8 i; *pTWI0_FIFO_CTRL = 0; *pTWI0_CONTROL = ( TWI_ENA | PRESCALE_VALUE ); *pTWI0_CLKDIV = ( ((CLKDIV_HI) << 8) | (CLKDIV_LO) ); // Целевой адрес устройства (7-битный адрес без бита R/~W): *pTWI0_MASTER_ADDR = AT24_I2C_ADDR; twiout(memaddr >> 8, ((uwCount+2) << 6) | MEN); twiout(memaddr & 0xFF, 0); for ( i=0; i < uwCount; i++ ) { twiout(*pTwiDataPointer, 0); pTwiDataPointer++; /* load the next sample into the TX FIFO */ } // Ожидание завершения передачи и установки бита MCOMP: while ((*pTWI0_INT_STAT & MCOMP) == 0) { ssync(); } // Установка TWI на обслуживание следующей передачи: *pTWI0_INT_STAT = ( XMTSERV | MCOMP ); delay_mks(PAGE_WRITE_MKS); } /*****************************************************************************
Выполняет чтение в режиме master без использования прерываний.
******************************************************************************/
void twi_mastermode_read(u16 memaddr, u8 *pTwiDataPointer, u16 uCount) { u8 i; *pTWI0_FIFO_CTRL = 0; *pTWI0_CONTROL = ( TWI_ENA | PRESCALE_VALUE ); *pTWI0_CLKDIV = ( ((CLKDIV_HI) << 8) | (CLKDIV_LO) ); *pTWI0_MASTER_ADDR = AT24_I2C_ADDR; *pTWI0_XMT_DATA16 = (memaddr >> 8) | ((memaddr & 0x00FF) << 8); // Запуск передачи, после её завершения будет выдан повторный START: *pTWI0_MASTER_CTRL = (2 << 6) | MEN | RSTART; // Ожидание опустошения FIFO передачи: while (*pTWI0_FIFO_STAT == XMTSTAT) { ssync(); } // Ожидание завершения передачи по установке бита MCOMP: while ((*pTWI0_INT_STAT & MCOMP) == 0) { ssync(); } // Сброс флагов для обслуживания следующей транзакции: *pTWI0_INT_STAT = XMTSERV | MCOMP; asm("nop;"); asm("nop;"); asm("nop;"); // Запуск приема данных: *pTWI0_MASTER_CTRL = (uCount << 6) | MEN | MDIR; for (i = 0; i < uCount; i++) { // Ожидание появления данных в FIFO приема: while (*pTWI0_FIFO_STAT == RCV_EMPTY) { ssync(); } // Чтение принятых данных: *pTwiDataPointer++ = *pTWI0_RCV_DATA8; ssync(); } // Ожидание завершения пприема по установке бита MCOMP: while ((*pTWI0_INT_STAT & MCOMP) == 0) { ssync(); } // Сброс флагов для обслуживания следующей транзакции: *pTWI0_INT_STAT = RCVSERV | MCOMP; asm("nop;"); asm("nop;"); asm("nop;"); } Пример чтения: twi_reset(); twi_mastermode_read(addr, pVal, count); Пример записи: twi_reset(); twi_mastermode_write(addr, pVal, count); Здесь параметр addr это абсолютный начальный адрес, указывающий первый байт памяти EEPROM, откуда начинается чтение или запись (для AT24C64D адрес может быть в диапазоне от 0 до 8191). Параметр pVal это указатель на буфер в памяти процессора. Переменная count задает количество записываемых или читаемых данных (не больше размера страницы, т. е. в диапазоне 1 .. 32). Обратите внимание, что обращение к AT24C64D в подпрограммах подразумевает работу в пределах одной страницы. Т. е. если нужно прочитать или записать блок памяти, данные которого пересекают границы страниц, то обращения к EEPROM необходимо разбить на части таким образом, чтобы каждое обращение происходило к данным только на одной странице памяти. Ниже показаны диаграммы шины I2C при чтении и записи (скриншоты утилиты логического анализатора АКИП-9103). Пример записи двух байт 55h и AAh по адресу 0000h: Запись осуществляется довольно просто: после сигнала START сначала нужно передать адрес устройства с битом R/W=0, потом передать старший байт адреса, затем младший байт адреса, и далее передать нужное количество байт (1 .. 32). Последовательность должна завершиться генерацией сигнала STOP. Пример чтения двух байт по адресу 0000h: Чтение происходит немного сложнее. Начинается оно так же, как запись, передачей адреса устройства с битом R/W=0 и затем двух байт адреса ячейки памяти. Эта операция устанавливает внутренний указатель адреса в микросхеме EEPROM. Потом нужно выдать повторный сигнал START, передать адрес устройства с битом R/W=1 (сигнализирует о том, что далее будет идти чтение), и после этого прочитать нужное количество байт. Последовательность должна завершиться генерацией мастером шины отрицательного подтверждения NACK и затем сигнала STOP. FM24W256 это микросхема памяти FRAM размером 32 килобайта с интерфейсом I2C, которая в отличие от традиционной последовательной памяти EEPROM или FLASH работает очень быстро, не требуя задержек ожидания во время циклов записи страниц. Мало того, память FM24W256 вообще свободна от страничной организации, и ко всем её ячейкам можно обращаться на чтение и запись с одинаковой скоростью и в произвольном порядке. [TWI.h] #pragma once
#include < services/services.h>
// Значение поля Prescale регистра TWIx_CONTROL для тактовой частоты
// шины SCK (кГц) и внутренней тактовой частоты TWI=10 МГц должно быть
// равно SCK / 10000 = 50000 / 10000 = 5. Здесь SCK равно тактовой
// частоте шины в килогерцах:
#define PRESCALE_VALUE (SCK/10000) /* PRESCALE = 50/10 = 5 */ #define TWI_RESET_VAL 0 /* значение RESET_TWI для контроллера */ // Если определен макрос FAST_I2C, то частота шины I2C будет
// 400 кГц, если же не определен, то 100 кГц:
#define FAST_I2C
#ifdef FAST_I2C
// Период SCL в тактах 10 МГц равен 10000 кГц / 400 кГц:
#define SCL_PERIOD (10000/400)
#else
// Период SCL в тактах 10 МГц равен 10000 кГц / 100 кГц:
#define SCL_PERIOD (10000/100)
#endif
// Константы для настройки скорости SCL в регистре pTWI_CLKDIV:
#define CLKDIV_HI (SCL_PERIOD/2) // длительность лог. 1 SCL #define CLKDIV_LO (SCL_PERIOD/2) // длительность лог. 0 SCL // У процессора ADSP-BF538 два порта TWI: I2C0 и I2C1.
// Если используется I2C0, то нужно для DevNumber определить 0.
// Если используется I2C1, то нужно для DevNumber определить 1.
#define DevNumber 1
#if (DevNumber == 0)
#define pTWI_MASTER_STAT pTWI0_MASTER_STAT
#define pTWI_INT_STAT pTWI0_INT_STAT
#define pTWI_FIFO_CTRL pTWI0_FIFO_CTRL
#define pTWI_CONTROL pTWI0_CONTROL
#define pTWI_XMT_DATA8 pTWI0_XMT_DATA8
#define pTWI_MASTER_CTRL pTWI0_MASTER_CTRL
#define pTWI_FIFO_STAT pTWI0_FIFO_STAT
#define pTWI_CLKDIV pTWI0_CLKDIV
#define pTWI_MASTER_ADDR pTWI0_MASTER_ADDR
#define pTWI_XMT_DATA16 pTWI0_XMT_DATA16
#define pTWI_RCV_DATA8 pTWI0_RCV_DATA8
#elif (DevNumber == 1)
#define pTWI_MASTER_STAT pTWI1_MASTER_STAT
#define pTWI_INT_STAT pTWI1_INT_STAT
#define pTWI_FIFO_CTRL pTWI1_FIFO_CTRL
#define pTWI_CONTROL pTWI1_CONTROL
#define pTWI_XMT_DATA8 pTWI1_XMT_DATA8
#define pTWI_MASTER_CTRL pTWI1_MASTER_CTRL
#define pTWI_FIFO_STAT pTWI1_FIFO_STAT
#define pTWI_CLKDIV pTWI1_CLKDIV
#define pTWI_MASTER_ADDR pTWI1_MASTER_ADDR
#define pTWI_XMT_DATA16 pTWI1_XMT_DATA16
#define pTWI_RCV_DATA8 pTWI1_RCV_DATA8
#endif
// Коды ошибок:
typedef enum { TWI_OK = 0, // 0 TWI_TIMEOUT_TWIOUT, // 1 TWI_TIMEOUT2, // 2 TWI_TIMEOUT_NACK_I2C_ADRESS, // 3 TWI_TIMEOUT4, // 4 TWI_TIMEOUT5, // 5 TWI_TIMEOUT6, // 6 TWI_TIMEOUT_STOP // 7 }TWIstate; extern u16 twi_master_stat;
const char *twierr_decode (TWIstate twistate); TWIstate twiout (u8 byte); TWIstate twi_STOP (void); TWIstate twiin (u8 *byte); TWIstate twi_START_write (u8 I2Caddr, u16 memaddr); TWIstate twi_START_read (u8 I2Caddr, u16 memaddr); [TWI.c] /*****************************************************************************
Подпрограммы для чтения/записи на низком уровне
регистров TWI (без использования прерываний).
*****************************************************************************/
#include "init_platform.h"
#include "TWI.h"
#include "delay.h"
#define TWI_TIMEOUT_MS 100
u16 twi_master_stat; const char *twierr_decode (TWIstate twistate) { const char *result = "twi unknown error"; switch(twistate) { case TWI_OK: result = "OK"; break; case TWI_TIMEOUT_TWIOUT: result = "TWI_TIMEOUT_TWIOUT"; break; case TWI_TIMEOUT2: result = "TWI_TIMEOUT2"; break; case TWI_TIMEOUT_NACK_I2C_ADRESS: // Отсутствует устройство на шине, или неправильный адрес I2C: result = "NACK to I2C address"; break; case TWI_TIMEOUT4: result = "TWI_TIMEOUT4"; break; case TWI_TIMEOUT5: result = "TWI_TIMEOUT5"; break; case TWI_TIMEOUT6: result = "TWI_TIMEOUT6"; break; case TWI_TIMEOUT_STOP: result = "TWI_TIMEOUT_STOP"; break; } return result; } static void twi_clear_all_stat (void) { /* Очищает все биты состояния */ //*pTWI_MASTER_STAT = ( BUFWRERR | BUFRDERR | DNAK | ANAK | LOSTARB); *pTWI_MASTER_STAT = *pTWI_MASTER_STAT; ssync(); /* Очищает все флаги прерываний, ожидающих обработки */ *pTWI_INT_STAT = *pTWI_INT_STAT; ssync(); /* Сброс буферов передачи и приема */ *pTWI_FIFO_CTRL = ( XMTFLUSH | RCVFLUSH ); ssync(); } /*****************************************************************************
Сбрасывает интерфейс TWI.
******************************************************************************/
static void twi_reset(void) { /* Сброс контроллера TWI */ *pTWI_CONTROL = TWI_RESET_VAL; ssync(); twi_clear_all_stat(); } TWIstate twiout (u8 byte) { TWIstate twiresult = TWI_OK; clock_t end_tick; *pTWI_XMT_DATA8 = byte; end_tick = clock() + TWI_TIMEOUT_MS * MS_TICKS; // Ожидание опустошения FIFO передачи: while (*pTWI_FIFO_STAT != XMT_EMPTY) { ssync(); if (end_tick < clock()) { twiresult = TWI_TIMEOUT_TWIOUT; twi_master_stat = *pTWI_MASTER_STAT; break; } } return twiresult; } TWIstate twi_STOP (void) { TWIstate twiresult = TWI_OK; clock_t end_tick; // Выдача сигнала STOP: *pTWI_MASTER_CTRL = MEN | MDIR | STOP; end_tick = clock() + TWI_TIMEOUT_MS * MS_TICKS; // Ожидание освобождения шины после сигнала STOP: while (*pTWI_MASTER_STAT & BUSBUSY) { ssync(); if (end_tick < clock()) { twiresult = TWI_TIMEOUT_STOP; twi_master_stat = *pTWI_MASTER_STAT; return twiresult; } } return twiresult; } TWIstate twiin (u8 *byte) { TWIstate twiresult = TWI_OK; clock_t end_tick; end_tick = clock() + TWI_TIMEOUT_MS * MS_TICKS; // Ожидание появления данных в FIFO приема: while (*pTWI_FIFO_STAT == RCV_EMPTY) { ssync(); if (end_tick < clock()) { twiresult = TWI_TIMEOUT5; twi_master_stat = *pTWI_MASTER_STAT; twi_STOP(); return twiresult; } } // Чтение принятых данных: *byte = *pTWI_RCV_DATA8; ssync(); return twiresult; } TWIstate twi_START_write (u8 I2Caddr, u16 memaddr) { TWIstate twiresult = TWI_OK; clock_t end_tick; twi_reset(); *pTWI_FIFO_CTRL = 0; // очистка бит вручную *pTWI_CONTROL = ( TWI_ENA | PRESCALE_VALUE ); *pTWI_CLKDIV = ( ((CLKDIV_HI) << 8) | (CLKDIV_LO) ); // Целевой адрес устройства (7-битный адрес без бита R/~W): *pTWI_MASTER_ADDR = I2Caddr; *pTWI_XMT_DATA16 = (memaddr << 8) | ((memaddr & 0xFF00) >> 8); // Запуск передачи, адреса I2C и 2 байт адреса памяти FLASH, // сначала старший байт, потом младший. В счетчик байт // загружается 255, что означает бесконечную передачу, // пока осуществляется запись в *pTWI_XMT_DATA8: *pTWI_MASTER_CTRL = (255 << 6) | MEN | RSTART; twiresult = TWI_OK; end_tick = clock() + TWI_TIMEOUT_MS * MS_TICKS; // Ожидание опустошения FIFO передачи: while (*pTWI_FIFO_STAT == XMTSTAT) { ssync(); if (end_tick < clock()) { // Устройство не ответило на адрес I2C. // Либо его нет, либо неправильный адрес. twiresult = TWI_TIMEOUT_NACK_I2C_ADRESS; twi_master_stat = *pTWI_MASTER_STAT; break; } } return twiresult; } TWIstate twi_START_read (u8 I2Caddr, u16 memaddr) { TWIstate twiresult = TWI_OK; clock_t end_tick; twi_reset(); *pTWI_FIFO_CTRL = 0; // очистка бит вручную *pTWI_CONTROL = ( TWI_ENA | PRESCALE_VALUE ); *pTWI_CLKDIV = ( ((CLKDIV_HI) << 8) | (CLKDIV_LO) ); // Целевой адрес устройства (7-битный адрес без бита R/~W): *pTWI_MASTER_ADDR = I2Caddr; *pTWI_XMT_DATA16 = (memaddr << 8) | ((memaddr & 0xFF00) >> 8); // Запуск передачи, адреса I2C и 2 байт адреса памяти FLASH, // сначала старший байт, потом младший. В счетчик байт // загружается 255, что означает бесконечную передачу, // пока осуществляется запись в *pTWI_XMT_DATA8: *pTWI_MASTER_CTRL = (2 << 6) | MEN | RSTART; twiresult = TWI_OK; end_tick = clock() + TWI_TIMEOUT_MS * MS_TICKS; // Ожидание опустошения FIFO передачи: //while (*pTWI_FIFO_STAT == XMTSTAT) while ((*pTWI_INT_STAT & MCOMP) == 0) { ssync(); if (end_tick < clock()) { // Устройство не ответило на адрес I2C. // Либо его нет, либо неправильный адрес. twiresult = TWI_TIMEOUT_NACK_I2C_ADRESS; twi_master_stat = *pTWI_MASTER_STAT; break; } } return twiresult; } [FM24W256.h] #pragma once
#include "TWI.h"
// I2C-адрес микросхемы EEPROM FM24W256-GTR (A2A1A0 = 110):
#define FM24W256_I2C_ADDR 0x56
// Размер памяти микросхемы EEPROM FM24W256-GTR, байт:
#define FM24W256_SIZE 0x8000
// I2Caddr: адрес I2C микросхемы
// memaddr: адрес байта внутри микросхемы (0 .. 32767)
// buffdata: указатель на буфер, откуда берутся записываемые данные
// uCount: количество записываемых данных TWIstate twi_mastermode_write(u8 I2Caddr, u16 memaddr, u8 *buffdata, u16 uCount); // I2Caddr: адрес I2C микросхемы
// memaddr: адрес начального байта внутри микросхемы (0 .. 32767)
// buffdata: указатель на буфер, куда будут прочитаны данные
// uCount: количество считываемых данных TWIstate twi_mastermode_read(u8 I2Caddr, u16 memaddr, u8 *buffdata, u16 uCount); [FM24W256.c] /*****************************************************************************
Выполняет запись в микросхему FM24W256 в режиме master
без использования прерываний.
******************************************************************************/ TWIstate twi_mastermode_write(u8 I2Caddr, u16 memaddr, u8 *buffdata, u16 uCount) { u16 i; TWIstate twiresult; clock_t end_tick; twiresult = twi_START_write (I2Caddr, memaddr); if (TWI_OK == twiresult) { // Цикл передачи данных: for ( i=0; i < uCount; i++ ) { twiresult = twiout(*buffdata++); if (TWI_OK != twiresult) { twi_STOP(); return twiresult; } } } twiresult = twi_STOP(); return twiresult; } /*****************************************************************************
Выполняет чтение из микросхемы FM24W256 в режиме master
без использования прерываний.
******************************************************************************/ TWIstate twi_mastermode_read(u8 I2Caddr, u16 memaddr, u8 *buffdata, u16 uCount) { u16 i; TWIstate twiresult; clock_t end_tick; // Запуск передачи START, адреса I2C, R/W=0, старший байт адреса // FLASH, младший байт адреса FLASH: twiresult = twi_START_read (I2Caddr, memaddr); if (TWI_OK == twiresult) { // Сброс флагов для обслуживания следующей транзакции: *pTWI_INT_STAT = XMTSERV | MCOMP; // Выдача повторного START, запуск приема данных: *pTWI_MASTER_CTRL = (255 << 6) | MEN | MDIR | RSTART; for (i = 0; i < uCount; i++) { // Перед приемом последнего байта заказываем выдачу STOP: if (i == (uCount-1)) { twiresult = twi_STOP(); if (twiresult != TWI_OK) return twiresult; } twiresult = twiin(buffdata++); if (TWI_OK != twiresult) { twi_STOP(); break; } } } return twiresult; } Пример использования: #include < stdio.h>
#include "FM24W256.h"
u32 address; TWIstate twistate; // Пример записи данных: twistate = twi_mastermode_write(FM24W256_I2C_ADDR, 0, (u8*)0x20000000, FM24W256_SIZE); if (TWI_OK != twistate) { print("error %s, TWI_MASTER_STAT: %04X\n", twierr_decode(twistate), twi_master_stat); } // Пример чтения данных: twistate = twi_mastermode_read(FM24W256_I2C_ADDR, 0, (u8*)SDRAM_BUF_BEGIN, FM24W256_SIZE); if (TWI_OK != twistate) { print("error %s, TWI_MASTER_STAT: %04X\n", twierr_decode(twistate), twi_master_stat); } [TWI.h] #pragma once
#include < services/services.h>
// Значение поля Prescale регистра TWIx_CONTROL для тактовой частоты
// шины SCK (кГц) и внутренней тактовой частоты TWI=10 МГц должно быть
// равно SCK / 10000 = 50000 / 10000 = 5. Здесь SCK равно тактовой
// частоте шины в килогерцах:
#define PRESCALE_VALUE (SCK/10000) /* PRESCALE = 50/10 = 5 */ #define TWI_RESET_VAL 0 /* значение RESET_TWI для контроллера */ // Если определен макрос FAST_I2C, то частота шины I2C будет
// 400 кГц, если же не определен, то 100 кГц:
#define FAST_I2C
#ifdef FAST_I2C
// Период SCL в тактах 10 МГц равен 10000 кГц / 400 кГц:
#define SCL_PERIOD (10000/400)
#else
// Период SCL в тактах 10 МГц равен 10000 кГц / 100 кГц:
#define SCL_PERIOD (10000/100)
#endif
// Константы для настройки скорости SCL в регистре pTWI_CLKDIV:
#define CLKDIV_HI (SCL_PERIOD/2) // длительность лог. 1 SCL #define CLKDIV_LO (SCL_PERIOD/2) // длительность лог. 0 SCL // У процессора ADSP-BF538 два порта TWI: I2C0 и I2C1.
// Если используется I2C0, то нужно для DevNumber определить 0.
// Если используется I2C1, то нужно для DevNumber определить 1.
#define DevNumber 1
#if (DevNumber==0)
#define pTWI_MASTER_STAT pTWI0_MASTER_STAT
#define pTWI_INT_STAT pTWI0_INT_STAT
#define pTWI_FIFO_CTRL pTWI0_FIFO_CTRL
#define pTWI_CONTROL pTWI0_CONTROL
#define pTWI_XMT_DATA8 pTWI0_XMT_DATA8
#define pTWI_XMT_DATA16 pTWI0_XMT_DATA16
#define pTWI_MASTER_CTRL pTWI0_MASTER_CTRL
#define pTWI_FIFO_STAT pTWI0_FIFO_STAT
#define pTWI_CLKDIV pTWI0_CLKDIV
#define pTWI_MASTER_ADDR pTWI0_MASTER_ADDR
#elif (DevNumber==1)
#define pTWI_MASTER_STAT pTWI1_MASTER_STAT
#define pTWI_INT_STAT pTWI1_INT_STAT
#define pTWI_FIFO_CTRL pTWI1_FIFO_CTRL
#define pTWI_CONTROL pTWI1_CONTROL
#define pTWI_XMT_DATA8 pTWI1_XMT_DATA8
#define pTWI_XMT_DATA16 pTWI1_XMT_DATA16
#define pTWI_MASTER_CTRL pTWI1_MASTER_CTRL
#define pTWI_FIFO_STAT pTWI1_FIFO_STAT
#define pTWI_CLKDIV pTWI1_CLKDIV
#define pTWI_MASTER_ADDR pTWI1_MASTER_ADDR
#else
#error "BAD TWI device (DevNumber)"
#endif
void twi_reset(void); [TWI.c] /****************************************************
Подпрограммы для работы с TWI на низком уровне.
*****************************************************/
#include "init_platform.h"
#include "TWI.h"
static void twi_clear_all_stat (void) { /* Очищает все биты состояния */ *pTWI_MASTER_STAT = *pTWI_MASTER_STAT; ssync(); /* Очищает все флаги прерываний, ожидающих обработки */ *pTWI_INT_STAT = *pTWI_INT_STAT; ssync(); /* Сброс буферов передачи и приема */ *pTWI_FIFO_CTRL = ( XMTFLUSH | RCVFLUSH ); ssync(); } // Процедура сбрасывает интерфейс TWI.
void twi_reset(void) { /* Сброс контроллера TWI */ *pTWI_CONTROL = TWI_RESET_VAL; ssync(); twi_clear_all_stat(); } [timer.h] #pragma once
#include "settings.h"
// Константы для настройки частоты прерываний таймера:
#define T0PERIOD (SCK/(SAMPLERATE/1000))
#define T0WIDTH (T0PERIOD >> 1)
// Идентификатор периферии таймера для привязки прерывания:
#define TIMER0_PERIPH_INT_ID 16
extern u8 ampl256;
extern u16 voltage;
void Timer0init (void); [timer.c] #include < sys/exception.h>
#include "pins.h"
#include "timer.h"
#include "TWI.h"
#include "AD5667.h"
u8 ampl256 = MAX;
u16 voltage = 600; static void Timer0stop (void) { // Запрет работы таймера: *pTIMER_DISABLE = TIMEN0; // Передача завершающей выборки с генерацией STOP: *pTWI_MASTER_CTRL = (2 << 6) | MEN; u16 val16 = SHIFT; *pTWI_XMT_DATA16 = (val16 >> 8)|(val16 << 8); // Ожидание завершения передачи I2C: *pTWI_INT_STAT = *pTWI_INT_STAT; while (0==(*pTWI_INT_STAT & MCOMP)) { ssync(); } twistate = TWI_IDLE; } // Обработчик прерывания таймера 0, который срабатывает
// с частотой 20 кГц (зависит от SAMPLERATE). При каждом
// срабатывании прерывания таймера в ЦАП AD5667R передается
// одна 16-битная выборка данных. При частоте тактов I2C
// 400 кГц масксимальная частота прерываний таймера
// ограничена 20 кГц. EX_INTERRUPT_HANDLER(Timer0ISR) { *pTIMER_STATUS = TIMIL0; // Счетчик фазы: static float phase = 0; // Указатель на таблицу синуса в SDRAM: s16 *ptr = 0; u16 val16phase; u16 val16; switch (twistate) { case TWI_IDLE: break; case TWI_RUNNING: LED(1); // Запись одной выборки: val16phase = (u16)phase; val16 = SHIFT + (ptr[val16phase] * (float)ampl256/600)*voltage; *pTWI_XMT_DATA16 = (val16 >> 8)|(val16 << 8); // Инкремент фазы для 375 Гц: phase += SINUS_TABLE_SIZE/((float)SAMPLERATE/375); if (phase > SINUS_TABLE_SIZE) phase = phase - SINUS_TABLE_SIZE; LED(0); break; case TWI_STOP: Timer0stop(); break; } } void Timer0init (void) { // Настройка таймера на частоту 20 кГц: *pTIMER0_PERIOD = T0PERIOD; *pTIMER0_WIDTH = T0WIDTH; *pTIMER0_CONFIG = PWM_OUT | PULSE_HI | PERIOD_CNT | IRQ_ENA; // Привязка периферии к IVG: *pSIC_IAR2 |= PX_IVG(TIMER0_PERIPH_INT_ID, ik_ivg7); // Регистрация обработчика прерывания: register_handler_ex(ik_ivg7, Timer0ISR, EX_INT_ENABLE); // Установка маски прерываний: *pSIC_IMASK0 |= TIMER0_IRQ; // Разрешение работы таймера: *pTIMER_ENABLE = TIMEN0; } [AD5667.h] #pragma once
#include < services_types.h>
#include "settings.h"
// I2C-адрес без бита R/W:
#define AD5667_I2C_ADDR 0x0F
// Запись только во входной регистр:
#define CMD_WRITE_NO_UPDATE (0 << 3)
// Обновить DAC данными входного регистра:
#define CMD_UPDATE (1 << 3)
// Записать в выбранный регистр, и сразу обновить весь DAC:
#define CMD_WRITE_N_AND_UPDATE_ALL (2 << 3)
// Записать и обновить канал n DAC:
#define CMD_WRITE_AND_UPDATE_CHNL (3 << 3)
// Команда управления питанием:
#define CMD_POWER (4 << 3)
// Команда программного сброса:
#define CMD_RESET (5 << 3)
// Команда настройки регистра LDAC:
#define CMD_LDAC_SETUP (6 << 3)
// Команда включения/выключения внутреннего источника опорного напряжения:
#define CMD_REFERENCE (7 << 3)
#define DAC_A 0
#define DAC_B 1
#define DAC_BOTH 7
#define S_MULTIBYTE (1 << 6)
// Значения, записываемые в счетчик передаваемых байт,
// чтобы генерировался или не генерировался сигнал STOP:
#define GENERATE_STOP 3
#define WITHOUT_STOP 0xFF
// Значения для управления источником опорного напряжения:
#define REF_EXTERNAL 0
#define REF_INTERNAL 1
// Состояния обработчика прерывания таймера для
// переменной twistate:
#define TWI_IDLE 0 // выборки не передаются #define TWI_RUNNING 1 // выборки передаются #define TWI_STOP 2 // нужна остановка с выдачей STOP в I2C/TWI extern volatile u8 twistate; extern u8 channelDAC;
void DAC_init (void); void DAC_write_value (u16 data); void DAC_set_reference (u8 ref); void DAC_softreset (void); void DAC_multiple_start (void); void DAC_multiple_stop (void); void DAC_set_channel (u8 channel); [AD5667.c] #include "AD5667.h"
#include "TWI.h"
#include "timer.h"
// Подпрограммы для управления ЦАП AD5667. Реализованы только
// функции записи. Каждая функция (кроме DAC_multiple_start
// и DAC_multiple_stop) осуществляет одиночную запись
// по следующему алгоритму:
// Отправка сигнала START
// Передача 7-битного адреса и бита W
// Передача байта команды
// Передача 2 байт данных
// Отправка сигнала STOP.
volatile u8 twistate = TWI_IDLE; u8 channelDAC = DAC_A; static inline void START (u8 stop_or_not) { // Очистка бит вручную: *pTWI_FIFO_CTRL = 0; // Настройка скорости: *pTWI_CONTROL = ( TWI_ENA | PRESCALE_VALUE ); // CLKDIV = (1/SCL)/(1/10MHz): *pTWI_CLKDIV = ( ((CLKDIV_HI) << 8) | (CLKDIV_LO) ); // Целевой адрес устройства (7-битный адрес без бита R/~W): *pTWI_MASTER_ADDR = AD5667_I2C_ADDR; // Если stop_or_not == 0xFF, то генерации STOP по завершению // передачи не будет: *pTWI_MASTER_CTRL = (stop_or_not << 6) | MEN; ssync(); } void DAC_init (void) { // Сброс железа I2C: //twi_reset(); } // Записывает слово в регистр данных (0 .. 65535), чтобы
// на выходе ЦАП появилось соответствующее напряжение.
void DAC_write_value (u16 data) { if (TWI_IDLE == twistate) { twi_reset(); // После передачи адреса и 3 байт будет сгенерирован STOP: START(GENERATE_STOP); // Передача команды и номера канала: *pTWI_XMT_DATA8 = CMD_WRITE_AND_UPDATE_CHNL | channelDAC; ssync(); // Передача данных выборки: while (*pTWI_FIFO_STAT != XMT_EMPTY) { ssync(); } *pTWI_XMT_DATA16 = (data << 8) | (data >> 8); ssync(); // Ожидание окончания передачи: *pTWI_INT_STAT = *pTWI_INT_STAT; while (0==(*pTWI_INT_STAT & MCOMP)) { ssync(); } } } // Устанавливает либо внутреннее, либо внешнее
// опорное напряжение ЦАП. По умолчанию, после
// включения питания, используется внешний источник
// опорного напряжения.
void DAC_set_reference (u8 ref) { if (TWI_IDLE == twistate) { twi_reset(); START(GENERATE_STOP); // Передача команды установки источника опорного напряжения: *pTWI_XMT_DATA8 = CMD_REFERENCE; ssync(); while (*pTWI_FIFO_STAT != XMT_EMPTY) { ssync(); } // Передача настройки внутренний/внешний источник опоры: *pTWI_XMT_DATA16 = ref << 8; ssync(); // Ожидание окончания передачи: *pTWI_INT_STAT = *pTWI_INT_STAT; while (0==(*pTWI_INT_STAT & MCOMP)) { ssync(); } } } void DAC_softreset (void) { // Остановка многословной передачи, если она активна: DAC_multiple_stop(); twi_reset(); START(GENERATE_STOP); // Передача команды сброса: *pTWI_XMT_DATA8 = CMD_RESET; ssync(); while (*pTWI_FIFO_STAT != XMT_EMPTY) { ssync(); } // Передача данных, которые ничего не значат: *pTWI_XMT_DATA16 = 0; ssync(); // Ожидание окончания передачи: *pTWI_INT_STAT = *pTWI_INT_STAT; while (0==(*pTWI_INT_STAT & MCOMP)) { ssync(); } } void DAC_multiple_start (void) { if (TWI_IDLE == twistate) { // Запись на выход ЦАП среднего значения: DAC_write_value(SHIFT); // Подача команды Multiple Block Write, после которой // каждая 16-битная выборка передается двумя байтами // бесконечно в цикле, без генерации STOP: START(WITHOUT_STOP); *pTWI_XMT_DATA8 = S_MULTIBYTE | CMD_WRITE_AND_UPDATE_CHNL | channelDAC; ssync(); // Ожидание опустошения FIFO передачи: while (*pTWI_FIFO_STAT != XMT_EMPTY) { ssync(); } twistate = TWI_RUNNING; // Запуск прерываний таймера: Timer0init(); } } void DAC_multiple_stop (void) { if (TWI_RUNNING == twistate) { // Переключение конечного автомата таймера // на остановку: twistate = TWI_STOP; // Ожидание остановки таймера: while (twistate != TWI_IDLE){} } } // Установка текущего канала ЦАП, A или B.
void DAC_set_channel (u8 channel) { if (TWI_RUNNING == twistate) { // Если таймер находится в режиме многобайтной // передачи, то требуется его остановка. DAC_multiple_stop(); channelDAC = channel; DAC_multiple_start(); } else channelDAC = channel; } Пример использования: /*****************************************************************************
* TestAD5667, проект проверяет 16-битный ЦАП AD5667R с интерфейсом I2C.
* Процессор ADSP-BF538. Инициализируются 32 мегабайта SDRAM на микросхеме
* памяти MT48LC16M16A2.
*
* На выходе канала A (ножка 1) ЦАП AD5667R формируется синусоидальный сигнал
* с частотой приблизительно 375 Гц.
*****************************************************************************/
#include < math.h>
#include < math_const.h>
#include "Initialize.h"
#include "pins.h"
#include "UARTconsole.h"
#include "delay.h"
#include "umsg.h"
#include "initsdram.h"
#include "TWI.h"
#include "timer.h"
#include "AD5667.h"
static void GenSinusTable (void) { s16* ptr = 0; int i; float phase = 0; for (i=0; i < SINUS_TABLE_SIZE; i++) { ptr[i] = 255 * sinf(phase); phase += (2*PI)/SINUS_TABLE_SIZE; } } static void ChangeAmplitude (void) { static bool increment = true; if (increment) { if(MAX == ampl256) increment = false; else ampl256++; } else { if(0 == ampl256) increment = true; else ampl256--; } } void main (void) { // Инициализация ядра и тактовых частот: Initialize(); // Конфигурирование GPIO входов и выходов: ConfigureInputs(); ConfigureOutputs(); // Инициализация UART на 115200 бод (для отладки): InitUARTdebug(); umsg("Тест AD5667 с передачей по I2C выборок 20 кГц,\n"); umsg("генерируется синусодида 375 Гц с плавно меняющейся\n"); umsg("амплитудой.\n\n"); umsg("Для подсказки по командам введите ? или help+Enter.\n\n"); UARTconsolePoll(); // Инициализация 32 мегабайт SDRAM: InitSDRAM(); // Создание таблицы синуса в SDRAM: GenSinusTable(); // Запуск ЦАП AD5667R: DAC_init(); DAC_set_reference(REF_EXTERNAL); DAC_multiple_start(); // Главный цикл ничего не делает, только меняет амплитуду ampl256 // от 0 до 255 и обратно. Эта амплитуда используется для регулирования // синуса, данные которого посылаются в ЦАП AD5667R в обработчике // прерываний EX_INTERRUPT_HANDLER(Timer0ISR). while(true) { delay_ms(10); ChangeAmplitude(); UARTconsolePoll(); } } [Ссылки] 1. Blackfin ADSP-BF538. |