aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/i2c.c51
-rw-r--r--libmaple/i2c.h43
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;
}