Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // i2c.c STM32F4Discovery
- //
- // Это всего лишь пример! Кроме как посмотреть регистры в процессе обмена, не надо его использовать!
- #include "i2c.h"
- #include <stm32f4xx.h>
- #define TIMEOUT 1000000UL;
- // Инициализация модуля
- void i2c_Init(void)
- {
- uint32_t Clock = 16000000UL; // Частота тактирования модуля
- uint32_t Speed = 100000UL; // 100 кГц
- // Включить тактирование порта GPIOB
- RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
- // Настроим выводы PB6, PB9
- // Open drain!
- GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9;
- // Подтяжка внешняя, потому тут не настраивается!
- // если надо, см. регистр GPIOB->PUPDR
- // Номер альтернативной функции
- GPIOB->AFR[0] &= ~(0x0FUL << (6 * 4)); // 6 очистим
- GPIOB->AFR[0] |= (0x04UL << (6 * 4)); // В 6 запишем 4
- GPIOB->AFR[1] &= ~(0x0FUL << ((9 - 8) * 4)); // 9 очистим
- GPIOB->AFR[1] |= (0x04UL << ((9 - 8) * 4)); // В 9 запишем 4
- // Режим: альтернативная функция
- GPIOB->MODER &= ~((0x03UL << (6 * 2)) | (0x03UL << (9 * 2))); // 6, 9 очистим
- GPIOB->MODER |= ((0x02UL << (6 * 2)) | (0x02UL << (9 * 2))); // В 6, 9 запишем 2
- // Включить тактирование модуля I2C1
- RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
- // На данный момент I2C должен быть выключен
- // Сбросим всё (SWRST == 1, сброс)
- I2C1->CR1 = I2C_CR1_SWRST;
- // PE == 0, это главное
- I2C1->CR1 = 0;
- // Считаем, что запущены от RC (16 МГц)
- // Предделителей в системе тактирования нет (все 1)
- // По-хорошему, надо бы вычислять это вс из
- // реальной частоты тактирования модуля
- I2C1->CR2 = Clock / 1000000UL; // 16 МГц
- // Настраиваем частоту
- {
- // Tclk = (1 / Fperiph);
- // Thigh = Tclk * CCR;
- // Tlow = Thigh;
- // Fi2c = 1 / CCR * 2;
- // CCR = Fperiph / (Fi2c * 2);
- uint16_t Value = (uint16_t)(Clock / (Speed * 2));
- // Минимальное значение: 4
- if(Value < 4) Value = 4;
- I2C1->CCR = Value;
- }
- // Задаём предельное время фронта
- // В стандартном режиме это время 1000 нс
- // Просто прибавляем к частоте, выраженной в МГц единицу (см. RM стр. 604).
- I2C1->TRISE = (Clock / 1000000UL) + 1;
- // Включим модуль
- I2C1->CR1 |= (I2C_CR1_PE);
- // Теперь можно что-нибудь делать
- }
- // Отправить условие старта
- bool i2c_SendStart(void)
- {
- int Timeout = TIMEOUT;
- // Отправь START!
- I2C1->CR1 |= (I2C_CR1_START);
- // Ждём флага завершения передачи условия START
- while(!(I2C1->SR1 & I2C_SR1_SB) && --Timeout);
- // Если Timeout не вышел, значит, отправилось.
- return (Timeout > 0);
- }
- // Отправить адрес (после START)
- bool i2c_SendAddress(uint8_t Address)
- {
- // Надо прочитать статусный регистр (хотя он уже прочитан был в i2c_SendStart)
- uint16_t Status = I2C1->SR1;
- int Timeout = TIMEOUT;
- // Отправим адрес
- I2C1->DR = Address;
- // Пока не появится ADDR или AF
- while ((((Status = I2C1->SR1) & (I2C_SR1_ADDR | I2C_SR1_AF)) == 0) && (--Timeout));
- {
- // Прочитаем SR2
- Status = I2C1->SR2;
- }
- return (Status & I2C_SR1_ADDR);
- }
- // Отправить данные (после Address)
- bool i2c_SendData(uint8_t Data)
- {
- int Timeout = TIMEOUT;
- // Отправим адрес
- I2C1->DR = Data;
- // Пока BUSY
- while(!(I2C1->SR1 & I2C_SR1_TXE) && (--Timeout));
- return (Timeout > 0);
- }
- // Принять данные (после Address)
- bool i2c_ReceiveData(uint8_t * Data)
- {
- int Timeout = TIMEOUT;
- // Пока не заполнен
- while(!(I2C1->SR1 & I2C_SR1_RXNE) && (--Timeout));
- // Запишем данные
- {
- uint8_t Result = I2C1->DR;
- *Data = Result;
- }
- return (Timeout > 0);
- }
- // Отправить условие стопа
- // Возвращает всегда false
- bool i2c_SendStop(void)
- {
- int Timeout = 1000UL;
- // Отправь STOP
- I2C1->CR1 |= (I2C_CR1_STOP);
- // Подождём немного на всякий случай
- while((I2C1->SR2 & I2C_SR2_BUSY) && --Timeout);
- // Если Timeout не вышел, значит, отправилось.
- return false;
- }
- // Отправить байт
- bool i2c_SendByte(uint8_t Address, uint8_t Register, uint8_t Data)
- {
- if(!i2c_SendStart()) return false;
- // Адрес микросхемы
- if(!i2c_SendAddress(Address)) return i2c_SendStop();
- // Адрес регистра
- if(!i2c_SendData(Register)) return i2c_SendStop();
- // Данные
- if(!i2c_SendData(Data)) return i2c_SendStop();
- // Стоп!
- i2c_SendStop();
- return true;
- }
- // Получить байт
- bool i2c_ReceiveByte(uint8_t Address, uint8_t Register, uint8_t * Data)
- {
- if(!i2c_SendStart()) return false;
- // Адрес микросхемы
- if(!i2c_SendAddress(Address)) return i2c_SendStop();
- // Адрес регистра
- if(!i2c_SendData(Register)) return i2c_SendStop();
- // Повторный старт
- if(!i2c_SendStart()) return false;
- // Адрес микросхемы (чтение)
- if(!i2c_SendAddress(Address | 1)) return i2c_SendStop();
- // Получим байт
- if(!i2c_ReceiveData(Data)) return i2c_SendStop();
- // Стоп!
- i2c_SendStop();
- return true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement