Программирование DSP ADSP-BF538: контроллеры интерфейса TWI (I2C) Thu, November 21 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


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 (подчиненное устройство на шине) в системах с несколькими устройствами.
• Поддержка арбитража для данных в системах multimaster (несколько главных устройств на одной шине).
• 7-битная адресация I2C.
• Скорости передачи 100K бит/сек и 400K бит/сек.
• Поддержка адреса общего вызова (General call address).
• Синхронизация тактов от устройства master и поддержка расширения лог. 0 для тактов SCL (clock low extension).
• Отдельные буферы FIFO для приема и передачи нескольких байт.
• Низкая частота возникновения прерываний.
• Индивидуальная отмена управления линиями данных и тактов при событиях блокировки шины.
• Входной фильтр для подавления иголок помех.
• Поддержка последовательной шины камер, определенной стандартом OmniVision Serial Camera Control Bus (SCCB).

Таблица 20-1 показывает выводы контроллеров TWI. Два двунаправленных вывода у каждого из контроллеров предназначены для подключения к шине I2C. Физически интерфейс очень прост, и кроме верхних подтягивающих резисторов, не требуется больше никаких внешних соединений или логических схем.

Таблица 20-1. Ножки контроллеров TWI корпуса BC-316 (CSP_BGA) процессора ADSP-BF538.

Вывод Шарик Функция
SCL0 B9 Сигнал тактов
SDA0 B10 Сигнал данных
SCL1 Y15 Сигнал тактов
SDA1 Y16 Сигнал данных

ADSP BF538 TWI pins

[Архитектура]

Рис. 20-1 показывает общую архитектуру контроллеров TWI. Периферийный интерфейс поддерживает передачи 16-битных данных, и используется для обращения к регистрам TWI и его буферам FIFO при операциях чтения и записи по шине I2C.

ADSP BF538 TWI block diagram fig20 01

Рис. 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 с помощью значения программирования прескалера.

ADSP BF538 TWI Control Register fig20 02

Рис. 20-2. TWI Control Register.

Описание бит регистра TWIx_CONTROL:

• SCCB Compatibility (SCCB).

Режим совместимости SCCB это опция, и обычно она не должна использоваться на шине I2C. Функция совместимости SCCB допустима только в ситуациях, когда управляется шина стандарта SCCB в режиме master. Передач режима slave следует избегать, когда эта функция разрешена, потому что контроллер TWI в режиме slave всегда генерирует положительное подтверждение (ACK).

1: передачи Master совместимы с SCCB. Этим мастером игнорируются все slave-устройства, которые выставляют биты подтверждения.
0: передачи Master не совместимы с SCCB.

• TWI Enable (TWIx_ENA).

Этот бит должен быть установлен в режиме slave или в режиме master. Рекомендуется устанавливать этот бит в момент времени, когда инициализировано и стабилизировалось время PRESCALE. Это будет гарантировать корректное функционирование логики детектирования занятости шины (bus busy detection).

1: разрешена внутренняя опорная частота. Обеспечивается работа режимов slave и master.
0: опорная внутренняя частота запрещена.

• 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).

ADSP BF538 TWI Clock Divider Register fig20 03

Рис. 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.

ADSP BF538 TWI Slave Mode Control Register fig20 04

Рис. 20-4. TWI Slave Mode Control Register.

Биты регистра TWIx_SLAVE_CTRL:

• General Call Enable (GEN).

Детектирование адреса общего вызова доступно только когда разрешен режим slave.

1: разрешено детектирование адреса общего вызова, при этом принимается транзакция общего вызова (general call). Обновятся все биты источников прерываний, связанных с передачами.
0: срабатывание на совпадение адреса общего вызова не разрешено.

• NAK (NAK).

1: на принимаемые транзакции данных slave будут генерировать data NAK (отсутствие подтверждения, not acknowledge). Slave-устройство все еще считается адресованным.
0: на принимаемые транзакции данных slave будут генерировать data ACK (положительное подтверждение).

• Slave Transmit Data Valid (STDVAL).

1: данные доступны для slave-передачи в передающем FIFO.
0: данные в передающем FIFO предназначены для передачи в режиме master, и их не разрешено использовать для slave-передачи, и передающий FIFO считается как бы пустым.

• Slave Enable (SEN).

