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.

This commit is contained in:
ziggurat29 2016-05-25 18:43:37 -05:00
parent b7935f5705
commit 003c2c737a
2 changed files with 115 additions and 103 deletions

View File

@ -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

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
*
* Copyright (C) 2011 Uros Platise. All rights reserved.
* 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.
* Author: Gregroy Nutt <gnutt@nuttx.org>
*
* 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 */