From f4cdcfa51096f73a49642c400681d91847137dfb Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Fri, 18 Feb 2011 05:22:39 -0500 Subject: checkpoint --- libmaple/i2c.c | 502 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 libmaple/i2c.c (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c new file mode 100644 index 0000000..2064723 --- /dev/null +++ b/libmaple/i2c.c @@ -0,0 +1,502 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * ****************************************************************************/ + +/** + * @brief + * TODO: Rejigger hard fault handler and error throbs to turn off all + * interrupts and jump to error throb to reenable usb bootloader + */ + +#include "libmaple.h" +#include "rcc.h" +#include "nvic.h" +#include "gpio.h" +#include "nvic.h" +#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 */ + +static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state); + +i2c_dev i2c_dev1 = { + .regs = (i2c_reg_map*)I2C1_BASE, + .gpio_port = GPIOB_BASE, + .sda_pin = 7, + .scl_pin = 6, + .clk_line = RCC_I2C1, + .ev_nvic_line = NVIC_I2C1_EV, + .er_nvic_line = NVIC_I2C1_ER, + .state = I2C_STATE_IDLE +}; + +/** + * @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; + uint32 sr2; +}; + +static struct crumb crumbs[100]; +static uint32 cur_crumb = 0; + +static inline void leave_big_crumb(uint32 event, uint32 sr1, uint32 sr2) { + if (cur_crumb < 100) { + struct crumb *crumb = &crumbs[cur_crumb++]; + crumb->event = event; + crumb->sr1 = sr1; + crumb->sr2 = sr2; + } +} + +enum { + IRQ_ENTRY = 1, + TXE_ONLY = 2, + TXE_BTF = 3, + STOP_SENT = 4, + TEST = 5, + RX_ADDR_START = 6, + RX_ADDR_STOP = 7, + RXNE_ONLY = 8, + RXNE_SENDING = 9, + RXNE_START_SENT = 10, + RXNE_STOP_SENT = 11, + RXNE_DONE = 12, +}; + +static void i2c_irq_handler(i2c_dev *dev) { + i2c_msg *msg = dev->msg; + + uint8 read = msg->flags & I2C_MSG_READ; + + uint32 sr1 = dev->regs->SR1; + uint32 sr2 = dev->regs->SR2; + leave_big_crumb(IRQ_ENTRY, sr1, sr2); + + /* + * EV5: Start condition sent + */ + if (sr1 & I2C_SR1_SB) { + msg->xferred = 0; + i2c_enable_irq(dev->regs, I2C_IRQ_BUFFER); + + /* + * Master receiver + */ + if (read) { + i2c_enable_ack(dev->regs); + } + i2c_send_slave_addr(dev->regs, msg->addr, read); + sr1 = sr2 = 0; + } + + /* + * EV6: Slave address sent + */ + if (sr1 & I2C_SR1_ADDR) { + /* + * Special case event EV6_1 for master receiver. + * Generate NACK and restart/stop condition after ADDR + * is cleared. + */ + if (read) { + if (msg->length == 1) { + i2c_disable_ack(dev->regs); + dev->msgs_left--; + if (dev->msgs_left) { + i2c_start_condition(dev->regs); + leave_big_crumb(RX_ADDR_START, 0, 0); + } else { + i2c_stop_condition(dev->regs); + leave_big_crumb(RX_ADDR_STOP, 0, 0); + } + } + } else { + /* + * 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++]); + } + sr1 = sr2 = 0; + } + + /* + * EV8: Master transmitter + * Transmit buffer empty, but we haven't finished transmitting the last + * byte written. + */ + 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++]); + 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); + dev->msgs_left--; + } + } else { + /* + * This should be impossible... + */ + throb(); + } + sr1 = sr2 = 0; + } + + /* + * EV8_2: Master transmitter + * Last byte sent, program repeated start/stop + */ + if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) { + leave_big_crumb(TXE_BTF, 0, 0); + if (dev->msgs_left) { + leave_big_crumb(TEST, 0, 0); + /* + * Repeated start insanity: We can't disable ITEVTEN or else SB + * won't interrupt, but if we don't disable ITEVTEN, BTF will + * continually interrupt us. What the fuck ST? + */ + i2c_start_condition(dev->regs); + while (!(dev->regs->SR1 & I2C_SR1_SB)) + ; + dev->msg++; + } else { + i2c_stop_condition(dev->regs); + /* + * 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); + leave_big_crumb(STOP_SENT, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } + sr1 = sr2 = 0; + } + + /* + * EV7: Master Receiver + */ + if (sr1 & I2C_SR1_RXNE) { + leave_big_crumb(RXNE_ONLY, 0, 0); + msg->data[msg->xferred++] = dev->regs->DR; + + /* + * EV7_1: Second to last byte in the reception? Set NACK and generate + * stop/restart condition in time for the last byte. We'll get one more + * RXNE interrupt before shutting things down. + */ + if (msg->xferred == (msg->length - 1)) { + i2c_disable_ack(dev->regs); + if (dev->msgs_left > 2) { + i2c_start_condition(dev->regs); + leave_big_crumb(RXNE_START_SENT, 0, 0); + } else { + i2c_stop_condition(dev->regs); + leave_big_crumb(RXNE_STOP_SENT, 0, 0); + } + } else if (msg->xferred == msg->length) { + dev->msgs_left--; + if (dev->msgs_left == 0) { + /* + * We're done. + */ + leave_big_crumb(RXNE_DONE, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } else { + dev->msg++; + } + } + } +} + +void I2C1_EV_IRQHandler(void) { + i2c_dev *dev = I2C1; + i2c_irq_handler(dev); +} + +static void i2c_bus_reset(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); + gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_MODE_OUTPUT_OD); + gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_MODE_OUTPUT_OD); + + /* + * Make sure the bus is free by clocking it until any slaves release the + * bus. + */ + while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + /* Wait for any clock stretching to finish */ + while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + ; + delay_us(10); + + /* Pull low */ + gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + delay_us(10); + + /* Release high again */ + gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + delay_us(10); + } + + /* Generate start then stop condition */ + gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); +} + +/** + * @brief Initialize an i2c device as bus master + * @param device to enable + * @param flags bitwise or of the following I2C options: + * I2C_FAST_MODE: 400 khz operation + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing + */ +void i2c_master_enable(i2c_dev *dev, uint32 flags) { +#define STANDARD_CCR (PCLK1/(100000*2)) +#define STANDARD_TRISE 37 + /* Reset the bus. Clock out any hung slaves. */ + i2c_bus_reset(dev); + + /* Turn on clock and set GPIO modes */ + rcc_reset_dev(dev->clk_line); + rcc_clk_enable(dev->clk_line); + gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_MODE_AF_OUTPUT_OD); + 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); + + /* 100 khz only for now */ + i2c_set_clk_control(dev->regs, 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); + + /* Enable event and buffer interrupts */ + nvic_irq_enable(dev->ev_nvic_line); + i2c_enable_irq(dev->regs, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); + + /* + * Important STM32 Errata: + * + * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8), + * Section 2.11.1, 2.11.2. + * + * 2.11.1: + * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not + * managed before the current byte is being transferred, problems may be + * encountered such as receiving an extra byte, reading the same data twice + * or missing data. + * + * 2.11.2: + * In Master Receiver mode, when closing the communication using + * method 2, the content of the last read data can be corrupted. + * + * If the user software is not able to read the data N-1 before the STOP + * condition is generated on the bus, the content of the shift register + * (data N) will be corrupted. (data N is shifted 1-bit to the left). + * + * ---------------------------------------------------------------------- + * + * In order to ensure that events are not missed, the i2c interrupt must + * not be preempted. We set the i2c interrupt priority to be the highest + * interrupt in the system (priority level 0). All other interrupts have + * been initialized to priority level 16. See nvic_init(). + */ + nvic_irq_set_priority(dev->ev_nvic_line, 0); + + /* Make it go! */ + i2c_peripheral_enable(dev->regs); +} + + +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; + + 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_start_condition(dev->regs); + rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE); + if (rc < 0) { + goto out; + } + + dev->state = I2C_STATE_IDLE; + rc = num; +out: + return rc; +} + +static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) { + int32 rc; + i2c_state tmp; + + while (1) { + tmp = dev->state; + if ((tmp == state) || (tmp == I2C_STATE_ERROR)) { + return (tmp == I2C_STATE_ERROR) ? -1 : 0; + } + } +} + + +/* + * 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; +} + + + -- cgit v1.2.3 From 07536e9a1a92af2b1bad8f32b1b0f6b868957d26 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Tue, 1 Mar 2011 12:33:59 -0500 Subject: Rename i2c irq handler to new naming convention. --- libmaple/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 2064723..1a595f5 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -261,7 +261,7 @@ static void i2c_irq_handler(i2c_dev *dev) { } } -void I2C1_EV_IRQHandler(void) { +void __irq_i2c1_ev(void) { i2c_dev *dev = I2C1; i2c_irq_handler(dev); } -- cgit v1.2.3 From 9872b3975bd40c55652bb9dead5f54e2be9740d0 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Thu, 10 Mar 2011 00:04:58 -0500 Subject: Fix merge error and compile error. --- libmaple/delay.h | 22 +++++++ libmaple/i2c.c | 168 ++++++++++++---------------------------------------- libmaple/i2c.h | 116 ++++++++++++++++++++++++++++-------- libmaple/libmaple.h | 2 + libmaple/rcc.c | 2 +- libmaple/stm32.h | 10 ++++ main.cpp | 28 ++++++--- wirish/time.c | 13 +--- 8 files changed, 186 insertions(+), 175 deletions(-) create mode 100644 libmaple/delay.h (limited to 'libmaple/i2c.c') 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); } -- cgit v1.2.3 From 334de50c49317f281d87f44e7b9278e08af19254 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 14 Mar 2011 18:37:56 -0400 Subject: Add rudimentary error handling for nack condition --- libmaple/i2c.c | 51 ++++++++++++++++++---------------------- libmaple/i2c.h | 43 ++++++++++++++++++++++++--------- main.cpp | 73 +++++++++++++++++++++++++++++++++++++++------------------ wirish/wirish.c | 24 +++++++++---------- 4 files changed, 117 insertions(+), 74 deletions(-) (limited to 'libmaple/i2c.c') 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 #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; -- cgit v1.2.3 From 1d97a8e7c55db7d9d52acefa90f66c19b3908b2d Mon Sep 17 00:00:00 2001 From: Anton Eltchaninov Date: Mon, 11 Apr 2011 18:17:09 +0700 Subject: Adding i2c2 and i2c fast mode Signed-off-by: Anton Eltchaninov --- libmaple/i2c.c | 54 +++++++++++++++++++++++++++++++++++++++++++----------- libmaple/i2c.h | 5 +++-- libmaple/rcc.c | 2 +- libmaple/rcc.h | 2 +- 4 files changed, 48 insertions(+), 15 deletions(-) (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c index a6638be..efe4dce 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -49,6 +49,19 @@ static i2c_dev i2c_dev1 = { i2c_dev* const I2C1 = &i2c_dev1; +static i2c_dev i2c_dev2 = { + .regs = I2C2_BASE, + .gpio_port = &gpiob, + .sda_pin = 11, + .scl_pin = 10, + .clk_line = RCC_I2C2, + .ev_nvic_line = NVIC_I2C2_EV, + .er_nvic_line = NVIC_I2C2_ER, + .state = I2C_STATE_IDLE +}; + +i2c_dev* const I2C2 = &i2c_dev2; + struct crumb { uint32 event; uint32 sr1; @@ -140,7 +153,8 @@ 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, msg->data[msg->xferred++]); + if (msg->length != 1) + i2c_write(dev, msg->data[msg->xferred++]); } sr1 = sr2 = 0; } @@ -243,6 +257,10 @@ void __irq_i2c1_ev(void) { i2c_irq_handler(&i2c_dev1); } +void __irq_i2c2_ev(void) { + i2c_irq_handler(&i2c_dev2); +} + static void i2c_irq_error_handler(i2c_dev *dev) { uint32 sr1 = dev->regs->SR1; uint32 sr2 = dev->regs->SR2; @@ -257,6 +275,10 @@ void __irq_i2c1_er(void) { i2c_irq_error_handler(&i2c_dev1); } +void __irq_i2c2_er(void) { + i2c_irq_error_handler(&i2c_dev2); +} + static void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); @@ -301,8 +323,11 @@ static void i2c_bus_reset(const i2c_dev *dev) { * I2C_10BIT_ADDRESSING: Enable 10-bit addressing */ void i2c_master_enable(i2c_dev *dev, uint32 flags) { +#define I2C_CLK (PCLK1/1000000) #define STANDARD_CCR (PCLK1/(100000*2)) -#define STANDARD_TRISE 37 +#define STANDARD_TRISE (I2C_CLK+1) +#define FAST_CCR (I2C_CLK/10) +#define FAST_TRISE ((I2C_CLK*3)/10+1) /* Reset the bus. Clock out any hung slaves. */ i2c_bus_reset(dev); @@ -313,17 +338,24 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ - i2c_set_input_clk(dev, 36); + i2c_set_input_clk(dev, I2C_CLK); - /* 100 khz only for now */ - i2c_set_clk_control(dev, STANDARD_CCR); + if(flags & I2C_FAST_MODE) { - /* - * 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, STANDARD_TRISE); + /* 400 kHz for fast mode, set DUTY and F/S bits */ + i2c_set_clk_control(dev, FAST_CCR|I2C_CCR_DUTY|I2C_CCR_FS); + + /* Set scl rise time, max rise time in fast mode: 300ns */ + i2c_set_trise(dev, FAST_TRISE); + + } else { + + /* 100 kHz for standard mode */ + i2c_set_clk_control(dev, STANDARD_CCR); + + /* Max rise time in standard mode: 1000 ns */ + i2c_set_trise(dev, STANDARD_TRISE); + } /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index a17e144..07ee260 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -71,8 +71,8 @@ typedef struct i2c_dev { i2c_msg *msg; } i2c_dev; - extern i2c_dev* const I2C1; +extern i2c_dev* const I2C2; #define I2C1_BASE (i2c_reg_map*)0x40005400 #define I2C2_BASE (i2c_reg_map*)0x40005800 @@ -100,7 +100,8 @@ extern i2c_dev* const I2C1; #define I2C_CR2_FREQ 0xFFF // Peripheral input frequency /* Clock control register bits */ -#define I2C_CCR_FS BIT(15) // Master mode selection +#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 */ diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 327e3ad..78abbcf 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -67,6 +67,7 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, @@ -83,7 +84,6 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, #endif #ifdef STM32_XL_DENSITY diff --git a/libmaple/rcc.h b/libmaple/rcc.h index e6fa196..91f77d0 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -449,6 +449,7 @@ typedef enum { RCC_PWR, RCC_BKP, RCC_I2C1, + RCC_I2C2, RCC_CRC, RCC_FLITF, RCC_SRAM, @@ -465,7 +466,6 @@ typedef enum { RCC_FSMC, RCC_DAC, RCC_DMA2, - RCC_I2C2, RCC_SDIO, #endif #ifdef STM32_XL_DENSITY -- cgit v1.2.3 From 834fa46360b7c4a714e0067a84948582b0dfa0c4 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 15:41:59 -0400 Subject: Making 1c05ac8497222a12a675ba31564e7c4864107de9 comply with coding standard. Whitespace corrections only. --- libmaple/i2c.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c index efe4dce..5fbafad 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -153,7 +153,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. */ - if (msg->length != 1) + if (msg->length != 1) i2c_write(dev, msg->data[msg->xferred++]); } sr1 = sr2 = 0; @@ -325,7 +325,7 @@ static void i2c_bus_reset(const i2c_dev *dev) { void i2c_master_enable(i2c_dev *dev, uint32 flags) { #define I2C_CLK (PCLK1/1000000) #define STANDARD_CCR (PCLK1/(100000*2)) -#define STANDARD_TRISE (I2C_CLK+1) +#define STANDARD_TRISE (I2C_CLK+1) #define FAST_CCR (I2C_CLK/10) #define FAST_TRISE ((I2C_CLK*3)/10+1) /* Reset the bus. Clock out any hung slaves. */ @@ -340,9 +340,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ i2c_set_input_clk(dev, I2C_CLK); - if(flags & I2C_FAST_MODE) { - - /* 400 kHz for fast mode, set DUTY and F/S bits */ + if(flags & I2C_FAST_MODE) { + /* 400 kHz for fast mode, set DUTY and F/S bits */ i2c_set_clk_control(dev, FAST_CCR|I2C_CCR_DUTY|I2C_CCR_FS); /* Set scl rise time, max rise time in fast mode: 300ns */ @@ -350,7 +349,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { } else { - /* 100 kHz for standard mode */ + /* 100 kHz for standard mode */ i2c_set_clk_control(dev, STANDARD_CCR); /* Max rise time in standard mode: 1000 ns */ -- cgit v1.2.3 From 7b43ce42bdf590509c18aecdc1a001477be8585f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 14 Apr 2011 14:00:47 -0400 Subject: i2c cleanups. Whitespace and column width changes only. --- libmaple/i2c.c | 55 +++++++++++++------------ libmaple/i2c.h | 126 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 90 insertions(+), 91 deletions(-) (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 5fbafad..3a1082a 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -1,29 +1,32 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 Perry Hung. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * ****************************************************************************/ + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ /** - * @brief + * @file i2c.c + * @brief Inter-Integrated Circuit (I2C) support. */ #include "libmaple.h" @@ -150,8 +153,9 @@ static void i2c_irq_handler(i2c_dev *dev) { } } else { /* - * Master transmitter: write first byte to fill shift register. - * We should get another TXE interrupt immediately to fill DR again. + * Master transmitter: write first byte to fill shift + * register. We should get another TXE interrupt + * immediately to fill DR again. */ if (msg->length != 1) i2c_write(dev, msg->data[msg->xferred++]); @@ -206,9 +210,10 @@ static void i2c_irq_handler(i2c_dev *dev) { i2c_stop_condition(dev); /* - * 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. + * 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, I2C_IRQ_EVENT); leave_big_crumb(STOP_SENT, 0, 0); @@ -395,7 +400,6 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_peripheral_enable(dev); } - int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { int32 rc; @@ -431,8 +435,3 @@ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) { } } } - - - - - diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 394fd57..27e24b2 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -1,29 +1,32 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 Perry Hung. * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * ****************************************************************************/ + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ /** - * @brief libmaple i2c header + * @file i2c.h + * @brief Inter-Integrated Circuit (I2C) peripheral support */ #ifndef _I2C_H_ @@ -78,57 +81,57 @@ extern i2c_dev* const I2C2; #define I2C2_BASE (i2c_reg_map*)0x40005800 /* i2c enable options */ -#define I2C_FAST_MODE 0x1 // 400 khz -#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio /* 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 -#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position -#define I2C_CR1_ACK BIT(10) // Acknowledge enable -#define I2C_CR1_START BIT(8) // Start generation -#define I2C_CR1_STOP BIT(9) // Stop generation -#define I2C_CR1_PE BIT(0) // Peripheral Enable +#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 +#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position +#define I2C_CR1_ACK BIT(10) // Acknowledge enable +#define I2C_CR1_START BIT(8) // Start generation +#define I2C_CR1_STOP BIT(9) // Stop generation +#define I2C_CR1_PE BIT(0) // Peripheral Enable /* Control register 2 bits */ -#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 -#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable -#define I2C_CR2_ITERREN BIT(8) // Error interupt enable -#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency +#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 +#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable +#define I2C_CR2_ITERREN BIT(8) // Error interupt enable +#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency /* Clock control register bits */ -#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 */ -#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 -#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent -#define I2C_SR1_STOPF BIT(4) // Stop detection -#define I2C_SR1_RXNE BIT(6) // Data register not empty -#define I2C_SR1_TXE BIT(7) // Data register empty -#define I2C_SR1_BERR BIT(8) // Bus error -#define I2C_SR1_ARLO BIT(9) // Arbitration lost -#define I2C_SR1_AF BIT(10) // Acknowledge failure -#define I2C_SR1_OVR BIT(11) // Overrun/underrun -#define I2C_SR1_PECERR BIT(12) // PEC Error in reception -#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error -#define I2C_SR1_SMBALERT BIT(15) // SMBus alert +#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 */ +#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 +#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent +#define I2C_SR1_STOPF BIT(4) // Stop detection +#define I2C_SR1_RXNE BIT(6) // Data register not empty +#define I2C_SR1_TXE BIT(7) // Data register empty +#define I2C_SR1_BERR BIT(8) // Bus error +#define I2C_SR1_ARLO BIT(9) // Arbitration lost +#define I2C_SR1_AF BIT(10) // Acknowledge failure +#define I2C_SR1_OVR BIT(11) // Overrun/underrun +#define I2C_SR1_PECERR BIT(12) // PEC Error in reception +#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error +#define I2C_SR1_SMBALERT BIT(15) // SMBus alert /* Status register 2 bits */ -#define I2C_SR2_MSL BIT(0) // Master/slave -#define I2C_SR2_BUSY BIT(1) // Bus busy -#define I2C_SR2_TRA BIT(2) // Transmitter/receiver -#define I2C_SR2_GENCALL BIT(4) // General call address -#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address -#define I2C_SR2_SMBHOST BIT(6) // SMBus host header -#define I2C_SR2_DUALF BIT(7) // Dual flag -#define I2C_SR2_PEC 0xFF00 // Packet error checking register +#define I2C_SR2_MSL BIT(0) // Master/slave +#define I2C_SR2_BUSY BIT(1) // Bus busy +#define I2C_SR2_TRA BIT(2) // Transmitter/receiver +#define I2C_SR2_GENCALL BIT(4) // General call address +#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address +#define I2C_SR2_SMBHOST BIT(6) // SMBus host header +#define I2C_SR2_DUALF BIT(7) // Dual flag +#define I2C_SR2_PEC 0xFF00 // Packet error checking register #ifdef __cplusplus extern "C" { @@ -166,7 +169,6 @@ static inline void i2c_write(i2c_dev *dev, uint8 byte) { dev->regs->DR = byte; } - /** * @brief Set input clock frequency, in mhz * @param dev i2c @@ -179,7 +181,6 @@ 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 @@ -257,4 +258,3 @@ static inline void i2c_disable_ack(i2c_dev *dev) { #endif #endif - -- cgit v1.2.3 From fb6cf96a4657e4d7ba462f457d9e8e4258b604bb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 16:12:57 -0400 Subject: I2C fixup. Added i2c_init() for consistency with rest of libmaple. --- libmaple/i2c.c | 17 +++++++++++++---- libmaple/i2c.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'libmaple/i2c.c') diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 3a1082a..f4cb522 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -320,10 +320,20 @@ static void i2c_bus_reset(const i2c_dev *dev) { gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); } +/** + * @brief Initialize an I2C device and reset its registers to their + * default values. + * @param dev Device to enable. + */ +void i2c_init(i2c_dev *dev) { + rcc_reset_dev(dev->clk_line); + rcc_clk_enable(dev->clk_line); +} + /** * @brief Initialize an i2c device as bus master - * @param device to enable - * @param flags bitwise or of the following I2C options: + * @param dev Device to enable + * @param flags Bitwise or of the following I2C options: * I2C_FAST_MODE: 400 khz operation * I2C_10BIT_ADDRESSING: Enable 10-bit addressing */ @@ -337,8 +347,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_bus_reset(dev); /* Turn on clock and set GPIO modes */ - rcc_reset_dev(dev->clk_line); - rcc_clk_enable(dev->clk_line); + i2c_init(dev); gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 27e24b2..3f351b2 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -137,6 +137,7 @@ extern i2c_dev* const I2C2; extern "C" { #endif +void i2c_init(i2c_dev *dev); void i2c_master_enable(i2c_dev *dev, uint32 flags); int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); -- cgit v1.2.3