1: Разрешен режим slave. Разрешено одновременно и конкурентно использовать режимы slave и master.
0: Режим slave не разрешен. Не делается попыток идентификации допустимого адреса. Если бит SEN очищен во время нормальной передачи, прекращается растягивание тактов, освобождается линия данных, и текущий байт не подтверждается.

Регистр адреса подчиненного устройства (TWIx_SLAVE_ADDR), показанный на рис. 20-5, хранит адрес, который распознается на шине в разрешенном режиме slave. Контроллер TWI сравнивает значение этого регистра с принятым адресом во время фазы адресации I2C.

ADSP BF538 TWI Slave Mode Address Register fig20 05

Рис. 20-5. TWI Slave Mode Address Register.

Во время и при окончании передач режима slave регистр состояния подчиненного режима (TWIx_SLAVE_STAT) содержит информацию по текущей передаче (см. рис. 20-6). Биты состояния режима slave не связаны с генерацией прерываний. Работа в режиме master не влияет на биты TWIx_SLAVE_STAT.

ADSP BF538 TWI Slave Mode Status Register fig20 06

Рис. 20-6. TWI Slave Mode Status Register.

Биты регистра TWIx_SLAVE_STAT:

• General Call (GCALL).

Этот бит очистится самостоятельно, если запрещен режим slave (SEN = 0).

1: в момент адресации был детектирован адрес общего вызова (general call).
0: в момент адресации не был определен адрес общего вызова.

• Slave Transfer Direction (SDIR).

Этот бит очистится самостоятельно, если запрещен режим slave (SEN = 0).

1: в момент адресации было определено направление slave-передачи (бит R/W адреса устройства в лог. 0).
0: в момент адресации было определено направление slave-приема (бит R/W адреса устройства в лог. 1).

Регистр управления режимом главного устройства (TWIx_MASTER_CTRL) управляет логикой, связанной с режимом работы master (см. рис. 20-7.) Биты в этих регистрах не влияют на режим работы slave, и они не должны модифицироваться для управлением функционала режима slave.

ADSP BF538 TWI Master Mode Control Register fig20 07

Рис. 20-7. TWI Master Mode Control Register.

Биты регистра TWIx_MASTER_CTRL:

• Serial Clock Override (SCLOVR).

Этот бит можно использовать, когда требуется прямое управление линией тактов. Обычный режим работы master и slave не должен требовать отмены работы тактов.

1: выход последовательных тактов переводится в активный 0, отменяя работу всей другой логики. Это состояние будет сохраняться до очистки бита SCLOVR. Растяжка уровня лог. 0 может использоваться slave-устройством для сигнализации о своей занятости.
0: обычное функционирование последовательных тактов по управлением системы генерации тактов в режиме master и логики растягивания тактов в режиме slave.

• Serial Data (SDA) Override (SDAOVR).

Этот бит можно использовать, когда требуется прямое управление линией данных. Обычный режим работы master и slave не должен требовать отмены работы данных.

1: выход последовательных данных переводится в активный лог. 0, отменяя работу всей другой логики. Это состояние будет сохраняться до очистки бита SDAOVR.
0: нормальная работа последовательных данных под управлением регистра сдвига и логики генерации подтверждения (ACK/NAK).

• 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.
0: передача завершилась сигналом Stop.

• Issue Stop Condition (STOP).

1: Передача завершится при первой возможности, избегая любых состояний ошибки (как если бы счетчик передачи досчитал до конца) и в этот момент обновится регистр состояния прерываний (TWIx_INT_STAT).
0: нормальное функционирование передачи.

• Fast Mode (FAST).

1: используется быстрый режим (скорость до 400 кбит/сек).
0: стандартный режим скорости (до 100 кбит/сек).

• Master Transfer Direction (MDIR).

1: инициированная транзакция - прием master.
0: инициированная транзакция - передача master.

• Master Mode Enable (MEN).

Этот бит очистится сам при завершении передачи (после того как декремент счетчика DCNT достигнет 0), включая ситуации, когда передача завершилась из-за ошибки.

