秀一个GD32的通用IIC主机驱动

[复制链接]
4441|11
 楼主| Simon21ic 发表于 2017-1-22 16:56 | 显示全部楼层 |阅读模式
本帖最后由 Simon21ic 于 2017-1-22 17:02 编辑

使用中断的方式,没有用DMA,把阻塞等待的代码减少了最少:
调用方式类似linux的IIC驱动方式,不过简化了非常多,代码也非常简单
不过,这个库是有BUG的,只是在我们目前的项目中,没问题,就懒得改了


  1. #include "app_cfg.h"
  2. #include "app_type.h"
  3. #include "interfaces.h"

  4. #if IFS_I2C_EN

  5. #include "../core.h"
  6. #define IIC_NUM                                2

  7. struct i2c_ctrl_t
  8. {
  9.         uint8_t chip_addr;
  10.         uint8_t msg_len;
  11.         uint8_t msg_prt;
  12.         uint16_t msg_buf_prt;
  13.         struct interface_i2c_msg_t *msg;
  14.         void *param;
  15.         void (*callback)(void *, vsf_err_t);
  16. } static gd32f1x0_i2c[IIC_NUM];

  17. struct i2c_param_t
  18. {
  19.         I2C_TypeDef *reg;
  20.         struct gd32f1x0_afio_pin_t sda[3];
  21.         struct gd32f1x0_afio_pin_t scl[3];
  22. } static const gd32f1x0_i2c_param[IIC_NUM] =
  23. {
  24. #if IIC_NUM >= 1
  25.         {
  26.                 I2C1,
  27.                 {
  28.                         {0, 10, 4},                // PA10, AF4
  29.                         {1, 7, 1},                // PB7, AF1
  30.                         {1, 9, 1},                // PB9, AF1
  31.                 },
  32.                 {
  33.                         {0, 9, 4},                // PA9, AF4
  34.                         {1, 6, 1},                // PB6, AF1
  35.                         {1, 8, 1},                // PB8, AF1
  36.                 },
  37.         },
  38. #endif
  39. #if IIC_NUM >= 2
  40.         {
  41.                 I2C2,
  42.                 {
  43.                         {0, 1, 4},                // PA1, AF4
  44.                         {1, 11, 1},                // PB11, AF1
  45.                         {6, 7, -1},                // PF7, default
  46.                 },
  47.                 {
  48.                         {0, 0, 4},                // PA0, AF4
  49.                         {1, 10, 1},                // PB10, AF1
  50.                         {6, 6, -1},                // PF6, default
  51.                 },
  52.         },
  53. #endif
  54. };

  55. // index spec(LSB to MSB):
  56. // 2-bit iic_idx, 3-bit sda_idx, 3-bit scl_idx
  57. vsf_err_t gd32f1x0_i2c_init(uint8_t index)
  58. {
  59.         uint8_t iic_idx = (index & 0x03) >> 0;
  60.         uint8_t sda_idx = (index & 0x1C) >> 2;
  61.         uint8_t scl_idx = (index & 0xE0) >> 5;
  62.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;

  63.         gd32f1x0_afio_config(&gd32f1x0_i2c_param[iic_idx].sda[sda_idx], gd32f1x0_GPIO_AF | gd32f1x0_GPIO_OD);
  64.         gd32f1x0_afio_config(&gd32f1x0_i2c_param[iic_idx].scl[scl_idx], gd32f1x0_GPIO_AF | gd32f1x0_GPIO_OD);
  65.         
  66.         RCC->APB1CCR |= RCC_APB1CCR_I2C1EN << iic_idx;
  67.         reg->CTLR1 = 0;
  68.         return VSFERR_NONE;
  69. }

  70. vsf_err_t gd32f1x0_i2c_fini(uint8_t index)
  71. {
  72.         uint8_t iic_idx = (index & 0x03) >> 0;
  73.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  74.         reg->CTLR1 = 0;
  75.         return VSFERR_NONE;
  76. }

  77. vsf_err_t gd32f1x0_i2c_config(uint8_t index, uint16_t kHz)
  78. {
  79.         uint8_t iic_idx = (index & 0x03) >> 0;
  80.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  81.         struct gd32f1x0_info_t *info;
  82.         uint16_t iic_clk, iic_freq;
  83.         
  84.         gd32f1x0_interface_get_info(&info);
  85.         iic_clk = info->apb_freq_hz / 1000000;
  86.         iic_clk = min(iic_clk, 36);
  87.         reg->CTLR2 = iic_clk;
  88.         
  89.         if (kHz <= 100)
  90.         {
  91.                 // standard mode
  92.                 iic_freq = info->apb_freq_hz / (kHz * 2000);
  93.                 if (iic_freq < 4)
  94.                         iic_freq = 4;
  95.                 reg->RTR = (iic_clk >= 36) ? 36 : iic_clk + 1;
  96.         }
  97.         else
  98.         {
  99.                 // fast mode
  100.                 iic_freq = info->apb_freq_hz / (kHz * 3000);
  101.                 if (!iic_freq)
  102.                         iic_freq = 1;
  103.                 reg->RTR = (uint16_t)(((iic_clk * 300) / 1000) + 1);
  104.         }
  105.         reg->CLKR = iic_freq;
  106.         reg->CTLR1 = I2C_CTLR1_I2CEN;
  107.         
  108.         switch (iic_idx)
  109.         {
  110. #if IIC_NUM >= 1
  111.         case 0: NVIC_EnableIRQ(I2C1_EV_IRQn); NVIC_EnableIRQ(I2C1_ER_IRQn); break;
  112. #endif
  113. #if IIC_NUM >= 2
  114.         case 1: NVIC_EnableIRQ(I2C2_EV_IRQn); NVIC_EnableIRQ(I2C2_ER_IRQn); break;
  115. #endif
  116.         }
  117.         reg->CTLR2 |= I2C_CTLR2_EE | I2C_CTLR2_EIE | I2C_CTLR2_BIE;
  118.         return VSFERR_NONE;
  119. }

  120. vsf_err_t gd32f1x0_i2c_config_cb(uint8_t index, void *param,
  121.                                                         void (*callback)(void *, vsf_err_t))
  122. {
  123.         uint8_t iic_idx = (index & 0x03) >> 0;
  124.         gd32f1x0_i2c[iic_idx].param = param;
  125.         gd32f1x0_i2c[iic_idx].callback = callback;
  126.         return VSFERR_NONE;
  127. }

  128. vsf_err_t gd32f1x0_i2c_xfer(uint8_t index, uint16_t chip_addr,
  129.                                                         struct interface_i2c_msg_t *msg, uint8_t msg_len)
  130. {
  131.         uint8_t iic_idx = (index & 0x03) >> 0;
  132.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;

  133.         if ((msg == NULL) || (msg_len == 0))
  134.                 return VSFERR_INVALID_PARAMETER;

  135.         gd32f1x0_i2c[iic_idx].chip_addr = chip_addr;
  136.         gd32f1x0_i2c[iic_idx].msg = msg;
  137.         gd32f1x0_i2c[iic_idx].msg_len = msg_len;
  138.         gd32f1x0_i2c[iic_idx].msg_prt = 0;
  139.         gd32f1x0_i2c[iic_idx].msg_buf_prt = 0;

  140.         reg->CTLR1 |= I2C_CTLR1_GENSTA;
  141.         return VSFERR_NONE;
  142. }

  143. static void gd32f1x0_i2c_cb(uint8_t iic_idx, vsf_err_t err)
  144. {
  145.         struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
  146.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  147.         
  148.         // MUST wait STOP clear, or next START will fail
  149.         reg->CTLR1 |= I2C_CTLR1_GENSTP;
  150.         while (reg->CTLR1 & I2C_CTLR1_GENSTP);
  151.         if (ctrl->callback != NULL)
  152.                 ctrl->callback(ctrl->param, err);
  153. }

  154. static void gd32f1x0_i2c_chk_recv_next(uint8_t iic_idx)
  155. {
  156.         struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
  157.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  158.         struct interface_i2c_msg_t *msg = &ctrl->msg[ctrl->msg_prt];

  159.         if ((msg->flag & I2C_ACKLAST) || (ctrl->msg_buf_prt < msg->len - 1) ||
  160.                 ((ctrl->msg_len > ctrl->msg_prt + 1) &&
  161.                         (ctrl->msg[ctrl->msg_prt + 1].flag & (I2C_READ | I2C_NOSTART))))
  162.         {
  163.                 reg->CTLR1 |= I2C_CTLR1_ACKEN;
  164.         }
  165.         else
  166.         {
  167.                 reg->CTLR1 &= ~I2C_CTLR1_ACKEN;
  168.         }
  169. }

  170. static void gd32f1x0_i2c_err(uint8_t iic_idx)
  171. {
  172.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  173.         reg->STR1 &= ~(I2C_STR1_BE | I2C_STR1_LOSTARB | I2C_STR1_AE);
  174.         gd32f1x0_i2c_cb(iic_idx, VSFERR_FAIL);
  175. }

  176. static void gd32f1x0_i2c_int(uint8_t iic_idx)
  177. {
  178.         struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
  179.         I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
  180.         struct interface_i2c_msg_t *msg = &ctrl->msg[ctrl->msg_prt];
  181.         uint16_t status = reg->STR1;

  182.         if (status & I2C_STR1_SBSEND)
  183.         {
  184.                 // I2C_STR1_SBSEND is cleared by reading STR1 and writing DTR
  185.                 reg->DTR = (ctrl->chip_addr << 1) | ((msg->flag & I2C_READ) ? 1 : 0);
  186.                 // can not put in I2C_STR1_ADDSEND, no idea why
  187.                 if (msg->flag & I2C_READ)
  188.                 {
  189.                         gd32f1x0_i2c_chk_recv_next(iic_idx);
  190.                 }
  191.         }
  192.         else if (status & I2C_STR1_ADDSEND)
  193.         {
  194.                 // I2C_STR1_ADDSEND is cleared by reading STR1 and reading STR2
  195.                 status = reg->STR2;
  196.         }
  197.         else if (status & I2C_STR1_TBE)
  198.         {
  199.                 // I2C_STR1_TBE is cleared by writing DTR while sending data
  200.                 if (ctrl->msg_buf_prt < msg->len)
  201.                 {
  202.                 send_data:
  203.                         reg->DTR = msg->buf[ctrl->msg_buf_prt++];
  204.                 }
  205.                 else if (++ctrl->msg_prt < ctrl->msg_len)
  206.                 {
  207.                         ctrl->msg_buf_prt = 0;
  208.                         msg = &ctrl->msg[ctrl->msg_prt];
  209.                         if (!(msg->flag & I2C_READ) && (msg->flag & I2C_NOSTART))
  210.                                 goto send_data;
  211.                         else
  212.                                 reg->CTLR1 |= I2C_CTLR1_GENSTA;
  213.                 }
  214.                 else
  215.                 {
  216.                         gd32f1x0_i2c_cb(iic_idx, VSFERR_NONE);
  217.                 }
  218.         }
  219.         else if (status & I2C_STR1_RBNE)
  220.         {
  221.                 msg->buf[ctrl->msg_buf_prt++] = reg->DTR;
  222.                 if (ctrl->msg_buf_prt < msg->len)
  223.                 {
  224.                 recv_data:
  225.                         gd32f1x0_i2c_chk_recv_next(iic_idx);
  226.                 }
  227.                 else if (++ctrl->msg_prt < ctrl->msg_len)
  228.                 {
  229.                         ctrl->msg_buf_prt = 0;
  230.                         msg = &ctrl->msg[ctrl->msg_prt];
  231.                         if ((msg->flag & I2C_READ) && (msg->flag & I2C_NOSTART))
  232.                                 goto recv_data;
  233.                         else
  234.                                 reg->CTLR1 |= I2C_CTLR1_GENSTA;
  235.                 }
  236.                 else
  237.                 {
  238.                         gd32f1x0_i2c_cb(iic_idx, VSFERR_NONE);
  239.                 }
  240.         }
  241. }

  242. #if IIC_NUM >= 1
  243. ROOTFUNC void I2C1_EV_IRQHandler(void)
  244. {
  245.         gd32f1x0_i2c_int(0);
  246. }
  247. ROOTFUNC void I2C1_ER_IRQHandler(void)
  248. {
  249.         gd32f1x0_i2c_err(0);
  250. }
  251. #endif

  252. #if IIC_NUM >= 2
  253. ROOTFUNC void I2C2_EV_IRQHandler(void)
  254. {
  255.         gd32f1x0_i2c_int(1);
  256. }
  257. ROOTFUNC void I2C2_ER_IRQHandler(void)
  258. {
  259.         gd32f1x0_i2c_err(1);
  260. }
  261. #endif
  262. #endif



