Настройка I2C на микроконтроллере STM8

Автор: | 16.07.2014

Сегодня я хотел бы кратко рассказать о модуле I2C на микроконтроллере STM8S003F и поделиться своими наработками в этой области.

Признаться честно, долго пришлось повозиться с модулем I2C– он ни в какую не хотел работать так, как нужно, пока я не прочитал errata и не устранил еще некоторые мелкие, но коварные ошибки, которые перекочевали в мою программу из примера, предоставленного на официальном сайте STMicroelectronics.

В этой статье я покажу как настроить I2C в режиме мастера без прерываний. В самом конце статьи можно будет скачать готовый аппартный драйвер I2C для STM8. В следющей статье попробуем подключить часы реального времени DS1307 и выводить время через UART. Возможно, в дальнейшем будет пример на прерываниях, или может кто-нибудь захочет поделиться своими наработками – милости прошу.

Для тех, кто желает разобраться в принципе работы I2C интерфейса, советую почитать краткую и в тоже время, полезную статью: Интерфейсная шина IIC (I2C)

Также советую почитать полезное замечание: Как я побеждал I2C (STM8L)

Еще нужно будет почитать статью по настройке модуля UART и ознакомиться с даташитами STM8S003 и Reference manual.

Рассмотрим основные возможности модуля I2C:

  • Поддержка режима Master и Slave(ведущий и ведомый)
  • Генерация и определение 7- и 10-битного адресов
  • Поддержка разных скоростей передачи:
    • Стандартный режим 100 кГц
    • Высокоскоростной режим 400 кГц

Как обычно начинаем с инициализации.

1. Задаем частоту тактирования модуля I2C. Это частота Fmaster, которая снимается перед делителем CPUDIV. Если Вы читали прошлую статью по настройке модуля UART, то знаете, что по умолчанию в качестве источника тактирования выбран RC-генератор (16МГц), с делением частоты на 8. Т.е. по умолчанию Fmaster= 2МГц. Значение Fmaster записывается в регистр I2C_FREQR в МГц. Значения, которые могут быть записаны в данный регистр, находятся в диапазоне 1…24 МГц.

2. Дальше нужно решить в каком режиме мы будем работать. DS1307 работает только в стандартном режиме  (100 кГц), поэтому его и выбираем. Стандартный режим выбирается сбросом бита F/в регистре I2C_CCRH.

3. Настраиваем регистры управления тактированием I2C_CCRи I2C_CCRH. Эти регистры определяют длительность импульса тактировании SCL и длительность паузы.

I2C_CCRL

I2C_CCRH

Коэффициент CСR вычисляется по разным формулам (они описаны в reference manual), в зависимости от выбранного режима работы. Для стандартного режима он вычисляется по формуле:

CCR= Period_I2C/(2*Tmaster), где

Period_I2C– период импульсов SСLна I2C шине, в стандартном режиме минимальный период равен 1/100кГц,

Tmaster– период частоты тактирования периферии, Tmaster= 1/Fmaster= 1/2 000 000 Гц.

Таким образом формула принимает вид:

CCR= (Fmaster* 1 000 000)/(2 * Fi2c), где

Fmaster — частота периферии в МГц,

Fi2c– частота I2Cшины.

Бит DUTY позволяет выбрать коэффициент заполнения для высокоскоростного режима.

4. Запрограммировать максимальное время нарастания сигнала SCL. По спецификации время нарастания сигнала SCL в стандартном режиме не должно превышать 1000 нс. Время нарастания задается в регистре TRISE.

Значение регистра вычисляется по формуле:

TRISE= (1000 нс/Tmaster) + 1.

Если частота Fmaster=2МГц, то период равен 500нс, значит значение регистра:

TRISE = (1000 нс/500нс) + 1 = 3

5. Включаем модуль I2C установкой бита PE=1 в регистре I2C_CR1.

6. Устанавливаем бит, разрешающий подтверждение принятого байта ACK=1 в регистре I2C_CR2

Опишу кратко регистры статуса и управления, с которыми нам придется дальше работать.

I2C_CR2

  • SWRST – программный сброс модуля I2C
  • POS– этот бит устанавливается только в случае, когда нужно принять два байта (N=2). Он должен быть установлен до начала приема данных. В этом случае импульс NACKсформируется после приема второго байта, и ACK можно сразу же сбросить сразу после отправки адреса.
  • ACK – разрешает отсылать подтверждения от мастера после приема каждого байта
  • STOP – дает указание мастеру сгенерировать стоповую посылку после приема текущего байта
  • START– дает указание мастеру сгенерировать стартовую посылку