1: разрешен функционал режима master. Если шина I2C свободна (находится в состоянии ожидания, когда оба сигнала SCL и SDA в лог. 1), сгенерируется сигнал Start.
0: запрещен функционал режима master. Если этот бит был очищен в момент активности по шине, передача обрывается, и сбрасывается вся логика, связанная с передачами режима master. После этого не будет осуществляться управление уровнями SDA и SCL (шина переходит в состояние ожидания, когда оба сигнала SCL и SDA в лог. 1). Биты состояния W1C "сброс при записи 1" остаются неизменными.

Во время фазы адресации контроллер 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.

ADSP BF538 TWI Master Mode Address Register fig20 08

Рис. 20-8. TWI Master Mode Address Register.

Регистр состояния режима master TWIx_MASTER_STAT, показанный на рис. 20-9, содержит информацию о передачах режима главного устройства и об их завершении. Биты состояния режима master не связаны напрямую с генерацией прерываний, однако предоставляют информацию по текущей транзакции. Функционирование в режиме slave никак не влияет на биты состояния режима master.

ADSP BF538 TWI Master Mode Status Register fig20 09

Рис. 20-9. TWI Master Mode Status Register.

Биты регистра TWIx_MASTER_STAT:

• Bus Busy (BUSBUSY).

Показывает текущее состояние шины I2C - занята она или свободна. Это показывает состояние для всех устройств на шине, не только для этого отдельного устройства. При сигнале Start установка значения этого регистра задерживается из-за наличия фильтрации по входу. При сигнале Stop очистка этого регистра происходит после интервала tBUF.

1: шина занята. Определено активное состояние тактов или данных.
0: шина свободна. Сигналы тактов и данных шины находятся в неактивном состоянии в течение соответствующего времени свободного состояния шины.

• Serial Clock Sense (SCLSEN).

Этот бит состояния может использоваться, когда требуется непосредственное чтение уровня линии тактов (SCL). Обновление значения регистра задерживается из-за входного фильтра (номинально на 50 нс). Обычно в режимах master и slave не требуется использовать эту функцию.

1: на линии тактов определен активный 0. Источник активного драйвера нуля не известен, и он может быть как внутренним, так и внешним.
0: на линии тактов определен не активный уровень 1.

• Serial Data Sense (SDASEN).

Этот бит состояния может использоваться, когда требуется непосредственное чтение уровня линии данных (SDA). Обновление значения регистра задерживается из-за входного фильтра (номинально на 50 нс). Обычно в режимах master и slave не требуется использовать эту функцию.

1: на линии данных определен активный 0. Источник активного драйвера нуля не известен, и он может быть как внутренним, так и внешним.
0: на линии данных определен не активный уровень 1.

• Buffer Write Error (BUFWRERR).

1: текущая master-транзакция была оборвана из-за ошибки записи в принимающий буфер. Принимающий буфер и принимающий регистр сдвига оба одновременно заполнены. Этот бит имеет тип W1C ("для очистки нужно записать 1").
0: в настоящий момент на master-приеме не была обнаружена ошибка записи в принимающий буфер.

• Buffer Read Error (BUFRDERR).

1: текущая master-транзакция была оборвана из-за ошибки чтения передающего буфера. В момент времени, когда требовались данные, буфер передающего регистра сдвига был пуст. Этот бит имеет тип W1C ("для очистки нужно записать 1").
0: в настоящий момент на master-передаче не было обнаружена ошибка чтения буфера.

• Data Not Acknowledged (DNAK).

1: текущая master-транзакция была оборвана из-за того, что был детектирован сигнал NAK при передаче данных. Этот бит имеет тип W1C ("для очистки нужно записать 1").
0: на текущем master-приеме не был обнаружен NAK при передаче данных.

• Address Not Acknowledged (ANAK).

1: текущая master-транзакция была оборвана из-за того, что был детектирован сигнал NAK во время фазы адреса устройства. Этот бит имеет тип W1C ("для очистки нужно записать 1").
0: на текущей master-передаче не был обнаружен NAK во время адресации.

• Lost Arbitration (LOSTARB).

1: текущая транзакция была оборвана из-за потери арбитража при конкуренции с другим устройством master на шине. Этот бит имеет тип W1C ("для очистки нужно записать 1").
0: не было потери арбитража при попытке доступа к шине.

• Master Transfer in Progress (MPROG).

1: идет процесс master-транзакции.
0: в настоящий момент не выполняется никакая транзакция. Это может произойти, когда транзакция завершена, или когда разрешенный master ждет освобождения шины.

