Advertisement
Guest User

libmaple i2c slave code v0.3

a guest
Sep 2nd, 2012
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. diff --git a/libmaple/i2c.c b/libmaple/i2c.c
  2. index 9c93d3f..b8e622d 100644
  3. --- a/libmaple/i2c.c
  4. +++ b/libmaple/i2c.c
  5. @@ -154,6 +154,7 @@ void i2c_bus_reset(const i2c_dev *dev) {
  6.  void i2c_init(i2c_dev *dev) {
  7.      rcc_reset_dev(dev->clk_id);
  8.      rcc_clk_enable(dev->clk_id);
  9. +    _i2c_irq_priority_fixup(dev);
  10.  }
  11.  
  12.  /* Hack for deprecated bit of STM32F1 functionality */
  13. @@ -198,12 +199,30 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
  14.      nvic_irq_enable(dev->er_nvic_line);
  15.      i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
  16.  
  17. +    /* Configure the slave unit */
  18. +    if (flags & I2C_SLAVE_DUAL_ADDRESS) {
  19. +        i2c_slave_dual_address_enable(dev);
  20. +    }
  21. +
  22. +    if (flags & I2C_SLAVE_GENERAL_CALL) {
  23. +        i2c_slave_general_call_enable(dev);
  24. +    }
  25. +
  26. +    /* store all of the flags */
  27. +    dev->config_flags = flags;
  28. +
  29.      /* Make it go! */
  30.      i2c_peripheral_enable(dev);
  31. +    i2c_enable_ack(dev);
  32.  
  33.      dev->state = I2C_STATE_IDLE;
  34.  }
  35.  
  36. +void i2c_slave_enable(i2c_dev *dev, uint32 flags) {
  37. +    i2c_disable(dev);
  38. +    i2c_master_enable(dev, dev->config_flags | flags);
  39. +}
  40. +
  41.  /**
  42.   * @brief Process an i2c transaction.
  43.   *
  44. @@ -303,6 +322,152 @@ void _i2c_irq_handler(i2c_dev *dev) {
  45.       */
  46.      dev->timestamp = systick_uptime();
  47.  
  48. +    /* Add Slave support
  49. +     * Barry Carter 2012
  50. +     * barry.carter@gmail.com
  51. +     */
  52. +    
  53. +    /* Check to see if MSL master slave bit is set */
  54. +    if ((sr2 & I2C_SR2_MSL) != I2C_SR2_MSL) { /* 0 = slave mode 1 = master */
  55. +
  56. +        /* Check for address match */
  57. +        if (sr1 & I2C_SR1_ADDR) {
  58. +            /* Find out which address was matched */
  59. +            /* Check the general call address first */
  60. +            if (sr2 & I2C_SR2_GENCALL) {
  61. +                dev->i2c_slave_msg->addr = 0;
  62. +            }
  63. +            /* We matched the secondary address */
  64. +            else if (sr2 & I2C_SR2_DUALF) {
  65. +                dev->i2c_slave_msg->addr = dev->regs->OAR2 & 0xFE;
  66. +            }
  67. +            /* We matched the primary address */
  68. +            else if ((sr2 & I2C_SR2_DUALF) != I2C_SR2_DUALF) {
  69. +                dev->i2c_slave_msg->addr = dev->regs->OAR1 & 0xFE;
  70. +            }
  71. +            /* Shouldn't get here */
  72. +            else {
  73. +                dev->i2c_slave_msg->addr = -1; /* uh oh */
  74. +            }
  75. +
  76. +            /* if we have buffered io */
  77. +            if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) ||
  78. +                (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
  79. +
  80. +                /* if receiving then this would be a repeated start
  81. +                 *
  82. +                 *if we have some bytes already
  83. +                 */
  84. +                if ((dev->state == I2C_STATE_SL_RX) &&
  85. +                    (dev->i2c_slave_msg->xferred > 0)  &&
  86. +                    (dev->config_flags & I2C_SLAVE_USE_RX_BUFFER)) {
  87. +                    /* Call the callback with the contents of the data */
  88. +                    if (dev->i2c_slave_recv_callback != NULL) {
  89. +                        (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
  90. +                    }
  91. +                }
  92. +
  93. +                /* Reset the message back to defaults.
  94. +                 * We are starting a new message
  95. +                 */
  96. +                dev->i2c_slave_msg->flags = 0;
  97. +                dev->i2c_slave_msg->length = 0;
  98. +                dev->i2c_slave_msg->xferred = 0;
  99. +                dev->msgs_left = 0;
  100. +                dev->timestamp = systick_uptime();
  101. +
  102. +                /* We have been addressed with SLA+R so
  103. +                 * the master wants us to transmit
  104. +                 */
  105. +                if ((sr1 & I2C_SR1_TXE) &&
  106. +                    (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
  107. +                    /* Call the transmit callback so it can populate the msg
  108. +                     * data with the bytes to go
  109. +                     */
  110. +                    if (dev->i2c_slave_transmit_callback != NULL) {
  111. +                        (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg);
  112. +                    }
  113. +                }
  114. +                dev->state = I2C_STATE_BUSY;
  115. +            }
  116. +
  117. +            sr1 = sr2 = 0;
  118. +        }
  119. +        
  120. +         /* EV3: Master requesting data from slave. Transmit a byte*/
  121. +        if (sr1 & I2C_SR1_TXE) {
  122. +            if (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER) {
  123. +                if (dev->i2c_slave_msg->xferred >= dev->i2c_slave_msg->length) {
  124. +                    /* End of the transmit buffer? If so we NACK */
  125. +                    i2c_disable_ack(dev);
  126. +                    /* We have to either issue a STOP or write something here.
  127. +                     * STOP here seems to screw up some masters,
  128. +                     * For now padding with 0
  129. +                     */
  130. +                    i2c_write(dev, 0);
  131. +                    /*i2c_stop_condition(dev); // This is causing bus lockups way more than it should !? Seems some I2C master devices freak out here*/
  132. +                }
  133. +                else
  134. +                {
  135. +                    /* NACk the last byte */
  136. +                    if (dev->i2c_slave_msg->xferred == dev->i2c_slave_msg->length-1) {
  137. +                        i2c_disable_ack(dev);
  138. +                    }
  139. +                    else {
  140. +                        i2c_enable_ack(dev);
  141. +                    }
  142. +                    i2c_write(dev, dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++]);
  143. +                }
  144. +            }
  145. +            else
  146. +            {
  147. +                /* Call the callback to get the data we need.
  148. +                 * The callback is expected to write using i2c_write(...)
  149. +                 * If the slave is going to terminate the transfer, this function should
  150. +                 * also do a NACK on the last byte!
  151. +                 */
  152. +                if (dev->i2c_slave_transmit_callback != NULL) (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg);
  153. +            }
  154. +
  155. +            dev->state = I2C_STATE_BUSY;
  156. +            sr1 = sr2 = 0;
  157. +        }
  158. +        
  159. +        /* EV2: Slave received data from a master. Get from DR */
  160. +        if (sr1 & I2C_SR1_RXNE) {
  161. +            if (dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) {
  162. +                /* Fill the buffer with the contents of the data register */
  163. +                dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++] = dev->regs->DR;
  164. +                dev->i2c_slave_msg->length++;
  165. +            }
  166. +            else  {
  167. +                /* Call the callback with the contents of the data */
  168. +                dev->i2c_slave_msg->data[0] = dev->regs->DR;
  169. +                if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
  170. +            }
  171. +            dev->state = I2C_STATE_SL_RX;
  172. +            sr1 = sr2 = 0;
  173. +        }
  174. +
  175. +        /* EV4: Slave has detected a STOP condition on the bus */
  176. +        if (sr1 & I2C_SR1_STOPF) {
  177. +            dev->regs->CR1 |= I2C_CR1_PE;
  178. +
  179. +            if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) ||
  180. +                (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
  181. +
  182. +                /* The callback with the data will happen on a NACK of the last data byte.
  183. +                 * This is handled in the error IRQ (AF bit)
  184. +                 */
  185. +            }
  186. +
  187. +            sr1 = sr2 = 0;
  188. +            dev->state = I2C_STATE_IDLE;
  189. +        }
  190. +
  191. +        return;
  192. +    }
  193. +    
  194.      /*
  195.       * EV5: Start condition sent
  196.       */
  197. @@ -447,6 +612,7 @@ void _i2c_irq_handler(i2c_dev *dev) {
  198.              }
  199.          }
  200.      }
  201. +
  202.  }
  203.  
  204.  /*
  205. @@ -456,10 +622,49 @@ void _i2c_irq_handler(i2c_dev *dev) {
  206.  void _i2c_irq_error_handler(i2c_dev *dev) {
  207.      I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
  208.  
  209. -    dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR |
  210. +    dev->error_flags = dev->regs->SR1 & (I2C_SR1_BERR |
  211.                                           I2C_SR1_ARLO |
  212.                                           I2C_SR1_AF |
  213.                                           I2C_SR1_OVR);
  214. +
  215. +    /* Are we in slave mode? */
  216. +    if ((dev->regs->SR2 & I2C_SR2_MSL) != I2C_SR2_MSL) {
  217. +        /* Check to see if the master device did a NAK on the last bit
  218. +         * This is perfectly valid for a master to do this on the bus.
  219. +         * We ignore this. Any further error processing takes us into dead
  220. +         * loop waiting for the stop condition that will never arrive
  221. +         */
  222. +        if (dev->regs->SR1 & I2C_SR1_AF) {
  223. +            /* Clear flags */
  224. +            dev->regs->SR1 = 0;
  225. +            dev->regs->SR2 = 0;
  226. +            /* We need to write something to CR1 to clear the flag.
  227. +             * This isn't really mentioned but seems important */
  228. +            i2c_enable_ack(dev);
  229. +
  230. +            if (dev->state == I2C_STATE_SL_RX &&
  231. +                dev->config_flags & I2C_SLAVE_USE_RX_BUFFER &&
  232. +                dev->i2c_slave_msg->xferred > 0) {
  233. +                /* Call the callback with the contents of the data */
  234. +                if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
  235. +            }
  236. +
  237. +            dev->state = I2C_STATE_IDLE;
  238. +            return;
  239. +        }
  240. +        /* Catch any other strange errors while in slave mode.
  241. +         * I have seen BERR caused by an over fast master device
  242. +         * as well as several overflows and arbitration failures.
  243. +         * We are going to reset SR flags and carry on at this point which
  244. +         * is not the best thing to do, but stops the bus locking up completely
  245. +         * If we carry on below and send the stop bit, the code spins forever */
  246. +        /* Clear flags */
  247. +        dev->regs->SR1 = 0;
  248. +        dev->regs->SR2 = 0;
  249. +        dev->state = I2C_STATE_IDLE;
  250. +        return;
  251. +    }
  252. +
  253.      /* Clear flags */
  254.      dev->regs->SR1 = 0;
  255.      dev->regs->SR2 = 0;
  256. @@ -507,3 +712,31 @@ static void set_ccr_trise(i2c_dev *dev, uint32 flags) {
  257.      i2c_set_clk_control(dev, ccr);
  258.      i2c_set_trise(dev, trise);
  259.  }
  260. +
  261. +
  262. +/**
  263. + * @brief callback for when the device acts as a slave. If using an rx buffer, this is triggered
  264. + * after the last byte, otherwise it is called for every incoming packet.
  265. + * @param dev I2C device
  266. + * @param msg The dev_msg to pass to the slave init code
  267. + * @param func The function pointer to call
  268. + */
  269. +void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func) {
  270. +    dev->i2c_slave_recv_callback = func;
  271. +    dev->i2c_slave_msg = msg;
  272. +    msg->xferred = 0;
  273. +}
  274. +
  275. +
  276. +/**
  277. + * @brief callback for when the device acts as a slave. If using a tx buffer, this is triggered
  278. + * after the device is successsfully addressed with SLA+R.
  279. + * @param dev I2C device
  280. + * @param msg The dev_msg to pass to the slave init code
  281. + * @param func The function pointer to call
  282. + */
  283. +void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func) {
  284. +    dev->i2c_slave_transmit_callback = func;
  285. +    dev->i2c_slave_msg = msg;
  286. +    msg->xferred = 0;
  287. +}
  288. diff --git a/libmaple/include/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h
  289. index ff1c313..d4eac61 100644
  290. --- a/libmaple/include/libmaple/i2c.h
  291. +++ b/libmaple/include/libmaple/i2c.h
  292. @@ -93,6 +93,7 @@ typedef struct i2c_msg {
  293.  
  294.  #define I2C_MSG_READ            0x1
  295.  #define I2C_MSG_10BIT_ADDR      0x2
  296. +
  297.      /**
  298.       * Bitwise OR of:
  299.       * - I2C_MSG_READ (write is default)
  300. @@ -197,6 +198,10 @@ typedef struct i2c_msg {
  301.  #define I2C_DUTY_16_9           0x2           // 16/9 duty ratio
  302.  /* Flag 0x4 is reserved; DO NOT USE. */
  303.  #define I2C_BUS_RESET           0x8           // Perform a bus reset
  304. +#define I2C_SLAVE_USE_RX_BUFFER 0x10          // Use a buffered message when doing a slave recv
  305. +#define I2C_SLAVE_USE_TX_BUFFER 0x20          // Use a buffered message when doing a slave transmit
  306. +#define I2C_SLAVE_DUAL_ADDRESS  0x40          // Enable the dual slave address scheme
  307. +#define I2C_SLAVE_GENERAL_CALL  0x80          // Enable the dual slave address scheme
  308.  void i2c_master_enable(i2c_dev *dev, uint32 flags);
  309.  
  310.  #define I2C_ERROR_PROTOCOL      (-1)
  311. @@ -406,6 +411,53 @@ static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
  312.      dev->regs->TRISE = trise;
  313.  }
  314.  
  315. +/* Barry Carter
  316. + * Slave support
  317. + */
  318. +
  319. +/**
  320. + * @brief Enable Dual addressing mode to allow peripheral to have 2 addresses
  321. + * @param dev I2C device
  322. +  */
  323. +static inline void i2c_slave_dual_address_enable(i2c_dev *dev) {
  324. +    dev->regs->OAR2 |= I2C_OAR2_ENDUAL;
  325. +}
  326. +
  327. +/**
  328. + * @brief Enable General Call to allow the  unit to respond on addr 0x00
  329. + * @param dev I2C device
  330. +  */
  331. +static inline void i2c_slave_general_call_enable(i2c_dev *dev) {
  332. +    dev->regs->CR1 |= I2C_CR1_ENGC;
  333. +}
  334. +
  335. +/* callback functions */
  336. +/* Callback handler for data received over the bus */
  337. +void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func);
  338. +
  339. +/* Callback handler for data being requested over the bus
  340. + * The callback function must call i2c_write to get the data over the bus
  341. + */
  342. +void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func);
  343. +
  344. +/**
  345. + * @brief Set the primary I2c slave address
  346. + * @param dev I2C device
  347. + * @param address the 8 or 10 bit i2c address
  348. +  */
  349. +static inline void i2c_slave_set_own_address(i2c_dev *dev, uint16 address) {
  350. +    dev->regs->OAR1 = address <<1;
  351. +}
  352. +
  353. +/**
  354. + * @brief Set the secondary I2c slave address
  355. + * @param dev I2C device
  356. + * @param address the 8 or 10 bit i2c address
  357. +  */
  358. +static inline void i2c_slave_set_own_address2(i2c_dev *dev, uint16 address) {
  359. +dev->regs->OAR2 = (address <<1 ) | I2C_OAR2_ENDUAL;
  360. +}
  361. +
  362.  #ifdef __cplusplus
  363.  }
  364.  #endif
  365. diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h
  366. index 17cabe3..5debcb8 100644
  367. --- a/libmaple/include/libmaple/i2c_common.h
  368. +++ b/libmaple/include/libmaple/i2c_common.h
  369. @@ -52,9 +52,12 @@ typedef enum i2c_state {
  370.      I2C_STATE_IDLE              = 1, /**< Idle */
  371.      I2C_STATE_XFER_DONE         = 2, /**< Done with transfer */
  372.      I2C_STATE_BUSY              = 3, /**< Busy */
  373. +    I2C_STATE_SL_RX             = 4, /**< Slave receiving */
  374.      I2C_STATE_ERROR             = -1 /**< Error occurred */
  375.  } i2c_state;
  376.  
  377. +typedef void (*i2c_slave_recv_callback_func)(struct i2c_msg *);
  378. +typedef void (*i2c_slave_transmit_callback_func)(struct i2c_msg *);
  379.  /**
  380.   * @brief I2C device type.
  381.   */
  382. @@ -88,6 +91,17 @@ typedef struct i2c_dev {
  383.      nvic_irq_num ev_nvic_line;  /**< Event IRQ number */
  384.      nvic_irq_num er_nvic_line;  /**< Error IRQ number */
  385.      volatile i2c_state state;   /**< Device state */
  386. +    uint32 config_flags;        /**< Configuration flags */
  387. +
  388. +    /* Barry Carter
  389. +     * Slave implementation. Callback functions in this struct allow
  390. +     * for a separate callback function for each I2C unit available onboard
  391. +     */
  392. +    i2c_slave_transmit_callback_func i2c_slave_transmit_callback;
  393. +    i2c_slave_recv_callback_func i2c_slave_recv_callback;
  394. +
  395. +    struct i2c_msg *i2c_slave_msg; /* the message that the i2c slave will use */
  396. +
  397.  } i2c_dev;
  398.  
  399.  #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement