i2c_bsp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /************************************************************************************************/
  2. /**
  3. * @file i2c_bsp.c
  4. * @author MCU Ecosystem Development Team + 我
  5. * @brief I2C BSP驱动函数,使用GPIO模拟I2C主模式,实现I2C主模式通信协议。
  6. *
  7. *
  8. **************************************************************************************************
  9. * @attention
  10. * Copyright (c) CEC Huada Electronic Design Co.,Ltd. All rights reserved.
  11. *
  12. **************************************************************************************************
  13. */
  14. #include "i2c_bsp.h"
  15. /*
  16. 华大i2c_bsp.c 模块说明
  17. 注意:本模块为了更适合使用,已经进行了修改了,标准100k iic通信
  18. 注意:延时函数一定要保证1us为基本单位: i2c_delay_time(uint32_t delay_time) 这延时必须要实现1us 在不同的系统频率下
  19. 标准100k,iic通信时序要求;
  20. 1.数据保存时间: 5us及以上
  21. 2.数据建立时间: 5us及以上
  22. 3.低电平时间: 5us及以上
  23. 4.高电平时间: 5us及以上
  24. 注意:模拟的一般只适合标准iic 100k的通信速率. 要根据系统时钟的修改,验证i2c_delay_time(1)必须是1us
  25. 使用方法:
  26. uint8_t err_flag = 0;
  27. uint8_t BULL[8] = {0X00, OX11, 0X22 , 0X33 , 0X44, 0X55 , 0X66 , 0X77};
  28. void my_iic_err_call(void){
  29. err_flag = 1;
  30. }
  31. int main(void){
  32. SN_SYSCLK_set(SYSCLK_48MHZ);
  33. std_delay_init();
  34. SN_IIC_IO_set(IIC_SCL_PB3 ,IIC_SCL_PB4 ,IIC_PULLUP); //设置iic通信引脚
  35. SN_IIC_ERROR_call(my_iic_err_call); //设置错误处理函数
  36. SN_IIC_slave(0x5a); //设置通信从机地址
  37. while(1){
  38. std_delayms(500);
  39. bsp_i2c_master_send(BULL,8); //发送数据给从机0x5a
  40. std_delayms(500);
  41. bsp_i2c_master_receive(BULL,8); //从0x5a从机中接收数据
  42. }
  43. }
  44. */
  45. __IO uint8_t SLAVE_ADDRESS = 0x00 ; //全局变量,从机id号码
  46. GPIO_t * I2C_PIN_PORT1 = NULL; //SCL的端口
  47. GPIO_t * I2C_PIN_PORT2 = NULL; //SDA的端口
  48. __IO uint16_t SCL_PIN = 0x0000000; //SCL引脚
  49. __IO uint16_t SDA_PIN = 0x0000000; //SDA引脚
  50. void (* SN_IIC_error_call ) (void) = NULL; //iic通信错误处理函数指针
  51. /*
  52. 函数: SN_IIC_IO_set(uint8_t SCL_PIN_x ,uint8_t SDA_PIN_x)
  53. 功能: 设置i2c_bsp模块的io引脚使用
  54. 参数: SCL_PIN_x
  55. @IIC_SCL_PA0
  56. @IIC_SCL_PA1
  57. @IIC_SCL_PA2 (仿真线)
  58. @IIC_SCL_PA3
  59. @IIC_SCL_PA4
  60. @IIC_SCL_PA5
  61. @IIC_SCL_PA6
  62. @IIC_SCL_PA7
  63. @IIC_SCL_PB0
  64. @IIC_SCL_PB1
  65. @IIC_SCL_PB2
  66. @IIC_SCL_PB3
  67. @IIC_SCL_PB4
  68. @IIC_SCL_PB5
  69. @IIC_SCL_PB6 (仿真线)
  70. @IIC_SCL_PB7
  71. @IIC_SCL_PC0 (复位线,必须修改选项字节才可以使用)
  72. @IIC_SCL_PC1
  73. 参数: SDA_PIN_x
  74. @IIC_SDA_PA0
  75. @IIC_SDA_PA1
  76. @IIC_SDA_PA2 (仿真线)
  77. @IIC_SDA_PA3
  78. @IIC_SDA_PA4
  79. @IIC_SDA_PA5
  80. @IIC_SDA_PA6
  81. @IIC_SDA_PA7
  82. @IIC_SDA_PB0
  83. @IIC_SDA_PB1
  84. @IIC_SDA_PB2
  85. @IIC_SDA_PB3
  86. @IIC_SDA_PB4
  87. @IIC_SDA_PB5
  88. @IIC_SDA_PB6 (仿真线)
  89. @IIC_SDA_PB7
  90. @IIC_SDA_PC0 (复位线,必须修改选项字节才可以使用)
  91. @IIC_SDA_PC1
  92. 参数: 是否使用内部上拉
  93. @IIC_PULLUP_NULL //不使用内部上拉,用户自己在iic总线加上拉电阻
  94. @IIC_PULLUP //使用内部30k上拉电阻 100k标准协议不影响
  95. 返回:无
  96. */
  97. void SN_IIC_IO_set(uint8_t SCL_PIN_x ,uint8_t SDA_PIN_x ,uint8_t PULLUP )
  98. {
  99. uint32_t GPIO_PULLUP_x = 0;
  100. GPIO_t * GPIO_x = NULL;
  101. uint16_t GPIO_PIN_x = 0;
  102. uint32_t RCC_PERIPH_CLK_GPIO_x = 0;
  103. std_gpio_init_t gpio_config = {0};
  104. //是否使用内部上拉电阻
  105. GPIO_PULLUP_x = (PULLUP) ? GPIO_PULLUP : GPIO_NOPULL ;
  106. //处理SCL
  107. GPIO_x = (SCL_PIN_x < 9)? GPIOA : (SCL_PIN_x < 16) ? GPIOB : GPIOC ;
  108. RCC_PERIPH_CLK_GPIO_x = (SCL_PIN_x < 9)? RCC_PERIPH_CLK_GPIOA : (SCL_PIN_x < 16) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC ;
  109. GPIO_PIN_x = (SCL_PIN_x < 9) ? (GPIO_PIN_0 << (SCL_PIN_x - 1)) : (SCL_PIN_x < 16) ? ( GPIO_PIN_0 << (SCL_PIN_x - 9)) : ( GPIO_PIN_0 << (SCL_PIN_x - 17)) ;
  110. //设置全局 scl引脚
  111. I2C_PIN_PORT1 = GPIO_x ;
  112. SCL_PIN = GPIO_PIN_x ;
  113. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIO_x);
  114. gpio_config.pin = GPIO_PIN_x;
  115. gpio_config.mode = GPIO_MODE_OUTPUT;
  116. gpio_config.output_type = GPIO_OUTPUT_OPENDRAIN;
  117. gpio_config.pull = GPIO_PULLUP_x ;
  118. std_gpio_init(GPIO_x, &gpio_config);
  119. //处理SDA
  120. GPIO_x = (SDA_PIN_x < 9)? GPIOA : (SDA_PIN_x < 16) ? GPIOB : GPIOC ;
  121. RCC_PERIPH_CLK_GPIO_x = (SDA_PIN_x < 9)? RCC_PERIPH_CLK_GPIOA : (SDA_PIN_x < 16) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC ;
  122. GPIO_PIN_x = (SDA_PIN_x < 9) ? (GPIO_PIN_0 << (SDA_PIN_x - 1)) : (SDA_PIN_x < 16) ? ( GPIO_PIN_0 << (SDA_PIN_x - 9)) : ( GPIO_PIN_0 << (SDA_PIN_x - 17)) ;
  123. //设置全局 scl引脚
  124. I2C_PIN_PORT2 = GPIO_x ;
  125. SDA_PIN = GPIO_PIN_x ;
  126. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIO_x);
  127. gpio_config.pin = GPIO_PIN_x;
  128. gpio_config.mode = GPIO_MODE_OUTPUT;
  129. gpio_config.output_type = GPIO_OUTPUT_OPENDRAIN;
  130. std_gpio_init(GPIO_x, &gpio_config);
  131. }
  132. /*
  133. 函数: SN_IIC_slave(uint16_t iic_slave_id )
  134. 功能: 设置通信从机ic
  135. 参数: 7位 或 10位 从机id
  136. 返回; 无
  137. */
  138. void SN_IIC_slave(uint8_t iic_slave_id ){
  139. SLAVE_ADDRESS = iic_slave_id ;
  140. }
  141. /*
  142. 函数: SN_IIC_ERROR_call(void (*error_call) (void) )
  143. 功能: 设置通信错误处理函数
  144. 参数: 错误回调函数 用户自己处理的情况: 1.发出地址没有应答 2,接收数据没有应答 3.超时没有应答
  145. 返回; 无
  146. */
  147. void SN_IIC_ERROR_call(void (*error_call) (void)){
  148. SN_IIC_error_call = error_call ;
  149. }
  150. /**
  151. * @brief 异常处理
  152. * @retval 无
  153. */
  154. void error_process(void)
  155. {
  156. /* 用户添加异常处理流程 */
  157. SN_IIC_error_call();
  158. }
  159. /**
  160. * @brief I2C延时函数
  161. * @param delay_time 延时计数值
  162. * @note 用户可更改延时计数值来调整I2C的通信速率 注意:软件就延时必须要看系统频率,测试一下这个时间在当前系统频率下是否正确
  163. * @retval 无
  164. 注意:必须实现1us的基本单位
  165. */
  166. void i2c_delay_time(uint32_t delay_time)
  167. {
  168. //------------------------------------软件延时处理--------
  169. uint32_t delay_cnt;
  170. for(delay_cnt=delay_time; delay_cnt>0; delay_cnt--);
  171. }
  172. /**
  173. * @brief I2C生成起始位
  174. * @retval 无
  175. */
  176. static void bsp_i2c_generate_start(void)
  177. {
  178. /* 切换输出模式前固定电平状态以避免毛刺 */
  179. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN );
  180. std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN );
  181. /* 设置SDA为输出模式 */
  182. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
  183. i2c_delay_time(CLK_DELAY);
  184. std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
  185. i2c_delay_time(CLK_DELAY);
  186. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  187. }
  188. /**
  189. * @brief I2C生成停止位
  190. * @retval 无
  191. */
  192. static void bsp_i2c_generate_stop(void)
  193. {
  194. /* 切换输出模式前固定电平状态以避免毛刺 */
  195. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN );
  196. std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN );
  197. /* 设置SDA为输出模式 */
  198. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
  199. i2c_delay_time(CLK_DELAY);
  200. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
  201. i2c_delay_time(CLK_DELAY);
  202. std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
  203. }
  204. /**
  205. * @brief I2C生成ACK/NACK
  206. * @param ack_type ACK类型
  207. * @arg RET_ACK: 主机发送ACK
  208. * @arg RET_NACK: 主机发送NACK
  209. * @retval 无
  210. */
  211. static void bsp_i2c_generate_ack(uint32_t ack_type)
  212. {
  213. /* 切换输出模式前根据返回ACK/NACK固定电平状态以避免毛刺 */
  214. if(ack_type == RET_ACK)
  215. {
  216. std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
  217. }
  218. else
  219. {
  220. std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
  221. }
  222. /* 设置SDA为输出模式 */
  223. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
  224. i2c_delay_time(CLK_DELAY);
  225. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
  226. i2c_delay_time(CLK_DELAY);
  227. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  228. }
  229. /**
  230. * @brief I2C主模式发送一个字节数据
  231. * @param data 发送数据
  232. * @retval uint32_t 返回从机ACK状态
  233. * @arg RET_ACK: 从机返回ACK
  234. * @arg RET_NACK: 从机返回NACK
  235. */
  236. static uint32_t bsp_i2c1_master_send_byte(uint8_t send_data)
  237. {
  238. uint32_t bit_cnt = 0;
  239. uint32_t ack_type = 0;
  240. /* 切换输出模式前固定电平状态以避免毛刺 */
  241. if (send_data & 0x80)
  242. {
  243. std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
  244. }
  245. else
  246. {
  247. std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
  248. }
  249. /* 设置SDA为输出模式 */
  250. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
  251. /* 发送8bit数据 */
  252. for (bit_cnt=0; bit_cnt < 8; bit_cnt++)
  253. {
  254. if ((send_data << bit_cnt) & 0x80)
  255. {
  256. std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
  257. }
  258. else
  259. {
  260. std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
  261. }
  262. i2c_delay_time(CLK_DELAY);
  263. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
  264. i2c_delay_time(CLK_DELAY);
  265. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  266. }
  267. /* 判断从机返回ACK */
  268. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_INPUT);
  269. i2c_delay_time(CLK_DELAY);
  270. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
  271. i2c_delay_time(ACK_DELAY);
  272. for (bit_cnt=0; bit_cnt < 5; bit_cnt++)
  273. {
  274. if (std_gpio_get_input_pin(I2C_PIN_PORT2, SDA_PIN) == false)
  275. {
  276. ack_type = RET_ACK;
  277. }
  278. else
  279. {
  280. ack_type = RET_NACK;
  281. break;
  282. }
  283. }
  284. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  285. i2c_delay_time(CLK_DELAY);
  286. return ack_type;
  287. }
  288. /**
  289. * @brief I2C主模式接收一个字节数据
  290. * @retval uint8_t 接收数据
  291. */
  292. static uint8_t bsp_i2c1_master_receive_byte(void)
  293. {
  294. uint32_t bit_cnt = 0;
  295. uint8_t receive_data = 0;
  296. /* 设置SDA为输入状态 */
  297. std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_INPUT);
  298. /* 接收8bit数据 */
  299. for (bit_cnt=0; bit_cnt<8; bit_cnt++)
  300. {
  301. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  302. i2c_delay_time(CLK_DELAY);
  303. std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
  304. i2c_delay_time(CLK_DELAY);
  305. receive_data = receive_data << 1;
  306. if (std_gpio_get_input_pin(I2C_PIN_PORT2, SDA_PIN) == true)
  307. {
  308. receive_data += 1;
  309. }
  310. }
  311. std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
  312. i2c_delay_time(CLK_DELAY);
  313. return receive_data;
  314. }
  315. //-------------------------------------------------------------------------------------------------------------------------------------------
  316. /**
  317. * @brief I2C主模式发送数据流程
  318. * @retval 无
  319. */
  320. void bsp_i2c_master_send(uint8_t * g_tx_buffer , uint16_t BUFF_SIZE)
  321. {
  322. uint32_t ack_type;
  323. uint32_t index;
  324. /* 发送start位 */
  325. bsp_i2c_generate_start();
  326. /* 发送从机地址及写请求 */
  327. ack_type = bsp_i2c1_master_send_byte(SLAVE_ADDRESS | REQ_WRITE);
  328. if (ack_type != RET_ACK)
  329. {
  330. error_process();
  331. }
  332. /* 地址匹配转数据发送延时 */
  333. /* 用户可根据实际从机地址匹配后的时序进行调整 */
  334. i2c_delay_time(USER_DELAY);
  335. /* 发送数据 */
  336. for (index=0; index<BUFF_SIZE; index++)
  337. {
  338. ack_type = bsp_i2c1_master_send_byte(g_tx_buffer[index]);
  339. if (ack_type != RET_ACK)
  340. {
  341. error_process();
  342. }
  343. }
  344. /* 发送stop位 */
  345. bsp_i2c_generate_stop();
  346. }
  347. /**
  348. * @brief I2C主模式接收数据
  349. * @retval 无
  350. */
  351. void bsp_i2c_master_receive(uint8_t * g_rx_buffer , uint16_t BUFF_SIZE)
  352. {
  353. uint32_t ack_type;
  354. uint32_t index;
  355. /* 发送start位 */
  356. bsp_i2c_generate_start();
  357. /* 发送从机地址及读请求 */
  358. ack_type = bsp_i2c1_master_send_byte(SLAVE_ADDRESS | REQ_READ);
  359. if (ack_type != RET_ACK)
  360. {
  361. error_process();
  362. }
  363. /* 地址匹配转数据接收延时 */
  364. /* 用户可根据实际从机地址匹配后的时序进行调整 */
  365. i2c_delay_time(USER_DELAY);
  366. /* 接收数据 */
  367. for (index=0; index<BUFF_SIZE-1; index++)
  368. {
  369. g_rx_buffer[index] = bsp_i2c1_master_receive_byte();
  370. bsp_i2c_generate_ack(RET_ACK);
  371. }
  372. g_rx_buffer[index] = bsp_i2c1_master_receive_byte();
  373. bsp_i2c_generate_ack(RET_NACK);
  374. /* 发送stop位 */
  375. bsp_i2c_generate_stop();
  376. }