Биты регистра управления FIFO TWIx_FIFO_CTRL влияют только на FIFO, и не привязаны ни к какой другой операции режима master или slave (см. рис. 20-10).

ADSP BF538 TWI FIFO Control Register fig20 10

Рис. 20-10. TWI FIFO Control Register.

Биты регистра TWIx_FIFO_CTRL:

• Receive Buffer Interrupt Length (RCVINTLEN).

Этот бит определяет частоту, с которой генерируются прерывания приемного буфера. Прерывания могут генерироваться на каждом принятом байте, или после приема двух байт.

1: флаг прерывания приема (RCVSERV) установится, когда поле RCVSTAT в регистре TWIx_FIFO_STAT покажет наличие двух байт в FIFO (FIFO заполнен, 11).
0: флаг прерывания приема (RCVSERV) установится, когда RCVSTAT покажет наличие одного или двух байт в FIFO (01 или 11).

• Transmit Buffer Interrupt Length (XMTINTLEN).

Этот бит определяет частоту, с которой генерируются прерывания буфера передачи. Прерывания могут генерироваться на каждом передаваемом байте, или после двух переданных байт.

1: флаг прерывания передачи (XMTSERV) установится, когда поле XMTSTAT в регистре TWIx_FIFO_STAT покажет, что FIFO передачи пуст (00).
0: флаг прерывания передачи (XMTSERV) установится, когда XMTSTAT покажет, что в FIFO передачи пуст наполовину или полностью (01 или 00).

• Receive Buffer Flush (RCVFLUSH).

1: сбрасывает (Flush) содержимое буфера приема и обновляет биты состояния RCVSTAT, чтобы показать пустоту этого буфера. Это состояние сохраняется до тех пор, пока бит RCVFLUSH не будет очищен. Во время активного прима буфер приема в этом состоянии отвечает логике приема так, как если бы он был полон.
0: нормальное функционирование приемного буфера и его бит состояния.

• Transmit Buffer Flush (XMTFLUSH).

1: сбрасывает (Flush) содержимое буфера передачи, и обновляет биты состояния XMTSTAT для индикации, что буфер пуст. Это состояние сохраняется, пока бит XMTFLUSH не будет очищен. Во время активной передачи в таком состоянии буфер передачи отвечает логике так, как если бы буфер передачи был пуст.
0: нормальное функционирование передающего буфера и его бит состояния.

Поля в регистре состояния FIFO (TWIx_FIFO_STAT), показанного на рис. 20-11, отражают состояние содержимого приема и передачи буферов FIFO. Буферы FIFO не разделяют данные master и данные slave. Путем использования предоставленных бит состояния и управления FIFO может обслуживаться таким образом, чтобы можно было реализовать одновременное функционирование режимов master и slave.

ADSP BF538 TWI FIFO Status Register fig20 11

Рис. 20-11. TWI FIFO Status Register.

Биты регистра TWIx_FIFO_STAT (все биты этого регистра доступны только на чтение, RO):

• Receive FIFO Status (RCVSTAT).

Поле RCVSTAT доступно только для чтения. Оно показывает количество достоверных байт данных в буфере приема FIFO. Состояние RCVSTAT обновляется с каждым чтением буфера FIFO с помощью шины данных периферии, или при доступе на запись со стороны регистра сдвига приема. Допускается наличие одновременного доступа.

11: FIFO заполнен и содержит 2 байта данных. Допускается одиночное или двойное чтение байта при обращении к периферийному устройству FIFO.
10: зарезервировано.
01: FIFO содержит один байт данных. Допускается одиночное чтение байта при обращении к периферийному устройству FIFO.
00: FIFO приема пуст.

• Transmit FIFO Status (XMTSTAT).

Поле XMTSTAT доступно только на чтение. Оно показывает количество достоверных байт данных в буфере передачи FIFO. Состояние XMTSTAT с каждой записью FIFO через шину периферийного устройства или с каждым чтением со стороны регистра сдвига передачи. Допускается наличие одновременного доступа.

11: FIFO передачи заполнен и содержит 2 байта данных.
10: зарезервировано.
01: в FIFO передачи содержится 1 байт данных. Допустима одиночная запись байта в FIFO передачи.
00: буфер FIFO передачи пуст. Допустима либо одиночная, либо двойная операция записи байта в FIFO передачи.

