|
@@ -15,7 +15,7 @@ extern __IO uint8_t I2C_timeout;
|
|
#define wait_event(event, timeout) I2C_timeout = timeout;\
|
|
#define wait_event(event, timeout) I2C_timeout = timeout;\
|
|
while(event && I2C_timeout);\
|
|
while(event && I2C_timeout);\
|
|
if(!I2C_timeout) return I2C_TIMEOUT;
|
|
if(!I2C_timeout) return I2C_TIMEOUT;
|
|
-
|
|
|
|
|
|
+#define set_I2C_timeout_ms(time) I2C_timeout = time
|
|
|
|
|
|
/**
|
|
/**
|
|
* @brief Инициализация I2C интерфейса
|
|
* @brief Инициализация I2C интерфейса
|
|
@@ -34,8 +34,12 @@ void i2c_master_init(void) {
|
|
//Отключаем I2C
|
|
//Отключаем I2C
|
|
I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
|
|
I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
|
|
|
|
|
|
- //Выбираем стандартный режим
|
|
|
|
|
|
+ //Выбираем режим
|
|
|
|
+#ifdef I2C_FAST
|
|
|
|
+ I2C->CCRH = I2C_CCRH_FS; // | I2C_CCRH_DUTY;
|
|
|
|
+#else
|
|
I2C->CCRH = 0;
|
|
I2C->CCRH = 0;
|
|
|
|
+#endif
|
|
|
|
|
|
//CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
|
|
//CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
|
|
ccr = (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ));
|
|
ccr = (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ));
|
|
@@ -45,7 +49,7 @@ void i2c_master_init(void) {
|
|
//= InputClockFrequencyMHz+1
|
|
//= InputClockFrequencyMHz+1
|
|
I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
|
|
I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
|
|
I2C->CCRL = (uint8_t)ccr;
|
|
I2C->CCRL = (uint8_t)ccr;
|
|
- I2C->CCRH = (uint8_t)((uint8_t)(ccr >> 8) & I2C_CCRH_CCR);
|
|
|
|
|
|
+ I2C->CCRH |= (uint8_t)((uint8_t)(ccr >> 8) & I2C_CCRH_CCR);
|
|
|
|
|
|
//Включаем I2C
|
|
//Включаем I2C
|
|
I2C->CR1 |= I2C_CR1_PE;
|
|
I2C->CR1 |= I2C_CR1_PE;
|
|
@@ -55,40 +59,43 @@ void i2c_master_init(void) {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @brief Запись регистра slave-устройства
|
|
|
|
|
|
+ * @brief Send data to slave device.
|
|
*/
|
|
*/
|
|
-t_i2c_status i2c_wr_reg(const uint8_t address, const uint8_t data) {
|
|
|
|
|
|
+t_i2c_status i2c_wr_data(const uint8_t address, const uint8_t num_bytes_to_wr, uint8_t * data) {
|
|
|
|
+ uint8_t adr = address << 1;
|
|
|
|
+ uint8_t length = num_bytes_to_wr;
|
|
|
|
|
|
//Ждем освобождения шины I2C
|
|
//Ждем освобождения шины I2C
|
|
wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
|
|
wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
|
|
-
|
|
|
|
|
|
+
|
|
//Генерация СТАРТ-посылки
|
|
//Генерация СТАРТ-посылки
|
|
I2C->CR2 |= I2C_CR2_START;
|
|
I2C->CR2 |= I2C_CR2_START;
|
|
//Ждем установки бита SB
|
|
//Ждем установки бита SB
|
|
wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
|
|
wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+
|
|
//Записываем в регистр данных адрес ведомого устройства
|
|
//Записываем в регистр данных адрес ведомого устройства
|
|
- I2C->DR = address & 0xFE;
|
|
|
|
|
|
+ I2C->DR = adr;
|
|
//Ждем подтверждения передачи адреса
|
|
//Ждем подтверждения передачи адреса
|
|
wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
//Очистка бита ADDR чтением регистра SR3
|
|
//Очистка бита ADDR чтением регистра SR3
|
|
I2C->SR3;
|
|
I2C->SR3;
|
|
-
|
|
|
|
-
|
|
|
|
- //Ждем освобождения регистра данных
|
|
|
|
- wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
|
|
|
|
- //Отправляем адрес регистра
|
|
|
|
- I2C->DR = data;
|
|
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ //Отправка данных
|
|
|
|
+ while (length--) {
|
|
|
|
+ //Ждем освобождения регистра данных
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
|
|
|
|
+ //Отправляем адрес регистра
|
|
|
|
+ I2C->DR = *data++;
|
|
|
|
+ }
|
|
|
|
+
|
|
//Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
|
|
//Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
|
|
wait_event(!((I2C->SR1 & I2C_SR1_TXE) && (I2C->SR1 & I2C_SR1_BTF)), 1);
|
|
wait_event(!((I2C->SR1 & I2C_SR1_TXE) && (I2C->SR1 & I2C_SR1_BTF)), 1);
|
|
-
|
|
|
|
|
|
+
|
|
//Посылаем СТОП-посылку
|
|
//Посылаем СТОП-посылку
|
|
I2C->CR2 |= I2C_CR2_STOP;
|
|
I2C->CR2 |= I2C_CR2_STOP;
|
|
//Ждем выполнения условия СТОП
|
|
//Ждем выполнения условия СТОП
|
|
wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
|
|
wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
|
|
-
|
|
|
|
|
|
+
|
|
return I2C_SUCCESS;
|
|
return I2C_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -96,47 +103,123 @@ t_i2c_status i2c_wr_reg(const uint8_t address, const uint8_t data) {
|
|
* @brief Чтение регистра slave-устройства
|
|
* @brief Чтение регистра slave-устройства
|
|
* @note Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop
|
|
* @note Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop
|
|
*/
|
|
*/
|
|
-t_i2c_status i2c_rd_reg(const uint8_t address, uint8_t * data) {
|
|
|
|
|
|
+t_i2c_status i2c_rd_data(const uint8_t address, const uint8_t num_bytes_to_rd, uint8_t * data) {
|
|
|
|
+ uint8_t addr = (address << 1) | 1;
|
|
|
|
+ uint8_t length = num_bytes_to_rd;
|
|
|
|
|
|
//Ждем освобождения шины I2C
|
|
//Ждем освобождения шины I2C
|
|
wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
|
|
wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
|
|
-
|
|
|
|
|
|
+
|
|
//Разрешаем подтверждение в конце посылки
|
|
//Разрешаем подтверждение в конце посылки
|
|
I2C->CR2 |= I2C_CR2_ACK;
|
|
I2C->CR2 |= I2C_CR2_ACK;
|
|
-
|
|
|
|
|
|
+
|
|
//Генерация СТАРТ-посылки
|
|
//Генерация СТАРТ-посылки
|
|
I2C->CR2 |= I2C_CR2_START;
|
|
I2C->CR2 |= I2C_CR2_START;
|
|
//Ждем установки бита SB
|
|
//Ждем установки бита SB
|
|
wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
|
|
wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
|
|
-
|
|
|
|
|
|
+
|
|
//Записываем в регистр данных адрес ведомого устройства и переходим
|
|
//Записываем в регистр данных адрес ведомого устройства и переходим
|
|
//в режим чтения (установкой младшего бита в 1)
|
|
//в режим чтения (установкой младшего бита в 1)
|
|
- I2C->DR = address | 0x01;
|
|
|
|
- //Бит который разрешает NACK на следующем принятом байте
|
|
|
|
- //I2C->CR2 |= I2C_CR2_POS;
|
|
|
|
- //Ждем подтверждения передачи адреса
|
|
|
|
- wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
|
|
- //Очистка бита ADDR чтением регистра SR3
|
|
|
|
- I2C->SR3;
|
|
|
|
- // wait for BTF
|
|
|
|
- wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
|
|
|
|
- //Запрещаем подтверждение в конце посылки
|
|
|
|
- I2C->CR2 &= (uint8_t)(~I2C_CR2_ACK);
|
|
|
|
- //Заплатка из Errata
|
|
|
|
- disableInterrupts();
|
|
|
|
- // Read 1st byte
|
|
|
|
- data[0] = I2C->DR;
|
|
|
|
- //Устанавлием бит STOP
|
|
|
|
- I2C->CR2 |= I2C_CR2_STOP;
|
|
|
|
- // Read 2nd byte
|
|
|
|
- data[1] = I2C->DR;
|
|
|
|
- //Заплатка из Errata
|
|
|
|
- enableInterrupts();
|
|
|
|
- // Wait for RXNE
|
|
|
|
- wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
|
|
|
|
- // Read 3rd Data byte
|
|
|
|
- data[2] = I2C->DR;
|
|
|
|
-
|
|
|
|
|
|
+ I2C->DR = addr;
|
|
|
|
+
|
|
|
|
+ //Дальше алгоритм зависит от количества принимаемых байт
|
|
|
|
+ //N=1
|
|
|
|
+ if(length == 1){
|
|
|
|
+ //Запрещаем подтверждение в конце посылки
|
|
|
|
+ I2C->CR2 &= ~I2C_CR2_ACK;
|
|
|
|
+ //Ждем подтверждения передачи адреса
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
|
|
+
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __disable_interrupt();
|
|
|
|
+ //Очистка бита ADDR чтением регистра SR3
|
|
|
|
+ I2C->SR3;
|
|
|
|
+
|
|
|
|
+ //Устанавлием бит STOP
|
|
|
|
+ I2C->CR2 |= I2C_CR2_STOP;
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __enable_interrupt();
|
|
|
|
+
|
|
|
|
+ //Ждем прихода данных в RD
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
|
|
|
|
+
|
|
|
|
+ //Читаем принятый байт
|
|
|
|
+ *data = I2C->DR;
|
|
|
|
+ }
|
|
|
|
+ //N=2
|
|
|
|
+ else if (length == 2) {
|
|
|
|
+ //Бит который разрешает NACK на следующем принятом байте
|
|
|
|
+ I2C->CR2 |= I2C_CR2_POS;
|
|
|
|
+ //Ждем подтверждения передачи адреса
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __disable_interrupt();
|
|
|
|
+ //Очистка бита ADDR чтением регистра SR3
|
|
|
|
+ I2C->SR3;
|
|
|
|
+ //Запрещаем подтверждение в конце посылки
|
|
|
|
+ I2C->CR2 &= ~I2C_CR2_ACK;
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __enable_interrupt();
|
|
|
|
+ //Ждем момента, когда первый байт окажется в DR,
|
|
|
|
+ //а второй в сдвиговом регистре
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
|
|
|
|
+
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __disable_interrupt();
|
|
|
|
+ //Устанавлием бит STOP
|
|
|
|
+ I2C->CR2 |= I2C_CR2_STOP;
|
|
|
|
+ //Читаем принятые байты
|
|
|
|
+ *data++ = I2C->DR;
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __enable_interrupt();
|
|
|
|
+ *data = I2C->DR;
|
|
|
|
+ }
|
|
|
|
+ //N>2
|
|
|
|
+ else if (length > 2) {
|
|
|
|
+ //Ждем подтверждения передачи адреса
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
|
|
|
|
+
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __disable_interrupt();
|
|
|
|
+
|
|
|
|
+ //Очистка бита ADDR чтением регистра SR3
|
|
|
|
+ I2C->SR3;
|
|
|
|
+
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __enable_interrupt();
|
|
|
|
+
|
|
|
|
+ while (length-- > 3 && I2C_timeout) {
|
|
|
|
+ //Ожидаем появления данных в DR и сдвиговом регистре
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
|
|
|
|
+ //Читаем принятый байт из DR
|
|
|
|
+ *data++ = I2C->DR;
|
|
|
|
+ }
|
|
|
|
+ //Время таймаута вышло
|
|
|
|
+ if (!I2C_timeout) return I2C_TIMEOUT;
|
|
|
|
+
|
|
|
|
+ //Осталось принять 3 последних байта
|
|
|
|
+ //Ждем, когда в DR окажется N-2 байт, а в сдвиговом регистре
|
|
|
|
+ //окажется N-1 байт
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
|
|
|
|
+ //Запрещаем подтверждение в конце посылки
|
|
|
|
+ I2C->CR2 &= ~I2C_CR2_ACK;
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __disable_interrupt();
|
|
|
|
+ //Читаем N-2 байт из RD, тем самым позволяя принять в сдвиговый
|
|
|
|
+ //регистр байт N, но теперь в конце приема отправится посылка NACK
|
|
|
|
+ *data++ = I2C->DR;
|
|
|
|
+ //Посылка STOP
|
|
|
|
+ I2C->CR2 |= I2C_CR2_STOP;
|
|
|
|
+ //Читаем N-1 байт
|
|
|
|
+ *data++ = I2C->DR;
|
|
|
|
+ //Заплатка из Errata
|
|
|
|
+ __enable_interrupt();
|
|
|
|
+ //Ждем, когда N-й байт попадет в DR из сдвигового регистра
|
|
|
|
+ wait_event(!(I2C->SR1 & I2C_SR1_RXNE), 1);
|
|
|
|
+ //Читаем N байт
|
|
|
|
+ *data++ = I2C->DR;
|
|
|
|
+ }
|
|
|
|
+
|
|
//Ждем отправки СТОП посылки
|
|
//Ждем отправки СТОП посылки
|
|
wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
|
|
wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
|
|
//Сбрасывает бит POS, если вдруг он был установлен
|
|
//Сбрасывает бит POS, если вдруг он был установлен
|