X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fi2c_stm32.c;h=9fd53f0128e1ea249ad28101842a9ff4517267aa;hb=8e6b1e394127c3e1635dffd1aa424b4971ef8a4f;hp=b48d251281b64bd5eee4a6e0804a82a502d496ab;hpb=d8e686668bfa23a83f2fa692d6931b144d1a2b5b;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/i2c_stm32.c b/bertos/cpu/cortex-m3/drv/i2c_stm32.c index b48d2512..9fd53f01 100644 --- a/bertos/cpu/cortex-m3/drv/i2c_stm32.c +++ b/bertos/cpu/cortex-m3/drv/i2c_stm32.c @@ -45,6 +45,7 @@ #include // BV() #include +#include #include #include #include @@ -63,16 +64,29 @@ struct I2cHardware bool cached; }; -#define WAIT_BTF(base) while( !(base->SR1 & BV(SR1_BTF)) ) -#define WAIT_RXNE(base) while( !(base->SR1 & BV(SR1_RXNE)) ) +#define WAIT_BTF(base) \ + do { \ + while (!(base->SR1 & BV(SR1_BTF))) \ + cpu_relax(); \ + } while (0) + +#define WAIT_RXNE(base) \ + do { \ + while (!(base->SR1 & BV(SR1_RXNE))) \ + cpu_relax(); \ + } while (0) INLINE uint32_t get_status(struct stm32_i2c *base) { return ((base->SR1 | (base->SR2 << 16)) & 0x00FFFFFF); } - -INLINE bool check_i2cStatus(I2c *i2c, uint32_t event) +/* + * This fuction read the status registers of the i2c device + * and waint until the selec event happen. If occur one error + * the funtions return false. + */ +INLINE bool wait_event(I2c *i2c, uint32_t event) { while (true) { @@ -84,174 +98,160 @@ INLINE bool check_i2cStatus(I2c *i2c, uint32_t event) if (stat & SR1_ERR_MASK) { i2c->hw->base->SR1 &= ~SR1_ERR_MASK; - i2c->hw->base->CR1 |= CR1_START_SET; return false; } - + cpu_relax(); } - return true; } -/** - * Send START condition on the bus. - * - * \return true on success, false otherwise. - */ -INLINE bool i2c_hw_restart(I2c *i2c) -{ - - i2c->hw->base->CR1 |= CR1_ACK_SET | CR1_START_SET; - - if(check_i2cStatus(i2c, I2C_EVENT_MASTER_MODE_SELECT)) - return true; - return false; -} - -/** - * Send STOP condition. - */ -static void i2c_hw_stop(I2c *i2c) +INLINE void start_w(struct I2c *i2c, uint16_t slave_addr) { - i2c->hw->base->CR1 |= CR1_STOP_SET; -} - -static void i2c_stm32_start(struct I2c *i2c, uint16_t slave_addr) -{ - i2c->hw->cached = false; - - if (I2C_TEST_START(i2c->flags) == I2C_START_W) - { - /* - * Loop on the select write sequence: when the eeprom is busy - * writing previously sent data it will reply to the SLA_W - * control byte with a NACK. In this case, we must - * keep trying until the eeprom responds with an ACK. - */ - ticks_t start = timer_clock(); - while (i2c_hw_restart(i2c)) - { - i2c->hw->base->DR = slave_addr & OAR1_ADD0_RESET; - - if(check_i2cStatus(i2c, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) - break; - - if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT)) - { - LOG_ERR("Timeout on I2C START\n"); - i2c->errors |= I2C_NO_ACK; - i2c_hw_stop(i2c); - break; - } - } - - } - else if (I2C_TEST_START(i2c->flags) == I2C_START_R) + /* + * Loop on the select write sequence: when the eeprom is busy + * writing previously sent data it will reply to the SLA_W + * control byte with a NACK. In this case, we must + * keep trying until the eeprom responds with an ACK. + */ + ticks_t start = timer_clock(); + while (true) { - i2c->hw->base->CR1 |= CR1_START_SET; + i2c->hw->base->CR1 |= CR1_ACK_SET | CR1_START_SET; - if(!check_i2cStatus(i2c, I2C_EVENT_MASTER_MODE_SELECT)) + if(!wait_event(i2c, I2C_EVENT_MASTER_MODE_SELECT)) { LOG_ERR("ARBIT lost\n"); i2c->errors |= I2C_ARB_LOST; - i2c_hw_stop(i2c); - return; + break; } - i2c->hw->base->DR = (slave_addr | OAR1_ADD0_SET); + i2c->hw->base->DR = slave_addr & OAR1_ADD0_RESET; - if (i2c->xfer_size == 2) - i2c->hw->base->CR1 |= CR1_ACK_SET | CR1_POS_SET; + if(wait_event(i2c, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + break; - if(!check_i2cStatus(i2c, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) + if (timer_clock() - start > ms_to_ticks(CONFIG_I2C_START_TIMEOUT)) { - LOG_ERR("SLAR NACK:%08lx\n", get_status(i2c->hw->base)); - i2c->errors |= I2C_NO_ACK; - i2c_hw_stop(i2c); - return; + LOG_ERR("Timeout on I2C START\n"); + i2c->errors |= I2C_START_TIMEOUT; + i2c->hw->base->CR1 |= CR1_STOP_SET; + break; } + } +} +INLINE bool start_and_addr(struct I2c *i2c, uint16_t slave_addr) +{ + i2c->hw->base->CR1 |= CR1_START_SET; + if(!wait_event(i2c, I2C_EVENT_MASTER_MODE_SELECT)) + { + LOG_ERR("ARBIT lost\n"); + i2c->errors |= I2C_ARB_LOST; + i2c->hw->base->CR1 |= CR1_STOP_SET; + return false; + } - if (i2c->xfer_size == 1) - { - i2c->hw->base->CR1 &= CR1_ACK_RESET; - - cpu_flags_t irq; - IRQ_SAVE_DISABLE(irq); - - (void)i2c->hw->base->SR2; - - if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) - i2c->hw->base->CR1 |= CR1_STOP_SET; - - IRQ_RESTORE(irq); + i2c->hw->base->DR = (slave_addr | OAR1_ADD0_SET); - WAIT_RXNE(i2c->hw->base); + if (i2c->xfer_size == 2) + i2c->hw->base->CR1 |= CR1_ACK_SET | CR1_POS_SET; - i2c->hw->cache[0] = i2c->hw->base->DR; - i2c->hw->cached = true; + if(!wait_event(i2c, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) + { + LOG_ERR("SLAR NACK:%08lx\n", get_status(i2c->hw->base)); + i2c->errors |= I2C_NO_ACK; + i2c->hw->base->CR1 |= CR1_STOP_SET; + return false; + } - if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) - while (i2c->hw->base->CR1 & CR1_STOP_SET); + return true; +} - i2c->hw->base->CR1 |= CR1_ACK_SET; +INLINE void start_r(struct I2c *i2c, uint16_t slave_addr) +{ + if (!start_and_addr(i2c, slave_addr)) + return; + /* + * Due to the hardware receive bytes from slave in automatically mode + * we should manage contextually all cases that we want to read one, two or more + * than two bytes. To comply this behaviour to our api we shoul bufferd some byte + * to hide all special case that needs to use this device. + */ + if (i2c->xfer_size == 1) + { + i2c->hw->base->CR1 &= CR1_ACK_RESET; - } - else if (i2c->xfer_size == 2) - { - cpu_flags_t irq; - IRQ_SAVE_DISABLE(irq); + cpu_flags_t irq; - (void)i2c->hw->base->SR2; + IRQ_SAVE_DISABLE(irq); + (void)i2c->hw->base->SR2; + if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) + i2c->hw->base->CR1 |= CR1_STOP_SET; + IRQ_RESTORE(irq); - i2c->hw->base->CR1 &= CR1_ACK_RESET; + WAIT_RXNE(i2c->hw->base); - IRQ_RESTORE(irq); + i2c->hw->cache[0] = i2c->hw->base->DR; + i2c->hw->cached = true; - WAIT_BTF(i2c->hw->base); + if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) + while (i2c->hw->base->CR1 & CR1_STOP_SET); - IRQ_SAVE_DISABLE(irq); + i2c->hw->base->CR1 |= CR1_ACK_SET; + } + else if (i2c->xfer_size == 2) + { + cpu_flags_t irq; - if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) - i2c->hw->base->CR1 |= CR1_STOP_SET; + IRQ_SAVE_DISABLE(irq); + (void)i2c->hw->base->SR2; + i2c->hw->base->CR1 &= CR1_ACK_RESET; + IRQ_RESTORE(irq); - /* - * We store read bytes like a fifo.. - */ - i2c->hw->cache[1] = i2c->hw->base->DR; - i2c->hw->cache[0] = i2c->hw->base->DR; - i2c->hw->cached = true; + WAIT_BTF(i2c->hw->base); - IRQ_RESTORE(irq); + IRQ_SAVE_DISABLE(irq); + if (I2C_TEST_STOP(i2c->flags) == I2C_STOP) + i2c->hw->base->CR1 |= CR1_STOP_SET; + /* + * We store read bytes like a fifo.. + */ + i2c->hw->cache[1] = i2c->hw->base->DR; + i2c->hw->cache[0] = i2c->hw->base->DR; + i2c->hw->cached = true; + IRQ_RESTORE(irq); - i2c->hw->base->CR1 &= CR1_POS_RESET; - i2c->hw->base->CR1 |= CR1_ACK_SET; - } - } - else - { - ASSERT(0); + i2c->hw->base->CR1 &= CR1_POS_RESET; + i2c->hw->base->CR1 |= CR1_ACK_SET; } +} +static void i2c_stm32_start(struct I2c *i2c, uint16_t slave_addr) +{ + i2c->hw->cached = false; + + if (I2C_TEST_START(i2c->flags) == I2C_START_W) + start_w(i2c, slave_addr); + else /* (I2C_TEST_START(i2c->flags) == I2C_START_R) */ + start_r(i2c, slave_addr); } -static void i2c_stm32_put(I2c *i2c, const uint8_t data) +static void i2c_stm32_putc(I2c *i2c, const uint8_t data) { i2c->hw->base->DR = data; WAIT_BTF(i2c->hw->base); - /* Generate the stop if we finish to send all programmed bytes */ - if ((i2c->xfer_size == 1) &&(I2C_TEST_STOP(i2c->flags) == I2C_STOP)) + if ((i2c->xfer_size == 1) && (I2C_TEST_STOP(i2c->flags) == I2C_STOP)) { - check_i2cStatus(i2c, I2C_EVENT_MASTER_BYTE_TRANSMITTED); - i2c_hw_stop(i2c); + wait_event(i2c, I2C_EVENT_MASTER_BYTE_TRANSMITTED); + i2c->hw->base->CR1 |= CR1_STOP_SET; } } -static uint8_t i2c_stm32_get(I2c *i2c) +static uint8_t i2c_stm32_getc(I2c *i2c) { if (i2c->hw->cached) { @@ -297,13 +297,13 @@ static uint8_t i2c_stm32_get(I2c *i2c) static const I2cVT i2c_stm32_vt = { .start = i2c_stm32_start, - .get = i2c_stm32_get, - .put = i2c_stm32_put, - .send = i2c_swSend, - .recv = i2c_swRecv, + .getc = i2c_stm32_getc, + .putc = i2c_stm32_putc, + .write = i2c_genericWrite, + .read = i2c_genericRead, }; -struct I2cHardware i2c_stm32_hw[] = +static struct I2cHardware i2c_stm32_hw[] = { { /* I2C1 */ .base = (struct stm32_i2c *)I2C1_BASE, @@ -317,8 +317,6 @@ struct I2cHardware i2c_stm32_hw[] = }, }; -MOD_DEFINE(i2c); - /** * Initialize I2C module. */ @@ -352,6 +350,4 @@ void i2c_hw_init(I2c *i2c, int dev, uint32_t clock) i2c->hw->base->TRISE |= (CR2_FREQ_36MHZ + 1); i2c->hw->base->CR1 |= CR1_PE_SET; - - MOD_INIT(i2c); }