Merged in ziggurat29/nuttx/stm32l4_i2c_lcd_mjkdz_001 (pull request #30)

get I2C working for STM32L4
This commit is contained in:
Gregory Nutt 2016-05-25 17:58:19 -06:00
commit 0d2698a710
2 changed files with 115 additions and 103 deletions

View File

@ -141,12 +141,12 @@ CHIP_CSRCS += stm32l4_exti_pwr.c
endif endif
ifeq ($(CONFIG_RTC),y) ifeq ($(CONFIG_RTC),y)
CHIP_CSRCS += stm32l4_rtcc.c
ifeq ($(CONFIG_RTC_ALARM),y) ifeq ($(CONFIG_RTC_ALARM),y)
CHIP_CSRCS += stm32l4_exti_alarm.c CHIP_CSRCS += stm32l4_exti_alarm.c
endif endif
ifeq ($(CONFIG_RTC_DRIVER),y) ifeq ($(CONFIG_RTC_DRIVER),y)
CHIP_CSRCS += stm32l4_rtc_lowerhalf.c CHIP_CSRCS += stm32l4_rtc_lowerhalf.c
CHIP_CSRCS += stm32l4_rtcc.c
endif endif
endif endif

View File

@ -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 * STM32L4 I2C driver - based on STM32F3 I2C Hardware Layer - Device Driver
* *
* Copyright (C) 2011 Uros Platise. All rights reserved. * Copyright (C) 2011 Uros Platise. All rights reserved.
* Author: Uros Platise <uros.platise@isotel.eu> * Author: Uros Platise <uros.platise@isotel.eu>
*
* With extensions and modifications for the F1, F2, and F4 by:
*
* Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved. * Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregroy Nutt <gnutt@nuttx.org> * Author: Gregroy Nutt <gnutt@nuttx.org>
*
* And this version for the STM32 F3 by
*
* Author: John Wharington * Author: John Wharington
*
* Modified for STM32L4 by
*
* Author: Sebastien Lorquet * Author: Sebastien Lorquet
* Author: dev@ziggurat29.com
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -96,6 +88,7 @@
#include "up_arch.h" #include "up_arch.h"
#include "stm32l4_gpio.h"
#include "stm32l4_rcc.h" #include "stm32l4_rcc.h"
#include "stm32l4_i2c.h" #include "stm32l4_i2c.h"
#include "stm32l4_waste.h" #include "stm32l4_waste.h"
@ -103,9 +96,6 @@
/* At least one I2C peripheral must be enabled */ /* At least one I2C peripheral must be enabled */
#if defined(CONFIG_STM32L4_I2C1) || defined(CONFIG_STM32L4_I2C2) || defined(CONFIG_STM32L4_I2C3) #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 * Pre-processor Definitions
@ -138,12 +128,10 @@
#endif #endif
#define I2C_OUTPUT \ #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) \ #define MKI2C_OUTPUT(p) \
(((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT)
/* Register setting unique to the STM32F30xx */
#define I2C_CR1_TXRX \ #define I2C_CR1_TXRX \
(I2C_CR1_RXIE | I2C_CR1_TXIE) (I2C_CR1_RXIE | I2C_CR1_TXIE)
#define I2C_CR1_ALLINTS \ #define I2C_CR1_ALLINTS \
@ -246,7 +234,7 @@ struct stm32l4_i2c_priv_s
{ {
const struct i2c_ops_s *ops; /* Standard I2C operations */ const struct i2c_ops_s *ops; /* Standard I2C operations */
const struct stm32l4_i2c_config_s *config; /* Port configuration */ const struct stm32l4_i2c_config_s *config; /* Port configuration */
int refs; /* Referernce count */ int refs; /* Reference count */
sem_t sem_excl; /* Mutual exclusion semaphore */ sem_t sem_excl; /* Mutual exclusion semaphore */
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
sem_t sem_isr; /* Interrupt wait semaphore */ sem_t sem_isr; /* Interrupt wait semaphore */
@ -279,15 +267,10 @@ struct stm32l4_i2c_priv_s
* Private Function Prototypes * Private Function Prototypes
************************************************************************************/ ************************************************************************************/
static inline uint16_t stm32l4_i2c_getreg(FAR struct stm32l4_i2c_priv_s *priv, static inline uint32_t stm32l4_i2c_getreg32(FAR struct stm32l4_i2c_priv_s *priv,
uint8_t offset); uint8_t offset);
static inline void stm32l4_i2c_putreg(FAR struct stm32l4_i2c_priv_s *priv, uint8_t offset,
uint16_t value);
static inline void stm32l4_i2c_putreg32(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); 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, static inline void stm32l4_i2c_modifyreg32(FAR struct stm32l4_i2c_priv_s *priv,
uint8_t offset, uint32_t clearbits, uint8_t offset, uint32_t clearbits,
uint32_t setbits); 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 = static const struct stm32l4_i2c_config_s stm32l4_i2c1_config =
{ {
.base = STM32L4_I2C1_BASE, .base = STM32L4_I2C1_BASE,
.clk_bit = RCC_APB1ENR_I2C1EN, .clk_bit = RCC_APB1ENR1_I2C1EN,
.reset_bit = RCC_APB1RSTR_I2C1RST, .reset_bit = RCC_APB1RSTR1_I2C1RST,
.scl_pin = GPIO_I2C1_SCL, .scl_pin = GPIO_I2C1_SCL,
.sda_pin = GPIO_I2C1_SDA, .sda_pin = GPIO_I2C1_SDA,
#ifndef CONFIG_I2C_POLLED #ifndef CONFIG_I2C_POLLED
@ -441,20 +424,6 @@ struct stm32l4_i2c_priv_s stm32l4_i2c3_priv =
* Private Functions * 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 * 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); 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 * 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); 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 * 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; struct timespec abstime;
irqstate_t flags; irqstate_t flags;
uint32_t regval;
int ret; int ret;
flags = enter_critical_section(); 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 */ /* 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) if ((sr & I2C_INT_TIMEOUT) != 0)
{ {
return; 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_h_period;
uint8_t scl_l_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? */ /* Has the I2C bus frequency changed? */
if (frequency != priv->frequency) if (frequency != priv->frequency)
@ -1079,40 +1035,100 @@ static void stm32l4_i2c_setclock(FAR struct stm32l4_i2c_priv_s *priv, uint32_t f
/* Update timing and control registers */ /* Update timing and control registers */
/* TODO: speed/timing calcs */ /* TODO: speed/timing calcs, taking into consideration
#warning "check set filters before timing, see RM0316" * STM32L4_PCLK1_FREQUENCY, or SYSCLK, or HSI16
* clock source, RCC_CCIPR, I2CxSEL, 0 = PCKL, 1 = SCLK, 2 = HSI16, 3 = reserved
/* values from 100khz at 8mhz i2c clock */ #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
/* prescaler */ * ANFOFF cr1
/* t_presc= (presc+1)*t_i2cclk */ * DNF cr1; 1-15 I2CCLK periods
/* RM0316 */ */
/* RM0351 35.4.9 p 1140 */
if (frequency == 10000) if (frequency == 10000)
{ {
presc = 0x01; #if 1
scl_l_period = 0xc7; /* 10 KHz values from I2C timing tool with clock 80mhz */
scl_h_period = 0xc3;
h_time = 0x02; presc = 0x0b; /* PRESC - (+1) prescale I2CCLK */
s_time = 0x04; 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) 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; presc = 0x01;
scl_l_period = 0x13; scl_l_period = 0x13;
scl_h_period = 0x0f; scl_h_period = 0x0f;
h_time = 0x02; h_time = 0x02;
s_time = 0x04; 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; presc = 0x00;
scl_l_period = 0x09; scl_l_period = 0x09;
scl_h_period = 0x03; scl_h_period = 0x03;
h_time = 0x01; h_time = 0x01;
s_time = 0x03; 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 = uint32_t timingr =
@ -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); 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) */ /* Re-enable the peripheral (or not) */
if (pe) if (pe)
@ -1318,7 +1330,7 @@ static int stm32l4_i2c_isr(struct stm32l4_i2c_priv_s *priv)
/* Send a byte */ /* Send a byte */
stm32l4_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt); 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--; priv->dcnt--;
} }
} }
@ -1354,7 +1366,7 @@ static int stm32l4_i2c_isr(struct stm32l4_i2c_priv_s *priv)
#endif #endif
/* Receive a byte */ /* 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 */ /* 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 */ /* Enable power and reset the peripheral */
modifyreg32(STM32L4_RCC_APB1ENR, 0, priv->config->clk_bit); modifyreg32(STM32L4_RCC_APB1ENR1, 0, priv->config->clk_bit);
modifyreg32(STM32L4_RCC_APB1RSTR, 0, priv->config->reset_bit); modifyreg32(STM32L4_RCC_APB1RSTR1, 0, priv->config->reset_bit);
modifyreg32(STM32L4_RCC_APB1RSTR, priv->config->reset_bit, 0); modifyreg32(STM32L4_RCC_APB1RSTR1, priv->config->reset_bit, 0);
/* Configure pins */ /* Configure pins */
@ -1588,8 +1600,8 @@ static int stm32l4_i2c_init(FAR struct stm32l4_i2c_priv_s *priv)
priv->frequency = 0; priv->frequency = 0;
/* TODO: f303 i2c clock source RCC_CFGR3 */ /* TODO: i2c clock source RCC_CCIPR */
/* RCC_CFGR3_I2C1SW (default is HSI clock) */ /* RCC_CCIPR I2CxSEL (default is PCLK clock) */
stm32l4_i2c_setclock(priv, 100000); stm32l4_i2c_setclock(priv, 100000);
@ -1629,7 +1641,7 @@ static int stm32l4_i2c_deinit(FAR struct stm32l4_i2c_priv_s *priv)
/* Disable clocking */ /* Disable clocking */
modifyreg32(STM32L4_RCC_APB1ENR, priv->config->clk_bit, 0); modifyreg32(STM32L4_RCC_APB1ENR1, priv->config->clk_bit, 0);
return OK; 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); status = stm32l4_i2c_getstatus(priv);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
i2cdbg("Timed out: CR1: %04x status: %08x\n", i2cdbg("Timed out: CR1: %08x status: %08x\n",
stm32l4_i2c_getreg(priv, STM32L4_I2C_CR1_OFFSET), status); stm32l4_i2c_getreg32(priv, STM32L4_I2C_CR1_OFFSET), status);
/* "Note: When the STOP, START or PEC bit is set, the software must /* "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 * 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 #ifdef CONFIG_I2C_RESET
static int stm32l4_i2c_reset(FAR struct i2c_master_s * dev) 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 clock_count;
unsigned int stretch_count; unsigned int stretch_count;
uint32_t scl_gpio; uint32_t scl_gpio;
@ -1962,7 +1975,7 @@ out:
FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port) FAR struct i2c_master_s *stm32l4_i2cbus_initialize(int port)
{ {
struct stm32l4_i2c_priv_s * priv = NULL; /* private data of device with multiple instances */ 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 #if STM32L4_PCLK1_FREQUENCY < 4000000
# warning STM32L4_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation. # 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; return OK;
} }
#endif /* CONFIG_STM32L4_STM32F30XX */
#endif /* CONFIG_STM32L4_I2C1 || CONFIG_STM32L4_I2C2 || CONFIG_STM32L4_I2C3 */ #endif /* CONFIG_STM32L4_I2C1 || CONFIG_STM32L4_I2C2 || CONFIG_STM32L4_I2C3 */