Advertisement
teplofizik

i2c.c

Mar 26th, 2013
2,093
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.41 KB | None | 0 0
  1. //
  2. // i2c.c STM32F4Discovery
  3. //
  4.  
  5. // Это всего лишь пример! Кроме как посмотреть регистры в процессе обмена, не надо его использовать!
  6.  
  7. #include "i2c.h"
  8. #include <stm32f4xx.h>
  9.  
  10. #define TIMEOUT 1000000UL;
  11.  
  12. // Инициализация модуля
  13. void i2c_Init(void)
  14. {
  15.     uint32_t Clock = 16000000UL; // Частота тактирования модуля
  16.     uint32_t Speed = 100000UL;   // 100 кГц
  17.    
  18.     // Включить тактирование порта GPIOB
  19.     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
  20.    
  21.     // Настроим выводы PB6, PB9
  22.     // Open drain!
  23.     GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9;
  24.    
  25.     // Подтяжка внешняя, потому тут не настраивается!
  26.     // если надо, см. регистр GPIOB->PUPDR
  27.  
  28.     // Номер альтернативной функции
  29.     GPIOB->AFR[0] &= ~(0x0FUL << (6 * 4)); // 6 очистим
  30.     GPIOB->AFR[0] |=  (0x04UL << (6 * 4)); // В 6 запишем 4
  31.    
  32.     GPIOB->AFR[1] &= ~(0x0FUL << ((9 - 8) * 4)); // 9 очистим
  33.     GPIOB->AFR[1] |=  (0x04UL << ((9 - 8) * 4)); // В 9 запишем 4
  34.    
  35.     // Режим: альтернативная функция
  36.     GPIOB->MODER &= ~((0x03UL << (6 * 2)) | (0x03UL << (9 * 2)));  // 6, 9 очистим
  37.     GPIOB->MODER |=  ((0x02UL << (6 * 2)) | (0x02UL << (9 * 2)));  // В 6, 9 запишем 2
  38.    
  39.     // Включить тактирование модуля I2C1
  40.     RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
  41.    
  42.     // На данный момент I2C должен быть выключен
  43.     // Сбросим всё (SWRST == 1, сброс)
  44.     I2C1->CR1 = I2C_CR1_SWRST;
  45.     // PE == 0, это главное
  46.     I2C1->CR1 = 0;
  47.    
  48.     // Считаем, что запущены от RC (16 МГц)
  49.     // Предделителей в системе тактирования нет (все 1)
  50.     // По-хорошему, надо бы вычислять это вс из
  51.     // реальной частоты тактирования модуля
  52.     I2C1->CR2 = Clock / 1000000UL; // 16 МГц
  53.    
  54.     // Настраиваем частоту
  55.     {
  56.         // Tclk = (1 / Fperiph);
  57.         // Thigh = Tclk * CCR;
  58.         // Tlow =  Thigh;
  59.         // Fi2c = 1 / CCR * 2;
  60.         // CCR = Fperiph / (Fi2c * 2);
  61.         uint16_t Value = (uint16_t)(Clock / (Speed * 2));
  62.        
  63.         // Минимальное значение: 4
  64.         if(Value < 4) Value = 4;
  65.        
  66.         I2C1->CCR = Value;
  67.     }
  68.    
  69.     // Задаём предельное время фронта
  70.     // В стандартном режиме это время 1000 нс
  71.     // Просто прибавляем к частоте, выраженной в МГц единицу (см. RM стр. 604).
  72.     I2C1->TRISE = (Clock / 1000000UL) + 1;
  73.  
  74.     // Включим модуль
  75.     I2C1->CR1 |= (I2C_CR1_PE);
  76.    
  77.     // Теперь можно что-нибудь делать
  78. }
  79.  
  80. // Отправить условие старта
  81. bool i2c_SendStart(void)
  82. {
  83.     int Timeout = TIMEOUT;
  84.    
  85.     // Отправь START!
  86.     I2C1->CR1 |= (I2C_CR1_START);
  87.    
  88.     // Ждём флага завершения передачи условия START
  89.     while(!(I2C1->SR1 & I2C_SR1_SB) && --Timeout);
  90.    
  91.     // Если Timeout не вышел, значит, отправилось.
  92.     return (Timeout > 0);
  93. }
  94.  
  95. // Отправить адрес (после START)
  96. bool i2c_SendAddress(uint8_t Address)
  97. {
  98.     // Надо прочитать статусный регистр (хотя он уже прочитан был в i2c_SendStart)
  99.     uint16_t Status = I2C1->SR1;
  100.     int Timeout = TIMEOUT;
  101.    
  102.     // Отправим адрес
  103.     I2C1->DR = Address;
  104.    
  105.     // Пока не появится ADDR или AF
  106.     while ((((Status = I2C1->SR1) & (I2C_SR1_ADDR | I2C_SR1_AF)) == 0) && (--Timeout));
  107.    
  108.     {
  109.         // Прочитаем SR2
  110.         Status = I2C1->SR2;
  111.     }
  112.     return (Status & I2C_SR1_ADDR);
  113. }
  114.  
  115. // Отправить данные (после Address)
  116. bool i2c_SendData(uint8_t Data)
  117. {
  118.     int Timeout = TIMEOUT;
  119.    
  120.     // Отправим адрес
  121.     I2C1->DR = Data;
  122.    
  123.     // Пока BUSY
  124.     while(!(I2C1->SR1 & I2C_SR1_TXE) && (--Timeout));
  125.    
  126.     return (Timeout > 0);
  127. }
  128.  
  129. // Принять данные (после Address)
  130. bool i2c_ReceiveData(uint8_t * Data)
  131. {
  132.     int Timeout = TIMEOUT;
  133.    
  134.     // Пока не заполнен
  135.     while(!(I2C1->SR1 & I2C_SR1_RXNE) && (--Timeout));
  136.    
  137.     // Запишем данные
  138.     {
  139.         uint8_t Result = I2C1->DR;
  140.         *Data = Result;
  141.     }
  142.    
  143.     return (Timeout > 0);
  144. }
  145.  
  146. // Отправить условие стопа
  147. // Возвращает всегда false
  148. bool i2c_SendStop(void)
  149. {
  150.     int Timeout = 1000UL;
  151.    
  152.     // Отправь STOP
  153.     I2C1->CR1 |= (I2C_CR1_STOP);
  154.    
  155.     // Подождём немного на всякий случай
  156.     while((I2C1->SR2 & I2C_SR2_BUSY) && --Timeout);
  157.    
  158.     // Если Timeout не вышел, значит, отправилось.
  159.     return false;
  160. }
  161.  
  162. // Отправить байт
  163. bool i2c_SendByte(uint8_t Address, uint8_t Register, uint8_t Data)
  164. {
  165.     if(!i2c_SendStart()) return false;
  166.    
  167.     // Адрес микросхемы
  168.     if(!i2c_SendAddress(Address)) return i2c_SendStop();
  169.    
  170.     // Адрес регистра
  171.     if(!i2c_SendData(Register)) return i2c_SendStop();
  172.    
  173.     // Данные
  174.     if(!i2c_SendData(Data)) return i2c_SendStop();
  175.    
  176.     // Стоп!
  177.     i2c_SendStop();
  178.     return true;
  179. }
  180.  
  181.  
  182. // Получить байт
  183. bool i2c_ReceiveByte(uint8_t Address, uint8_t Register, uint8_t * Data)
  184. {
  185.     if(!i2c_SendStart()) return false;
  186.    
  187.     // Адрес микросхемы
  188.     if(!i2c_SendAddress(Address)) return i2c_SendStop();
  189.    
  190.     // Адрес регистра
  191.     if(!i2c_SendData(Register)) return i2c_SendStop();
  192.    
  193.     // Повторный старт
  194.     if(!i2c_SendStart()) return false;
  195.    
  196.     // Адрес микросхемы (чтение)
  197.     if(!i2c_SendAddress(Address | 1)) return i2c_SendStop();
  198.    
  199.     // Получим байт
  200.     if(!i2c_ReceiveData(Data)) return i2c_SendStop();
  201.    
  202.     // Стоп!
  203.     i2c_SendStop();
  204.     return true;
  205. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement