diff --git a/MDK-ARM/Core/App/i2c.c b/MDK-ARM/Core/App/i2c.c
new file mode 100644
index 0000000..57fadd8
--- /dev/null
+++ b/MDK-ARM/Core/App/i2c.c
@@ -0,0 +1,971 @@
+/**
+ ******************************************************************************
+ * @file i2c.c
+ * @author Разваляев Алексей
+ * @brief Драйвер I2C на основе PLIB035.
+ * Этот файл содержит:
+ * + Инициализацию I2C
+ * + Функции для работы в режиме мастера (блокирующие):
+ * - Блокирующая передача/прием
+ * - Функции чтения/записи регистров устройств
+ * - Проверка наличия устройства
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Использование этого драйвера предполагает наличие корректных настроек:
+ * - Определена конфигурационная структура i2c_config в periph_config.h
+ * - Определены пины SDA/SCL для I2C
+ *
+ ******************************************************************************
+ * @verbatim
+ ==============================================================================
+ ##### Как использовать этот драйвер #####
+ ==============================================================================
+
+ 1. Настройка в periph_config.h:
+ (+) Определите i2c_config для I2C
+ (+) Настройте частоту SCL (FSFreq для стандартного режима, HSFreq для высокоскоростного)
+ (+) Используйте enum для настройки:
+ • I2C_Mode_Master - режим мастера
+ • I2C_Mode_Slave - режим ведомого
+
+ 2. Инициализация:
+ (+) i2c_init_first() - настройка GPIO, тактирования
+ (+) i2c_init(&hi2c, &config) - инициализация I2C
+
+ 3. Запуск I2C:
+ (+) I2C_Start(&hi2c) - включение I2C
+
+ 4. Работа в режиме мастера (блокирующие функции):
+ - Основные функции:
+ (+) I2C_Master_Transmit(&hi2c, addr, buf, size, timeout) - передача данных
+ (+) I2C_Master_Receive(&hi2c, addr, buf, size, timeout) - прием данных
+ (+) I2C_Master_WriteReg(&hi2c, addr, reg, val, timeout) - запись регистра
+ (+) I2C_Master_ReadReg(&hi2c, addr, reg, buf, size, timeout) - чтение регистра
+ (+) I2C_Master_WriteRegs(&hi2c, addr, reg, buf, size, timeout) - запись нескольких регистров
+ (+) I2C_Master_ReadRegs(&hi2c, addr, reg, buf, size, timeout) - чтение нескольких регистров
+ (+) I2C_Master_IsDeviceReady(&hi2c, addr, timeout) - проверка наличия устройства
+
+ 5. Обработка ошибок:
+ (+) I2C_GetLastError(&hi2c) - получение кода последней ошибки
+ (+) Callback-функция ошибки вызывается автоматически при ошибках
+
+ 6. GPIO для I2C:
+ (+) Пины настраиваются автоматически при вызове i2c_init_first()
+ (+) При необходимости можно вызвать i2c_gpio_deinit() для восстановления
+
+ ==============================================================================
+ ##### Особенности работы #####
+ ==============================================================================
+
+ - Режимы работы:
+ - Master: инициирует передачу данных, управляет шиной
+ - Slave: реагирует на запросы мастера
+
+ - Скорости работы:
+ - Standard Mode (до 100 кГц)
+ - Fast Mode (до 400 кГц)
+ - Fast Mode Plus (до 1 МГц)
+ - High Speed Mode (до 3.4 МГц)
+
+ - Адресация:
+ - 7-битная адресация (стандартная)
+ - 10-битная адресация (поддерживается)
+
+ - Обработка ошибок:
+ - Обрабатываются ошибки шины, арбитража, таймаута
+ - При ошибке вызывается ErrCallback и сохраняется код ошибки
+ - После ошибки требуется переинициализация I2C
+
+ - Функции работы с регистрами:
+ - Упрощают чтение/запись регистров устройств на шине I2C
+ - Поддерживают различные размеры регистров (8/16 бит)
+
+ - Проверка устройства:
+ - Функция проверяет ответ устройства на свой адрес
+ - Полезна для проверки подключения устройств
+
+ @endverbatim
+ ******************************************************************************
+ */
+
+//-- Includes ------------------------------------------------------------------
+#include "periph_config.h"
+
+I2C_HandleTypeDef hi2c; /*!< Хендл I2C */
+
+//-- Private function prototypes -----------------------------------------------
+static OperationStatus __i2c_master_wait_bus_free(I2C_HandleTypeDef *hi2c, uint32_t timeout);
+static OperationStatus __i2c_master_send_start(I2C_HandleTypeDef *hi2c, uint32_t timeout);
+static OperationStatus __i2c_master_send_address(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t direction, uint32_t timeout);
+static OperationStatus __i2c_master_send_stop(I2C_HandleTypeDef *hi2c, uint32_t timeout);
+static OperationStatus __i2c_master_transmit_blocking(I2C_HandleTypeDef *hi2c, uint8_t *buf, uint16_t size, uint32_t timeout);
+static OperationStatus __i2c_master_receive_blocking(I2C_HandleTypeDef *hi2c, uint8_t *buf, uint16_t size, uint32_t timeout);
+static void __i2c_set_error(I2C_HandleTypeDef *hi2c, uint8_t error);
+
+//-- I2C Init functions -------------------------------------------------------
+
+/**
+ * @brief Первичная инициализация I2C
+ * @details Настройка I2C и хендла: GPIO, тактирование
+ */
+void i2c_init_first(void)
+{
+#if (USE_I2C==1)
+ // Настройка пинов для I2C
+ i2c_gpio_init();
+
+ // Включение тактирования и сброс I2C
+ RCU_APBClkCmd(RCU_APBClk_I2C, ENABLE);
+ RCU_APBRstCmd(RCU_APBRst_I2C, ENABLE);
+
+ // Инициализируем I2C
+ hi2c.Instance = I2C;
+ hi2c.LastError = I2C_ERROR_NONE;
+ i2c_init(&hi2c, &i2c_config);
+#endif
+}
+
+/**
+ * @brief Инициализация I2C
+ * @param hi2c указатель на хендл I2C
+ * @param NewConfig указатель на новую конфигурацию I2C, иначе используется та, что в структуре
+ * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка
+ */
+OperationStatus i2c_init(I2C_HandleTypeDef *hi2c, I2C_ExtInit_TypeDef *NewConfig)
+{
+ if(!hi2c || !hi2c->Instance)
+ return ERROR;
+
+ if(NewConfig != NULL)
+ {
+ hi2c->Config = NewConfig;
+ }
+ if(hi2c->Config == NULL)
+ {
+ return ERROR;
+ }
+
+ // Сбрасываем ошибку
+ hi2c->LastError = I2C_ERROR_NONE;
+
+ // Настраиваем частоту SCL
+ if(hi2c->Config->I2C_Init.HSMode == ENABLE)
+ {
+ // Высокоскоростной режим
+ I2C_HSFreqConfig(hi2c->Config->HSFreq, hi2c->Config->I2CFreq);
+ }
+ else
+ {
+ // Стандартный/быстрый режим
+ I2C_FSFreqConfig(hi2c->Config->FSFreq, hi2c->Config->I2CFreq);
+ }
+
+ // Настраиваем таймаут
+ if(hi2c->Config->I2C_Init.Timeout != DISABLE)
+ {
+ I2C_TimeoutClkDivConfig(hi2c->Config->I2C_Init.TimeoutClkDiv);
+ I2C_SetTimeoutCounterLoad(hi2c->Config->I2C_Init.TimeoutLoad);
+ }
+
+ // Настраиваем дополнительные функции
+ I2C_AlertResponseMatchCmd(hi2c->Config->I2C_Init.AlertResponse);
+ I2C_GlobalCallMatchCmd(hi2c->Config->I2C_Init.GlobalCall);
+
+ return OK;
+}
+
+/**
+ * @brief Установка коллбека I2C
+ * @param hi2c указатель на хендл I2C
+ * @param CallbackType Тип коллбека
+ * @param Callback Функция коллбека
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке
+ */
+OperationStatus I2C_Set_Callback(I2C_HandleTypeDef* hi2c, I2C_CallbackTypeDef CallbackType, void (*Callback)())
+{
+ if (!hi2c || !hi2c->Instance || !hi2c->Config)
+ return ERROR;
+
+ switch(CallbackType)
+ {
+ case I2C_Callback_Tx:
+ hi2c->Config->TxCallback = Callback;
+ break;
+ case I2C_Callback_Rx:
+ hi2c->Config->RxCallback = Callback;
+ break;
+ case I2C_Callback_Addr:
+ hi2c->Config->AddrCallback = Callback;
+ break;
+ case I2C_Callback_Error:
+ hi2c->Config->ErrCallback = Callback;
+ break;
+
+ default:
+ return ERROR;
+ }
+ return OK;
+}
+
+//-- I2C API functions --------------------------------------------------------
+
+/**
+ * @brief Запуск I2C
+ * @param hi2c указатель на хендл I2C
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке
+ */
+OperationStatus I2C_Start(I2C_HandleTypeDef *hi2c)
+{
+ if (!hi2c)
+ return ERROR;
+
+ // Сбрасываем ошибку
+ hi2c->LastError = I2C_ERROR_NONE;
+
+ // Включаем I2C
+ I2C_Cmd(ENABLE);
+
+ // Если режим ведомого, настраиваем адрес и включаем распознавание
+ if(hi2c->Config->I2C_Init.Mode == I2C_Mode_Slave)
+ {
+ if(hi2c->Config->I2C_Init.Addr10Bit == ENABLE)
+ {
+ I2C_Slave10AddrCmd(ENABLE);
+ I2C_SetSlave10Addr(hi2c->Config->I2C_Init.SlaveAddr >> 8);
+ I2C_SetSlaveAddr(hi2c->Config->I2C_Init.SlaveAddr & 0xFF);
+ }
+ else
+ {
+ I2C_Slave10AddrCmd(DISABLE);
+ I2C_SetSlaveAddr(hi2c->Config->I2C_Init.SlaveAddr);
+ }
+ I2C_SlaveCmd(ENABLE);
+ }
+
+ return OK;
+}
+
+/**
+ * @brief Остановка I2C
+ * @param hi2c указатель на хендл I2C
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке
+ */
+OperationStatus I2C_Stop(I2C_HandleTypeDef *hi2c)
+{
+ if (!hi2c)
+ return ERROR;
+
+ // Выключаем I2C
+ I2C_Cmd(DISABLE);
+
+ // Если режим ведомого, выключаем распознавание адреса
+ if(hi2c->Config->I2C_Init.Mode == I2C_Mode_Slave)
+ {
+ I2C_SlaveCmd(DISABLE);
+ }
+
+ return OK;
+}
+
+/**
+ * @brief Получение кода последней ошибки
+ * @param hi2c указатель на хендл I2C
+ * @retval Код последней ошибки I2C
+ */
+uint8_t I2C_GetLastError(I2C_HandleTypeDef *hi2c)
+{
+ if (!hi2c)
+ return I2C_ERROR_NONE;
+
+ return hi2c->LastError;
+}
+
+//-- I2C Master functions -----------------------------------------------------
+
+/**
+ * @brief Передача данных в режиме мастера (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param buf указатель на буфер данных
+ * @param size размер данных в байтах
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_Transmit(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint8_t *buf,
+ uint16_t size,
+ uint32_t timeout)
+{
+ OperationStatus status;
+
+ if (!hi2c || !buf || size == 0)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_NONE);
+ return ERROR;
+ }
+
+ // Проверяем, свободна ли шина
+ status = __i2c_master_wait_bus_free(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем START
+ status = __i2c_master_send_start(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем адрес с направлением "запись"
+ status = __i2c_master_send_address(hi2c, addr, I2C_Direction_Transmitter, timeout);
+ if (status != OK)
+ {
+ // При NACK отправляем STOP и выходим
+ if (hi2c->LastError == I2C_ERROR_NACK)
+ {
+ __i2c_master_send_stop(hi2c, timeout);
+ }
+ return status;
+ }
+
+ // Передаем данные
+ status = __i2c_master_transmit_blocking(hi2c, buf, size, timeout);
+
+ // Отправляем STOP (даже при ошибке в данных)
+ __i2c_master_send_stop(hi2c, timeout);
+
+ // Если была ошибка передачи данных, возвращаем ошибку
+ if (status != OK)
+ return status;
+
+ // Вызываем callback успешной передачи
+ if (hi2c->Config->TxCallback)
+ hi2c->Config->TxCallback();
+
+ return OK;
+}
+
+/**
+ * @brief Прием данных в режиме мастера (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param buf указатель на буфер приема
+ * @param size количество принимаемых байт
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_Receive(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint8_t *buf,
+ uint16_t size,
+ uint32_t timeout)
+{
+ OperationStatus status;
+
+ if (!hi2c || !buf || size == 0)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_NONE);
+ return ERROR;
+ }
+
+ // Проверяем, свободна ли шина
+ status = __i2c_master_wait_bus_free(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем START
+ status = __i2c_master_send_start(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем адрес с направлением "чтение"
+ status = __i2c_master_send_address(hi2c, addr, I2C_Direction_Receiver, timeout);
+ if (status != OK)
+ {
+ // При NACK отправляем STOP и выходим
+ if (hi2c->LastError == I2C_ERROR_NACK)
+ {
+ __i2c_master_send_stop(hi2c, timeout);
+ }
+ return status;
+ }
+
+ // Принимаем данные
+ status = __i2c_master_receive_blocking(hi2c, buf, size, timeout);
+
+ // Отправляем STOP (даже при ошибке приема)
+ __i2c_master_send_stop(hi2c, timeout);
+
+ // Если была ошибка приема данных, возвращаем ошибку
+ if (status != OK)
+ return status;
+
+ // Вызываем callback успешного приема
+ if (hi2c->Config->RxCallback)
+ hi2c->Config->RxCallback();
+
+ return OK;
+}
+
+/**
+ * @brief Запись регистра устройства (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param reg адрес регистра
+ * @param value значение для записи
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_WriteReg(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint16_t reg,
+ uint8_t value,
+ uint32_t timeout)
+{
+ uint8_t data[3];
+ uint16_t reg_size = (hi2c->Config->I2C_Init.RegSize == I2C_RegSize_8bit) ? 1 : 2;
+
+ if (reg_size == 1)
+ {
+ data[0] = (uint8_t)reg;
+ data[1] = value;
+ return I2C_Master_Transmit(hi2c, addr, data, 2, timeout);
+ }
+ else
+ {
+ data[0] = (uint8_t)(reg >> 8);
+ data[1] = (uint8_t)reg;
+ data[2] = value;
+ return I2C_Master_Transmit(hi2c, addr, data, 3, timeout);
+ }
+}
+
+/**
+ * @brief Чтение регистра устройства (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param reg адрес регистра
+ * @param buf указатель на буфер для данных
+ * @param size размер данных для чтения
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_ReadReg(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint16_t reg,
+ uint8_t *buf,
+ uint16_t size,
+ uint32_t timeout)
+{
+ OperationStatus status;
+ uint8_t reg_data[2];
+ uint16_t reg_size = (hi2c->Config->I2C_Init.RegSize == I2C_RegSize_8bit) ? 1 : 2;
+
+ // Сначала отправляем адрес регистра
+ if (reg_size == 1)
+ {
+ reg_data[0] = (uint8_t)reg;
+ status = I2C_Master_Transmit(hi2c, addr, reg_data, 1, timeout);
+ }
+ else
+ {
+ reg_data[0] = (uint8_t)(reg >> 8);
+ reg_data[1] = (uint8_t)reg;
+ status = I2C_Master_Transmit(hi2c, addr, reg_data, 2, timeout);
+ }
+
+ if (status != OK)
+ return status;
+
+ // Затем читаем данные
+ return I2C_Master_Receive(hi2c, addr, buf, size, timeout);
+}
+
+/**
+ * @brief Запись нескольких регистров (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param reg начальный адрес регистра
+ * @param buf указатель на буфер данных
+ * @param size количество регистров для записи
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_WriteRegs(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint16_t reg,
+ uint8_t *buf,
+ uint16_t size,
+ uint32_t timeout)
+{
+ OperationStatus status;
+ uint16_t reg_size = (hi2c->Config->I2C_Init.RegSize == I2C_RegSize_8bit) ? 1 : 2;
+
+ // Проверяем, свободна ли шина
+ status = __i2c_master_wait_bus_free(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем START
+ status = __i2c_master_send_start(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем адрес с направлением "запись"
+ status = __i2c_master_send_address(hi2c, addr, I2C_Direction_Transmitter, timeout);
+ if (status != OK)
+ {
+ // При NACK отправляем STOP и выходим
+ if (hi2c->LastError == I2C_ERROR_NACK)
+ {
+ __i2c_master_send_stop(hi2c, timeout);
+ }
+ return status;
+ }
+
+ // Отправляем адрес регистра (первый байт)
+ if (reg_size == 1)
+ {
+ status = __i2c_master_transmit_blocking(hi2c, (uint8_t*)®, 1, timeout);
+ }
+ else
+ {
+ // Для 16-битного адреса отправляем старший, затем младший байт
+ uint8_t reg_bytes[2] = {(uint8_t)(reg >> 8), (uint8_t)reg};
+ status = __i2c_master_transmit_blocking(hi2c, reg_bytes, 2, timeout);
+ }
+
+ if (status != OK)
+ {
+ __i2c_master_send_stop(hi2c, timeout);
+ return status;
+ }
+
+ // Отправляем данные
+ status = __i2c_master_transmit_blocking(hi2c, buf, size, timeout);
+
+ // Отправляем STOP
+ __i2c_master_send_stop(hi2c, timeout);
+
+ // Если была ошибка передачи данных, возвращаем ошибку
+ if (status != OK)
+ return status;
+
+ // Вызываем callback успешной передачи
+ if (hi2c->Config->TxCallback)
+ hi2c->Config->TxCallback();
+
+ return OK;
+}
+
+/**
+ * @brief Чтение нескольких регистров (блокирующий режим)
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param reg начальный адрес регистра
+ * @param buf указатель на буфер для данных
+ * @param size количество регистров для чтения
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
+ */
+OperationStatus I2C_Master_ReadRegs(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint16_t reg,
+ uint8_t *buf,
+ uint16_t size,
+ uint32_t timeout)
+{
+ // Для чтения нескольких регистров используется та же функция, что и для одного
+ // т.к. после отправки адреса регистра можно читать любое количество байт
+ return I2C_Master_ReadReg(hi2c, addr, reg, buf, size, timeout);
+}
+
+/**
+ * @brief Проверка наличия устройства на шине
+ * @param hi2c указатель на хендл I2C
+ * @param addr адрес устройства на шине I2C
+ * @param timeout таймаут ожидания (мс)
+ * @retval OperationStatus OK - если устройство отвечает, ERROR - если нет ответа
+ */
+OperationStatus I2C_Master_IsDeviceReady(I2C_HandleTypeDef *hi2c,
+ uint16_t addr,
+ uint32_t timeout)
+{
+ OperationStatus status;
+
+ if (!hi2c)
+ return ERROR;
+
+ // Проверяем, свободна ли шина
+ status = __i2c_master_wait_bus_free(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем START
+ status = __i2c_master_send_start(hi2c, timeout);
+ if (status != OK)
+ return status;
+
+ // Отправляем адрес с направлением "запись" (любое направление подойдет для проверки)
+ status = __i2c_master_send_address(hi2c, addr, I2C_Direction_Transmitter, timeout);
+
+ // Отправляем STOP независимо от результата
+ __i2c_master_send_stop(hi2c, timeout);
+
+ // Если устройство ответило ACK, значит оно готово
+ if (status == OK && hi2c->LastError == I2C_ERROR_NONE)
+ return OK;
+
+ return ERROR;
+}
+
+//-- I2C GPIO functions -------------------------------------------------------
+
+/**
+ * @brief Инициализация GPIO для I2C
+ */
+void i2c_gpio_init(void)
+{
+#if USE_I2C==1
+ // Получаем структуры
+ GPIO_Init_TypeDef *sda_config = gpio_get_init(I2C_GPIO_Port, I2C_SDA_Pin);
+ GPIO_Init_TypeDef *scl_config = gpio_get_init(I2C_GPIO_Port, I2C_SCL_Pin);
+
+ // SDA пин
+ if (sda_config != NULL)
+ {
+ GPIO_StructInit(sda_config);
+ sda_config->Pin = I2C_SDA_Pin;
+ sda_config->AltFunc = ENABLE;
+ sda_config->Digital = ENABLE;
+ sda_config->OutMode = GPIO_OutMode_OD; // Открытый сток для I2C
+ sda_config->PullMode = GPIO_PullMode_PU; // Подтяжка к питанию для I2C
+ GPIO_Init(I2C_GPIO_Port, sda_config);
+ }
+
+ // SCL пин
+ if (scl_config != NULL)
+ {
+ GPIO_StructInit(scl_config);
+ scl_config->Pin = I2C_SCL_Pin;
+ scl_config->AltFunc = ENABLE;
+ scl_config->Digital = ENABLE;
+ scl_config->OutMode = GPIO_OutMode_OD; // Открытый сток для I2C
+ scl_config->PullMode = GPIO_PullMode_PU; // Подтяжка к питанию для I2C
+ GPIO_Init(I2C_GPIO_Port, scl_config);
+ }
+#endif
+}
+
+/**
+ * @brief Деинициализация GPIO для I2C
+ */
+void i2c_gpio_deinit(void)
+{
+#if USE_I2C==1
+ // Получаем структуры
+ GPIO_Init_TypeDef *sda_config = gpio_get_init(I2C_GPIO_Port, I2C_SDA_Pin);
+ GPIO_Init_TypeDef *scl_config = gpio_get_init(I2C_GPIO_Port, I2C_SCL_Pin);
+
+ // Восстанавливаем оригинальные настройки из таблицы
+ if (sda_config != NULL)
+ {
+ GPIO_StructInit(sda_config);
+ sda_config->Pin = I2C_SDA_Pin;
+ GPIO_Init(I2C_GPIO_Port, sda_config);
+ }
+
+ if (scl_config != NULL)
+ {
+ GPIO_StructInit(scl_config);
+ scl_config->Pin = I2C_SCL_Pin;
+ GPIO_Init(I2C_GPIO_Port, scl_config);
+ }
+#endif
+}
+
+//-- I2C private functions ----------------------------------------------------
+
+/**
+ * @brief Установка ошибки I2C
+ */
+static void __i2c_set_error(I2C_HandleTypeDef *hi2c, uint8_t error)
+{
+ if (!hi2c)
+ return;
+
+ hi2c->LastError = error;
+
+ // Вызываем callback ошибки, если он установлен
+ if (hi2c->Config->ErrCallback)
+ hi2c->Config->ErrCallback(error);
+}
+
+/**
+ * @brief Ожидание освобождения шины I2C
+ */
+static OperationStatus __i2c_master_wait_bus_free(I2C_HandleTypeDef *hi2c, uint32_t timeout)
+{
+ uint32_t starttick = millis();
+
+ while(I2C_BusBusyStatus() == SET)
+ {
+ if(millis() - starttick > timeout)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_BUS_BUSY);
+ return ERROR;
+ }
+ }
+
+ return OK;
+}
+
+/**
+ * @brief Отправка условия START
+ */
+static OperationStatus __i2c_master_send_start(I2C_HandleTypeDef *hi2c, uint32_t timeout)
+{
+ uint32_t starttick = millis();
+ I2C_State_TypeDef state;
+
+ // Формируем START
+ I2C_StartCmd();
+
+ // Ожидаем подтверждения формирования START
+ while(1)
+ {
+ state = I2C_GetState();
+
+ if (state == I2C_State_STDONE || state == I2C_State_HMTMCOK)
+ {
+ // START успешно сформирован
+ return OK;
+ }
+ else if (state == I2C_State_BERROR)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_BUS_ERROR);
+ return ERROR;
+ }
+ else if (state == I2C_State_IDLARL || state == I2C_State_HIDLARL)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_ARBITRATION_LOST);
+ return ERROR;
+ }
+
+ if(millis() - starttick > timeout)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_TIMEOUT);
+ return ERROR;
+ }
+ }
+}
+
+/**
+ * @brief Отправка адреса устройства
+ */
+static OperationStatus __i2c_master_send_address(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t direction, uint32_t timeout)
+{
+ uint8_t address;
+ uint32_t starttick = millis();
+ I2C_State_TypeDef state;
+
+ // Формируем адрес
+ if (addr > 0x7F)
+ {
+ // 10-битный адрес - первая часть всегда на запись
+ address = 0xF0 | ((addr >> 7) & 0x06);
+ I2C_SetData(address | I2C_Direction_Transmitter);
+ }
+ else
+ {
+ // 7-битный адрес
+ address = (addr << 1);
+ I2C_SetData(address | direction);
+ }
+
+ // Сбрасываем флаг прерывания
+ I2C_ITStatusClear();
+
+ // Ожидаем подтверждения адреса
+ while(1)
+ {
+ state = I2C_GetState();
+
+ // ACK получен для 7-битного адреса
+ if ((direction == I2C_Direction_Transmitter &&
+ (state == I2C_State_MTADPA || state == I2C_State_HMTADPA)) ||
+ (direction == I2C_Direction_Receiver &&
+ (state == I2C_State_MRADPA || state == I2C_State_HMRADPA)))
+ {
+ return OK;
+ }
+ // NACK получен
+ else if ((direction == I2C_Direction_Transmitter &&
+ (state == I2C_State_MTADNA || state == I2C_State_HMTADNA)) ||
+ (direction == I2C_Direction_Receiver &&
+ (state == I2C_State_MRADNA || state == I2C_State_HMRADNA)))
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_NACK);
+ return ERROR;
+ }
+ // Ошибка шины
+ else if (state == I2C_State_BERROR)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_BUS_ERROR);
+ return ERROR;
+ }
+ // Потеря арбитража
+ else if (state == I2C_State_IDLARL || state == I2C_State_HIDLARL)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_ARBITRATION_LOST);
+ return ERROR;
+ }
+
+ if(millis() - starttick > timeout)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_TIMEOUT);
+ return ERROR;
+ }
+ }
+}
+
+/**
+ * @brief Отправка условия STOP
+ */
+static OperationStatus __i2c_master_send_stop(I2C_HandleTypeDef *hi2c, uint32_t timeout)
+{
+ uint32_t starttick = millis();
+
+ // Формируем STOP
+ I2C_StopCmd();
+
+ // Сбрасываем флаг прерывания
+ I2C_ITStatusClear();
+
+ // Ожидаем освобождения шины (опционально, не обязательно)
+ // while(I2C_BusBusyStatus() == SET)
+ // {
+ // if(millis() - starttick > timeout)
+ // {
+ // __i2c_set_error(hi2c, I2C_ERROR_TIMEOUT);
+ // return ERROR;
+ // }
+ // }
+
+ return OK;
+}
+
+/**
+ * @brief Блокирующая передача данных
+ */
+static OperationStatus __i2c_master_transmit_blocking(I2C_HandleTypeDef *hi2c, uint8_t *buf, uint16_t size, uint32_t timeout)
+{
+ uint32_t starttick;
+ I2C_State_TypeDef state;
+
+ for(uint16_t i = 0; i < size; i++)
+ {
+ // Отправляем байт данных
+ I2C_SetData(buf[i]);
+
+ // Сбрасываем флаг прерывания
+ I2C_ITStatusClear();
+
+ starttick = millis();
+
+ // Ожидаем подтверждения байта
+ while(1)
+ {
+ state = I2C_GetState();
+
+ // ACK получен
+ if (state == I2C_State_MTDAPA || state == I2C_State_HMTDAPA)
+ {
+ break;
+ }
+ // NACK получен
+ else if (state == I2C_State_MTDANA || state == I2C_State_HMTDANA)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_NACK);
+ return ERROR;
+ }
+ // Ошибка шины
+ else if (state == I2C_State_BERROR)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_BUS_ERROR);
+ return ERROR;
+ }
+ // Потеря арбитража
+ else if (state == I2C_State_IDLARL || state == I2C_State_HIDLARL)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_ARBITRATION_LOST);
+ return ERROR;
+ }
+
+ if(millis() - starttick > timeout)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_TIMEOUT);
+ return ERROR;
+ }
+ }
+ }
+
+ return OK;
+}
+
+/**
+ * @brief Блокирующий прием данных
+ */
+static OperationStatus __i2c_master_receive_blocking(I2C_HandleTypeDef *hi2c, uint8_t *buf, uint16_t size, uint32_t timeout)
+{
+ uint32_t starttick;
+ I2C_State_TypeDef state;
+
+ for(uint16_t i = 0; i < size; i++)
+ {
+ starttick = millis();
+
+ // Ожидаем приема байта
+ while(1)
+ {
+ state = I2C_GetState();
+
+ // Байт получен с ACK или NACK
+ if (state == I2C_State_MRDAPA || state == I2C_State_MRDANA ||
+ state == I2C_State_HMRDAPA || state == I2C_State_HMRDANA)
+ {
+ // Читаем данные
+ buf[i] = I2C_GetData();
+
+ // Для последнего байта отправляем NACK
+ if (i == size - 1)
+ {
+ I2C_NACKCmd();
+ }
+
+ break;
+ }
+ // Ошибка шины
+ else if (state == I2C_State_BERROR)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_BUS_ERROR);
+ return ERROR;
+ }
+ // Потеря арбитража
+ else if (state == I2C_State_IDLARL || state == I2C_State_HIDLARL)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_ARBITRATION_LOST);
+ return ERROR;
+ }
+
+ if(millis() - starttick > timeout)
+ {
+ __i2c_set_error(hi2c, I2C_ERROR_TIMEOUT);
+ return ERROR;
+ }
+ }
+ }
+
+ return OK;
+}
diff --git a/MDK-ARM/Core/App/i2c.h b/MDK-ARM/Core/App/i2c.h
new file mode 100644
index 0000000..aa90e8b
--- /dev/null
+++ b/MDK-ARM/Core/App/i2c.h
@@ -0,0 +1,183 @@
+/**
+ ******************************************************************************
+ * @file i2c.h
+ * @author Разваляев Алексей
+ * @brief Драйвер I2C на основе PLIB035.
+ * Данный файл содержит определения типов, структур и прототипы функций
+ * для работы с I2C, включая:
+ * + Структуры и typedef для I2C
+ * + Прототипы функций для инициализации и API драйвера
+ *
+ ******************************************************************************
+ */
+
+#ifndef __I2C_H
+#define __I2C_H
+
+//-- Includes ------------------------------------------------------------------
+#include "plib035.h"
+#include "plib035_i2c.h"
+#include "retarget_conf.h"
+
+//-- Defines -------------------------------------------------------------------
+// Дефайны для пинов I2C
+#define I2C_SCL_Pin GPIO_Pin_0 /**< PA0 — I2C SCL */
+#define I2C_SDA_Pin GPIO_Pin_1 /**< PA1 — I2C SDA */
+#define I2C_GPIO_Port GPIOA /**< GPIO порт I2C */
+
+// Стандартные частоты I2C
+#define I2C_STANDARD_MODE 100000 /**< 100 kHz */
+#define I2C_FAST_MODE 400000 /**< 400 kHz */
+#define I2C_FAST_MODE_PLUS 1000000 /**< 1 MHz */
+#define I2C_HIGH_SPEED_MODE 3400000 /**< 3.4 MHz */
+
+// Максимальное время ожидания по умолчанию (мс)
+#define I2C_DEFAULT_TIMEOUT 1000
+
+// Коды ошибок I2C
+#define I2C_ERROR_NONE 0x00
+#define I2C_ERROR_BUS_BUSY 0x01
+#define I2C_ERROR_TIMEOUT 0x02
+#define I2C_ERROR_NACK 0x03
+#define I2C_ERROR_ARBITRATION_LOST 0x04
+#define I2C_ERROR_BUS_ERROR 0x05
+#define I2C_ERROR_PEC_FAIL 0x06
+
+//-- Types ---------------------------------------------------------------------
+
+/**
+ * @brief Типы callback-функций I2C
+ */
+typedef enum
+{
+ I2C_Callback_Tx, /*!< Передача данных завершена */
+ I2C_Callback_Rx, /*!< Приём данных завершён */
+ I2C_Callback_Addr, /*!< Ведомый получил свой адрес */
+ I2C_Callback_Error, /*!< Ошибка I2C */
+
+} I2C_CallbackTypeDef;
+
+/**
+ * @brief Режимы работы I2C
+ */
+typedef enum
+{
+ I2C_Mode_Master, /*!< Режим мастера */
+ I2C_Mode_Slave, /*!< Режим ведомого */
+} I2C_ModeTypeDef;
+
+/**
+ * @brief Направление передачи I2C
+ */
+typedef enum
+{
+ I2C_Direction_Transmitter, /*!< Направление: передатчик */
+ I2C_Direction_Receiver, /*!< Направление: приемник */
+} I2C_DirectionTypeDef;
+
+/**
+ * @brief Размер регистра устройства
+ */
+typedef enum
+{
+ I2C_RegSize_8bit, /*!< Размер регистра: 8 бит */
+ I2C_RegSize_16bit, /*!< Размер регистра: 16 бит */
+} I2C_RegSizeTypeDef;
+
+/**
+ * @brief Структура инициализации I2C
+ */
+typedef struct
+{
+ I2C_ModeTypeDef Mode; /*!< Режим работы: I2C_Mode_Master или I2C_Mode_Slave */
+ FunctionalState HSMode; /*!< Высокоскоростной режим */
+ FunctionalState Addr10Bit; /*!< 10-битная адресация */
+ I2C_RegSizeTypeDef RegSize; /*!< Размер регистра: I2C_RegSize_8bit или I2C_RegSize_16bit */
+ uint16_t SlaveAddr; /*!< Адрес ведомого (для режима Slave) */
+
+ FunctionalState Timeout; /*!< Таймаут: */
+ I2C_TimeoutClkDiv_TypeDef TimeoutClkDiv; /*!< Делитель тактирования таймаута */
+ uint8_t TimeoutLoad; /*!< Значение загрузки счетчика таймаута */
+
+ FunctionalState AlertResponse; /*!< Ответ на тревогу */
+ FunctionalState GlobalCall; /*!< Общий вызов */
+
+} I2C_Init_TypeDef;
+
+/**
+ * @brief Расширенная конфигурация I2C
+ */
+typedef struct
+{
+ I2C_Init_TypeDef I2C_Init; /*!< Базовая конфигурация I2C */
+
+ uint32_t I2CFreq; /*!< Частота тактирования I2C в Гц */
+ uint32_t FSFreq; /*!< Частота SCL в стандартном режиме в Гц */
+ uint32_t HSFreq; /*!< Частота SCL в высокоскоростном режиме в Гц */
+
+ /* Callback функции */
+ void (*TxCallback)(void); /*!< Вызывается при завершении передачи */
+ void (*RxCallback)(void); /*!< Вызывается при завершении приема */
+ void (*AddrCallback)(void); /*!< Вызывается когда ведомый получает свой адрес */
+ void (*ErrCallback)(uint8_t error); /*!< Вызывается при ошибке I2C с кодом ошибки */
+
+} I2C_ExtInit_TypeDef;
+
+/**
+ * @brief Хендл I2C
+ */
+typedef struct
+{
+ I2C_TypeDef *Instance; /*!< Регистры I2C */
+ I2C_ExtInit_TypeDef *Config; /*!< Конфигурация I2C */
+
+ uint8_t LastError; /*!< Код последней ошибки */
+
+} I2C_HandleTypeDef;
+
+//-- External handles ----------------------------------------------------------
+
+extern I2C_HandleTypeDef hi2c;
+
+//-- Exported functions prototypes ---------------------------------------------
+
+/* Init functions */
+
+/* Первичная инициализация I2C */
+void i2c_init_first(void);
+/* Инициализация I2C */
+OperationStatus i2c_init(I2C_HandleTypeDef *hi2c, I2C_ExtInit_TypeDef *NewConfig);
+/* Инициализация GPIO для I2C */
+void i2c_gpio_init(void);
+/* Деинициализация GPIO для I2C */
+void i2c_gpio_deinit(void);
+
+/* API functions*/
+
+/* Установка callback-функции I2C */
+OperationStatus I2C_Set_Callback(I2C_HandleTypeDef *hi2c, I2C_CallbackTypeDef CallbackType, void (*Callback)());
+/* Запуск I2C */
+OperationStatus I2C_Start(I2C_HandleTypeDef *hi2c);
+/* Остановка I2C */
+OperationStatus I2C_Stop(I2C_HandleTypeDef *hi2c);
+
+/* Получение кода последней ошибки */
+uint8_t I2C_GetLastError(I2C_HandleTypeDef *hi2c);
+
+/* Передача данных в режиме мастера (блокирующий режим) */
+OperationStatus I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t *buf, uint16_t size, uint32_t timeout);
+/* Прием данных в режиме мастера (блокирующий режим) */
+OperationStatus I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t addr, uint8_t *buf, uint16_t size, uint32_t timeout);
+/* Запись регистра устройства (блокирующий режим) */
+OperationStatus I2C_Master_WriteReg(I2C_HandleTypeDef *hi2c, uint16_t addr, uint16_t reg, uint8_t value, uint32_t timeout);
+/* Чтение регистра устройства (блокирующий режим) */
+OperationStatus I2C_Master_ReadReg(I2C_HandleTypeDef *hi2c, uint16_t addr, uint16_t reg, uint8_t *buf, uint16_t size, uint32_t timeout);
+/* Запись нескольких регистров (блокирующий режим) */
+OperationStatus I2C_Master_WriteRegs(I2C_HandleTypeDef *hi2c, uint16_t addr, uint16_t reg, uint8_t *buf, uint16_t size, uint32_t timeout);
+/* Чтение нескольких регистров (блокирующий режим) */
+OperationStatus I2C_Master_ReadRegs(I2C_HandleTypeDef *hi2c, uint16_t addr, uint16_t reg, uint8_t *buf, uint16_t size, uint32_t timeout);
+
+/* Проверка наличия устройства на шине */
+OperationStatus I2C_Master_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t addr, uint32_t timeout);
+
+#endif /*__I2C_H*/
diff --git a/MDK-ARM/Core/App/main.c b/MDK-ARM/Core/App/main.c
index 3e1b17f..c939f39 100644
--- a/MDK-ARM/Core/App/main.c
+++ b/MDK-ARM/Core/App/main.c
@@ -17,8 +17,9 @@ void periph_init()
{
sysclk_init();
uart_init_first();
- adc_init_first();
tmr_init_first();
+ adc_init_first();
+ i2c_init_first();
gpio_init();
#ifdef RETARGET
retarget_init();
diff --git a/MDK-ARM/Core/Config/periph_config.h b/MDK-ARM/Core/Config/periph_config.h
index 734aee3..19811f3 100644
--- a/MDK-ARM/Core/Config/periph_config.h
+++ b/MDK-ARM/Core/Config/periph_config.h
@@ -33,6 +33,7 @@
#include "uart.h"
#include "tmr.h"
#include "adc.h"
+#include "i2c.h"
/* Обработчик ошибок */
void Error_Handler(void);
@@ -59,6 +60,10 @@ void Error_Handler(void);
#define USE_ADC_DC2 0 /*!< Использовать Компаратор 2 */
#define USE_ADC_DC3 0 /*!< Использовать Компаратор 3 */
+/* I2C */
+#define USE_I2C 0 /*!< Использовать I2C */
+
+
/** @note Для RETARGET надо объявить этот дефайн в проекте
Options for Target -> C/C++ -> Defines
*/
@@ -306,6 +311,23 @@ static ADC_DC_ExtInit_TypeDef adc_dc3_config = {
};
#endif
+
+//-- I2C Конфигурации ---------------------------------------------------------
+#if USE_I2C==1
+static I2C_ExtInit_TypeDef i2c_config = {
+//Mode, HSMode, Addr10Bit, RegSize, SlaveAddr
+ I2C_Mode_Master, DISABLE, DISABLE, I2C_RegSize_8bit, 0x00,
+//Timeout, TimeoutClkDiv, TimeoutLoad
+ DISABLE, I2C_TimeoutClkDiv_Div4, 0x00,
+//AlertResponse, GlobalCall
+ DISABLE, DISABLE,
+//I2CFreq, FSFreq, HSFreq
+ SYSCLK_CORE_CLOCK_MHZ * __MHZ, I2C_STANDARD_MODE, I2C_HIGH_SPEED_MODE,
+//TxCallback, RxCallback, AddrCallback, ErrCallback
+ NULL, NULL, NULL, NULL
+};
+#endif
+
//-- NVIC Конфигурации --------------------------------------------------------
/** @brief Приоритеты прерываний, 0 - самый высокий приоритет*/
static uint8_t NCIV_Priorities[] =
diff --git a/MDK-ARM/Template.uvoptx b/MDK-ARM/Template.uvoptx
index cd80bec..5ef52ac 100644
--- a/MDK-ARM/Template.uvoptx
+++ b/MDK-ARM/Template.uvoptx
@@ -380,6 +380,18 @@
0
0
0
+ .\Core\App\i2c.c
+ i2c.c
+ 0
+ 0
+
+
+ 2
+ 11
+ 1
+ 0
+ 0
+ 0
.\Core\App\sysclk.c
sysclk.c
0
@@ -387,7 +399,7 @@
2
- 11
+ 12
1
0
0
@@ -407,7 +419,7 @@
0
3
- 12
+ 13
5
0
0
@@ -419,7 +431,7 @@
3
- 13
+ 14
5
0
0
@@ -431,7 +443,7 @@
3
- 14
+ 15
5
0
0
@@ -443,7 +455,7 @@
3
- 15
+ 16
5
0
0
@@ -455,7 +467,7 @@
3
- 16
+ 17
5
0
0
@@ -467,7 +479,7 @@
3
- 17
+ 18
5
0
0
@@ -479,7 +491,7 @@
3
- 18
+ 19
1
0
0
@@ -491,7 +503,7 @@
3
- 19
+ 20
1
0
0
@@ -503,7 +515,7 @@
3
- 20
+ 21
5
0
0
@@ -515,7 +527,7 @@
3
- 21
+ 22
1
0
0
@@ -535,7 +547,7 @@
0
4
- 22
+ 23
1
0
0
@@ -547,7 +559,7 @@
4
- 23
+ 24
2
0
0
@@ -567,7 +579,7 @@
0
5
- 24
+ 25
1
0
0
@@ -579,7 +591,7 @@
5
- 25
+ 26
1
0
0
@@ -591,7 +603,7 @@
5
- 26
+ 27
1
0
0
@@ -603,7 +615,7 @@
5
- 27
+ 28
1
0
0
@@ -615,7 +627,7 @@
5
- 28
+ 29
1
0
0
@@ -627,7 +639,7 @@
5
- 29
+ 30
1
0
0
@@ -639,7 +651,7 @@
5
- 30
+ 31
1
0
0
@@ -651,7 +663,7 @@
5
- 31
+ 32
1
0
0
@@ -663,7 +675,7 @@
5
- 32
+ 33
1
0
0
@@ -675,7 +687,7 @@
5
- 33
+ 34
1
0
0
@@ -687,7 +699,7 @@
5
- 34
+ 35
1
0
0
@@ -699,7 +711,7 @@
5
- 35
+ 36
1
0
0
@@ -711,7 +723,7 @@
5
- 36
+ 37
1
0
0
@@ -723,7 +735,7 @@
5
- 37
+ 38
1
0
0
@@ -735,7 +747,7 @@
5
- 38
+ 39
1
0
0
@@ -755,7 +767,7 @@
0
6
- 39
+ 40
1
0
0
@@ -767,7 +779,7 @@
6
- 40
+ 41
1
0
0
@@ -779,7 +791,7 @@
6
- 41
+ 42
5
0
0
diff --git a/MDK-ARM/Template.uvprojx b/MDK-ARM/Template.uvprojx
index 2fbcc92..0cf3359 100644
--- a/MDK-ARM/Template.uvprojx
+++ b/MDK-ARM/Template.uvprojx
@@ -434,6 +434,11 @@
1
.\Core\App\adc.c
+
+ i2c.c
+ 1
+ .\Core\App\i2c.c
+
sysclk.c
1
diff --git a/Pinout.xlsx b/Pinout.xlsx
new file mode 100644
index 0000000..28e500f
Binary files /dev/null and b/Pinout.xlsx differ