summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2011-12-04 02:08:56 +0100
committerVegard Storheil Eriksen <zyp@jvnv.net>2011-12-04 02:08:56 +0100
commit8e8dbf2c2aa18a25f3a330db9135fd64de8ebf6c (patch)
tree7b4fa7908d55a40ef329f365c23a5b1a34720152
parenta91546773296485bceff48c13d0c8211515b7fce (diff)
Moved I2C register definitions into separate header, improved I2C implementation.
-rw-r--r--hal/i2c.cpp149
-rw-r--r--hal/i2c.h52
-rw-r--r--hal/stm32.h15
-rw-r--r--main.cpp5
4 files changed, 87 insertions, 134 deletions
diff --git a/hal/i2c.cpp b/hal/i2c.cpp
index 867597a..db9c919 100644
--- a/hal/i2c.cpp
+++ b/hal/i2c.cpp
@@ -1,53 +1,49 @@
#include "i2c.h"
#include "rcc.h"
-#include "stm32.h"
#include "thread.h"
-I2C* I2C::self;
+#if defined(STM32F1)
+I2C_t I2C1(0x40005400, 36000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER);
+I2C_t I2C2(0x40005800, 36000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER);
+#elif defined(STM32F4)
+I2C_t I2C1(0x40005400, 42000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER);
+I2C_t I2C2(0x40005800, 42000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER);
+//I2C_t I2C3(0x40005c00, 42000000, Interrupt::I2C3_EV, Interrupt::I2C3_ER);
+#endif
-template <>
-void interrupt<Interrupt::I2C1_EV>() {
- I2C::self->irq_ev();
-}
-
-template <>
-void interrupt<Interrupt::I2C1_ER>() {
- I2C::self->irq_er();
-}
-
-void I2C::irq_ev() {
- uint32_t sr1 = I2C1.SR1;
- I2C1.SR2;
+void I2C_t::irq_ev() {
+ uint32_t sr1 = reg.SR1;
+ reg.SR2;
// EV5, SB = 1: Start condition sent.
if(sr1 & 0x01) {
// Send address.
- I2C1.DR = (addr << 1) | (writing ? 0 : 1);
+ reg.DR = (addr << 1) | (writing ? 0 : 1);
}
// EV6, ADDR = 1: Address sent.
if(sr1 & 0x02) {
if(writing) {
- I2C1.DR = *write_p++;
+ reg.DR = *write_p++;
writing--;
} else {
if(reading > 1) {
- I2C1.CR1 |= 0x400; // Set ACK.
+ reg.CR1 |= 0x400; // Set ACK.
} else {
- I2C1.CR1 |= 0x200; // Set STOP.
+ reg.CR1 |= 0x200; // Set STOP.
}
}
}
// EV7, RxNE = 1: Receive buffer not empty.
if(sr1 & 0x40) {
- *read_p++ = I2C1.DR;
+ *read_p++ = reg.DR;
reading--;
if(reading == 1) {
// Unset ACK, set STOP.
- I2C1.CR1 = (I2C1.CR1 & ~0x400) | 0x200;
+ reg.CR1 = (reg.CR1 & ~0x400) | 0x200;
}
if(reading == 0) {
@@ -55,141 +51,92 @@ void I2C::irq_ev() {
}
}
- //I2C1.CR1 &= ~0x400;
+ //reg.CR1 &= ~0x400;
// EV8, TxE = 1, BTF = 0: Transmit buffer empty, still writing.
if(sr1 & 0x80 && !(sr1 & 0x04)) {
if(writing) {
// Send data.
- I2C1.DR = *write_p++;
+ reg.DR = *write_p++;
writing--;
} else {
// All data sent.
if(reading) {
// Send repeat start.
- I2C1.CR1 |= 0x100;
+ reg.CR1 |= 0x100;
} else {
// Send stop.
- I2C1.CR1 |= 0x200;
+ reg.CR1 |= 0x200;
busy = 0;
}
}
}
}
-void I2C::irq_er() {
+void I2C_t::irq_er() {
handle_error();
}
-void I2C::handle_error() {
- I2C1.SR1;
- I2C1.SR2;
+void I2C_t::handle_error() {
+ reg.SR1;
+ reg.SR2;
//while(1);
- I2C1.CR1 |= 0x200;
+ reg.CR1 |= 0x200;
busy = 0;
}
-void I2C::enable() {
+void I2C_t::enable(Pin& scl, Pin& sda) {
RCC.enable(RCC.I2C1);
asm volatile("nop");
- I2C1.CR1 = 0x8000;
- I2C1.CR1 = 0;
+ scl.set_af(4);
+ sda.set_af(4);
+ scl.set_type(Pin::OpenDrain);
+ sda.set_type(Pin::OpenDrain);
+ scl.set_mode(Pin::AF);
+ sda.set_mode(Pin::AF);
+
+ reg.CR1 = 0x8000;
+ reg.CR1 = 0;
- I2C1.CR2 = 0x700 | 36;
- I2C1.TRISE = 37;
- I2C1.CCR = 180;
+ reg.CR2 = 0x700 | (clk / 1000000);
+ reg.TRISE = clk / 1000000 + 1;
+ reg.CCR = clk / 2 / 100000;
- Interrupt::enable(Interrupt::I2C1_EV);
- Interrupt::enable(Interrupt::I2C1_ER);
+ Interrupt::enable(irq_ev_n, &I2C_t::irq_ev, this);
+ Interrupt::enable(irq_er_n, &I2C_t::irq_er, this);
- I2C1.CR1 = 1;
+ reg.CR1 = 1;
}
-void I2C::write_reg(uint8_t addr_, uint8_t reg, uint8_t data) {
+void I2C_t::write_reg(uint8_t addr_, uint8_t reg_, uint8_t data) {
addr = addr_;
writing = 2;
reading = 0;
- volatile uint8_t buf[] = {reg, data};
+ volatile uint8_t buf[] = {reg_, data};
write_p = buf;
busy = 1;
- I2C1.CR1 |= 0x100;
+ reg.CR1 |= 0x100;
while(busy) {
Thread::yield();
}
-
- /*
- while(!(I2C1.SR1 & 0x01)); // Wait for SB.
-
- I2C1.DR = (addr << 1) | 0;
- while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
- I2C1.SR2;
-
- I2C1.DR = reg;
- while (!(I2C1.SR1 & 0x80)); // Wait for TxE.
-
- I2C1.DR = data;
- while (!(I2C1.SR1 & 0x04)); // Wait for BTF.
-
- I2C1.CR1 |= 0x200;*/
}
-void I2C::read_reg(uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf) {
+void I2C_t::read_reg(uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf) {
addr = addr_;
writing = 1;
reading = len;
- write_p = &reg;
+ write_p = &reg_;
read_p = buf;
busy = 1;
- I2C1.CR1 |= 0x100;
+ reg.CR1 |= 0x100;
while(busy) {
Thread::yield();
}
-
- /*
- I2C1.CR1 |= 0x100;
- while(!(I2C1.SR1 & 0x01)); // Wait for SB.
-
- I2C1.DR = (addr << 1) | 0;
- while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
- I2C1.SR2;
-
- I2C1.DR = reg;
- while (!(I2C1.SR1 & 0x80)); // Wait for TxE.
-
- I2C1.CR1 |= 0x100;
- while(!(I2C1.SR1 & 0x01)); // Wait for SB.
-
- I2C1.DR = (addr << 1) | 1;
- while (!(I2C1.SR1 & 0x02)); // Wait for ADDR.
- I2C1.SR2;
-
- I2C1.CR1 |= 0x400; // Set ACK.
-
- while(len) {
- if(len == 3) {
- while (!(I2C1.SR1 & 0x04)); // Wait for BTF.
-
- I2C1.CR1 &= ~0x400; // Clear ACK.
- *buf++ = I2C1.DR;
- len--;
-
- I2C1.CR1 |= 0x200; // Set STOP.
- *buf++ = I2C1.DR;
- len--;
-
- } else {
- while (!(I2C1.SR1 & 0x40)); // Wait for RxNE.
-
- *buf++ = I2C1.DR;
- len--;
- }
- }
- */
}
diff --git a/hal/i2c.h b/hal/i2c.h
index 3d58056..a61950c 100644
--- a/hal/i2c.h
+++ b/hal/i2c.h
@@ -2,16 +2,23 @@
#define I2C_H
#include <stdint.h>
-
#include "interrupt.h"
+#include "pin.h"
-class I2C {
- friend void interrupt<Interrupt::I2C1_EV>();
- friend void interrupt<Interrupt::I2C1_ER>();
-
+struct I2C_reg_t {
+ volatile uint32_t CR1;
+ volatile uint32_t CR2;
+ volatile uint32_t OAR1;
+ volatile uint32_t OAR2;
+ volatile uint32_t DR;
+ volatile uint32_t SR1;
+ volatile uint32_t SR2;
+ volatile uint32_t CCR;
+ volatile uint32_t TRISE;
+};
+
+class I2C_t {
private:
- static I2C* self;
-
volatile uint8_t addr;
volatile uint8_t writing;
volatile uint8_t reading;
@@ -19,22 +26,37 @@ class I2C {
volatile uint8_t* read_p;
volatile bool busy;
+
+ public:
+ I2C_reg_t& reg;
+ const uint32_t clk;
+ Interrupt::IRQ irq_ev_n;
+ Interrupt::IRQ irq_er_n;
+
+ I2C_t(uint32_t reg_addr, uint32_t bus_clk, Interrupt::IRQ ev_n, Interrupt::IRQ er_n) : reg(*(I2C_reg_t*)reg_addr), clk(bus_clk), irq_ev_n(ev_n), irq_er_n(er_n) {
+ reading = writing = 0;
+ }
void irq_ev();
void irq_er();
+
void handle_error();
-
- public:
- I2C() {
- self = this;
- }
- void enable();
+ void enable(Pin& scl, Pin& sda);
- void write_reg(uint8_t addr_, uint8_t reg, uint8_t data);
- void read_reg(uint8_t addr_, uint8_t reg, uint8_t len, uint8_t* buf);
+ void write_reg(uint8_t addr_, uint8_t reg_, uint8_t data);
+ void read_reg(uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf);
};
+#if defined(STM32F1)
+extern I2C_t I2C1;
+extern I2C_t I2C2;
+#elif defined(STM32F4)
+extern I2C_t I2C1;
+extern I2C_t I2C2;
+extern I2C_t I2C3;
+#endif
+typedef I2C_t I2C;
#endif
diff --git a/hal/stm32.h b/hal/stm32.h
index 7ddb479..6c7a04b 100644
--- a/hal/stm32.h
+++ b/hal/stm32.h
@@ -42,21 +42,6 @@ struct STK_t {
static STK_t& STK = *(STK_t*)0xe000e010;
-struct I2C_t {
- volatile uint32_t CR1;
- volatile uint32_t CR2;
- volatile uint32_t OAR1;
- volatile uint32_t OAR2;
- volatile uint32_t DR;
- volatile uint32_t SR1;
- volatile uint32_t SR2;
- volatile uint32_t CCR;
- volatile uint32_t TRISE;
-};
-
-static I2C_t& I2C1 = *(I2C_t*)0x40005400;
-static I2C_t& I2C2 = *(I2C_t*)0x40005800;
-
struct TIM_t {
volatile uint32_t CR1;
volatile uint32_t CR2;
diff --git a/main.cpp b/main.cpp
index e34d90e..309ff60 100644
--- a/main.cpp
+++ b/main.cpp
@@ -61,8 +61,7 @@ class PID {
}
};
-I2C i2c;
-AHRS ahrs(i2c);
+AHRS ahrs(I2C1);
volatile uint16_t motors[4];
@@ -112,7 +111,7 @@ int main() {
// Give all hardware enough time to initialize.
Time::sleep(200);
- i2c.enable();
+ I2C1.enable(PB8, PB9);
ahrs.init();
PPMSum ppmsum;