I2C_SR1

  • TXE – регистр данных DR пуст
  • RXNE – в регистре данных DRсодержится принятый байт
  • STOPF– обнаружена стоп-посылка на шине
  • ADD10 – мастер отправил первый байт 10-битного адреса
  • BTF– устанавливается когда в приемный регистр DR поступил байт, но не был прочитан, и уже пришел новый байт в сдвиговый регистр
  • ADDR – мастер передал адрес
  • SB– мастер сгенерировал старт-посылку

I2C_SR2

  • WUFH – выход из спящего режима
  • OVR – ошибка  переполнения регистра данных
  • AF– ошибка подтверждения отправленного мастером байта
  • ARLO – потеря арбитража (на шине, где более одного мастера)
  • BERR– ошибка шины (например когда послан неуместный старт или стоп)

I2C_SR3

  • TRA– если данные приняты = 0, если переданы = 1
  • BUSY – сигнализирует о занятости шины
  • MSL – показывает в каком режиме находится модуль I2C. 1 – мастер, 0 – слейв

Также есть регистр настройки прерываний I2C_ITR, который мы не будем настраивать в данном примере. Также для слейва имеются регистры, в которые записывается собственный адрес I2C устройства — I2C_OARL, I2C_OARH.

Дальше я немного перевел для вас информации из reference manual. Если где-то ошибся, то прошу меня поправить.

Режим мастера

В режиме мастера I2Cинтерфейс инициирует передачу данных и генерирует clockсигнал тактирования. Каждая передача начинается СТАРТ условием и оканчивается СТОП условием. Режим мастера включается сразу же после генерации СТАРТ.

Входная частота должна быть не меньше:

  • 1 MHz в стандартном режиме
  • 4 MHz в быстром режиме

Стартовое условие (стартовая посылка)

Установка бита STARTприводит к генерации стартовой посылки и переключает в режим мастера, при условии, что BUSY= 0.

Заметка: В режиме мастера установка START бита генерирует посылку рестарта (повторного старта) в конце текущего передаваемого байта.

Сразу же после стартовой посылки устанавливает бит SB и генерируется прерывание, если оно разрешено ITEVTEN= 1.

Далее мастер ожидает чтение регистра SR1, после чего в регистр DR записывается адрес слейв-устройтва (slaveaddress).

Передача слейв-адреса

Cлейв-адрес передается в SDA линию из сдвигового регистра.

● В 10-битном режиме адресации отправка сопровождается следующими событиями:

Устанавливается бит ADD10 аппаратно и генерируется прерывание, если оно разрешено в ITEVTEN.

Затем мастер ожидает чтения регистра SR1, после чего в DR записывается вторая часть адреса.

Устанавливается бит ADDRаппаратно и генерируется прерывание, если оно разрешено в ITEVTEN.

Затем мастер ожидает чтения регистра SR1 и регистра SR3, что позволяет сбросить бит ADDR и продолжить передачу.

● В 7-битном режиме адресации отправляется только один байт.

Сразу же после отправки байта адреса устанавливается аппаратно бит ADDR и генерируется прерывание, если оно разрешено в ITEVTEN.

Затем мастер ожидает чтения регистра SR1 и регистра SR3.

Мастер может решать перейти в режим передачи или приема в соответствии с 0-м битом слейв-адреса.

Если нулевой бит = 0, то передача, если = 1, то прием.

● В режиме 10-битной адресации:

– Для входа в режим передачи мастер отправляет заголовок (11110xx0) и слейв-адрес (где xx– это два старших бита адреса).

– Для входа в режим приема мастер отправляет заголовок (11110xx0) слейв-адрес. Затем оправляется повторная реСТАРТ-посылка,затем заголовок (11110xx1).

Бит TRA  показывает в каком режиме находится мастер: прием или передача.

Мастер в режиме передатчика

После передачи адреса и очистки бита ADDR, мастер отправляет байт из регистра DR на SDA линию через внутренний сдвиговый регистр.

Мастер ожидает до тех пор, пока в DR запишется первый байт данных (событие  EV8_1).

Когда принят сигнал (импульс) подтверждения:

