diff options
author | Perry Hung <iperry@gmail.com> | 2011-03-14 18:37:56 -0400 |
---|---|---|
committer | Perry Hung <iperry@gmail.com> | 2011-03-14 22:52:06 -0400 |
commit | 334de50c49317f281d87f44e7b9278e08af19254 (patch) | |
tree | 2aa29c4f6aecb60c2f4ce5964d876745b1757d60 /libmaple | |
parent | 9872b3975bd40c55652bb9dead5f54e2be9740d0 (diff) | |
download | librambutan-334de50c49317f281d87f44e7b9278e08af19254.tar.gz librambutan-334de50c49317f281d87f44e7b9278e08af19254.zip |
Add rudimentary error handling for nack condition
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/i2c.c | 51 | ||||
-rw-r--r-- | libmaple/i2c.h | 43 |
2 files changed, 55 insertions, 39 deletions
diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 3e948f6..8bd252c 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -23,9 +23,7 @@ * ****************************************************************************/ /** - * @brief - * TODO: Rejigger hard fault handler and error throbs to turn off all - * interrupts and jump to error throb to reenable usb bootloader + * @brief */ #include "libmaple.h" @@ -36,12 +34,6 @@ #include "i2c.h" #include "string.h" -/* 2/17 Started 10pm-4am - * 2/19 Started 7pm-2am - * 2/20 Started 7pm-7pm - * 2/23 Started 8pm-8am - * 3/9 Started 11pm */ - static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state); static i2c_dev i2c_dev1 = { @@ -57,22 +49,18 @@ static i2c_dev i2c_dev1 = { i2c_dev* const I2C1 = &i2c_dev1; -/** - * @brief IRQ handler for i2c master. Handles transmission/reception. - * @param dev i2c device - */ - struct crumb { uint32 event; uint32 sr1; uint32 sr2; }; -static struct crumb crumbs[100]; +#define NR_CRUMBS 128 +static struct crumb crumbs[NR_CRUMBS]; static uint32 cur_crumb = 0; static inline void leave_big_crumb(uint32 event, uint32 sr1, uint32 sr2) { - if (cur_crumb < 100) { + if (cur_crumb < NR_CRUMBS) { struct crumb *crumb = &crumbs[cur_crumb++]; crumb->event = event; crumb->sr1 = sr1; @@ -93,8 +81,13 @@ enum { RXNE_START_SENT = 10, RXNE_STOP_SENT = 11, RXNE_DONE = 12, + ERROR_ENTRY = 13, }; +/** + * @brief IRQ handler for i2c master. Handles transmission/reception. + * @param dev i2c device + */ static void i2c_irq_handler(i2c_dev *dev) { i2c_msg *msg = dev->msg; @@ -117,6 +110,7 @@ static void i2c_irq_handler(i2c_dev *dev) { if (read) { i2c_enable_ack(dev); } + i2c_send_slave_addr(dev, msg->addr, read); sr1 = sr2 = 0; } @@ -133,8 +127,7 @@ static void i2c_irq_handler(i2c_dev *dev) { if (read) { if (msg->length == 1) { i2c_disable_ack(dev); - dev->msgs_left--; - if (dev->msgs_left) { + if (dev->msgs_left > 1) { i2c_start_condition(dev); leave_big_crumb(RX_ADDR_START, 0, 0); } else { @@ -197,9 +190,7 @@ static void i2c_irq_handler(i2c_dev *dev) { dev->msg++; } else { i2c_stop_condition(dev); -// while (dev->regs->CR1 & I2C_CR1_STOP) { -// ; -// } + /* * Turn off event interrupts to keep BTF from firing until the end * of the stop condition. Why on earth they didn't have a start/stop @@ -253,7 +244,13 @@ void __irq_i2c1_ev(void) { } static void i2c_irq_error_handler(i2c_dev *dev) { - __error(); + uint32 sr1 = dev->regs->SR1; + uint32 sr2 = dev->regs->SR2; + leave_big_crumb(ERROR_ENTRY, sr1, sr2); + + i2c_stop_condition(dev); + i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR); + dev->state = I2C_STATE_ERROR; } void __irq_i2c1_er(void) { @@ -330,7 +327,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); - i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); + nvic_irq_enable(dev->er_nvic_line); + i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); /* * Important STM32 Errata: @@ -360,6 +358,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { * been initialized to priority level 16. See nvic_init(). */ nvic_irq_set_priority(dev->ev_nvic_line, 0); + nvic_irq_set_priority(dev->er_nvic_line, 0); /* Make it go! */ i2c_peripheral_enable(dev); @@ -372,15 +371,11 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { dev->msg = msgs; dev->msgs_left = num; - memset(crumbs, 0, sizeof crumbs); - - dev->regs->CR2 |= I2C_CR2_ITEVTEN; - - /* Is this necessary? */ while (dev->regs->SR2 & I2C_SR2_BUSY) ; dev->state = I2C_STATE_BUSY; + i2c_enable_irq(dev, I2C_IRQ_EVENT); i2c_start_condition(dev); rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index be05615..a9e2c7b 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -136,17 +136,13 @@ extern "C" { void i2c_master_enable(i2c_dev *dev, uint32 flags); int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); -static inline void i2c_write(i2c_dev *dev, uint8 byte) { - dev->regs->DR = byte; -} - /* * Low level register twiddling functions */ /** * @brief turn on an i2c peripheral - * @param map i2c peripheral register base + * @param dev i2c device */ static inline void i2c_peripheral_enable(i2c_dev *dev) { dev->regs->CR1 |= I2C_CR1_PE; @@ -154,15 +150,25 @@ static inline void i2c_peripheral_enable(i2c_dev *dev) { /** * @brief turn off an i2c peripheral - * @param map i2c peripheral register base + * @param dev i2c device */ static inline void i2c_peripheral_disable(i2c_dev *dev) { dev->regs->CR1 &= ~I2C_CR1_PE; } /** + * @brief Fill transmit register + * @param dev i2c device + * @param byte byte to write + */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + + +/** * @brief Set input clock frequency, in mhz - * @param device to configure + * @param dev i2c * @param freq frequency in megahertz (2-36) */ static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { @@ -172,6 +178,13 @@ static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { dev->regs->CR2 = freq; } + +/** + * @brief Set i2c clock control register. See RM008 + * @param dev i2c device + * @return + * @sideeffect + */ static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { uint32 ccr = dev->regs->CCR; ccr &= ~I2C_CCR_CCR; @@ -195,15 +208,23 @@ static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { dev->regs->TRISE = trise; } -extern void toggle(void); static inline void i2c_start_condition(i2c_dev *dev) { - uint32 cr1 = dev->regs->CR1; -// if (cr1 & (I2C_CR1_START | I2C_CR1_STOP | I2C_CR1_PEC)) { -// } + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } dev->regs->CR1 |= I2C_CR1_START; } static inline void i2c_stop_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } dev->regs->CR1 |= I2C_CR1_STOP; } |