diff options
author | Marti Bolivar <mbolivar@leaflabs.com> | 2012-06-21 15:45:38 -0400 |
---|---|---|
committer | Marti Bolivar <mbolivar@leaflabs.com> | 2012-06-22 14:06:10 -0400 |
commit | 70f22b667a7d91c68d663c1bf9ef1c0bdcbdd377 (patch) | |
tree | 4cb7a320aa0dac59d38b00d6357f2df8073a7e23 /libmaple | |
parent | 3ba9c0ecd6fd881d21292a369f8b7e45be5d2cb4 (diff) | |
download | librambutan-70f22b667a7d91c68d663c1bf9ef1c0bdcbdd377.tar.gz librambutan-70f22b667a7d91c68d663c1bf9ef1c0bdcbdd377.zip |
I2C: Move F1-only errata workarounds out of libmaple/i2c.c.
The IRQ priority hack is unnecessary on targets with properly
functioning I2C IRQ handlers, so we shouldn't use it unless we have
to. Add a mechanism so a series header can provide such a hack if
necessary. Have the F1 series header use this mechanism.
Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/i2c.c | 30 | ||||
-rw-r--r-- | libmaple/include/libmaple/i2c.h | 18 | ||||
-rw-r--r-- | libmaple/stm32f1/i2c.c | 36 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/i2c.h | 3 |
4 files changed, 57 insertions, 30 deletions
diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 2e11f54..291bf16 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -223,36 +223,6 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { nvic_irq_enable(dev->er_nvic_line); i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); - /* - * 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); - nvic_irq_set_priority(dev->er_nvic_line, 0); - /* Make it go! */ i2c_peripheral_enable(dev); diff --git a/libmaple/include/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h index 8ce6674..c66ebcb 100644 --- a/libmaple/include/libmaple/i2c.h +++ b/libmaple/include/libmaple/i2c.h @@ -50,6 +50,17 @@ extern "C" { * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in * MHz. (This is for internal use only). * + * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1. + * This is for internal use only. It's a hack to work around a + * silicon bug related to I2C IRQ pre-emption on some targets. If 1, + * the series header must also declare and implement a routine with + * this signature (it may also be provided as a macro): + * + * void _i2c_irq_priority_fixup(i2c_dev*) + * + * This will be called by i2c_enable_irq() before actually enabling + * I2C interrupts. + * * - Reg. map base pointers, device pointer declarations. */ @@ -243,6 +254,12 @@ static inline void i2c_stop_condition(i2c_dev *dev) { /* IRQ enable/disable */ +#ifndef _I2C_HAVE_IRQ_FIXUP +/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined, + * but we need it either way. */ +#define _i2c_irq_priority_fixup(dev) ((void)0) +#endif + #define I2C_IRQ_ERROR I2C_CR2_ITERREN #define I2C_IRQ_EVENT I2C_CR2_ITEVTEN #define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN @@ -255,6 +272,7 @@ static inline void i2c_stop_condition(i2c_dev *dev) { * I2C_IRQ_BUFFER (buffer interrupt). */ static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { + _i2c_irq_priority_fixup(dev); dev->regs->CR2 |= irqs; } diff --git a/libmaple/stm32f1/i2c.c b/libmaple/stm32f1/i2c.c index ed0ca97..4e918ad 100644 --- a/libmaple/stm32f1/i2c.c +++ b/libmaple/stm32f1/i2c.c @@ -74,3 +74,39 @@ void __irq_i2c1_er(void) { void __irq_i2c2_er(void) { _i2c_irq_error_handler(I2C2); } + +/* + * Internal APIs + */ + +void _i2c_irq_priority_fixup(i2c_dev *dev) { + /* + * 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); + nvic_irq_set_priority(dev->er_nvic_line, 0); +} diff --git a/libmaple/stm32f1/include/series/i2c.h b/libmaple/stm32f1/include/series/i2c.h index 0c89df4..315a7e3 100644 --- a/libmaple/stm32f1/include/series/i2c.h +++ b/libmaple/stm32f1/include/series/i2c.h @@ -63,4 +63,7 @@ static inline uint32 _i2c_bus_clk(i2c_dev *dev) { return STM32_PCLK1 / (1000 * 1000); } +#define _I2C_HAVE_IRQ_FIXUP 1 +void _i2c_irq_priority_fixup(i2c_dev *dev); + #endif /* _LIBMAPLE_STM32F1_I2C_H_ */ |