● Устанавливается аппаратно бит TXE и генерируется прерывание, если оно разрешено в ITEVTEN, а также устанавливается бит ITBUFEN.

● Если TXE установлен и байт данных не был записан в DR до окончания следующей передачи данных, устанавливается бит BTF, и интерфейс ожидает, пока он не будет очищен, что делается чтением регистра SR1 и записью в DR, SCL удерживается в низком состоянии.

Завершения связи (передачи)

После записи последнего байта в DR, устанавливают бит STOP, который вызывает генерацию СТОП посылки (событие EV8_2). Интерфейс автоматически переходит в режим слейв. (MSLбит сбрасывается).

Заметка: Стоп-посылка должна быть запрограммирована во время события EV8_2, когда TXE или BTF установлены.

Передача STM8 I2C master slave

S= Старт,

Sr= Повторный старт,

P= Стоп,

A= Подтвеждение,

NA= неподтверждение,

EVx= событие

EV5:SB=1 очищается чтением регистра SR1, далее записывается адрес в DR.

EV6:ADDR=1, очищается чтением регистра SR1 и последующим чтением SR3.

EV8_1:TXE=1, сдвиговый регистр пуст, регистр данных пуст, запись данных в  DR.

EV8:TXE=1, сдвиговый регистр не пуст, регистр данных DR пуст, очищается записью в  DR.

EV8_2:TXE=1, BTF= 1, Программируется STOP запрос. TXEи BTF очищаются аппаратно после генерации стоп-посылки.

EV9:ADD10=1, очищается чтением регистра SR1, далее записывается регистр DR.

Событие EVдолжно быть выполнено до конца передачи текущего байта. В противном случае рекомендуется использовать BTF вместо TXE с замедлением связи.

Мастер в режиме приемника

После передачи адреса и очистки бита ADDR I2C интерфейс входит в режим приемника. В этом режиме интерфейс принимает байты из SDA линии в DR регистр через внутренний сдвиговый регистр.

После каждого байта интерфейс генерирует последовательность:

● Подтверждающий импульс, если бит ACK установлен

● Установка бита RXNE и генерация прерывания, если биты ITEVTEN и ITBUFEN установлены.

Если бит RXNE установлен и данные не были прочитаны из DR до того, как был принят следующий байт, аппаратно устанавливается бит BTF и интерфейс ожидает, пока этот бит будет очищен чтением I2C_SR1 и I2C_DR, SCL удерживается в низком состоянии.

Завершение соединения

Метод 1: Этот метод подходит в том случае, если I2C использует прерывания, которые имеют наивысший приоритет в приложении.

Мастер отправляет NACK в конце последнего байта от слейва.

После приема этого NACK слейв освобождает линии SCL и SDA. Затем мастер может отправить Стоп или Рестарт посылку.

● В случает генерации NACK импульса после последнего принятого байта, бит ACK должен быть очищен точно после чтения предпоследнего байта (после предпоследнего события RXNE).

● В случае генерации Стоп или Рестарта приложение должно установить бит STOP/START сразу после чтения предпоследнего байта (после предпоследнего события RXNE).

● В случае приема одного байта, подтверждение деактивируется и генерируется СТОП после события EV6 (в EV6 сразу после очистки ADDR).

После генерации СТОП посылки интерфейс автоматически переходит в режим слейва. (MSL= 0).

Прием STM8 I2C по методу 1

EV5:SB=1, очищается чтением SR1 с последующей записью в DR.

EV6:ADDR=1, очищается чтением SR1 и последующим чтением SR3. В 10-битном режиме мастера-приемника эта последовательность должна следовать после записи в CR2 бита START= 1.

EV6_1:нет флагов данного события, используется только для однобайтного приема. Программируется ACK=0 и STOP=1 после очистки ADDR.

EV7:RXNE=1, очищается чтением DR.

EV7_1:RXNE=1, очищается чтением DR, программируется ACK=0 и STOP запрос

EV9:ADD10=1, очищается чтением SR1 с последующей записью в DR.

1.Если регистр DR заполнен, прием следующих данных выполняется после очистки события EV7.

2. EV5, EV6 и EV9 события удерживают SCL в низкоуровневом состоянии до конца соответствующей последовательности действий в приложении.

3. EV7 программная последовательность должна быть завершена до конца передачи текущего байта. В противном случае рекомендуется использовать BTF вместо RXNE, тем самым замедляя скорость связи.