tongbu2015 发表于 2017-1-30 18:24 | 显示全部楼层
这个例程的主要实现了什么功能的?
tongbu2015 发表于 2017-1-30 18:25 | 显示全部楼层
只是个简单的I2C总线通讯的?
baimiaocun2015 发表于 2017-1-31 10:26 | 显示全部楼层
这个程序的分享的比较好
叶覃 发表于 2017-1-31 22:42 | 显示全部楼层
代码看上去写的非常好,非常规范。我多会也写的这么牛X就好了。
 楼主| Simon21ic 发表于 2017-2-7 22:06 | 显示全部楼层
tongbu2015 发表于 2017-1-30 18:25
只是个简单的I2C总线通讯的?

这个是我们的系统构架下的IIC底层驱动,实现IIC主机功能
 楼主| Simon21ic 发表于 2017-2-7 22:09 | 显示全部楼层
叶覃 发表于 2017-1-31 22:42
代码看上去写的非常好,非常规范。我多会也写的这么牛X就好了。

写着写着就发现自己越来越牛了,所有人都这样
shenmu2012 发表于 2017-2-10 22:08 | 显示全部楼层
利用中断的方式处理有优势的,,只需要设置好优先级 的
vivilzb1985 发表于 2017-2-12 22:04 | 显示全部楼层
IIC的总线数据通讯的还是蛮重要的
firstblood 发表于 2017-2-12 22:51 | 显示全部楼层
这个代码的分享的确很给力的,,连通讯的容错功能的都有的
smilingangel 发表于 2017-2-12 23:15 | 显示全部楼层
IIC的主机驱动的是比较重要的
angerbird 发表于 2017-2-14 23:03 | 显示全部楼层
struct i2c_ctrl_t
{
        uint8_t chip_addr;
        uint8_t msg_len;
        uint8_t msg_prt;
        uint16_t msg_buf_prt;
        struct interface_i2c_msg_t *msg;
        void *param;
        void (*callback)(void *, vsf_err_t);
} static gd32f1x0_i2c[IIC_NUM];

采用结构体设计管理的,非常好
您需要登录后才可以回帖 登录 | 注册

本版积分规则

266

主题

2597

帖子

104

粉丝
快速回复 在线客服 返回列表 返回顶部