diff options
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/i2c.c | 96 | ||||
-rw-r--r-- | libmaple/i2c.h | 132 |
2 files changed, 137 insertions, 91 deletions
diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 0ef8e70..8f6967b 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -26,8 +26,9 @@ /** * @file i2c.c - * @brief Inter-Integrated Circuit (I2C) support. Currently supports only master - * mode. + * @brief Inter-Integrated Circuit (I2C) support. + * + * Currently, only master mode is supported. */ #include "libmaple.h" @@ -43,11 +44,12 @@ static i2c_dev i2c_dev1 = { .gpio_port = &gpiob, .sda_pin = 7, .scl_pin = 6, - .clk_line = RCC_I2C1, + .clk_id = RCC_I2C1, .ev_nvic_line = NVIC_I2C1_EV, .er_nvic_line = NVIC_I2C1_ER, .state = I2C_STATE_DISABLED }; +/** I2C1 device */ i2c_dev* const I2C1 = &i2c_dev1; static i2c_dev i2c_dev2 = { @@ -55,11 +57,12 @@ static i2c_dev i2c_dev2 = { .gpio_port = &gpiob, .sda_pin = 11, .scl_pin = 10, - .clk_line = RCC_I2C2, + .clk_id = RCC_I2C2, .ev_nvic_line = NVIC_I2C2_EV, .er_nvic_line = NVIC_I2C2_ER, .state = I2C_STATE_DISABLED }; +/** I2C2 device */ i2c_dev* const I2C2 = &i2c_dev2; static inline int32 wait_for_state_change(i2c_dev *dev, @@ -68,9 +71,9 @@ static inline int32 wait_for_state_change(i2c_dev *dev, /** * @brief Fill data register with slave address - * @param dev i2c device - * @param addr slave address - * @param rw read/write bit + * @param dev I2C device + * @param addr Slave address + * @param rw Read/write bit */ static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) { dev->regs->DR = (addr << 1) | rw; @@ -121,10 +124,9 @@ enum { ERROR_ENTRY = 13, }; - /** - * @brief IRQ handler for i2c master. Handles transmission/reception. - * @param dev i2c device + * @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; @@ -294,11 +296,10 @@ void __irq_i2c2_ev(void) { i2c_irq_handler(&i2c_dev2); } - /** - * @brief Interrupt handler for i2c error conditions - * @param dev i2c device - * @sideeffect Aborts any pending i2c transactions + * @brief Interrupt handler for I2C error conditions + * @param dev I2C device + * @sideeffect Aborts any pending I2C transactions */ static void i2c_irq_error_handler(i2c_dev *dev) { I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2); @@ -324,12 +325,14 @@ void __irq_i2c2_er(void) { i2c_irq_error_handler(&i2c_dev2); } - /** - * @brief Reset an i2c bus by clocking out pulses until any hung - * slaves release SDA and SCL, then generate a START condition, then - * a STOP condition. - * @param dev i2c device + * @brief Reset an I2C bus. + * + * Reset is accomplished by clocking out pulses until any hung slaves + * release SDA and SCL, then generating a START condition, then a STOP + * condition. + * + * @param dev I2C device */ void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ @@ -370,22 +373,24 @@ void i2c_bus_reset(const i2c_dev *dev) { /** * @brief Initialize an I2C device and reset its registers to their * default values. - * @param dev Device to enable. + * @param dev Device to initialize. */ void i2c_init(i2c_dev *dev) { - rcc_reset_dev(dev->clk_line); - rcc_clk_enable(dev->clk_line); + rcc_reset_dev(dev->clk_id); + rcc_clk_enable(dev->clk_id); } /** - * @brief Initialize an i2c device as bus master + * @brief Initialize an I2C device as bus master * @param dev Device to enable * @param flags Bitwise or of the following I2C options: - * I2C_FAST_MODE: 400 khz operation - * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for fast mode) - * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on initialization - * I2C_10BIT_ADDRESSING: Enable 10-bit addressing - * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9 + * I2C_FAST_MODE: 400 khz operation, + * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for + * fast mode), + * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on + * initialization, + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, + * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9. */ void i2c_master_enable(i2c_dev *dev, uint32 flags) { #define I2C_CLK (PCLK1/1000000) @@ -484,17 +489,20 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /** - * @brief Process an i2c transaction. Transactions are composed of - * one or more i2c_msg's and may be read or write tranfers. Multiple i2c_msg's - * will generate a repeated start inbetween messages. - * @param dev i2c device - * @param msgs messages to send/receive - * @param num number of messages to send/receive - * @param timeout bus idle timeout in milliseconds before aborting the - * transfer. 0 denotes no timeout. - * @return 0 on success - * I2C_ERROR_PROTOCOL if there was a protocol error. - * I2C_ERROR_TIMEOUT if the transfer timed out. + * @brief Process an i2c transaction. + * + * Transactions are composed of one or more i2c_msg's, and may be read + * or write tranfers. Multiple i2c_msg's will generate a repeated + * start in between messages. + * + * @param dev I2C device + * @param msgs Messages to send/receive + * @param num Number of messages to send/receive + * @param timeout Bus idle timeout in milliseconds before aborting the + * transfer. 0 denotes no timeout. + * @return 0 on success, + * I2C_ERROR_PROTOCOL if there was a protocol error, + * I2C_ERROR_TIMEOUT if the transfer timed out. */ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, @@ -524,11 +532,11 @@ out: /** - * @brief Wait for an i2c event, or timeout in case of error - * @param dev i2c device - * @param state i2c_state state to wait for - * @param timeout timeout in milliseconds - * @return 0 if target state is reached, <0 on error + * @brief Wait for an I2C event, or time out in case of error. + * @param dev I2C device + * @param state I2C_state state to wait for + * @param timeout Timeout, in milliseconds + * @return 0 if target state is reached, a negative value on error. */ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state, diff --git a/libmaple/i2c.h b/libmaple/i2c.h index d6285b3..3a397aa 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -32,58 +32,82 @@ #ifndef _I2C_H_ #define _I2C_H_ +/** I2C register map type */ typedef struct i2c_reg_map { - __io uint32 CR1; - __io uint32 CR2; - __io uint32 OAR1; - __io uint32 OAR2; - __io uint32 DR; - __io uint32 SR1; - __io uint32 SR2; - __io uint32 CCR; - __io uint32 TRISE; + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 OAR1; /**< Own address register 1 */ + __io uint32 OAR2; /**< Own address register 2 */ + __io uint32 DR; /**< Data register */ + __io uint32 SR1; /**< Status register 1 */ + __io uint32 SR2; /**< Status register 2 */ + __io uint32 CCR; /**< Clock control register */ + __io uint32 TRISE; /**< TRISE register */ } i2c_reg_map; +/** I2C device states */ typedef enum i2c_state { - I2C_STATE_DISABLED = 0, - I2C_STATE_IDLE = 1, - I2C_STATE_XFER_DONE = 2, - I2C_STATE_BUSY = 3, - I2C_STATE_ERROR = -1 + I2C_STATE_DISABLED = 0, /**< Disabled */ + I2C_STATE_IDLE = 1, /**< Idle */ + I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ + I2C_STATE_BUSY = 3, /**< Busy */ + I2C_STATE_ERROR = -1 /**< Error occurred */ } i2c_state; +/** + * @brief I2C message type + */ typedef struct i2c_msg { - uint16 addr; + uint16 addr; /**< Address */ #define I2C_MSG_READ 0x1 #define I2C_MSG_10BIT_ADDR 0x2 - uint16 flags; - uint16 length; - uint16 xferred; - uint8 *data; + uint16 flags; /**< Bitwise OR of I2C_MSG_READ and + I2C_MSG_10BIT_ADDR */ + uint16 length; /**< Message length */ + uint16 xferred; /**< Messages transferred */ + uint8 *data; /**< Data */ } i2c_msg; +/** + * I2C device type. + */ typedef struct i2c_dev { - i2c_reg_map *regs; - gpio_dev *gpio_port; - uint8 sda_pin; - uint8 scl_pin; - uint8 clk_line; - uint8 ev_nvic_line; - uint8 er_nvic_line; - volatile i2c_state state; - uint16 msgs_left; - i2c_msg *msg; - volatile uint32 timestamp; - uint32 error_flags; + i2c_reg_map *regs; /**< Register map */ + gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ + uint8 sda_pin; /**< SDA bit on gpio_port */ + uint8 scl_pin; /**< SCL bit on gpio_port */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num ev_nvic_line; /**< Event IRQ number */ + nvic_irq_num er_nvic_line; /**< Error IRQ number */ + volatile i2c_state state; /**< Device state */ + uint16 msgs_left; /**< Messages left */ + i2c_msg *msg; /**< Messages */ + volatile uint32 timestamp; /**< For internal use */ + uint32 error_flags; /**< Error flags, set on I2C error condition */ } i2c_dev; +/* + * Devices + */ + extern i2c_dev* const I2C1; extern i2c_dev* const I2C2; -#define I2C1_BASE (i2c_reg_map*)0x40005400 -#define I2C2_BASE (i2c_reg_map*)0x40005800 +/* + * Register map base pointers + */ + +/** I2C1 register map base pointer */ +#define I2C1_BASE ((struct i2c_reg_map*)0x40005400) +/** I2C2 register map base pointer */ +#define I2C2_BASE ((struct i2c_reg_map*)0x40005800) + +/* + * Register bit definitions + */ + +/* Control register 1 */ -/* Control register 1 bits */ #define I2C_CR1_SWRST BIT(15) // Software reset #define I2C_CR1_ALERT BIT(13) // SMBus alert #define I2C_CR1_PEC BIT(12) // Packet error checking @@ -93,7 +117,8 @@ extern i2c_dev* const I2C2; #define I2C_CR1_STOP BIT(9) // Stop generation #define I2C_CR1_PE BIT(0) // Peripheral Enable -/* Control register 2 bits */ +/* Control register 2 */ + #define I2C_CR2_LAST BIT(12) // DMA last transfer #define I2C_CR2_DMAEN BIT(11) // DMA requests enable #define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable @@ -101,12 +126,14 @@ extern i2c_dev* const I2C2; #define I2C_CR2_ITERREN BIT(8) // Error interupt enable #define I2C_CR2_FREQ 0xFFF // Peripheral input frequency -/* Clock control register bits */ +/* Clock control register */ + #define I2C_CCR_FS BIT(15) // Fast mode selection #define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio #define I2C_CCR_CCR 0xFFF // Clock control bits -/* Status register 1 bits */ +/* Status register 1 */ + #define I2C_SR1_SB BIT(0) // Start bit #define I2C_SR1_ADDR BIT(1) // Address sent/matched #define I2C_SR1_BTF BIT(2) // Byte transfer finished @@ -122,7 +149,8 @@ extern i2c_dev* const I2C2; #define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error #define I2C_SR1_SMBALERT BIT(15) // SMBus alert -/* Status register 2 bits */ +/* Status register 2 */ + #define I2C_SR2_MSL BIT(0) // Master/slave #define I2C_SR2_BUSY BIT(1) // Bus busy #define I2C_SR2_TRA BIT(2) // Transmitter/receiver @@ -132,11 +160,17 @@ extern i2c_dev* const I2C2; #define I2C_SR2_DUALF BIT(7) // Dual flag #define I2C_SR2_PEC 0xFF00 // Packet error checking register +/* + * Convenience routines + */ + #ifdef __cplusplus extern "C" { #endif -/* i2c enable options */ +void i2c_init(i2c_dev *dev); + +/* I2C enable options */ #define I2C_FAST_MODE BIT(0) // 400 khz #define I2C_DUTY_16_9 BIT(1) // 16/9 duty ratio #define I2C_REMAP BIT(2) // Use alternate pin mapping @@ -149,26 +183,30 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout); void i2c_bus_reset(const i2c_dev *dev); +/** + * @brief Disable an I2C device + * + * This function disables the corresponding peripheral and marks dev's + * state as I2C_STATE_DISABLED. + * + * @param dev Device to disable. + */ static inline void i2c_disable(i2c_dev *dev) { dev->regs->CR1 &= ~I2C_CR1_PE; dev->state = I2C_STATE_DISABLED; } -/* - * Low level register twiddling functions - */ - /** - * @brief turn on an i2c peripheral - * @param dev i2c device + * @brief Turn on an I2C peripheral + * @param dev Device to enable */ static inline void i2c_peripheral_enable(i2c_dev *dev) { dev->regs->CR1 |= I2C_CR1_PE; } /** - * @brief turn off an i2c peripheral - * @param dev i2c device + * @brief Turn off an I2C peripheral + * @param dev Device to turn off */ static inline void i2c_peripheral_disable(i2c_dev *dev) { dev->regs->CR1 &= ~I2C_CR1_PE; |