4. Последовательность EV6_1 или EV7_1 должна быть завершена до импульса подтверждения ACK текущего байта.

Метод 2: Этот метод подходит для тех случаев, когда используются прерывания, которые не имеют наивысшего приоритета в приложении и когда I2используется в режиме опроса.

● DataN_2 не читается, так что после DataN_1 соединение замедляется (оба бита установлены RxNE и BTF).

● Далее, бит ACK должен быть очищен до чтения DataN-2 из DR для уверенности, что этот бит был очищен до импульса подтверждения DataN.

● После этого сразу после чтения DataN_2, приложения должно установить бит STOP/START и прочитать DataN_1. После установки RXNE читается DataN.

Прием I2C STM8 по методу 2, когда N>2

EV5: SB=1, очищается чтением SR1 с последующей записью в DR.

EV6:ADDR1, очищается чтением SR1 с последующим чтением SR3.

В 10-битном режиме мастера-приемника эта последовательность должна следовать после записи в CR2 бита START= 1.

EV7: RxNE=1, очищается чтением DR.

EV7_2: BTF= 1, DataN-2 в DR, а DataN-1 в сдвиговом регистре, программируется ACK= 0, читаются данные DataN-2 из DR. Устанавливается STOP= 1, читается DataN-1.

EV9: ADD10= 1, очищается чтением SR1 с последующей записью в DR.

Когда остается прочитать 3 байта (N>2):

● RxNE= 1 => ничего не делать (DataN-2 не читаем).

● DataN-1 принят

● BTF= 1 потому что сдвиговый и регистр данных заполнены: DataN-2 в DR и DataN-1 в сдвиговом регистре => SCL удерживается в низком состоянии: никакие другие данные не будут получены из шины.

● Сбрасываем ACK= 0

● Читаем DataN-2 из DR=> Это позволяет DataN попасть в сдвиговый регистр

● DataN принят (с посылкой NACK)

● Программируется бит START/STOP

● Читаются данные DataN-1

● Ожидается установка RxNE= 1

● Читаются данные DataN

Процедура, описанная выше, подходит для случая, когда нужно принять байт N>2.

Когда нужно принять один (N=1) байт или два(N=2), обработка будет отличаться:

Случай N=1

– Ожидаем установки ADDR, сбрасывает бит ACK=0.

– Сбрасывает ADDR=0

– Устанавлием бит STOP/START.

– Читаем данные, после того, как установится RxNE.

Случай N=2

– Устанавливаются POS=1 и ACK=1

– Ожидается установка ADDR=1

– Очищается ADDR

–Очищается ACK

– Ожидается установка BTF=1

–Программируется STOP=1

– Читаем DR дважды

Прием I2C STM8 по методу 2, когда N=2

EV5: SB=1, очищается чтением SR1 с последующей записью в DR.

EV6:ADDR1, очищается чтением SR1 с последующим чтением SR3.

В 10-битном режиме мастера-приемника эта последовательность должна следовать после записи в CR2 бита START= 1.

EV6_1:нет флагов данного события. Подтверждение должно быть отключено сразу после события EV6, после чего ADDRочищается

EV7_3: BTF= 1, программируется STOP=1, дважды читается регистр DR сразу после установки бита STOP.

EV9: ADD10= 1, очищается чтением SR1 с последующей записью в DR.

EV5, EV6 и EV9 события удерживают SCLв низкоуровневом состоянии до конца соответствующей последовательности действий в приложении.

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

Ну и наконец пример кода:

//Результат выполнения операции с i2c
typedef enum {
    I2C_SUCCESS = 0,
    I2C_TIMEOUT,
    I2C_ERROR
} t_i2c_status;

//Таймаут ожидания события I2C
static unsigned long int i2c_timeout;

//Задать таймаут в микросекундах
#define set_tmo_us(time)
  i2c_timeout = (unsigned long int)(F_MASTER_MHZ * time)

//Задать таймаут в миллисекундах
#define set_tmo_ms(time)
  i2c_timeout = (unsigned long int)(F_MASTER_MHZ * time * 1000)

#define tmo               i2c_timeout--

//Ожидание наступления события event
//в течении времени timeout в мс
#define wait_event(event, timeout) set_tmo_ms(timeout);
                                   while(event && i2c_timeout);
                                   if(!i2c_timeout) return TIMEOUT;

