summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/stm32/stm32_i2c.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-28 15:01:43 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-03-28 15:01:43 +0000
commit82fb23b2cc78fade702316d00510efcf9d65954f (patch)
treea997a6f40b080a1e31890359dde9fc466e726221 /nuttx/arch/arm/src/stm32/stm32_i2c.c
parentb197eb1609652b2b766bb79caf00b23ef07eed40 (diff)
downloadpx4-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.c302
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) */