Регистр маски прерываний TWIx_INT_ENABLE, показанный на рис. 20-12, разрешает источники прерываний для активации выхода генерации прерывания TWI. Каждый бит маски соответствует одному биту источника прерывания в регистре состояния прерываний TWI (TWIx_INT_STAT). Чтение и запись регистров маски прерываний TWI не влияет на содержимое регистра состояния прерываний TWI.

ADSP BF538 TWI Interrupt Mask Register fig20 12

Рис. 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.
1: лог. 1 в 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.
1: лог. 1 в XMTSERV приведет к генерации прерывания TWI.

• Master Transfer Error Mask (MERRM).

0: запрещена генерация прерывания при установке бита MERR в регистре состояния прерываний TWI.
1: лог. 1 в MERR приведет к генерации прерывания TWI.

• Master Transfer Complete Mask (MCOMPM).

0: запрещена генерация прерывания при установке бита MCOMP регистра состояния прерываний TWI.
1: лог. 1 в MCOMP приведет к генерации прерывания TWI.

• Slave Overflow Mask (SOVFM).

0: запрещена генерация прерывания при установке бита SOVF регистра состояния прерываний TWI.
1: лог. 1 в SOVF приведет к генерации прерывания TWI.

• Slave Transfer Error Mask (SERRM).

0: запрещена генерация прерывания при установке бита SERR регистра состояния прерываний TWI.
1: лог. 1 в SERR приведет к генерации прерывания TWI.

• Slave Transfer Complete Mask (SCOMPM).

0: запрещена генерация прерывания при установке бита SCOMP регистра состояния прерываний TWI.
1: лог. 1 в SCOMP приведет к генерации прерывания TWI.

• Slave Transfer Initiated Mask (SINITM).

0: запрещена генерация прерывания при установке бита SINIT регистра состояния прерываний TWI.
1: лог. 1 в SINIT приведет к генерации прерывания TWI.

Регистр состояния прерываний TWI (TWIx_INT_STAT), показанный на рис. 20-13, содержит информацию о функциональной области TWI, которая возможно требует немедленного обслуживания. Многие из этих бит работают как индикатор дополнительного чтения и обслуживания различных регистров состояния. После обслуживания источника прерывания, связанного с определенным битом, пользователь должен очистить этот бит источника прерывания.

ADSP BF538 TWI Interrupt Status Register fig20 13

Рис. 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 байта, где содержатся принятые данные (оттуда можно прочитать эти данные).
0: FIFO приема не требует обслуживания, или поле RCVSTAT не изменилось с момента, когда бит RCVSERV был очищен в последний раз.

• Transmit FIFO Service (XMTSERV).

Если бит XMTINTLEN в регистре TWIx_FIFO_CTRL сброшен в 0, то бит XMTSERV установится всякий раз, когда поле XMTSTAT в регистре TWIx_FIFO_STAT обновится либо в 01, либо в 00. Если бит XMTINTLEN установлен в 1, то бит XMTSERV установится всякий раз, когда поле XMTSTAT обновится в значение 00.

1: в буфере FIFO передачи есть одна или две свободные 8-битные ячейки, в которые можно записать передаваемые данные.
0: FIFO передачи не требует обслуживания, или поле XMTSTAT не поменяло свое значение с момента, когда XMTSERV был очищен в последний раз.

• Master Transfer Error (MERR).

1: произошла ошибка master. Условия возникновения ошибки показаны регистром состояния master (TWIx_MASTER_STAT).
0: не было обнаружено ошибок.

• Master Transfer Complete (MCOMP).

1: была завершена инициированная транзакция master. При отсутствии repeat start шина I2C освобождается.
0: не было обнаружено завершение транзакции.

• Slave Overflow (SOVF).

1: бит завершения slave-транзакции (SCOMP) был установлен в момент подтверждения последующей транзакции на фазе адреса. Транзакция продолжилась, однако могут быть сложности в отделении одной транзакции от другой.
0: не было детектировано переполнение.

• Slave Transfer Error (SERR).

1: произошла ошибка slave. Произошла выдача повторного сигнала Start или выдача сигнала Stop во время фазы приема данных транзакции.
0: ошибки не были обнаружены.

