From 003c2c737ac3678887a53f5986feaee45fea75c0 Mon Sep 17 00:00:00 2001 From: ziggurat29 Date: Wed, 25 May 2016 18:43:37 -0500 Subject: [PATCH] get I2C working. some more work regarding clocking computation is needed, as is some inhertited 'todo's from the basis code. but it does work with the devices tested so far. --- arch/arm/src/stm32l4/Make.defs | 2 +- arch/arm/src/stm32l4/stm32l4_i2c.c | 216 +++++++++++++++-------------- 2 files changed, 115 insertions(+), 103 deletions(-) diff --git a/arch/arm/src/stm32l4/Make.defs b/arch/arm/src/stm32l4/Make.defs index 84acfadd1ac..d7b602efe47 100644 --- a/arch/arm/src/stm32l4/Make.defs +++ b/arch/arm/src/stm32l4/Make.defs @@ -141,12 +141,12 @@ CHIP_CSRCS += stm32l4_exti_pwr.c endif ifeq ($(CONFIG_RTC),y) -CHIP_CSRCS += stm32l4_rtcc.c ifeq ($(CONFIG_RTC_ALARM),y) CHIP_CSRCS += stm32l4_exti_alarm.c endif ifeq ($(CONFIG_RTC_DRIVER),y) CHIP_CSRCS += stm32l4_rtc_lowerhalf.c +CHIP_CSRCS += stm32l4_rtcc.c endif endif diff --git a/arch/arm/src/stm32l4/stm32l4_i2c.c b/arch/arm/src/stm32l4/stm32l4_i2c.c index 3a394cda750..7e083a31acc 100644 --- a/arch/arm/src/stm32l4/stm32l4_i2c.c +++ b/arch/arm/src/stm32l4/stm32l4_i2c.c @@ -1,22 +1,14 @@ /************************************************************************************ - * arch/arm/src/stm32l4/stm32f3xx_i2c.c + * arch/arm/src/stm32l4/stm32l4_i2c.c * STM32L4 I2C driver - based on STM32F3 I2C Hardware Layer - Device Driver * * Copyright (C) 2011 Uros Platise. All rights reserved. * Author: Uros Platise - * - * With extensions and modifications for the F1, F2, and F4 by: - * * Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved. * Author: Gregroy Nutt - * - * And this version for the STM32 F3 by - * * Author: John Wharington - * - * Modified for STM32L4 by - * * Author: Sebastien Lorquet + * Author: dev@ziggurat29.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -96,6 +88,7 @@ #include "up_arch.h" +#include "stm32l4_gpio.h" #include "stm32l4_rcc.h" #include "stm32l4_i2c.h" #include "stm32l4_waste.h" @@ -103,9 +96,6 @@ /* At least one I2C peripheral must be enabled */ #if defined(CONFIG_STM32L4_I2C1) || defined(CONFIG_STM32L4_I2C2) || defined(CONFIG_STM32L4_I2C3) -/* This implementation is for the STM32 F1, F2, and F4 only */ - -#if defined(CONFIG_STM32L4_STM32F30XX) /************************************************************************************ * Pre-processor Definitions @@ -138,12 +128,10 @@ #endif #define I2C_OUTPUT \ - (GPIO_OUTPUT | GPIO_OUTPUT_SET | GPIO_CNF_OUTOD | GPIO_MODE_50MHz) + (GPIO_OUTPUT | GPIO_OUTPUT_SET | GPIO_OPENDRAIN | GPIO_SPEED_50MHz) #define MKI2C_OUTPUT(p) \ (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) -/* Register setting unique to the STM32F30xx */ - #define I2C_CR1_TXRX \ (I2C_CR1_RXIE | I2C_CR1_TXIE) #define I2C_CR1_ALLINTS \ @@ -246,7 +234,7 @@ struct stm32l4_i2c_priv_s { const struct i2c_ops_s *ops; /* Standard I2C operations */ const struct stm32l4_i2c_config_s *config; /* Port configuration */ - int refs; /* Referernce count */ + int refs; /* Reference count */ sem_t sem_excl; /* Mutual exclusion semaphore */ #ifndef CONFIG_I2C_POLLED sem_t sem_isr; /* Interrupt wait semaphore */ @@ -279,15 +267,10 @@ struct stm32l4_i2c_priv_s * Private Function Prototypes ************************************************************************************/ -static inline uint16_t stm32l4_i2c_getreg(FAR struct stm32l4_i2c_priv_s *priv, - uint8_t offset); -static inline void stm32l4_i2c_putreg(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, - uint16_t value); +static inline uint32_t stm32l4_i2c_getreg32(FAR struct stm32l4_i2c_priv_s *priv, + uint8_t offset); static inline void stm32l4_i2c_putreg32(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, uint32_t value); -static inline void stm32l4_i2c_modifyreg(FAR struct stm32l4_i2c_priv_s *priv, - uint8_t offset, uint16_t clearbits, - uint16_t setbits); static inline void stm32l4_i2c_modifyreg32(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, uint32_t clearbits, uint32_t setbits); @@ -351,8 +334,8 @@ const struct i2c_ops_s stm32l4_i2c_ops = static const struct stm32l4_i2c_config_s stm32l4_i2c1_config = { .base = STM32L4_I2C1_BASE, - .clk_bit = RCC_APB1ENR_I2C1EN, - .reset_bit = RCC_APB1RSTR_I2C1RST, + .clk_bit = RCC_APB1ENR1_I2C1EN, + .reset_bit = RCC_APB1RSTR1_I2C1RST, .scl_pin = GPIO_I2C1_SCL, .sda_pin = GPIO_I2C1_SDA, #ifndef CONFIG_I2C_POLLED @@ -441,20 +424,6 @@ struct stm32l4_i2c_priv_s stm32l4_i2c3_priv = * Private Functions ************************************************************************************/ -/************************************************************************************ - * Name: stm32l4_i2c_getreg - * - * Description: - * Get a 16-bit register value by offset - * - ************************************************************************************/ - -static inline uint16_t stm32l4_i2c_getreg(FAR struct stm32l4_i2c_priv_s *priv, - uint8_t offset) -{ - return getreg16(priv->config->base + offset); -} - /************************************************************************************ * Name: stm32l4_i2c_getreg32 * @@ -469,20 +438,6 @@ static inline uint32_t stm32l4_i2c_getreg32(FAR struct stm32l4_i2c_priv_s *priv, return getreg32(priv->config->base + offset); } -/************************************************************************************ - * Name: stm32l4_i2c_putreg - * - * Description: - * Put a 16-bit register value by offset - * - ************************************************************************************/ - -static inline void stm32l4_i2c_putreg(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset, - uint16_t value) -{ - putreg16(value, priv->config->base + offset); -} - /************************************************************************************ * Name: stm32l4_i2c_putreg32 * @@ -497,21 +452,6 @@ static inline void stm32l4_i2c_putreg32(FAR struct stm32l4_i2c_priv_s *priv, putreg32(value, priv->config->base + offset); } -/************************************************************************************ - * Name: stm32l4_i2c_modifyreg - * - * Description: - * Modify a 16-bit register value by offset - * - ************************************************************************************/ - -static inline void stm32l4_i2c_modifyreg(FAR struct stm32l4_i2c_priv_s *priv, - uint8_t offset, uint16_t clearbits, - uint16_t setbits) -{ - modifyreg16(priv->config->base + offset, clearbits, setbits); -} - /************************************************************************************ * Name: stm32l4_i2c_modifyreg32 * @@ -615,7 +555,6 @@ static inline int stm32l4_i2c_sem_waitdone(FAR struct stm32l4_i2c_priv_s *priv) { struct timespec abstime; irqstate_t flags; - uint32_t regval; int ret; flags = enter_critical_section(); @@ -866,7 +805,7 @@ static inline void stm32l4_i2c_sem_waitstop(FAR struct stm32l4_i2c_priv_s *priv) /* Check for timeout error */ - sr = stm32l4_i2c_getreg(priv, STM32L4_I2C_ISR_OFFSET); + sr = stm32l4_i2c_getreg32(priv, STM32L4_I2C_ISR_OFFSET); if ((sr & I2C_INT_TIMEOUT) != 0) { return; @@ -1065,6 +1004,23 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, uint32_t f uint8_t scl_h_period; uint8_t scl_l_period; + /* XXX haque; these are the only freqs we support at the moment, until we can compute the values ourself */ + + if (frequency == 10000) + {} + else if (frequency == 100000) + {} + else if (frequency == 400000) + {} + else + { +#if 1 + frequency = 1000000; +#else + frequency = 500000; +#endif + } + /* Has the I2C bus frequency changed? */ if (frequency != priv->frequency) @@ -1079,41 +1035,101 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, uint32_t f /* Update timing and control registers */ - /* TODO: speed/timing calcs */ -#warning "check set filters before timing, see RM0316" - - /* values from 100khz at 8mhz i2c clock */ - - /* prescaler */ - /* t_presc= (presc+1)*t_i2cclk */ - /* RM0316 */ + /* TODO: speed/timing calcs, taking into consideration + * STM32L4_PCLK1_FREQUENCY, or SYSCLK, or HSI16 + * clock source, RCC_CCIPR, I2CxSEL, 0 = PCKL, 1 = SCLK, 2 = HSI16, 3 = reserved +#warning "check set filters before timing, see RM0351 35.4.4 p 1112" + * analog filter; suppress spikes up to 50 ns in fast-mode and fast-mode plus + * ANFOFF cr1 + * DNF cr1; 1-15 I2CCLK periods + */ + /* RM0351 35.4.9 p 1140 */ if (frequency == 10000) { - presc = 0x01; - scl_l_period = 0xc7; - scl_h_period = 0xc3; - h_time = 0x02; - s_time = 0x04; +#if 1 + /* 10 KHz values from I2C timing tool with clock 80mhz */ + + presc = 0x0b; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0xff; /* SCLL - SCL low period in master mode */ + scl_h_period = 0xba; /* SCLH - SCL high period in master mode */ + h_time = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + s_time = 0x01; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + +#else + /* 10 KHz values from datasheet with clock 8mhz */ + + presc = 0x03; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0xc7; /* SCLL - SCL low period in master mode */ + scl_h_period = 0xc3; /* SCLH - SCL high period in master mode */ + h_time = 0x02; /* SDADEL - (+1) data hold time after SCL falling edge */ + s_time = 0x04; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ +#endif } else if (frequency == 100000) { - /* values from datasheet with clock 8mhz */ +#if 1 + /* 100 KHz values from I2C timing tool with clock 80mhz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0xe7; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x9b; /* SCLH - SCL high period in master mode */ + h_time = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + s_time = 0x0d; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ +#else + /* 100 KHz values from datasheet with clock 8mhz */ presc = 0x01; scl_l_period = 0x13; scl_h_period = 0x0f; h_time = 0x02; s_time = 0x04; +#endif } - else + else if (frequency == 400000) { +#if 1 + /* 400 KHz values from I2C timing tool for clock of 80mhz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0x43; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ + h_time = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + s_time = 0x07; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ +#else + /* 400 KHz values from datasheet for clock of 8mhz */ + presc = 0x00; scl_l_period = 0x09; scl_h_period = 0x03; h_time = 0x01; s_time = 0x03; +#endif } + else + { +#if 1 + /* 1000 KHhz values from I2C timing tool for clock of 80mhz */ + + presc = 0x01; /* PRESC - (+1) prescale I2CCLK */ + scl_l_period = 0x14; /* SCLL - SCL low period in master mode */ + scl_h_period = 0x13; /* SCLH - SCL high period in master mode */ + h_time = 0x00; /* SDADEL - (+1) data hold time after SCL falling edge */ + s_time = 0x05; /* SCLDEL - (+1) data setup time from SDA edge to SCL rising edge */ + + frequency = 1000000; +#else + /* 500 KHhz values from datasheet for clock of 8mhz */ + + presc = 0x00; + scl_l_period = 0x06; + scl_h_period = 0x03; + h_time = 0x00; + s_time = 0x01; + + frequency = 500000; +#endif + } uint32_t timingr = (presc << I2C_TIMINGR_PRESC_SHIFT) | @@ -1124,10 +1140,6 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, uint32_t f stm32l4_i2c_putreg32(priv, STM32L4_I2C_TIMINGR_OFFSET, timingr); - /* Bit 14 of OAR1 must be configured and kept at 1 */ - - stm32l4_i2c_putreg(priv, STM32L4_I2C_OAR1_OFFSET, I2C_OAR1_ONE); - /* Re-enable the peripheral (or not) */ if (pe) @@ -1318,7 +1330,7 @@ static int stm32l4_i2c_isr(struct stm32l4_i2c_priv_s *priv) /* Send a byte */ stm32l4_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt); - stm32l4_i2c_putreg(priv, STM32L4_I2C_TXDR_OFFSET, *priv->ptr++); + stm32l4_i2c_putreg32(priv, STM32L4_I2C_TXDR_OFFSET, *priv->ptr++); priv->dcnt--; } } @@ -1354,7 +1366,7 @@ static int stm32l4_i2c_isr(struct stm32l4_i2c_priv_s *priv) #endif /* Receive a byte */ - *priv->ptr++ = stm32l4_i2c_getreg(priv, STM32L4_I2C_RXDR_OFFSET); + *priv->ptr++ = (uint8_t) stm32l4_i2c_getreg32(priv, STM32L4_I2C_RXDR_OFFSET); /* Disable acknowledge when last byte is to be received */ @@ -1554,9 +1566,9 @@ static int stm32l4_i2c_init(FAR struct stm32l4_i2c_priv_s *priv) /* Enable power and reset the peripheral */ - modifyreg32(STM32L4_RCC_APB1ENR, 0, priv->config->clk_bit); - modifyreg32(STM32L4_RCC_APB1RSTR, 0, priv->config->reset_bit); - modifyreg32(STM32L4_RCC_APB1RSTR, priv->config->reset_bit, 0); + modifyreg32(STM32L4_RCC_APB1ENR1, 0, priv->config->clk_bit); + modifyreg32(STM32L4_RCC_APB1RSTR1, 0, priv->config->reset_bit); + modifyreg32(STM32L4_RCC_APB1RSTR1, priv->config->reset_bit, 0); /* Configure pins */ @@ -1588,8 +1600,8 @@ static int stm32l4_i2c_init(FAR struct stm32l4_i2c_priv_s *priv) priv->frequency = 0; - /* TODO: f303 i2c clock source RCC_CFGR3 */ - /* RCC_CFGR3_I2C1SW (default is HSI clock) */ + /* TODO: i2c clock source RCC_CCIPR */ + /* RCC_CCIPR I2CxSEL (default is PCLK clock) */ stm32l4_i2c_setclock(priv, 100000); @@ -1629,7 +1641,7 @@ static int stm32l4_i2c_deinit(FAR struct stm32l4_i2c_priv_s *priv) /* Disable clocking */ - modifyreg32(STM32L4_RCC_APB1ENR, priv->config->clk_bit, 0); + modifyreg32(STM32L4_RCC_APB1ENR1, priv->config->clk_bit, 0); return OK; } @@ -1713,8 +1725,8 @@ static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg status = stm32l4_i2c_getstatus(priv); ret = -ETIMEDOUT; - i2cdbg("Timed out: CR1: %04x status: %08x\n", - stm32l4_i2c_getreg(priv, STM32L4_I2C_CR1_OFFSET), status); + i2cdbg("Timed out: CR1: %08x status: %08x\n", + stm32l4_i2c_getreg32(priv, STM32L4_I2C_CR1_OFFSET), status); /* "Note: When the STOP, START or PEC bit is set, the software must * not perform any write access to I2C_CR1 before this bit is @@ -1836,6 +1848,7 @@ static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg #ifdef CONFIG_I2C_RESET static int stm32l4_i2c_reset(FAR struct i2c_master_s * dev) { + FAR struct stm32l4_i2c_priv_s *priv = (struct stm32l4_i2c_priv_s *)dev; unsigned int clock_count; unsigned int stretch_count; uint32_t scl_gpio; @@ -1962,7 +1975,7 @@ out: FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port) { struct stm32l4_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ - irqtate_t flags; + irqstate_t flags; #if STM32L4_PCLK1_FREQUENCY < 4000000 # warning STM32L4_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. @@ -2054,6 +2067,5 @@ int stm32l4_i2cbus_uninitialize(FAR struct i2c_master_s * dev) return OK; } -#endif /* CONFIG_STM32L4_STM32F30XX */ #endif /* CONFIG_STM32L4_I2C1 || CONFIG_STM32L4_I2C2 || CONFIG_STM32L4_I2C3 */