Найти тему

Инициализация модуля шины данных I2C микроконтроллера STM32 на примере STM32F103

Данная реализация функции осуществляется на основе данных из rm0008 и es096.
Тайминги заданные в примере рассчитаны для режима стандартной скорости (100кГц) при частоте тактирования шины 8МГц.

void I2C1_Init (void) {
//1 - Отключите периферийное устройство I2C, очистив бит PE в регистре I2Cx_CR1.
I2C1->CR1 &= ~I2C_CR1_PE; //Отключение модуля

//2 - Настройте входы/выходы SCL и SDA как выходы общего назначения с открытым стоком, высокий уровень (запишите 1 в GPIOx_ODR).
GPIOB->CRL |= GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1 | GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0; //SCL and SDA - Open-Drain выходы общего назначения, макс.скорость 2МГц
GPIOB->BSRR = GPIO_BSRR_BS6 | GPIO_BSRR_BS7; //Высокий уровень на выходах SCL и SDA
//3 - Check SCL and SDA High level in GPIOx_IDR. Проверьте высокий уровень SCL и SDA в GPIOx_IDR.
while (!(GPIOB->IDR &(GPIO_IDR_IDR6 | GPIO_IDR_IDR7)));

//4 - Настройте ввод-вывод SDA как выход общего назначения с открытым стоком, низкий уровень (запишите 0 в GPIOx_ODR).
GPIOB->CRL |= GPIO_CRL_MODE7_1 | GPIO_CRL_CNF7_0; //SDA - Open-Drain выходы общего назначения, макс.скорость 2МГц
GPIOB->BSRR = GPIO_BSRR_BR7; //Низкий уровень на выходе SDA
//5 - Check SDA Low level in GPIOx_IDR. Проверьте низкий уровень SDA в GPIOx_IDR.
while (GPIOB->IDR & GPIO_IDR_IDR7);

//6 - Настройте ввод/вывод SCL как выход общего назначения с открытым стоком, низкий уровень (запишите 0 в GPIOx_ODR).
GPIOB->CRL |= GPIO_CRL_MODE6_1 | GPIO_CRL_CNF6_0; //SCL - Open-Drain выходы общего назначения, макс.скорость 2МГц
GPIOB->BSRR = GPIO_BSRR_BR6; //Низкий уровень на выходе SCL
//7 - Check SCL Low level in GPIOx_IDR. Проверьте низкий уровень SCL в GPIOx_IDR.
while (GPIOB->IDR & GPIO_IDR_IDR6);

//8 - Настройте ввод-вывод SCL как выход общего назначения с открытым стоком, высокий уровень (запишите 1 в GPIOx_ODR).
GPIOB->CRL |= GPIO_CRL_MODE6_1 | GPIO_CRL_CNF6_0;
GPIOB->BSRR = GPIO_BSRR_BS6;
//9 - Check SCL High level in GPIOx_IDR. Проверьте высокий уровень SCL в GPIOx_IDR.
while (!(GPIOB->IDR & GPIO_IDR_IDR6));

//10 - Настройте ввод-вывод SDA как выход общего назначения с открытым стоком, высокий уровень (запишите 1 в GPIOx_ODR).
GPIOB->CRL |= GPIO_CRL_MODE7_1 | GPIO_CRL_CNF7_0;
GPIOB->BSRR = GPIO_BSRR_BS7;
//11 - Check SDA High level in GPIOx_IDR. Проверьте высокий уровень SDA в GPIOx_IDR.
while (!(GPIOB->IDR & GPIO_IDR_IDR7));

//12 - Настройте входы/выходы SCL и SDA как альтернативную функцию с открытым стоком.
GPIOB->CRL |= GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1 | GPIO_CRL_CNF6_0 | GPIO_CRL_CNF6_1 | GPIO_CRL_CNF7_0 | GPIO_CRL_CNF7_1;

//13 - Установите бит SWRST в регистре I2Cx_CR1.
I2C1->CR1 |= I2C_CR1_SWRST;

//14 - Очистить бит SWRST в регистре I2Cx_CR1.
I2C1->CR1 &= ~I2C_CR1_SWRST;
//----------------------------------------------
//15
//На 100кГц при частоте шины 8МГц
//I2C1->OAR1 &= ~I2C_OAR1_ADDMODE; //7-ми битный режим адресации (по умолчанию)
I2C1->OAR1 |= (1<<14); //Программно необходимо всегда поддерживать значение "1"
I2C1->OAR1 |= 0x00FE; //Собственный адрес устройства 0xFE

//I2C1->OAR2 &= ~I2C_OAR2_ENDUAL; //Отключить режим двойной адресации (по умолчанию)
//I2C1->CR1 &= ~I2C_CR1_ENGC; //Отключить отклик на широковещательный запрос (по умолчанию)
//I2C1->CR1 &= ~I2C_CR1_NOSTRETCH; //Включить растягивание тактового сигнала (по умолчанию)
I2C1->CR1 |= I2C_CR1_ACK; //разрешение отправки ACK/NACK после приема байта адреса или данных.
I2C1->CR2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN | I2C_CR2_ITBUFEN; //Разрешить прерывания по событию, при ошибке и буферное

I2C1->CR2 |= 0x0010; //Записываем значение частоты тактирования шина (8МГц) в битовое поле FREQ[5:0]
I2C1->CCR |= 0x0028; //Настройка частоты CCR[11:0]=40
I2C1->TRISE = 0x0009; //Задание времени нарастания фронта TRISE=9

NVIC_EnableIRQ (I2C1_EV_IRQn); //Разрешения прерывания по событию I2C в контроллере прерываний
NVIC_EnableIRQ (I2C1_ER_IRQn); //Разрешения прерывания по ошибке I2C в контроллере прерываний

I2C1->CR1 |= I2C_CR1_PE; //Включить модуль
}


Манипуляции произведенные в пунктах 1 ... 14 необходимы для исключения ошибочной установки флага занятости из-за работы аналогового фильтра. Подробную информацию можно прочитать в es096 п.2.8.7