• Slave Transfer Complete (SCOMP).

1: транзакция завершена, и был детектирован либо сигнал Stop, либо сигнал повторного Start.
0: не было обнаружено завершение транзакции.

• Slave Transfer Initiated (SINIT).

1: slave обнаружил совпадение адреса, и была инициирована транзакция.
0: нет выполняющейся транзакции. Не было совпадения адреса с момента, когда этот бит был очищен.

Регистр 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.

ADSP BF538 TWI FIFO Transmit Data Single Byte Register fig20 14

Рис. 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.

ADSP BF538 TWI FIFO Transmit Data Double Byte Register fig20 15

Рис. 20-15. TWI FIFO Transmit Data Double Byte Register.

Данные записываются в порядке байт little endian [2], показанном на рис. 20-16. Здесь байт 0 (B0) это первый байт, который будет передан, и байт 1 (B1) это второй передаваемый байт. С каждым таким доступом обновляется поле состояния передачи (XMTSTAT) в регистре TWIx_FIFO_STAT. Если доступ осуществляется, когда буфер FIFO не опустошился, то запись игнорируется, и существующие в буфере FIFO данные и их состояние не изменяется.

  B1       B0  

Рис. 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).

ADSP BF538 TWI FIFO Receive Data Single Byte Register fig20 17

Рис. 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).

ADSP BF538 TWI FIFO Receive Data Double Byte Register fig20 18

Рис. 20-18. TWI FIFO Receive Data Double Byte Register.

  B1       B0  

Рис. 20-19. Little Endian Byte Order.

[Механика транзакций данных]

Контроллеры TWI следуют протоколу транзакций Philips I2C Bus Specification версии 2.1, опубликованному в январе 2000 года. Одиночная полная транзакция показана на рис. 20-20.

 S   7-битный адрес   R/W  ACK  8 бит данных  ACK  P 

Рис. 20-20. Базовая передача данных.

S = сигнал START
P = сигнал STOP
ACK = ACKNOWLEDGE (положительное подтверждение)

Чтобы лучше понимать отображение регистров контроллера TWI на базовую передачу данных, рис. 20-21 показывает ту же самую транзакцию, как на рисунке 20-20, с соответствующими именами бит контроллера TWI. На этой иллюстрации контроллер TWI успешно передает 1 байт данных. Устройство slave подтверждает (ACK) и адрес, и данные.

 S   MADDR[6:0]   MDIR  ACK  XMITDATA8[7:0]  ACK  P 

Рис. 20-21. Базовая передача данных с использованием бит контроллера TWI.

[Генерация тактов и синхронизация]

Реализация контроллера TWI выдает такты только в режиме работы master, и только тогда, когда была инициирована транзакция. Если арбитраж на шине потерян, выход SCK немедленно переходит в третье состояние. Если несколько выходов тактов одновременно управляют сигналом SCK шины I2C, то контроллер синхронизирует свои такты с другими источниками тактов. Это показано на рис. 20-22.

ADSP BF538 TWI Clock Synchronization fig20 22

Рис. 20-22. Синхронизация тактов SCK контроллера TWI.

Выход SCK контроллера TWI следует следующим правилам:

• Как только завершился отсчет периода лог. 1 тактов (CLKHI), выход SCK подтягивается к лог. 0, начинается отсчет периода лог. 0 выхода тактов (CLKLOW).
• Как только закончится отсчет периода лог. 0, сигнал тактов SCK переводится в третье состояние, и логика синхронизации тактов входит в режим задержки (затененная на рисунке область) до момента, когда на линии SCL будет детектирован уровень лог. 1. В этот момент времени начнется отсчет периода лог. 1 тактов (CLKHI).

[Арбитраж на шине]

Контроллеры TWI инициируют передачу в режиме master (MEN) только когда шина в состоянии ожидания (idle), что означает не занятость шины другими устройствами master. Если шина находится в состоянии ожидания, и два устройства masters одновременно инициировали передачу, начнется арбитраж по шине. Это показано на рис. 20-23.

ADSP BF538 TWI Bus Arbitration fig20 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.

ADSP BF538 TWI Start and Stop Conditions fig20 24

Рис. 20-24. Сигналы Start и Stop протокола I2C.

