i2c.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /******************************************************************************
  2. * Драйвер модуля I2C микроконтроллера STM8S003F
  3. *
  4. * Автор: Осипов Андрей
  5. * Дата: 17 июля 2014
  6. * URL: http://hamlab.net/mcu/stm8/i2c.html
  7. ******************************************************************************/
  8. #include "i2c.h"
  9. /* Таймаут ожидания события I2C */
  10. extern __IO uint8_t I2C_timeout;
  11. /* Ожидание наступления события event в течении времени timeout в мс */
  12. #define wait_event(event, timeout) I2C_timeout = timeout;\
  13. while(event && I2C_timeout);\
  14. if(!I2C_timeout) return I2C_TIMEOUT;
  15. /**
  16. * @brief Инициализация I2C интерфейса
  17. */
  18. void i2c_master_init(void) {
  19. uint16_t ccr;
  20. /* Настройка GPIO SDA SCL - HiZ, Open drain, Fast */
  21. GPIOB->DDR |= (GPIO_PIN_4 | GPIO_PIN_5);
  22. GPIOB->ODR |= (GPIO_PIN_4 | GPIO_PIN_5);
  23. GPIOB->CR2 |= (GPIO_PIN_5 | GPIO_PIN_5);
  24. //Частота тактирования периферии MHz
  25. I2C->FREQR = (uint8_t)(F_MASTER_MHZ);
  26. //Отключаем I2C
  27. I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
  28. //Выбираем стандартный режим
  29. I2C->CCRH = 0;
  30. //CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
  31. ccr = (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ));
  32. //Set Maximum Rise Time: 1000ns max in Standard Mode
  33. //= [1000ns/(1/InputClockFrequencyMHz.10e6)]+1
  34. //= InputClockFrequencyMHz+1
  35. I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
  36. I2C->CCRL = (uint8_t)ccr;
  37. I2C->CCRH = (uint8_t)((uint8_t)(ccr >> 8) & I2C_CCRH_CCR);
  38. //Включаем I2C
  39. I2C->CR1 |= I2C_CR1_PE;
  40. //Разрешаем подтверждение в конце посылки
  41. I2C->CR2 |= I2C_CR2_ACK;
  42. }
  43. /**
  44. * @brief Запись регистра slave-устройства
  45. */
  46. t_i2c_status i2c_wr_reg(uint8_t address, uint8_t reg_addr, uint16_t data) {
  47. //Ждем освобождения шины I2C
  48. wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
  49. //Генерация СТАРТ-посылки
  50. I2C->CR2 |= I2C_CR2_START;
  51. //Ждем установки бита SB
  52. wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
  53. //Записываем в регистр данных адрес ведомого устройства
  54. I2C->DR = address & 0xFE;
  55. //Ждем подтверждения передачи адреса
  56. wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
  57. //Очистка бита ADDR чтением регистра SR3
  58. I2C->SR3;
  59. //Ждем освобождения регистра данных
  60. wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
  61. //Отправляем адрес регистра
  62. I2C->DR = reg_addr;
  63. //Отправка данных
  64. //Ждем освобождения регистра данных
  65. wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
  66. //Отправляем адрес регистра
  67. I2C->DR = (uint8_t)(data >> 8);
  68. //Ждем освобождения регистра данных
  69. wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
  70. //Отправляем адрес регистра
  71. I2C->DR = (uint8_t)data;
  72. //Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
  73. wait_event(!((I2C->SR1 & I2C_SR1_TXE) && (I2C->SR1 & I2C_SR1_BTF)), 1);
  74. //Посылаем СТОП-посылку
  75. I2C->CR2 |= I2C_CR2_STOP;
  76. //Ждем выполнения условия СТОП
  77. wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
  78. return I2C_SUCCESS;
  79. }
  80. /**
  81. * @brief Чтение регистра slave-устройства
  82. * @note Start -> Slave Addr -> Reg. addr -> Restart -> Slave Addr <- data ... -> Stop
  83. */
  84. t_i2c_status i2c_rd_reg(uint8_t address, uint8_t reg_addr, uint16_t * data) {
  85. //Ждем освобождения шины I2C
  86. wait_event((I2C->SR3 & I2C_SR3_BUSY), 10);
  87. //Разрешаем подтверждение в конце посылки
  88. I2C->CR2 |= I2C_CR2_ACK;
  89. //Генерация СТАРТ-посылки
  90. I2C->CR2 |= I2C_CR2_START;
  91. //Ждем установки бита SB
  92. wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
  93. //Записываем в регистр данных адрес ведомого устройства
  94. I2C->DR = address & 0xFE;
  95. //Ждем подтверждения передачи адреса
  96. wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
  97. //Очистка бита ADDR чтением регистра SR3
  98. I2C->SR3;
  99. //Ждем освобождения регистра данных RD
  100. wait_event(!(I2C->SR1 & I2C_SR1_TXE), 1);
  101. //Передаем адрес регистра slave-устройства, который хотим прочитать
  102. I2C->DR = reg_addr;
  103. //Ловим момент, когда DR освободился и данные попали в сдвиговый регистр
  104. wait_event(!((I2C->SR1 & I2C_SR1_TXE) && (I2C->SR1 & I2C_SR1_BTF)), 1);
  105. //Генерация СТАРТ-посылки (рестарт)
  106. I2C->CR2 |= I2C_CR2_START;
  107. //Ждем установки бита SB
  108. wait_event(!(I2C->SR1 & I2C_SR1_SB), 1);
  109. //Записываем в регистр данных адрес ведомого устройства и переходим
  110. //в режим чтения (установкой младшего бита в 1)
  111. I2C->DR = address | 0x01;
  112. //Отправка двух байт данных
  113. //Бит который разрешает NACK на следующем принятом байте
  114. I2C->CR2 |= I2C_CR2_POS;
  115. //Ждем подтверждения передачи адреса
  116. wait_event(!(I2C->SR1 & I2C_SR1_ADDR), 1);
  117. //Заплатка из Errata
  118. disableInterrupts();
  119. //Очистка бита ADDR чтением регистра SR3
  120. I2C->SR3;
  121. //Запрещаем подтверждение в конце посылки
  122. I2C->CR2 &= (uint8_t)(~I2C_CR2_ACK);
  123. //Заплатка из Errata
  124. enableInterrupts();
  125. //Ждем момента, когда первый байт окажется в DR,
  126. //а второй в сдвиговом регистре
  127. wait_event(!(I2C->SR1 & I2C_SR1_BTF), 1);
  128. //Заплатка из Errata
  129. disableInterrupts();
  130. //Устанавлием бит STOP
  131. I2C->CR2 |= I2C_CR2_STOP;
  132. //Читаем принятые байты
  133. *data = I2C->DR << 8;
  134. //Заплатка из Errata
  135. enableInterrupts();
  136. *data |= I2C->DR;
  137. //Ждем отправки СТОП посылки
  138. wait_event((I2C->CR2 & I2C_CR2_STOP), 1);
  139. //Сбрасывает бит POS, если вдруг он был установлен
  140. I2C->CR2 &= ~I2C_CR2_POS;
  141. return I2C_SUCCESS;
  142. }