Fix I2C/FSMC conflict for STM32; Fix STM32 clock setup
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3942 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
19e5bfd627
commit
d96149a9d1
@ -2060,3 +2060,7 @@
|
|||||||
Li Zhuoyi (Lzyy).
|
Li Zhuoyi (Lzyy).
|
||||||
* arch/arm/src/lpc17xx/lpc17_i2c.c: I2C driver for the NXP LPC17xx family
|
* arch/arm/src/lpc17xx/lpc17_i2c.c: I2C driver for the NXP LPC17xx family
|
||||||
submitted by Li Zhuoyi (Lzyy)
|
submitted by Li Zhuoyi (Lzyy)
|
||||||
|
* arch/arm/src/stm32_i2c.c: Correct two issues with the STM32 I2C driver:
|
||||||
|
(1) Clocking needs to be based on PCLK1, not HCLK and fast speed settings
|
||||||
|
need some additional bits; and (2) Correct a hang that will occur on
|
||||||
|
I2C1 if FSMC is also enabled.
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
/* Control register 1 */
|
/* Control register 1 */
|
||||||
|
|
||||||
#define I2C_CR1_PE (1 << 0) /* Bit 0: Peripheral Enable*/
|
#define I2C_CR1_PE (1 << 0) /* Bit 0: Peripheral Enable */
|
||||||
#define I2C_CR1_SMBUS (1 << 1) /* Bit 1: SMBus Mode */
|
#define I2C_CR1_SMBUS (1 << 1) /* Bit 1: SMBus Mode */
|
||||||
#define I2C_CR1_SMBTYPE (1 << 3) /* Bit 3: SMBus Type */
|
#define I2C_CR1_SMBTYPE (1 << 3) /* Bit 3: SMBus Type */
|
||||||
#define I2C_CR1_ENARP (1 << 4) /* Bit 4: ARP Enable */
|
#define I2C_CR1_ENARP (1 << 4) /* Bit 4: ARP Enable */
|
||||||
@ -167,7 +167,7 @@
|
|||||||
#define I2C_CCR_CCR_SHIFT (0) /* Bits 11-0: Clock Control Register in Fast/Standard mode (Master mode) */
|
#define I2C_CCR_CCR_SHIFT (0) /* Bits 11-0: Clock Control Register in Fast/Standard mode (Master mode) */
|
||||||
#define I2C_CCR_CCR_MASK (0x0fff << I2C_CCR_CCR_SHIFT)
|
#define I2C_CCR_CCR_MASK (0x0fff << I2C_CCR_CCR_SHIFT)
|
||||||
#define I2C_CCR_DUTY (1 << 14) /* Bit 14: Fast Mode Duty Cycle */
|
#define I2C_CCR_DUTY (1 << 14) /* Bit 14: Fast Mode Duty Cycle */
|
||||||
#define I2C_CCR_FS (1 << 15) /* Bit 15: I2C Master Mode Selection */
|
#define I2C_CCR_FS (1 << 15) /* Bit 15: Fast Mode Selection */
|
||||||
|
|
||||||
/* TRISE Register */
|
/* TRISE Register */
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@
|
|||||||
|
|
||||||
/* APB2 Peripheral reset register */
|
/* APB2 Peripheral reset register */
|
||||||
|
|
||||||
#define RCC_APB2RSTR_AFIORST (1 << 0) /* Bit 0: Alternate Function I/O reset */
|
#define RCC_APB2RSTR_AFIORST (1 << 0) /* Bit 0: Alternate Function I/O reset */
|
||||||
#define RCC_APB2RSTR_IOPARST (1 << 2) /* Bit 2: I/O port A reset */
|
#define RCC_APB2RSTR_IOPARST (1 << 2) /* Bit 2: I/O port A reset */
|
||||||
#define RCC_APB2RSTR_IOPBRST (1 << 3) /* Bit 3: IO port B reset */
|
#define RCC_APB2RSTR_IOPBRST (1 << 3) /* Bit 3: IO port B reset */
|
||||||
#define RCC_APB2RSTR_IOPCRST (1 << 4) /* Bit 4: IO port C reset */
|
#define RCC_APB2RSTR_IOPCRST (1 << 4) /* Bit 4: IO port C reset */
|
||||||
|
@ -94,8 +94,9 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
/* Configuration ********************************************************************/
|
/* Configuration ********************************************************************/
|
||||||
/* Interrupt wait timeout in milliseconds */
|
/* Interrupt wait timeout in seconds and milliseconds */
|
||||||
|
|
||||||
|
#undef CONFIG_STM32_I2CTIMEOSEC
|
||||||
#ifndef CONFIG_STM32_I2CTIMEOMS
|
#ifndef CONFIG_STM32_I2CTIMEOMS
|
||||||
# define CONFIG_STM32_I2CTIMEOMS 50
|
# define CONFIG_STM32_I2CTIMEOMS 50
|
||||||
#endif
|
#endif
|
||||||
@ -104,61 +105,65 @@
|
|||||||
* Private Types
|
* Private Types
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
/** I2C Device Private Data
|
/* I2C Device Private Data */
|
||||||
*/
|
|
||||||
struct stm32_i2c_priv_s {
|
struct stm32_i2c_priv_s
|
||||||
uint32_t base;
|
{
|
||||||
int refs;
|
uint32_t base;
|
||||||
sem_t sem_excl;
|
int refs;
|
||||||
sem_t sem_isr;
|
sem_t sem_excl;
|
||||||
|
sem_t sem_isr;
|
||||||
|
|
||||||
uint8_t msgc;
|
uint8_t msgc;
|
||||||
struct i2c_msg_s *msgv;
|
struct i2c_msg_s *msgv;
|
||||||
uint8_t * ptr;
|
uint8_t *ptr;
|
||||||
int dcnt;
|
int dcnt;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** I2C Device, Instance
|
/* I2C Device, Instance */
|
||||||
*/
|
|
||||||
struct stm32_i2c_inst_s {
|
struct stm32_i2c_inst_s
|
||||||
struct i2c_ops_s * ops;
|
{
|
||||||
struct stm32_i2c_priv_s * priv;
|
struct i2c_ops_s *ops;
|
||||||
|
struct stm32_i2c_priv_s *priv;
|
||||||
|
|
||||||
uint32_t frequency;
|
uint32_t frequency;
|
||||||
int address;
|
int address;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C1
|
#ifdef CONFIG_STM32_I2C1
|
||||||
struct stm32_i2c_priv_s stm32_i2c1_priv = {
|
struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||||
.base = STM32_I2C1_BASE,
|
{
|
||||||
.refs = 0,
|
.base = STM32_I2C1_BASE,
|
||||||
.msgc = 0,
|
.refs = 0,
|
||||||
.msgv = NULL,
|
.msgc = 0,
|
||||||
.ptr = NULL,
|
.msgv = NULL,
|
||||||
.dcnt = 0,
|
.ptr = NULL,
|
||||||
.flags = 0,
|
.dcnt = 0,
|
||||||
.status = 0
|
.flags = 0,
|
||||||
|
.status = 0
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C2
|
#ifdef CONFIG_STM32_I2C2
|
||||||
struct stm32_i2c_priv_s stm32_i2c2_priv = {
|
struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||||
.base = STM32_I2C2_BASE,
|
{
|
||||||
.refs = 0,
|
.base = STM32_I2C2_BASE,
|
||||||
.msgc = 0,
|
.refs = 0,
|
||||||
.msgv = NULL,
|
.msgc = 0,
|
||||||
.ptr = NULL,
|
.msgv = NULL,
|
||||||
.dcnt = 0,
|
.ptr = NULL,
|
||||||
.flags = 0,
|
.dcnt = 0,
|
||||||
.status = 0
|
.flags = 0,
|
||||||
|
.status = 0
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -200,13 +205,24 @@ int inline stm32_i2c_sem_waitisr(FAR struct i2c_dev_s *dev)
|
|||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
/* Get the current time */
|
||||||
|
|
||||||
(void)clock_gettime(CLOCK_REALTIME, &abstime);
|
(void)clock_gettime(CLOCK_REALTIME, &abstime);
|
||||||
|
|
||||||
|
/* Calculate a time in the future */
|
||||||
|
|
||||||
|
#if defined(CONFIG_STM32_I2CTIMEOSEC) && CONFIG_STM32_I2CTIMEOSEC > 0
|
||||||
|
abstime.tv_sec += CONFIG_STM32_I2CTIMEOSEC;
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_STM32_I2CTIMEOMS) && CONFIG_STM32_I2CTIMEOMS > 0
|
||||||
abstime.tv_nsec += CONFIG_STM32_I2CTIMEOMS * 1000 * 1000;
|
abstime.tv_nsec += CONFIG_STM32_I2CTIMEOMS * 1000 * 1000;
|
||||||
if (abstime.tv_nsec > 1000 * 1000 * 1000)
|
if (abstime.tv_nsec > 1000 * 1000 * 1000)
|
||||||
{
|
{
|
||||||
abstime.tv_sec++;
|
abstime.tv_sec++;
|
||||||
abstime.tv_nsec -= 1000 * 1000 * 1000;
|
abstime.tv_nsec -= 1000 * 1000 * 1000;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
/* Wait until either the transfer is complete or the timeout expires */
|
||||||
|
|
||||||
ret = sem_timedwait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_isr, &abstime);
|
ret = sem_timedwait(&((struct stm32_i2c_inst_s *)dev)->priv->sem_isr, &abstime);
|
||||||
}
|
}
|
||||||
@ -235,58 +251,166 @@ void inline stm32_i2c_sem_destroy(FAR struct i2c_dev_s *dev)
|
|||||||
|
|
||||||
static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequency)
|
static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequency)
|
||||||
{
|
{
|
||||||
/* Disable Peripheral if rising time is to be changed,
|
uint16_t cr1;
|
||||||
* and restore state on return. */
|
uint16_t ccr;
|
||||||
|
uint16_t trise;
|
||||||
|
uint16_t freqmhz;
|
||||||
|
uint16_t speed;
|
||||||
|
|
||||||
uint16_t cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET);
|
/* Disable the selected I2C peripheral to configure TRISE */
|
||||||
|
|
||||||
if (cr1 & I2C_CR1_PE)
|
cr1 = stm32_i2c_getreg(priv, STM32_I2C_CR1_OFFSET);
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 ^ I2C_CR1_PE);
|
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1 & ~I2C_CR1_PE);
|
||||||
|
|
||||||
/* Update timing and control registers */
|
/* Update timing and control registers */
|
||||||
|
|
||||||
if (frequency < 400000) {
|
freqmhz = (uint16_t)(STM32_PCLK1_FREQUENCY / 1000000);
|
||||||
|
ccr = 0;
|
||||||
/* Speed: 100 kHz
|
|
||||||
* Risetime: 1000 ns
|
/* Configure speed in standard mode */
|
||||||
* Duty: t_low / t_high = 1
|
|
||||||
*/
|
if (frequency <= 100000)
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK/200000);
|
{
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, STM32_BOARD_HCLK/1000000 + 1);
|
/* Standard mode speed calculation */
|
||||||
|
|
||||||
|
speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency << 1));
|
||||||
|
|
||||||
|
/* The CCR fault must be >= 4 */
|
||||||
|
|
||||||
|
if (speed < 4)
|
||||||
|
{
|
||||||
|
/* Set the minimum allowed value */
|
||||||
|
|
||||||
|
speed = 4;
|
||||||
|
}
|
||||||
|
ccr |= speed;
|
||||||
|
|
||||||
|
/* Set Maximum Rise Time for standard mode */
|
||||||
|
|
||||||
|
trise = freqmhz + 1;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
/* Configure speed in fast mode */
|
||||||
/* Speed: 400 kHz
|
|
||||||
* Duty: t_low / t_high = 2
|
else /* (frequency <= 400000) */
|
||||||
*/
|
{
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, STM32_BOARD_HCLK/1200000);
|
/* Fast mode speed calculation with Tlow/Thigh = 16/9 */
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, 300*(STM32_BOARD_HCLK / 1000000)/1000 + 1);
|
|
||||||
|
#ifdef CONFIG_I2C_DUTY16_9
|
||||||
|
speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 25));
|
||||||
|
|
||||||
|
/* Set DUTY and fast speed bits */
|
||||||
|
|
||||||
|
ccr |= (I2C_CCR_DUTY|I2C_CCR_FS);
|
||||||
|
#else
|
||||||
|
/* Fast mode speed calculation with Tlow/Thigh = 2 */
|
||||||
|
|
||||||
|
speed = (uint16_t)(STM32_PCLK1_FREQUENCY / (frequency * 3));
|
||||||
|
|
||||||
|
/* Set fast speed bit */
|
||||||
|
|
||||||
|
ccr |= I2C_CCR_FS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Verify that the CCR speed value is nonzero */
|
||||||
|
|
||||||
|
if (speed < 1)
|
||||||
|
{
|
||||||
|
/* Set the minimum allowed value */
|
||||||
|
|
||||||
|
speed = 1;
|
||||||
|
}
|
||||||
|
ccr |= speed;
|
||||||
|
|
||||||
|
/* Set Maximum Rise Time for fast mode */
|
||||||
|
|
||||||
|
trise = (uint16_t)(((freqmhz * 300) / 1000) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore state */
|
/* Write the new values of the CCR and TRISE registers */
|
||||||
|
|
||||||
if (cr1 & I2C_CR1_PE)
|
stm32_i2c_putreg(priv, STM32_I2C_CCR_OFFSET, ccr);
|
||||||
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1);
|
stm32_i2c_putreg(priv, STM32_I2C_TRISE_OFFSET, trise);
|
||||||
|
|
||||||
|
/* Bit 14 of OAR1 must be configured and kept at 1 */
|
||||||
|
|
||||||
|
stm32_i2c_putreg(priv, STM32_I2C_OAR1_OFFSET, I2C_OAR1_ONE);
|
||||||
|
|
||||||
|
/* Re-enable the peripheral (or not) */
|
||||||
|
|
||||||
|
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stm32_i2c_sendstart(FAR struct stm32_i2c_priv_s *priv)
|
static inline void stm32_i2c_sendstart(FAR struct stm32_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
/* Disable ACK on receive by default and generate START */
|
/* Disable ACK on receive by default and generate START */
|
||||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_START);
|
|
||||||
|
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stm32_i2c_clrstart(FAR struct stm32_i2c_priv_s *priv)
|
||||||
|
{
|
||||||
|
/* "This [START] bit is set and cleared by software and cleared by hardware
|
||||||
|
* when start is sent or PE=0." The bit must be cleared by software if the
|
||||||
|
* START is never sent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_START, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stm32_i2c_sendstop(FAR struct stm32_i2c_priv_s *priv)
|
static inline void stm32_i2c_sendstop(FAR struct stm32_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_STOP);
|
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t stm32_i2c_getstatus(FAR struct stm32_i2c_priv_s *priv)
|
static inline uint32_t stm32_i2c_getstatus(FAR struct stm32_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
uint32_t status = stm32_i2c_getreg(priv, STM32_I2C_SR1_OFFSET);
|
uint32_t status = stm32_i2c_getreg(priv, STM32_I2C_SR1_OFFSET);
|
||||||
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
|
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FSMC must be disable while accessing I2C1 because it uses a common resource (LBAR) */
|
||||||
|
|
||||||
|
#if defined(CONFIG_STM32_FSMC) && defined (CONFIG_STM32_I2C1)
|
||||||
|
static inline uint32_t stm32_i2c_disablefsmc(FAR struct stm32_i2c_priv_s *priv)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Is this I2C1 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32_I2C2
|
||||||
|
if (priv->base == STM32_I2C1_BASE)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Disable FSMC unconditionally */
|
||||||
|
|
||||||
|
ret = getreg32( STM32_RCC_AHBENR);
|
||||||
|
regval = ret & ~RCC_AHBENR_FSMCEN;
|
||||||
|
putreg32(regval, STM32_RCC_AHBENR);
|
||||||
|
}
|
||||||
|
return regval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void stm32_i2c_enablefsmc(uint32_t ahbenr)
|
||||||
|
{
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Enable AHB clocking to the FSMC only if it was previously enabled. */
|
||||||
|
|
||||||
|
if ((ahbenr & RCC_AHBENR_FSMCEN) != 0)
|
||||||
|
{
|
||||||
|
regval = getreg32( STM32_RCC_AHBENR);
|
||||||
|
regval |= RCC_AHBENR_FSMCEN;
|
||||||
|
putreg32(regval, STM32_RCC_AHBENR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define stm32_i2c_disablefsmc() (0)
|
||||||
|
# define stm32_i2c_enablefsmc(ahbenr)
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Interrupt Service Routines
|
* Interrupt Service Routines
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
@ -456,14 +580,14 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s * priv)
|
|||||||
|
|
||||||
/* Decode ***************************************************************************/
|
/* Decode ***************************************************************************/
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C1
|
#ifdef CONFIG_STM32_I2C1
|
||||||
static int stm32_i2c1_isr(int irq, void *context)
|
static int stm32_i2c1_isr(int irq, void *context)
|
||||||
{
|
{
|
||||||
return stm32_i2c_isr(&stm32_i2c1_priv);
|
return stm32_i2c_isr(&stm32_i2c1_priv);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C2
|
#ifdef CONFIG_STM32_I2C2
|
||||||
static int stm32_i2c2_isr(int irq, void *context)
|
static int stm32_i2c2_isr(int irq, void *context)
|
||||||
{
|
{
|
||||||
return stm32_i2c_isr(&stm32_i2c2_priv);
|
return stm32_i2c_isr(&stm32_i2c2_priv);
|
||||||
@ -481,16 +605,16 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
|
|
||||||
switch( priv->base ) {
|
switch( priv->base ) {
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C1
|
#ifdef CONFIG_STM32_I2C1
|
||||||
case STM32_I2C1_BASE:
|
case STM32_I2C1_BASE:
|
||||||
|
|
||||||
/* enable power and reset the peripheral */
|
/* enable power and reset the peripheral */
|
||||||
|
|
||||||
modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_I2C1EN);
|
modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_I2C1EN);
|
||||||
|
|
||||||
modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_I2C1RST);
|
modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_I2C1RST);
|
||||||
modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST, 0);
|
modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST, 0);
|
||||||
|
|
||||||
/* configure pins */
|
/* configure pins */
|
||||||
|
|
||||||
if (stm32_configgpio(GPIO_I2C1_SCL)==ERROR) return ERROR;
|
if (stm32_configgpio(GPIO_I2C1_SCL)==ERROR) return ERROR;
|
||||||
@ -498,7 +622,7 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
stm32_unconfiggpio(GPIO_I2C1_SCL);
|
stm32_unconfiggpio(GPIO_I2C1_SCL);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* attach ISRs */
|
/* attach ISRs */
|
||||||
|
|
||||||
irq_attach(STM32_IRQ_I2C1EV, stm32_i2c1_isr);
|
irq_attach(STM32_IRQ_I2C1EV, stm32_i2c1_isr);
|
||||||
@ -508,7 +632,7 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C2
|
#ifdef CONFIG_STM32_I2C2
|
||||||
case STM32_I2C2_BASE:
|
case STM32_I2C2_BASE:
|
||||||
|
|
||||||
/* enable power and reset the peripheral */
|
/* enable power and reset the peripheral */
|
||||||
@ -546,7 +670,7 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
#ifndef NON_ISR
|
#ifndef NON_ISR
|
||||||
I2C_CR2_ITERREN | I2C_CR2_ITEVFEN | // I2C_CR2_ITBUFEN |
|
I2C_CR2_ITERREN | I2C_CR2_ITEVFEN | // I2C_CR2_ITBUFEN |
|
||||||
#endif
|
#endif
|
||||||
(STM32_BOARD_HCLK / 1000000)
|
(STM32_PCLK1_FREQUENCY / 1000000)
|
||||||
);
|
);
|
||||||
|
|
||||||
stm32_i2c_setclock(priv, 100000);
|
stm32_i2c_setclock(priv, 100000);
|
||||||
@ -567,7 +691,7 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
|
|
||||||
switch( priv->base ) {
|
switch( priv->base ) {
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C1
|
#ifdef CONFIG_STM32_I2C1
|
||||||
case STM32_I2C1_BASE:
|
case STM32_I2C1_BASE:
|
||||||
stm32_unconfiggpio(GPIO_I2C1_SCL);
|
stm32_unconfiggpio(GPIO_I2C1_SCL);
|
||||||
stm32_unconfiggpio(GPIO_I2C1_SDA);
|
stm32_unconfiggpio(GPIO_I2C1_SDA);
|
||||||
@ -581,7 +705,7 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_STM32_I2C2
|
#ifdef CONFIG_STM32_I2C2
|
||||||
case STM32_I2C2_BASE:
|
case STM32_I2C2_BASE:
|
||||||
stm32_unconfiggpio(GPIO_I2C2_SCL);
|
stm32_unconfiggpio(GPIO_I2C2_SCL);
|
||||||
stm32_unconfiggpio(GPIO_I2C2_SDA);
|
stm32_unconfiggpio(GPIO_I2C2_SDA);
|
||||||
@ -609,7 +733,7 @@ uint32_t stm32_i2c_setfrequency(FAR struct i2c_dev_s *dev, uint32_t frequency)
|
|||||||
{
|
{
|
||||||
stm32_i2c_sem_wait(dev);
|
stm32_i2c_sem_wait(dev);
|
||||||
|
|
||||||
#if STM32_BOARD_HCLK < 4000000
|
#if STM32_PCLK1_FREQUENCY < 4000000
|
||||||
((struct stm32_i2c_inst_s *)dev)->frequency = 100000;
|
((struct stm32_i2c_inst_s *)dev)->frequency = 100000;
|
||||||
#else
|
#else
|
||||||
((struct stm32_i2c_inst_s *)dev)->frequency = frequency;
|
((struct stm32_i2c_inst_s *)dev)->frequency = frequency;
|
||||||
@ -632,82 +756,135 @@ int stm32_i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits)
|
|||||||
|
|
||||||
int stm32_i2c_process(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, int count)
|
int stm32_i2c_process(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, int count)
|
||||||
{
|
{
|
||||||
struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev;
|
struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev;
|
||||||
uint32_t status = 0;
|
uint32_t status = 0;
|
||||||
int status_errno = 0;
|
uint32_t ahbenr;
|
||||||
|
int status_errno = 0;
|
||||||
ASSERT(count);
|
|
||||||
|
|
||||||
/* wait as stop might still be in progress
|
|
||||||
*
|
|
||||||
* \todo GET RID OF THIS PERFORMANCE LOSS and for() loop
|
|
||||||
*/
|
|
||||||
for (; stm32_i2c_getreg(inst->priv, STM32_I2C_CR1_OFFSET) & I2C_CR1_STOP; ) up_waste();
|
|
||||||
|
|
||||||
/* Old transfers are done */
|
|
||||||
inst->priv->msgv = msgs;
|
|
||||||
inst->priv->msgc = count;
|
|
||||||
|
|
||||||
/* Set clock (on change it toggles I2C_CR1_PE !) */
|
|
||||||
stm32_i2c_setclock(inst->priv, inst->frequency);
|
|
||||||
|
|
||||||
/* Trigger start condition, then the process moves into the ISR */
|
ASSERT(count);
|
||||||
stm32_i2c_sendstart(inst->priv);
|
|
||||||
|
/* Disable FSMC that shares a pin with I2C1 (LBAR) */
|
||||||
|
|
||||||
|
ahbenr = stm32_i2c_disablefsmc(inst->priv);
|
||||||
|
|
||||||
|
/* wait as stop might still be in progress
|
||||||
|
*
|
||||||
|
* \todo GET RID OF THIS PERFORMANCE LOSS and for() loop
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (; stm32_i2c_getreg(inst->priv, STM32_I2C_CR1_OFFSET) & I2C_CR1_STOP; )
|
||||||
|
{
|
||||||
|
up_waste();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Old transfers are done */
|
||||||
|
|
||||||
|
inst->priv->msgv = msgs;
|
||||||
|
inst->priv->msgc = count;
|
||||||
|
|
||||||
|
/* Set clock (on change it toggles I2C_CR1_PE !) */
|
||||||
|
|
||||||
|
stm32_i2c_setclock(inst->priv, inst->frequency);
|
||||||
|
|
||||||
|
/* Trigger start condition, then the process moves into the ISR */
|
||||||
|
|
||||||
|
stm32_i2c_sendstart(inst->priv);
|
||||||
|
|
||||||
#ifdef NON_ISR
|
#ifdef NON_ISR
|
||||||
do {
|
do
|
||||||
do {
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
stm32_i2c_isr(&stm32_i2c1_priv);
|
stm32_i2c_isr(&stm32_i2c1_priv);
|
||||||
status = inst->priv->status;
|
status = inst->priv->status;
|
||||||
} while( status & (I2C_SR2_BUSY<<16) );
|
}
|
||||||
|
while (status & (I2C_SR2_BUSY << 16));
|
||||||
}
|
}
|
||||||
while( sem_trywait( &((struct stm32_i2c_inst_s *)dev)->priv->sem_isr ) != 0 );
|
while( sem_trywait( &((struct stm32_i2c_inst_s *)dev)->priv->sem_isr ) != 0 );
|
||||||
#else
|
#else
|
||||||
#if 1
|
#if 1
|
||||||
/* Wait for an ISR, if there was a timeout, fetch latest status to get the BUSY flag */
|
/* Wait for an ISR, if there was a timeout, fetch latest status to get
|
||||||
|
* the BUSY flag.
|
||||||
|
*/
|
||||||
|
|
||||||
if (stm32_i2c_sem_waitisr(dev) == ERROR) {
|
if (stm32_i2c_sem_waitisr(dev) == ERROR)
|
||||||
status = stm32_i2c_getstatus(inst->priv);
|
{
|
||||||
status_errno = ETIMEDOUT;
|
status = stm32_i2c_getstatus(inst->priv);
|
||||||
|
status_errno = ETIMEDOUT;
|
||||||
|
|
||||||
|
/* " 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
|
||||||
|
* cleared by hardware. Otherwise there is a risk of setting a
|
||||||
|
* second STOP, START or PEC request."
|
||||||
|
*/
|
||||||
|
|
||||||
|
stm32_i2c_clrstart(inst->priv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* clear SR2 (BUSY flag) as we've done successfully */
|
||||||
|
|
||||||
|
status = inst->priv->status & 0xffff;
|
||||||
}
|
}
|
||||||
else status = inst->priv->status & 0xFFFF; /* clear SR2 (BUSY flag) as we've done successfully */
|
|
||||||
#else
|
#else
|
||||||
do {
|
do
|
||||||
printf("%x, %d\n", inst->priv->status, isr_count );
|
{
|
||||||
|
printf("%x, %d\n", inst->priv->status, isr_count );
|
||||||
}
|
}
|
||||||
while( sem_trywait( &inst->priv->sem_isr ) != 0 );
|
while( sem_trywait( &inst->priv->sem_isr ) != 0 );
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (status & I2C_SR1_BERR) { /* Bus Error */
|
if (status & I2C_SR1_BERR)
|
||||||
status_errno = EIO;
|
{
|
||||||
|
/* Bus Error */
|
||||||
|
|
||||||
|
status_errno = EIO;
|
||||||
}
|
}
|
||||||
else if (status & I2C_SR1_ARLO) { /* Arbitration Lost (master mode) */
|
else if (status & I2C_SR1_ARLO)
|
||||||
status_errno = EAGAIN;
|
{
|
||||||
|
/* Arbitration Lost (master mode) */
|
||||||
|
|
||||||
|
status_errno = EAGAIN;
|
||||||
}
|
}
|
||||||
else if (status & I2C_SR1_AF) { /* Acknowledge Failure */
|
else if (status & I2C_SR1_AF)
|
||||||
status_errno = ENXIO;
|
{
|
||||||
|
/* Acknowledge Failure */
|
||||||
|
|
||||||
|
status_errno = ENXIO;
|
||||||
}
|
}
|
||||||
else if (status & I2C_SR1_OVR) { /* Overrun/Underrun */
|
else if (status & I2C_SR1_OVR)
|
||||||
status_errno = EIO;
|
{
|
||||||
|
/* Overrun/Underrun */
|
||||||
|
|
||||||
|
status_errno = EIO;
|
||||||
}
|
}
|
||||||
else if (status & I2C_SR1_PECERR) { /* PEC Error in reception */
|
else if (status & I2C_SR1_PECERR)
|
||||||
status_errno = EPROTO;
|
{
|
||||||
|
/* PEC Error in reception */
|
||||||
|
|
||||||
|
status_errno = EPROTO;
|
||||||
}
|
}
|
||||||
else if (status & I2C_SR1_TIMEOUT) {/* Timeout or Tlow Error */
|
else if (status & I2C_SR1_TIMEOUT)
|
||||||
status_errno = ETIME;
|
{
|
||||||
|
/* Timeout or Tlow Error */
|
||||||
|
|
||||||
|
status_errno = ETIME;
|
||||||
}
|
}
|
||||||
else if (status & (I2C_SR2_BUSY<<16) ) { /* I2C Bus is for some reason busy */
|
else if (status & (I2C_SR2_BUSY << 16))
|
||||||
status_errno = EBUSY;
|
{
|
||||||
|
/* I2C Bus is for some reason busy */
|
||||||
|
|
||||||
|
status_errno = EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("end_count = %d, dcnt=%d\n", isr_count, inst->priv->dcnt); fflush(stdout);
|
/* Re-enable the FSMC */
|
||||||
|
|
||||||
stm32_i2c_sem_post(dev);
|
stm32_i2c_enablefsmc(ahbenr);
|
||||||
|
stm32_i2c_sem_post(dev);
|
||||||
errno = status_errno;
|
|
||||||
return -status_errno;
|
errno = status_errno;
|
||||||
|
return -status_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stm32_i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, int buflen)
|
int stm32_i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, int buflen)
|
||||||
@ -802,11 +979,11 @@ FAR struct i2c_dev_s * up_i2cinitialize(int port)
|
|||||||
struct stm32_i2c_inst_s * inst = NULL; /* device, single instance */
|
struct stm32_i2c_inst_s * inst = NULL; /* device, single instance */
|
||||||
int irqs;
|
int irqs;
|
||||||
|
|
||||||
#if STM32_BOARD_HCLK < 4000000
|
#if STM32_PCLK1_FREQUENCY < 4000000
|
||||||
# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation.
|
# warning STM32_I2C_INIT: Peripheral clock must be at least 4 MHz to support 400 kHz operation.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_BOARD_HCLK < 2000000
|
#if STM32_PCLK1_FREQUENCY < 2000000
|
||||||
# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation.
|
# warning STM32_I2C_INIT: Peripheral clock must be at least 2 MHz to support 100 kHz operation.
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -814,10 +991,10 @@ FAR struct i2c_dev_s * up_i2cinitialize(int port)
|
|||||||
/* Get I2C private structure */
|
/* Get I2C private structure */
|
||||||
|
|
||||||
switch(port) {
|
switch(port) {
|
||||||
#if CONFIG_STM32_I2C1
|
#ifdef CONFIG_STM32_I2C1
|
||||||
case 1: priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; break;
|
case 1: priv = (struct stm32_i2c_priv_s *)&stm32_i2c1_priv; break;
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_STM32_I2C2
|
#ifdef CONFIG_STM32_I2C2
|
||||||
case 2: priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; break;
|
case 2: priv = (struct stm32_i2c_priv_s *)&stm32_i2c2_priv; break;
|
||||||
#endif
|
#endif
|
||||||
default: return NULL;
|
default: return NULL;
|
||||||
|
@ -360,6 +360,12 @@ STM3210E-EVAL-specific Configuration Options
|
|||||||
CONFIG_STM32_USART1
|
CONFIG_STM32_USART1
|
||||||
CONFIG_STM32_ADC3
|
CONFIG_STM32_ADC3
|
||||||
|
|
||||||
|
Timer and I2C devices may need to the following to force power to be applied
|
||||||
|
unconditionally at power up. (Otherwise, the device is powered when it is
|
||||||
|
initialized).
|
||||||
|
|
||||||
|
CONFIG_STM32_FORCEPOWER
|
||||||
|
|
||||||
Alternate pin mappings (should not be used with the STM3210E-EVAL board):
|
Alternate pin mappings (should not be used with the STM3210E-EVAL board):
|
||||||
|
|
||||||
CONFIG_STM32_TIM1_FULL_REMAP
|
CONFIG_STM32_TIM1_FULL_REMAP
|
||||||
|
@ -127,6 +127,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -141,6 +141,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -139,6 +139,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
* *JP7 will switch to PD6
|
* *JP7 will switch to PD6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* GPIO configurations unique to SRAM */
|
/* GPIO configurations unique to the LCD */
|
||||||
|
|
||||||
static const uint16_t g_lcdconfig[] =
|
static const uint16_t g_lcdconfig[] =
|
||||||
{
|
{
|
||||||
|
@ -139,6 +139,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
@ -137,6 +137,11 @@ CONFIG_STM32_TIM8=n
|
|||||||
CONFIG_STM32_USART1=y
|
CONFIG_STM32_USART1=y
|
||||||
CONFIG_STM32_ADC3=n
|
CONFIG_STM32_ADC3=n
|
||||||
|
|
||||||
|
#
|
||||||
|
# Timer and I2C devices may need to the following to force power to be applied:
|
||||||
|
#
|
||||||
|
#CONFIG_STM32_FORCEPOWER=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# STM32F103Z specific serial device driver settings
|
# STM32F103Z specific serial device driver settings
|
||||||
#
|
#
|
||||||
|
Loading…
x
Reference in New Issue
Block a user