aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmaple/i2c.c51
-rw-r--r--libmaple/i2c.h43
-rw-r--r--main.cpp73
-rw-r--r--wirish/wirish.c24
4 files changed, 117 insertions, 74 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;
}
diff --git a/main.cpp b/main.cpp
index 7771fa7..db310c0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,12 +1,13 @@
// Sample i2c master example for development i2c branch. Writes 0-63 to
// addresses 0-63 on a 24LC256 EEPROM, then reads them back.
+#include <string.h>
#include "wirish.h"
#include "i2c.h"
static const uint8 slave_address = 0b1010001;
-#define NR_ELEMENTS 4
+#define NR_ELEMENTS 64
uint8 buf0[NR_ELEMENTS + 2] = {0x0, 0x0};
uint8 buf1[] = {0x0, 0x0};
uint8 buf2[NR_ELEMENTS];
@@ -19,12 +20,15 @@ void toggle(void) {
}
void setup() {
+ uint32 bytes = 1;
uint32 i;
+ int32 rc = -1;
pinMode(BOARD_LED_PIN, OUTPUT);
- pinMode(2, OUTPUT);
Serial2.begin(9600);
Serial2.println("Hello!");
+
+ pinMode(2, OUTPUT);
digitalWrite(2, LOW);
for (i = 2; i < sizeof buf0; i++) {
@@ -33,31 +37,54 @@ void setup() {
i2c_master_enable(I2C1, 0);
- /* Write some bytes */
- msgs[0].addr = slave_address;
- msgs[0].flags = 0;
- msgs[0].length = sizeof buf0;
- msgs[0].data = buf0;
- i2c_master_xfer(I2C1, msgs, 1);
- delay(5);
-
+ while (bytes < 64) {
+ Serial2.print("Writing ");
+ Serial2.print(bytes);
+ Serial2.print(" bytes...");
+
+ /* Write test pattern */
+ msgs[0].addr = slave_address;
+ msgs[0].flags = 0;
+ msgs[0].length = 2+ bytes;
+ msgs[0].data = buf0;
+ i2c_master_xfer(I2C1, msgs, 1);
+ delay(5);
+
+ /* Read it back */
+ msgs[1].addr = slave_address;
+ msgs[1].flags = 0;
+ msgs[1].length = 2;
+ msgs[1].data = buf1;
+ /* Repeated start condition */
+ msgs[2].addr = slave_address;
+ msgs[2].flags = I2C_MSG_READ;
+ msgs[2].length = bytes;
+ msgs[2].data = buf2;
+ i2c_master_xfer(I2C1, msgs + 1, 2);
+
+ /* Compare */
+ rc = memcmp(&buf0[2], buf2, bytes);
+ if (rc == 0) {
+ Serial2.println("good!");
+ } else {
+ Serial2.println("failed!");
+ }
+
+ delay(5);
+ bytes++;
+ }
}
+int32 rc;
+
void loop() {
- delay(100);
toggleLED();
- /* Write slave address to read */
- msgs[1].addr = slave_address;
- msgs[1].flags = 0;
- msgs[1].length = 2;
- msgs[1].data = buf1;
-
- /* Repeated start condition, then read NR_ELEMENTS bytes back */
- msgs[2].addr = slave_address;
- msgs[2].flags = I2C_MSG_READ;
- msgs[2].length = sizeof buf2;
- msgs[2].data = buf2;
- i2c_master_xfer(I2C1, msgs + 1, 2);
+ delay(100);
+ rc = i2c_master_xfer(I2C1, msgs + 1, 2);
+ if (rc < 0) {
+ Serial2.println("Failed transfer!");
+ i2c_master_enable(I2C1, 0);
+ }
}
// Force init to be called *first*, i.e. before static object allocation.
diff --git a/wirish/wirish.c b/wirish/wirish.c
index 4c84d26..2b128f1 100644
--- a/wirish/wirish.c
+++ b/wirish/wirish.c
@@ -63,18 +63,18 @@ void init(void) {
/* Initialize the ADC for slow conversions, to allow for high
impedance inputs. */
- adc_init(ADC1, 0);
- adc_set_sample_rate(ADC1, ADC_SMPR_55_5);
-
- timer_init(TIMER1, 1);
- timer_init(TIMER2, 1);
- timer_init(TIMER3, 1);
- timer_init(TIMER4, 1);
-#ifdef STM32_HIGH_DENSITY
- timer_init(TIMER5, 1);
- timer_init(TIMER8, 1);
-#endif
- setupUSB();
+// adc_init(ADC1, 0);
+// adc_set_sample_rate(ADC1, ADC_SMPR_55_5);
+//
+// timer_init(TIMER1, 1);
+// timer_init(TIMER2, 1);
+// timer_init(TIMER3, 1);
+// timer_init(TIMER4, 1);
+//#ifdef STM32_HIGH_DENSITY
+// timer_init(TIMER5, 1);
+// timer_init(TIMER8, 1);
+//#endif
+// setupUSB();
/* include the board-specific init macro */
BOARD_INIT;