aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmaple/delay.h22
-rw-r--r--libmaple/i2c.c168
-rw-r--r--libmaple/i2c.h116
-rw-r--r--libmaple/libmaple.h2
-rw-r--r--libmaple/rcc.c2
-rw-r--r--libmaple/stm32.h10
-rw-r--r--main.cpp28
-rw-r--r--wirish/time.c13
8 files changed, 186 insertions, 175 deletions
diff --git a/libmaple/delay.h b/libmaple/delay.h
new file mode 100644
index 0000000..10839c9
--- /dev/null
+++ b/libmaple/delay.h
@@ -0,0 +1,22 @@
+/**
+ * @brief
+ */
+
+#ifndef _DELAY_H_
+#define _DELAY_H_
+
+static inline void delay_us(uint32 us) {
+ /* So (2^32)/12 micros max, or less than 6 minutes */
+ us *= 12;
+
+ /* fudge for function call overhead */
+ us--;
+ asm volatile(" mov r0, %[us] \n\t"
+ "1: subs r0, #1 \n\t"
+ " bhi 1b \n\t"
+ :
+ : [us] "r" (us)
+ : "r0");
+}
+#endif
+
diff --git a/libmaple/i2c.c b/libmaple/i2c.c
index 1a595f5..3e948f6 100644
--- a/libmaple/i2c.c
+++ b/libmaple/i2c.c
@@ -39,11 +39,12 @@
/* 2/17 Started 10pm-4am
* 2/19 Started 7pm-2am
* 2/20 Started 7pm-7pm
- * 2/23 Started 8pm */
+ * 2/23 Started 8pm-8am
+ * 3/9 Started 11pm */
static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state);
-i2c_dev i2c_dev1 = {
+static i2c_dev i2c_dev1 = {
.regs = (i2c_reg_map*)I2C1_BASE,
.gpio_port = GPIOB_BASE,
.sda_pin = 7,
@@ -54,30 +55,13 @@ i2c_dev i2c_dev1 = {
.state = I2C_STATE_IDLE
};
+i2c_dev* const I2C1 = &i2c_dev1;
+
/**
* @brief IRQ handler for i2c master. Handles transmission/reception.
* @param dev i2c device
*/
-void delay_us(uint32 us) {
- /* So (2^32)/12 micros max, or less than 6 minutes */
- us *= 12;
-
- /* fudge for function call overhead */
- us--;
- asm volatile(" mov r0, %[us] \n\t"
- "1: subs r0, #1 \n\t"
- " bhi 1b \n\t"
- :
- : [us] "r" (us)
- : "r0");
-}
-static inline void debug_toggle(uint32 delay) {
- gpio_write_bit(GPIOA_BASE, 5, 1);
- delay_us(delay);
- gpio_write_bit(GPIOA_BASE, 5, 0);
-}
-
struct crumb {
uint32 event;
uint32 sr1;
@@ -125,15 +109,15 @@ static void i2c_irq_handler(i2c_dev *dev) {
*/
if (sr1 & I2C_SR1_SB) {
msg->xferred = 0;
- i2c_enable_irq(dev->regs, I2C_IRQ_BUFFER);
+ i2c_enable_irq(dev, I2C_IRQ_BUFFER);
/*
* Master receiver
*/
if (read) {
- i2c_enable_ack(dev->regs);
+ i2c_enable_ack(dev);
}
- i2c_send_slave_addr(dev->regs, msg->addr, read);
+ i2c_send_slave_addr(dev, msg->addr, read);
sr1 = sr2 = 0;
}
@@ -148,13 +132,13 @@ static void i2c_irq_handler(i2c_dev *dev) {
*/
if (read) {
if (msg->length == 1) {
- i2c_disable_ack(dev->regs);
+ i2c_disable_ack(dev);
dev->msgs_left--;
if (dev->msgs_left) {
- i2c_start_condition(dev->regs);
+ i2c_start_condition(dev);
leave_big_crumb(RX_ADDR_START, 0, 0);
} else {
- i2c_stop_condition(dev->regs);
+ i2c_stop_condition(dev);
leave_big_crumb(RX_ADDR_STOP, 0, 0);
}
}
@@ -163,7 +147,7 @@ static void i2c_irq_handler(i2c_dev *dev) {
* Master transmitter: write first byte to fill shift register.
* We should get another TXE interrupt immediately to fill DR again.
*/
- i2c_write(dev->regs, msg->data[msg->xferred++]);
+ i2c_write(dev, msg->data[msg->xferred++]);
}
sr1 = sr2 = 0;
}
@@ -176,13 +160,13 @@ static void i2c_irq_handler(i2c_dev *dev) {
if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) {
leave_big_crumb(TXE_ONLY, 0, 0);
if (dev->msgs_left) {
- i2c_write(dev->regs, msg->data[msg->xferred++]);
+ i2c_write(dev, msg->data[msg->xferred++]);
if (msg->xferred == msg->length) {
/*
* End of this message. Turn off TXE/RXNE and wait for
* BTF to send repeated start or stop condition.
*/
- i2c_disable_irq(dev->regs, I2C_IRQ_BUFFER);
+ i2c_disable_irq(dev, I2C_IRQ_BUFFER);
dev->msgs_left--;
}
} else {
@@ -207,18 +191,21 @@ static void i2c_irq_handler(i2c_dev *dev) {
* won't interrupt, but if we don't disable ITEVTEN, BTF will
* continually interrupt us. What the fuck ST?
*/
- i2c_start_condition(dev->regs);
+ i2c_start_condition(dev);
while (!(dev->regs->SR1 & I2C_SR1_SB))
;
dev->msg++;
} else {
- i2c_stop_condition(dev->regs);
+ 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
* condition request clear BTF is beyond me.
*/
- i2c_disable_irq(dev->regs, I2C_IRQ_EVENT);
+ i2c_disable_irq(dev, I2C_IRQ_EVENT);
leave_big_crumb(STOP_SENT, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
}
@@ -238,12 +225,12 @@ static void i2c_irq_handler(i2c_dev *dev) {
* RXNE interrupt before shutting things down.
*/
if (msg->xferred == (msg->length - 1)) {
- i2c_disable_ack(dev->regs);
+ i2c_disable_ack(dev);
if (dev->msgs_left > 2) {
- i2c_start_condition(dev->regs);
+ i2c_start_condition(dev);
leave_big_crumb(RXNE_START_SENT, 0, 0);
} else {
- i2c_stop_condition(dev->regs);
+ i2c_stop_condition(dev);
leave_big_crumb(RXNE_STOP_SENT, 0, 0);
}
} else if (msg->xferred == msg->length) {
@@ -262,11 +249,18 @@ static void i2c_irq_handler(i2c_dev *dev) {
}
void __irq_i2c1_ev(void) {
- i2c_dev *dev = I2C1;
- i2c_irq_handler(dev);
+ i2c_irq_handler(&i2c_dev1);
+}
+
+static void i2c_irq_error_handler(i2c_dev *dev) {
+ __error();
}
-static void i2c_bus_reset(i2c_dev *dev) {
+void __irq_i2c1_er(void) {
+ i2c_irq_error_handler(&i2c_dev1);
+}
+
+static void i2c_bus_reset(const i2c_dev *dev) {
/* Release both lines */
gpio_write_bit(dev->gpio_port, dev->scl_pin, 1);
gpio_write_bit(dev->gpio_port, dev->sda_pin, 1);
@@ -322,21 +316,21 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_MODE_AF_OUTPUT_OD);
/* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */
- i2c_set_input_clk(dev->regs, 36);
+ i2c_set_input_clk(dev, 36);
/* 100 khz only for now */
- i2c_set_clk_control(dev->regs, STANDARD_CCR);
+ i2c_set_clk_control(dev, STANDARD_CCR);
/*
* Set scl rise time, standard mode for now.
* Max rise time in standard mode: 1000 ns
* Max rise time in fast mode: 300ns
*/
- i2c_set_trise(dev->regs, STANDARD_TRISE);
+ i2c_set_trise(dev, STANDARD_TRISE);
/* Enable event and buffer interrupts */
nvic_irq_enable(dev->ev_nvic_line);
- i2c_enable_irq(dev->regs, I2C_IRQ_EVENT | I2C_IRQ_BUFFER);
+ i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER);
/*
* Important STM32 Errata:
@@ -368,13 +362,12 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
nvic_irq_set_priority(dev->ev_nvic_line, 0);
/* Make it go! */
- i2c_peripheral_enable(dev->regs);
+ i2c_peripheral_enable(dev);
}
int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) {
int32 rc;
- static int times = 0;
dev->msg = msgs;
dev->msgs_left = num;
@@ -389,7 +382,7 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) {
dev->state = I2C_STATE_BUSY;
- i2c_start_condition(dev->regs);
+ i2c_start_condition(dev);
rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE);
if (rc < 0) {
goto out;
@@ -414,89 +407,6 @@ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) {
}
-/*
- * Low level register twiddling functions
- */
-
-/**
- * @brief turn on an i2c peripheral
- * @param map i2c peripheral register base
- */
-void i2c_peripheral_enable(i2c_reg_map *regs) {
- regs->CR1 |= I2C_CR1_PE;
-}
-
-/**
- * @brief turn off an i2c peripheral
- * @param map i2c peripheral register base
- */
-void i2c_peripheral_disable(i2c_reg_map *regs) {
- regs->CR1 &= ~I2C_CR1_PE;
-}
-
-/**
- * @brief Set input clock frequency, in mhz
- * @param device to configure
- * @param freq frequency in megahertz (2-36)
- */
-void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq) {
- uint32 cr2 = regs->CR2;
- cr2 &= ~I2C_CR2_FREQ;
- cr2 |= freq;
- regs->CR2 = freq;
-}
-
-void i2c_set_clk_control(i2c_reg_map *regs, uint32 val) {
- uint32 ccr = regs->CCR;
- ccr &= ~I2C_CCR_CCR;
- ccr |= val;
- regs->CCR = ccr;
-}
-
-void i2c_set_fast_mode(i2c_reg_map *regs) {
- regs->CCR |= I2C_CCR_FS;
-}
-
-void i2c_set_standard_mode(i2c_reg_map *regs) {
- regs->CCR &= ~I2C_CCR_FS;
-}
-
-/**
- * @brief Set SCL rise time
- * @param
- */
-
-void i2c_set_trise(i2c_reg_map *regs, uint32 trise) {
- regs->TRISE = trise;
-}
-
-void i2c_start_condition(i2c_reg_map *regs) {
- regs->CR1 |= I2C_CR1_START;
-}
-
-void i2c_stop_condition(i2c_reg_map *regs) {
- regs->CR1 |= I2C_CR1_STOP;
-}
-
-void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw) {
- regs->DR = (addr << 1) | rw;
-}
-
-void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs) {
- regs->CR2 |= irqs;
-}
-
-void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs) {
- regs->CR2 &= ~irqs;
-}
-
-void i2c_enable_ack(i2c_reg_map *regs) {
- regs->CR1 |= I2C_CR1_ACK;
-}
-
-void i2c_disable_ack(i2c_reg_map *regs) {
- regs->CR1 &= ~I2C_CR1_ACK;
-}
diff --git a/libmaple/i2c.h b/libmaple/i2c.h
index 2e6d00d..be05615 100644
--- a/libmaple/i2c.h
+++ b/libmaple/i2c.h
@@ -72,14 +72,10 @@ typedef struct i2c_dev {
} i2c_dev;
-extern i2c_dev i2c_dev1;
-extern i2c_dev i2c_dev2;
+extern i2c_dev* const I2C1;
-#define I2C1 (i2c_dev*)&i2c_dev1
-#define I2C2 (i2c_dev*)&i2c_dev2
-
-#define I2C1_BASE 0x40005400
-#define I2C2_BASE 0x40005800
+#define I2C1_BASE (i2c_reg_map*)0x40005400
+#define I2C2_BASE (i2c_reg_map*)0x40005800
/* i2c enable options */
#define I2C_FAST_MODE 0x1 // 400 khz
@@ -140,28 +136,98 @@ extern "C" {
void i2c_master_enable(i2c_dev *dev, uint32 flags);
int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num);
-void i2c_start_condition(i2c_reg_map *regs);
-void i2c_stop_condition(i2c_reg_map *regs);
-void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw);
-void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq);
-void i2c_set_clk_control(i2c_reg_map *regs, uint32 val);
-void i2c_set_fast_mode(i2c_reg_map *regs);
-void i2c_set_standard_mode(i2c_reg_map *regs);
-void i2c_set_trise(i2c_reg_map *regs, uint32 trise);
-void i2c_enable_ack(i2c_reg_map *regs);
-void i2c_disable_ack(i2c_reg_map *regs);
-
-/* interrupt flags */
+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
+ */
+static inline void i2c_peripheral_enable(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief turn off an i2c peripheral
+ * @param map i2c peripheral register base
+ */
+static inline void i2c_peripheral_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+}
+
+/**
+ * @brief Set input clock frequency, in mhz
+ * @param device to configure
+ * @param freq frequency in megahertz (2-36)
+ */
+static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
+ uint32 cr2 = dev->regs->CR2;
+ cr2 &= ~I2C_CR2_FREQ;
+ cr2 |= freq;
+ dev->regs->CR2 = freq;
+}
+
+static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
+ uint32 ccr = dev->regs->CCR;
+ ccr &= ~I2C_CCR_CCR;
+ ccr |= val;
+ dev->regs->CCR = ccr;
+}
+
+static inline void i2c_set_fast_mode(i2c_dev *dev) {
+ dev->regs->CCR |= I2C_CCR_FS;
+}
+
+static inline void i2c_set_standard_mode(i2c_dev *dev) {
+ dev->regs->CCR &= ~I2C_CCR_FS;
+}
+
+/**
+ * @brief Set SCL rise time
+ * @param
+ */
+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)) {
+// }
+ dev->regs->CR1 |= I2C_CR1_START;
+}
+
+static inline void i2c_stop_condition(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_STOP;
+}
+
+static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
+ dev->regs->DR = (addr << 1) | rw;
+}
+
#define I2C_IRQ_ERROR I2C_CR2_ITERREN
#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
-void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs);
-void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs);
-void i2c_peripheral_enable(i2c_reg_map *regs);
-void i2c_peripheral_disable(i2c_reg_map *regs);
+static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
+ dev->regs->CR2 |= irqs;
+}
+
+static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
+ dev->regs->CR2 &= ~irqs;
+}
+
+static inline void i2c_enable_ack(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_ACK;
+}
-static inline void i2c_write(i2c_reg_map *regs, uint8 byte) {
- regs->DR = byte;
+static inline void i2c_disable_ack(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_ACK;
}
#ifdef __cplusplus
diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h
index 6b75c96..50887bc 100644
--- a/libmaple/libmaple.h
+++ b/libmaple/libmaple.h
@@ -31,7 +31,9 @@
#define _LIBMAPLE_H_
#include "libmaple_types.h"
+#include "stm32.h"
#include "util.h"
+#include "delay.h"
/*
* Where to put usercode, based on space reserved for bootloader.
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index d3fb6a3..6445958 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -75,7 +75,7 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
[RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only
[RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
- [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}
+ [RCC_BKP] = { .clk_domain = APB1, .line_num = 27},
[RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, // High-density only
[RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, // High-density only
};
diff --git a/libmaple/stm32.h b/libmaple/stm32.h
index e65b28c..21c18df 100644
--- a/libmaple/stm32.h
+++ b/libmaple/stm32.h
@@ -8,5 +8,15 @@
#define PCLK1 36000000U
#define PCLK2 72000000U
+#ifdef STM32_MEDIUM_DENSITY
+ #define NR_INTERRUPTS 43
+#else
+#ifdef STM32_HIGH_DENSITY
+ #define NR_INTERRUPTS 60
+#else
+#error "No STM32 board type defined!"
+#endif
+#endif
+
#endif
diff --git a/main.cpp b/main.cpp
index 5e3ddf3..7771fa7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -6,19 +6,29 @@
static const uint8 slave_address = 0b1010001;
-#define NR_ELEMENTS 64
+#define NR_ELEMENTS 4
uint8 buf0[NR_ELEMENTS + 2] = {0x0, 0x0};
uint8 buf1[] = {0x0, 0x0};
uint8 buf2[NR_ELEMENTS];
+i2c_msg msgs[3];
+
+void toggle(void) {
+ digitalWrite(2, HIGH);
+ digitalWrite(2, LOW);
+}
+
void setup() {
- i2c_msg msgs[3];
uint32 i;
pinMode(BOARD_LED_PIN, OUTPUT);
+ pinMode(2, OUTPUT);
+ Serial2.begin(9600);
+ Serial2.println("Hello!");
+ digitalWrite(2, LOW);
- for (i = 0; i < sizeof buf0; i++) {
- buf0[i + 2] = i & 0xFF;
+ for (i = 2; i < sizeof buf0; i++) {
+ buf0[i] = i - 2;
}
i2c_master_enable(I2C1, 0);
@@ -31,6 +41,11 @@ void setup() {
i2c_master_xfer(I2C1, msgs, 1);
delay(5);
+}
+
+void loop() {
+ delay(100);
+ toggleLED();
/* Write slave address to read */
msgs[1].addr = slave_address;
msgs[1].flags = 0;
@@ -45,11 +60,6 @@ void setup() {
i2c_master_xfer(I2C1, msgs + 1, 2);
}
-void loop() {
- toggleLED();
- delay(100);
-}
-
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated object that need libmaple may fail.
__attribute__(( constructor )) void premain() {
diff --git a/wirish/time.c b/wirish/time.c
index c0a0649..b5663b0 100644
--- a/wirish/time.c
+++ b/wirish/time.c
@@ -29,6 +29,7 @@
#include "libmaple.h"
#include "systick.h"
#include "time.h"
+#include "delay.h"
void delay(unsigned long ms) {
uint32 i;
@@ -38,15 +39,5 @@ void delay(unsigned long ms) {
}
void delayMicroseconds(uint32 us) {
- /* So (2^32)/12 micros max, or less than 6 minutes */
- us *= 12;
-
- /* fudge for function call overhead */
- us--;
- asm volatile(" mov r0, %[us] \n\t"
- "1: subs r0, #1 \n\t"
- " bhi 1b \n\t"
- :
- : [us] "r" (us)
- : "r0");
+ delay_us(us);
}