diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-12-04 02:08:56 +0100 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2011-12-04 02:08:56 +0100 |
commit | 8e8dbf2c2aa18a25f3a330db9135fd64de8ebf6c (patch) | |
tree | 7b4fa7908d55a40ef329f365c23a5b1a34720152 /hal | |
parent | a91546773296485bceff48c13d0c8211515b7fce (diff) |
Moved I2C register definitions into separate header, improved I2C implementation.
Diffstat (limited to 'hal')
-rw-r--r-- | hal/i2c.cpp | 149 | ||||
-rw-r--r-- | hal/i2c.h | 52 | ||||
-rw-r--r-- | hal/stm32.h | 15 |
3 files changed, 85 insertions, 131 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 = ® + write_p = ®_; 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--; - } - } - */ } @@ -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; |