Guest User

libmaple i2c slave code v0.3

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