//******************************************************************************
// Инициализация I2C интерфейса      
// f_master_hz - частота тактирования периферии Fmaster          
// f_i2c_hz - скорость передачи данных по I2C             
//******************************************************************************                                   
void i2c_master_init(unsigned long f_master_hz, unsigned long f_i2c_hz){
  unsigned long int ccr;
  
  PB_DDR_bit.DDR4 = 0;
  PB_DDR_bit.DDR5 = 0;
  PB_ODR_bit.ODR5 = 1;  //SDA
  PB_ODR_bit.ODR4 = 1;  //SCL
  
  PB_CR1_bit.C14 = 0;
  PB_CR1_bit.C15 = 0;
  
  PB_CR2_bit.C24 = 0;
  PB_CR2_bit.C25 = 0;
  
  //Частота тактирования периферии MHz
  I2C_FREQR_FREQ = 12;
  //Отключаем I2C
  I2C_CR1_PE = 0;
  //В стандартном режиме скорость I2C max = 100 кбит/с
  //Выбираем стандартный режим 
  I2C_CCRH_F_S = 0;
  //CCR = Fmaster/2*Fiic= 12MHz/2*100kHz
  ccr = f_master_hz/(2*f_i2c_hz);
  //Set Maximum Rise Time: 1000ns max in Standard Mode
  //= [1000ns/(1/InputClockFrequencyMHz.10e6)]+1
  //= InputClockFrequencyMHz+1
  I2C_TRISER_TRISE = 12+1;
  I2C_CCRL = ccr & 0xFF;
  I2C_CCRH_CCR = (ccr >> 8) & 0x0F;
  //Включаем I2C
  I2C_CR1_PE = 1;
  //Разрешаем подтверждение в конце посылки
  I2C_CR2_ACK = 1;
}

//******************************************************************************
// Запись регистра slave-устройства
//******************************************************************************                                   
t_i2c_status i2c_wr_reg(unsigned char address, unsigned char reg_addr,
                              char * data, unsigned char length)
{                                  
                                
  //Ждем освобождения шины I2C
  wait_event(I2C_SR3_BUSY, 10);
    
  //Генерация СТАРТ-посылки
  I2C_CR2_START = 1;
  //Ждем установки бита SB
  wait_event(!I2C_SR1_SB, 1);
  
  
  //Записываем в регистр данных адрес ведомого устройства
  I2C_DR = address & 0xFE;
  //Ждем подтверждения передачи адреса
  wait_event(!I2C_SR1_ADDR, 1);
  //Очистка бита ADDR чтением регистра SR3
  I2C_SR3;
  
  
  //Ждем освобождения регистра данных
  wait_event(!I2C_SR1_TXE, 1);
  //Отправляем адрес регистра
  I2C_DR = reg_addr;
  
  //Отправка данных
  while(length--){
    //Ждем освобождения регистра данных
    wait_event(!I2C_SR1_TXE, 1);
    //Отправляем адрес регистра
    I2C_DR = *data++;
  }
  
  //Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
  wait_event(!(I2C_SR1_TXE && I2C_SR1_BTF), 1);
  
  //Посылаем СТОП-посылку
  I2C_CR2_STOP = 1;
  //Ждем выполнения условия СТОП
  wait_event(I2C_CR2_STOP, 1);
  
  return I2C_SUCCESS;
}

//******************************************************************************
// Чтение регистра slave-устройства
// Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop 
//******************************************************************************                                   
t_i2c_status i2c_rd_reg(unsigned char address, unsigned char reg_addr,
                              char * data, unsigned char length)
{
  
  //Ждем освобождения шины I2C
  wait_event(I2C_SR3_BUSY, 10);
    
  //Разрешаем подтверждение в конце посылки
  I2C_CR2_ACK = 1;
  
  //Генерация СТАРТ-посылки
  I2C_CR2_START = 1;
  //Ждем установки бита SB
  wait_event(!I2C_SR1_SB, 1);
  
  //Записываем в регистр данных адрес ведомого устройства
  I2C_DR = address & 0xFE;
  //Ждем подтверждения передачи адреса
  wait_event(!I2C_SR1_ADDR, 1);
  //Очистка бита ADDR чтением регистра SR3
  I2C_SR3;
  
  //Ждем освобождения регистра данных RD
  wait_event(!I2C_SR1_TXE, 1);
  
  //Передаем адрес регистра slave-устройства, который хотим прочитать
  I2C_DR = reg_addr;
  //Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
  wait_event(!(I2C_SR1_TXE && I2C_SR1_BTF), 1);
  
  //Генерация СТАРТ-посылки (рестарт)
  I2C_CR2_START = 1;
  //Ждем установки бита SB
  wait_event(!I2C_SR1_SB, 1);
  
  //Записываем в регистр данных адрес ведомого устройства и переходим
  //в режим чтения (установкой младшего бита в 1)
  I2C_DR = address | 0x01;
  
  //Дальше алгоритм зависит от количества принимаемых байт
  //N=1
  if(length == 1){
    //Запрещаем подтверждение в конце посылки
    I2C_CR2_ACK = 0;
    //Ждем подтверждения передачи адреса
    wait_event(!I2C_SR1_ADDR, 1);
    
    //Заплатка из Errata
    __disable_interrupt();
    //Очистка бита ADDR чтением регистра SR3
    I2C_SR3;
    
    //Устанавлием бит STOP
    I2C_CR2_STOP = 1;
    //Заплатка из Errata
    __enable_interrupt();
    
    //Ждем прихода данных в RD
    wait_event(!I2C_SR1_RXNE, 1);
    
    //Читаем принятый байт
    *data = I2C_DR;
  } 
  //N=2
  else if(length == 2){
    //Бит который разрешает NACK на следующем принятом байте
    I2C_CR2_POS = 1;
    //Ждем подтверждения передачи адреса
    wait_event(!I2C_SR1_ADDR, 1);
    //Заплатка из Errata
    __disable_interrupt();
    //Очистка бита ADDR чтением регистра SR3
    I2C_SR3;
    //Запрещаем подтверждение в конце посылки
    I2C_CR2_ACK = 0;
    //Заплатка из Errata
    __enable_interrupt();
    //Ждем момента, когда первый байт окажется в DR,
    //а второй в сдвиговом регистре
    wait_event(!I2C_SR1_BTF, 1);
    
    //Заплатка из Errata
    __disable_interrupt();
    //Устанавлием бит STOP
    I2C_CR2_STOP = 1;
    //Читаем принятые байты
    *data++ = I2C_DR;
    //Заплатка из Errata
    __enable_interrupt();
    *data = I2C_DR;
  } 
  //N>2
  else if(length > 2){
    //Ждем подтверждения передачи адреса
    wait_event(!I2C_SR1_ADDR, 1);
    
    //Заплатка из Errata
    __disable_interrupt();
    
    //Очистка бита ADDR чтением регистра SR3
    I2C_SR3;
    
    //Заплатка из Errata
    __enable_interrupt();
    
    while(length-- > 3 && tmo){
      //Ожидаем появления данных в DR и сдвиговом регистре
      wait_event(!I2C_SR1_BTF, 1);
      //Читаем принятый байт из DR
      *data++ = I2C_DR;
    }
    //Время таймаута вышло
    if(!tmo) return I2C_TIMEOUT;
    
    //Осталось принять 3 последних байта
    //Ждем, когда в DR окажется N-2 байт, а в сдвиговом регистре
    //окажется N-1 байт
    wait_event(!I2C_SR1_BTF, 1);
    //Запрещаем подтверждение в конце посылки
    I2C_CR2_ACK = 0;
    //Заплатка из Errata
    __disable_interrupt();
    //Читаем N-2 байт из RD, тем самым позволяя принять в сдвиговый
    //регистр байт N, но теперь в конце приема отправится посылка NACK
    *data++ = I2C_DR;
    //Посылка STOP
    I2C_CR2_STOP = 1;
    //Читаем N-1 байт
    *data++ = I2C_DR;
    //Заплатка из Errata
    __enable_interrupt();
    //Ждем, когда N-й байт попадет в DR из сдвигового регистра
    wait_event(!I2C_SR1_RXNE, 1);
    //Читаем N байт
    *data++ = I2C_DR;
  }
  
  //Ждем отправки СТОП посылки
  wait_event(I2C_CR2_STOP, 1);
  //Сбрасывает бит POS, если вдруг он был установлен
  I2C_CR2_POS = 0;
  
  return I2C_SUCCESS;
}

Драйвер I2C для STM8 в IAR

1

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Код безопасности