diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-03-28 15:01:43 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-03-28 15:01:43 +0000 |
commit | 82fb23b2cc78fade702316d00510efcf9d65954f (patch) | |
tree | a997a6f40b080a1e31890359dde9fc466e726221 /nuttx/arch/arm/src/stm32/stm32_i2c.c | |
parent | b197eb1609652b2b766bb79caf00b23ef07eed40 (diff) | |
download | px4-nuttx-82fb23b2cc78fade702316d00510efcf9d65954f.tar.gz px4-nuttx-82fb23b2cc78fade702316d00510efcf9d65954f.tar.bz2 px4-nuttx-82fb23b2cc78fade702316d00510efcf9d65954f.zip |
More changes from Uros
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3431 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_i2c.c')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_i2c.c | 302 |
1 files changed, 232 insertions, 70 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c index 583541e59..05afd5a7b 100644 --- a/nuttx/arch/arm/src/stm32/stm32_i2c.c +++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c @@ -79,7 +79,7 @@ #include "stm32_rcc.h" #include "stm32_i2c.h" -#if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C1) +#if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2) /************************************************************************************ * Private Types @@ -92,6 +92,9 @@ struct stm32_i2c_priv_s { uint32_t base; int refs; sem_t sem; + + uint8_t msgc; + FAR struct i2c_msg_s *msgv; }; @@ -103,8 +106,27 @@ struct stm32_i2c_inst_s { uint32_t frequency; int address; + uint16_t flags; +}; + + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +#if CONFIG_STM32_I2C1 +struct stm32_i2c_priv_s stm32_i2c1_priv = { + .base = STM32_I2C1_BASE, + .refs = 0 }; +#endif +#if CONFIG_STM32_I2C2 +struct stm32_i2c_priv_s stm32_i2c2_priv = { + .base = STM32_I2C2_BASE, + .refs = 0 +}; +#endif /************************************************************************************ @@ -159,7 +181,7 @@ void inline stm32_i2c_sem_destroy(FAR struct i2c_dev_s *dev) } -static void stm32_i2c_setclock(FAR struct i2c_dev_s *inst) +static void stm32_i2c_setclock(FAR struct i2c_dev_s *inst, uint32_t frequency) { /* Disable Peripheral if rising time is to be changed, * and restore state on return. */ @@ -171,13 +193,13 @@ static void stm32_i2c_setclock(FAR struct i2c_dev_s *inst) /* Update timing and control registers */ - if (((struct stm32_i2c_inst_s *)inst)->frequency < 400e3) { + if (frequency < 400e3) { /* Speed: 100 kHz * Risetime: 1000 ns * Duty: t_low / t_high = 1 */ - stm32_i2c_putreg(inst, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK / 200000); + stm32_i2c_putreg(inst, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK/200000); stm32_i2c_putreg(inst, STM32_I2C_TRISE_OFFSET, 1 + STM32_BOARD_HCLK/1000000); } else { @@ -186,7 +208,7 @@ static void stm32_i2c_setclock(FAR struct i2c_dev_s *inst) * Risetime: 1000 ns ??? \todo check rise time for 400 kHz devices * Duty: t_low / t_high = 2 */ - stm32_i2c_putreg(inst, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK / 1200000); + stm32_i2c_putreg(inst, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK/1200000); stm32_i2c_putreg(inst, STM32_I2C_TRISE_OFFSET, 1 + STM32_BOARD_HCLK/1000000); } @@ -197,23 +219,103 @@ static void stm32_i2c_setclock(FAR struct i2c_dev_s *inst) } +static inline void stm32_i2c_sendstart(FAR struct i2c_dev_s *inst) +{ + stm32_i2c_modifyreg(inst, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_START); +} + + +static inline void stm32_i2c_sendstop(FAR struct i2c_dev_s *inst) +{ + stm32_i2c_modifyreg(inst, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_STOP); +} + + +/************************************************************************************ + * Interrupt Service Routines + ************************************************************************************/ + +static int stm32_i2c_event_isr(struct stm32_i2c_priv_s * priv) +{ + return OK; +} + + +static int stm32_i2c_error_isr(struct stm32_i2c_priv_s * priv) +{ + return OK; +} + + +/* Decode ***************************************************************************/ + +#if CONFIG_STM32_I2C1 +static int stm32_i2c1_event_isr(int irq, void *context) +{ + return stm32_i2c_event_isr(&stm32_i2c1_priv); +} + +static int stm32_i2c1_error_isr(int irq, void *context) +{ + return stm32_i2c_error_isr(&stm32_i2c1_priv); +} +#endif + +#if CONFIG_STM32_I2C2 +static int stm32_i2c2_event_isr(int irq, void *context) +{ + return stm32_i2c_event_isr(&stm32_i2c2_priv); +} + +static int stm32_i2c2_error_isr(int irq, void *context) +{ + return stm32_i2c_error_isr(&stm32_i2c1_priv); +} +#endif + + +/************************************************************************************ + * Private Initialization and Deinitialization + ************************************************************************************/ + /** Setup the I2C hardware, ready for operation with defaults */ static int stm32_i2c_init(FAR struct i2c_dev_s *inst) { /* Power-up and configure GPIOs */ switch( ((struct stm32_i2c_inst_s *)inst)->priv->base ) { + +#if CONFIG_STM32_I2C1 case STM32_I2C1_BASE: modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_I2C1EN); - stm32_configgpio(GPIO_I2C1_SCL); - stm32_configgpio(GPIO_I2C1_SDA); - break; + if (stm32_configgpio(GPIO_I2C1_SCL)==ERROR) return ERROR; + if (stm32_configgpio(GPIO_I2C1_SDA)==ERROR) { + stm32_unconfiggpio(GPIO_I2C1_SCL); + return ERROR; + } + irq_attach(STM32_IRQ_I2C1EV, stm32_i2c1_event_isr); + irq_attach(STM32_IRQ_I2C1ER, stm32_i2c1_error_isr); + up_enable_irq(STM32_IRQ_I2C1EV); + up_enable_irq(STM32_IRQ_I2C1ER); + break; +#endif + +#if CONFIG_STM32_I2C2 case STM32_I2C2_BASE: modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_I2C2EN); - stm32_configgpio(GPIO_I2C2_SCL); - stm32_configgpio(GPIO_I2C2_SDA); + + if (stm32_configgpio(GPIO_I2C2_SCL)==ERROR) return ERROR; + if (stm32_configgpio(GPIO_I2C2_SDA)==ERROR) { + stm32_unconfiggpio(GPIO_I2C2_SCL); + return ERROR; + } + irq_attach(STM32_IRQ_I2C2EV, stm32_i2c2_event_isr); + irq_attach(STM32_IRQ_I2C2ER, stm32_i2c2_error_isr); + up_enable_irq(STM32_IRQ_I2C2EV); + up_enable_irq(STM32_IRQ_I2C2ER); break; +#endif default: return ERROR; } @@ -221,18 +323,14 @@ static int stm32_i2c_init(FAR struct i2c_dev_s *inst) /* Set peripheral frequency, where it must be at least 2 MHz * for 100 kHz or 4 MHz for 400 kHz. Enable interrupt generation. */ - -#if STM32_BOARD_HCLK < 4000000 -# error STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 100/400 kHz operation. -#endif - + stm32_i2c_putreg(inst, STM32_I2C_CR2_OFFSET, I2C_CR2_ITERREN | I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN | (STM32_BOARD_HCLK / 1000000) ); - stm32_i2c_setclock(inst); - + stm32_i2c_setclock(inst, 100000); + /* Enable I2C */ stm32_i2c_putreg(inst, STM32_I2C_CR1_OFFSET, I2C_CR1_PE); @@ -249,17 +347,34 @@ static int stm32_i2c_deinit(FAR struct i2c_dev_s *inst) stm32_i2c_putreg(inst, STM32_I2C_CR1_OFFSET, 0); switch( ((struct stm32_i2c_inst_s *)inst)->priv->base ) { + +#if CONFIG_STM32_I2C1 case STM32_I2C1_BASE: stm32_unconfiggpio(GPIO_I2C1_SCL); stm32_unconfiggpio(GPIO_I2C1_SDA); + + up_disable_irq(STM32_IRQ_I2C1EV); + up_disable_irq(STM32_IRQ_I2C1ER); + irq_detach(STM32_IRQ_I2C1EV); + irq_detach(STM32_IRQ_I2C1ER); + modifyreg32(STM32_RCC_APB1ENR, RCC_APB1ENR_I2C1EN, 0); break; - +#endif + +#if CONFIG_STM32_I2C2 case STM32_I2C2_BASE: stm32_unconfiggpio(GPIO_I2C2_SCL); stm32_unconfiggpio(GPIO_I2C2_SDA); + + up_disable_irq(STM32_IRQ_I2C1EV); + up_disable_irq(STM32_IRQ_I2C1ER); + irq_detach(STM32_IRQ_I2C1EV); + irq_detach(STM32_IRQ_I2C1ER); + modifyreg32(STM32_RCC_APB1ENR, RCC_APB1ENR_I2C2EN, 0); break; +#endif default: return ERROR; } @@ -269,24 +384,6 @@ static int stm32_i2c_deinit(FAR struct i2c_dev_s *inst) /************************************************************************************ - * Interrupt Service Routines - ************************************************************************************/ - -static int stm32_i2c1_isr(int irq, void *context) -{ - // ACK before return! - return OK; -} - - -static int stm32_i2c2_isr(int irq, void *context) -{ - // ACK before return! - return OK; -} - - -/************************************************************************************ * Device Driver OPS - Blocking Type ************************************************************************************/ @@ -294,8 +391,12 @@ uint32_t stm32_i2c_setfrequency(FAR struct i2c_dev_s *inst, uint32_t frequency) { stm32_i2c_sem_wait(inst); +#if STM32_BOARD_HCLK < 4000000 + ((struct stm32_i2c_inst_s *)inst)->frequency = 100000; +#else ((struct stm32_i2c_inst_s *)inst)->frequency = frequency; - +#endif + stm32_i2c_sem_post(inst); return ((struct stm32_i2c_inst_s *)inst)->frequency; } @@ -306,42 +407,96 @@ int stm32_i2c_setaddress(FAR struct i2c_dev_s *inst, int addr, int nbits) stm32_i2c_sem_wait(inst); ((struct stm32_i2c_inst_s *)inst)->address = addr; + ((struct stm32_i2c_inst_s *)inst)->flags = (nbits == 10) ? I2C_M_TEN : 0; stm32_i2c_sem_post(inst); return OK; } + +int stm32_i2c_process(FAR struct i2c_dev_s *inst, FAR struct i2c_msg_s *msgs, int count) +{ + /* The semaphore already ensures that I2C is ours, since we do not yet support + * non-blocking operation. + */ + + ((struct stm32_i2c_inst_s *)inst)->priv->msgv = msgs; + ((struct stm32_i2c_inst_s *)inst)->priv->msgc = count; + + stm32_i2c_setclock(inst, ((struct stm32_i2c_inst_s *)inst)->frequency); + stm32_i2c_sendstart(inst); + + /* Trigger start condition, then the process moves into the ISR, + * until semaphore is posted. + */ + + stm32_i2c_sem_wait(inst); /* wait again for the semaphore and */ + stm32_i2c_sem_post(inst); /* release it immediately. */ + return OK; +} + int stm32_i2c_write(FAR struct i2c_dev_s *inst, const uint8_t *buffer, int buflen) { - stm32_i2c_sem_wait(inst); + stm32_i2c_sem_wait(inst); /* ensure that address or flags don't change meanwhile */ - stm32_i2c_setclock(inst); + struct i2c_msg_s msgv = { + .addr = ((struct stm32_i2c_inst_s *)inst)->address, + .flags = ((struct stm32_i2c_inst_s *)inst)->flags, + .buffer = (uint8_t *)buffer, + .length = buflen + }; - stm32_i2c_sem_post(inst); - return OK; + return stm32_i2c_process(inst, &msgv, 1); } int stm32_i2c_read(FAR struct i2c_dev_s *inst, uint8_t *buffer, int buflen) { - stm32_i2c_sem_wait(inst); + stm32_i2c_sem_wait(inst); /* ensure that address or flags don't change meanwhile */ - stm32_i2c_setclock(inst); + struct i2c_msg_s msgv = { + .addr = ((struct stm32_i2c_inst_s *)inst)->address, + .flags = ((struct stm32_i2c_inst_s *)inst)->flags | I2C_M_READ, + .buffer = buffer, + .length = buflen + }; - stm32_i2c_sem_post(inst); - return OK; + return stm32_i2c_process(inst, &msgv, 1); } +#ifdef CONFIG_I2C_WRITEREAD +int stm32_i2c_writeread(FAR struct i2c_dev_s *inst, const uint8_t *wbuffer, int wbuflen, + uint8_t *rbuffer, int rbuflen) +{ + stm32_i2c_sem_wait(inst); /* ensure that address or flags don't change meanwhile */ + + struct i2c_msg_s msgv[2] = { + { + .addr = ((struct stm32_i2c_inst_s *)inst)->address, + .flags = ((struct stm32_i2c_inst_s *)inst)->flags, + .buffer = (uint8_t *)wbuffer, /* this is really ugly, sorry const ... */ + .length = wbuflen + }, + { + .addr = ((struct stm32_i2c_inst_s *)inst)->address, + .flags = ((struct stm32_i2c_inst_s *)inst)->flags | I2C_M_READ, + .buffer = rbuffer, + .length = rbuflen + } + }; + + return stm32_i2c_process(inst, msgv, 2); +} +#endif + + #ifdef CONFIG_I2C_TRANSFER int stm32_i2c_transfer(FAR struct i2c_dev_s *inst, FAR struct i2c_msg_s *msgs, int count) { - stm32_i2c_sem_wait(inst); - - - stm32_i2c_sem_post(inst); - return OK; + stm32_i2c_sem_wait(inst); /* ensure that address or flags don't change meanwhile */ + return stm32_i2c_process(inst, msgs, count); } #endif @@ -351,29 +506,23 @@ int stm32_i2c_transfer(FAR struct i2c_dev_s *inst, FAR struct i2c_msg_s *msgs, i ************************************************************************************/ struct i2c_ops_s stm32_i2c_ops = { - .setfrequency = stm32_i2c_setfrequency, - .setaddress = stm32_i2c_setaddress, - .write = stm32_i2c_write, - .read = stm32_i2c_read + .setfrequency = stm32_i2c_setfrequency, + .setaddress = stm32_i2c_setaddress, + .write = stm32_i2c_write, + .read = stm32_i2c_read, +#ifdef CONFIG_I2C_WRITEREAD + .writeread = stm32_i2c_writeread +#endif #ifdef CONFIG_I2C_TRANSFER - , .transfer = stm32_i2c_transfer + , .transfer = stm32_i2c_transfer +#endif +#ifdef CONFIG_I2C_SLAVE + , .setownaddress = stm32_i2c_setownaddress, + .registercallback = stm32_i2c_registercallback #endif }; -struct stm32_i2c_priv_s stm32_i2c1_priv = { - .base = STM32_I2C1_BASE, - .refs = 0 -}; - - -struct stm32_i2c_priv_s stm32_i2c2_priv = { - .base = STM32_I2C2_BASE, - .refs = 0 -}; - - - /************************************************************************************ * Public Function - Initialization ************************************************************************************/ @@ -383,12 +532,25 @@ FAR struct i2c_dev_s * up_i2cinitialize(int port) struct stm32_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ struct stm32_i2c_inst_s * inst = NULL; /* device, single instance */ int irqs; + +#if STM32_BOARD_HCLK < 4000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. +#endif + +#if STM32_BOARD_HCLK < 2000000 +# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation. + return NULL; +#endif /* Get structure and enable power */ switch(port) { +#if CONFIG_STM32_I2C1 case 1: priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; break; +#endif +#if CONFIG_STM32_I2C2 case 2: priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; break; +#endif default: return NULL; } @@ -402,6 +564,7 @@ FAR struct i2c_dev_s * up_i2cinitialize(int port) inst->priv = priv; inst->frequency = 100e3; inst->address = 0; + inst->flags = 0; /* Init private data for the first time, increment refs count, * power-up hardware and configure GPIOs. @@ -453,5 +616,4 @@ int up_i2cuninitialize(FAR struct i2c_dev_s * inst) return OK; } -#endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C1 */ - +#endif /* defined(CONFIG_STM32_I2C1) && defined(CONFIG_STM32_I2C2) */ |