Специальные случаи сигналов Start и Stop для контроллера TWI:

• Контроллер TWI адресован как slave-приемник. Если master выдал сигнал Stop во время фазы данных транзакции, контроллер TWI завершает эту транзакцию (SCOMP).
• Контроллер TWI адресован как slave-передатчик. Если master выдал сигнал Stop во время фазы данных транзакции, контроллер TWI завершает эту транзакцию (SCOMP) и показывает состояние ошибки slave-транзакции (SERR).
• Контроллер TWI работает как master-передатчик или master-приемник. Если бит STOP в регистре TWIx_MASTER_CTRL установлен во время активной транзакции, контроллер TWI выдаст сигнал Stop при первой возможности, избегая возникновения любой ошибки (как если бы обнулился счетчик транзакции данных при нормальной передаче).

[Поддержка адреса общего вызова (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).
• Время установки сигнала Stop от SCK до SDA (tSU;STO).
• Время освобождения шины между сигналами Stop и Start (tBUF).

[Примеры программирования]

Ниже показаны примеры, как делать общую настройку, как работать в режиме 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.

Контроллер TWI Ядро процессора
Прерывание: SINIT - происходит slave-транзакция. Подтверждение: очистка бита источника прерывания.
Прерывание: RCVSERV - буфер приема заполнен. Чтение из буфера FIFO приема.
Подтверждение: очистка бита источника прерывания.
... ...
Прерывание: SCOMP - slave-транзакция завершена. Чтение из буфера FIFO приема.
Подтверждение: очистка бита источника прерывания.

Настройка тактов в режиме 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-передачи.

Контроллер TWI Ядро процессора
Прерывание: XMTEMPTY - буфер FIFO передачи пуст. Запись в буфер FIFO передачи.
Подтверждение: очистка бита источника прерывания.
... ...
Прерывание: MCOMP - 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-приема.

Контроллер TWI Ядро процессора
Прерывание: RCVSERV - буфер FIFO приема заполнен. Чтение из буфера FIFO приема.
Подтверждение: очистка бита источника прерывания.
... ...
Прерывание: MCOMP - master-транзакция завершена. Чтение из буфера FIFO приема.
Подтверждение: очистка бита источника прерывания.

[Сигнал Repeated Start]

Сигнал repeated start (повторный старт) это просто отсутствие сигнала Stop между двумя транзакциями, и поскольку каждая транзакция начинается сигналом Start, получается так называемый повторный старт Repeated Start. При этом эти две передачи могут быть любого направления. Например, осуществляется прием сразу после передачи, или передача после приема. В последующих секциях содержится информация, которая поможет программисту написать соответствующий код обработчика прерывания.

Последовательность Repeated Start при передаче/приеме. На рис. 20-25 показана передача данных, за которой сразу идет последовательность приема данных.

ADSP BF538 TWI Transmit Receive Data Repeated Start fig20 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 показан прием данных, за которой сразу идет последовательность передачи данных.

ADSP BF538 TWI Receive Transmit Data Repeated Start fig20 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.
• Растягивание тактов при переполнении FIFO.
• Растягивание тактов при сигнале Repeated Start.

Примечание: растягивание тактов в данном контексте это увеличение длительности лог. 0 сигнала SCK, которое сигнализирует о занятости шины и о том, что устройство master требует от slave-устройства ожидания для подготовки/выполнения каких-то своих внутренних операций.

Растягивание тактов при недогрузке FIFO. При передаче в режиме master генерируется прерывание, когда буфер FIFO опустошился. В это время начинает передаваться новый байт. Если прерывание XMTSERV не обработано, то растягивается завершающая подтверждения транзакции. Растягивание тактов продолжается, пока в буфер FIFO передачи не будут записаны новые данные (путем записи в регистр TWI_XMT_DATA8 или TWI_XMT_DATA16). Для того, чтобы освободить такты и продолжит передачу, никаких других действий не требуется. Это поведение продолжается, пока не завершится вся передача (DCNT = 0). Завершение передачи показывается битом MCOMP, как иллюстрировано на рис. 20-27 и описано в таблице 20-5.

ADSP BF538 TWI Clock Stretching During FIFO Underflow fig20 27

Рис. 20-27. Растягивание тактов при недогрузке FIFO.

Таблица 20-5. Случай недогрузки FIFO.

Контроллер TWI Ядро процессора
Прерывание: XMTSERV - буфер FIFO передачи пуст. Подтверждение: очистка бита источника прерывания.
Запись в буфер FIFO передачи.
... ...
Прерывание: MCOMP - master-транзакция завершена (DCNT = 0). Подтверждение: очистка бита источника прерывания.

Растягивание тактов при переполнении FIFO. Во время приема в режиме master прерывание генерируется в момент, когда буфер FIFO приема становится заполненным. При этом на фазе подтверждения последнего принятого байта начинается растягивание тактов. Не делается попыток инициировать прием дополнительного байта. Растягивание тактов продолжается, пока ранее принятые данные не будут прочитаны из буфера FIFO (через регистры TWI_RCV_DATA8, TWI_RCV_DATA16). Для освобождения тактов и продолжения приема не требуется никаких других действий. Это поведение продолжается, пока не будут полностью приняты все данные (DCNT = 0). Тогда прием завершается (MCOMP), как показано на рис. 20-28 и описано в таблице 20-6.

ADSP BF538 TWI Clock Stretching During FIFO Overflow fig20 28

Рис. 20-28. Растягивание тактов при переполнении FIFO.

Таблица 20-6. Случай переполнения FIFO.

Контроллер TWI Ядро процессора
Прерывание: RCVSERV - буфер FIFO приема заполнен. Подтверждение: очистка бита источника прерывания.
Чтение буфера FIFO приема.
... ...
Прерывание: MCOMP - master-транзакция завершена. Подтверждение: очистка бита источника прерывания.

Растягивание тактов при сигнале Repeated Start. Функция повторного старта в протоколе I2C требует перехода между двумя соседними транзакциями. С помощью растягивания тактов задача управления этим переходом упрощается, и она одинаковая для всех типов транзакций.

Как только завершена начальная master-транзакция TWI (приема или передачи), во время фазы repeated start (которая происходит между транзакциями) такты начинают растягиваться. Конкурентно с этим событием начальная транзакция приведет к генерации прерывания завершения транзакции (MCOMP), которое сигнализирует о завершении начальной транзакции (DCNT = 0). Эта начальная транзакция обрабатывается без каких-либо специальных установок бит или таймингов. Здесь применяется вышеописанная логика растягивания тактов. Нет никаких системных ограничений по времени на последующую транзакцию (приема или передач), чтобы она была настроена и активирована. Эта последовательность может быть повторена любое необходимое количество раз. Процесс показан на рис. 20-29 и описан в таблице 20-7.

ADSP BF538 TWI Clock Stretching During Repeated Start Condition fig20 29

Рис. 20-29. Растягивание тактов при Repeated Start.

Таблица 20-7. Случай Repeated Start.

Контроллер TWI Ядро процессора
Прерывание: MCOMP - начальная транзакция завершена и DCNT = 0.

Примечание: передача продолжается, ранее был установлен бит RSTART.
Подтверждение: очистка бита источника прерывания.

Запись Write TWI_MASTER_CTL, установка бита MDIR (прием), очистка RSTART и установка нового не нулевого значения DCNT.
Прерывание: RCVSERV – буфер FIFO приема заполнен. Подтверждение: очистка бита источника прерывания.
Чтение буфера FIFO приема.
... ...
Прерывание: MCOMP - master-транзакция завершена. Подтверждение: очистка бита источника прерывания.

Ниже во врезках приведено несколько примеров работы с 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:

AT24C64D write example

Запись осуществляется довольно просто: после сигнала START сначала нужно передать адрес устройства с битом R/W=0, потом передать старший байт адреса, затем младший байт адреса, и далее передать нужное количество байт (1 .. 32). Последовательность должна завершиться генерацией сигнала STOP.

Пример чтения двух байт по адресу 0000h:

AT24C64D read example

Чтение происходит немного сложнее. Начинается оно так же, как запись, передачей адреса устройства с битом 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.
2. Порядок следования байт (endianness).
3Аппаратный драйвер I2C/TWI для Blackfin.
4. AT24C64: Serial EEPROM с интерфейсом I2C (TWI).
5. Flash Programmer для I2C EEPROM AT24C64D.

 

Добавить комментарий


Защитный код
Обновить

Top of Page