Merge remote-tracking branch 'origin/master' into clicker2
This commit is contained in:
commit
571aad3cf1
@ -6190,6 +6190,16 @@ config STM32_I2C_DUTY16_9
|
||||
default n
|
||||
depends on STM32_I2C
|
||||
|
||||
config STM32_I2C_DMA
|
||||
bool "I2C DMA Support"
|
||||
default n
|
||||
depends on STM32_I2C && STM32_STM32F40XX && STM32_DMA1
|
||||
---help---
|
||||
This option enables the DMA for I2C transfers.
|
||||
Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value for the
|
||||
I2C dma streams, else the default priority level is set to medium.
|
||||
Note: This option is compatible with CONFIG_I2C_POLLED.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "SDIO Configuration"
|
||||
|
@ -63,7 +63,6 @@
|
||||
* - 1 x 10 bit addresses + 1 x 7 bit address (?)
|
||||
* - plus the broadcast address (general call)
|
||||
* - Multi-master support
|
||||
* - DMA (to get rid of too many CPU wake-ups and interventions)
|
||||
* - Be ready for IPMI
|
||||
*/
|
||||
|
||||
@ -95,6 +94,7 @@
|
||||
#include "stm32_rcc.h"
|
||||
#include "stm32_i2c.h"
|
||||
#include "stm32_waste.h"
|
||||
#include "stm32_dma.h"
|
||||
|
||||
/* At least one I2C peripheral must be enabled */
|
||||
|
||||
@ -162,6 +162,21 @@
|
||||
|
||||
#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT)
|
||||
|
||||
/* I2C DMA priority */
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
|
||||
# if defined(CONFIG_I2C_DMAPRIO)
|
||||
# if (CONFIG_I2C_DMAPRIO & ~DMA_SCR_PL_MASK) != 0
|
||||
# error "Illegal value for CONFIG_I2C_DMAPRIO"
|
||||
# endif
|
||||
# define I2C_DMA_PRIO CONFIG_I2C_DMAPRIO
|
||||
# else
|
||||
# define I2C_DMA_PRIO DMA_SCR_PRIMED
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Debug ****************************************************************************/
|
||||
|
||||
/* I2C event trace logic. NOTE: trace uses the internal, non-standard, low-level
|
||||
@ -253,7 +268,7 @@ struct stm32_i2c_priv_s
|
||||
struct i2c_msg_s *msgv; /* Message list */
|
||||
uint8_t *ptr; /* Current message buffer */
|
||||
uint32_t frequency; /* Current I2C frequency */
|
||||
int dcnt; /* Current message length */
|
||||
volatile int dcnt; /* Current message length */
|
||||
uint16_t flags; /* Current message flags */
|
||||
bool check_addr_ACK; /* Flag to signal if on next interrupt address has ACKed */
|
||||
uint8_t total_msg_len; /* Flag to signal a short read sequence */
|
||||
@ -270,6 +285,15 @@ struct stm32_i2c_priv_s
|
||||
#endif
|
||||
|
||||
uint32_t status; /* End of transfer SR2|SR1 status */
|
||||
|
||||
/* I2C DMA support */
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
DMA_HANDLE txdma; /* TX DMA handle */
|
||||
DMA_HANDLE rxdma; /* RX DMA handle */
|
||||
uint8_t txch; /* TX DMA channel */
|
||||
uint8_t rxch; /* RX DMA channel */
|
||||
#endif
|
||||
};
|
||||
|
||||
/************************************************************************************
|
||||
@ -337,6 +361,13 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
|
||||
static int stm32_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
#endif
|
||||
|
||||
/* DMA support */
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg);
|
||||
static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg);
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
* Private Data
|
||||
************************************************************************************/
|
||||
@ -398,7 +429,16 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||
.ptr = NULL,
|
||||
.dcnt = 0,
|
||||
.flags = 0,
|
||||
.status = 0
|
||||
.status = 0,
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
# ifndef CONFIG_STM32_DMA1
|
||||
# error "I2C1 enabled with DMA but corresponding DMA controller 1 is not enabled!"
|
||||
# endif
|
||||
/* TODO: ch for i2c 1 and 2 could be *X_2 based on stream priority */
|
||||
|
||||
.rxch = DMAMAP_I2C1_RX,
|
||||
.txch = DMAMAP_I2C1_TX,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -428,7 +468,14 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||
.ptr = NULL,
|
||||
.dcnt = 0,
|
||||
.flags = 0,
|
||||
.status = 0
|
||||
.status = 0,
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
# ifndef CONFIG_STM32_DMA1
|
||||
# error "I2C2 enabled with DMA but corresponding DMA controller 1 is not enabled!"
|
||||
# endif
|
||||
.rxch = DMAMAP_I2C2_RX,
|
||||
.txch = DMAMAP_I2C2_TX,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -458,7 +505,14 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv =
|
||||
.ptr = NULL,
|
||||
.dcnt = 0,
|
||||
.flags = 0,
|
||||
.status = 0
|
||||
.status = 0,
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
# ifndef CONFIG_STM32_DMA1
|
||||
# error "I2C3 enabled with DMA but corresponding DMA controller 1 is not enabled!"
|
||||
# endif
|
||||
.rxch = DMAMAP_I2C3_RX,
|
||||
.txch = DMAMAP_I2C3_TX,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -521,7 +575,7 @@ static inline void stm32_i2c_sem_wait(FAR struct stm32_i2c_priv_s *priv)
|
||||
{
|
||||
while (sem_wait(&priv->sem_excl) != 0)
|
||||
{
|
||||
ASSERT(errno == EINTR);
|
||||
DEBUGASSERT(errno == EINTR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1185,6 +1239,12 @@ static inline void stm32_i2c_enablefsmc(uint32_t ahbenr)
|
||||
static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
{
|
||||
uint32_t status;
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
uint32_t regval;
|
||||
#endif
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
uint16_t cr2;
|
||||
#endif
|
||||
|
||||
i2cinfo("I2C ISR called\n");
|
||||
|
||||
@ -1228,6 +1288,23 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
* stm32_i2c_sem_waitdone() waiting process.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* If ISR gets called (ex. polling mode) while DMA is still in
|
||||
* progress, we should just return and let the DMA finish.
|
||||
*/
|
||||
|
||||
cr2 = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
|
||||
if ((cr2 & I2C_CR2_DMAEN) != 0)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_I2C_INFO
|
||||
size_t left = stm32_dmaresidual(priv->rxdma);
|
||||
|
||||
i2cinfo("DMA in progress: %ld [bytes] remainining. Returning.\n", left);
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (priv->dcnt == -1 && priv->msgc > 0)
|
||||
{
|
||||
i2cinfo("Switch to new message\n");
|
||||
@ -1484,6 +1561,46 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
/* Trace */
|
||||
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, 0);
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* DMA only when not doing a short read */
|
||||
|
||||
i2cinfo("Starting dma transfer and disabling interrupts\n");
|
||||
|
||||
/* The DMA must be initialized and enabled before the I2C data transfer.
|
||||
* The DMAEN bit must be set in the I2C_CR2 register before the ADDR event.
|
||||
*/
|
||||
|
||||
stm32_dmasetup(priv->rxdma, priv->config->base+STM32_I2C_DR_OFFSET,
|
||||
(uint32_t) priv->ptr, priv->dcnt,
|
||||
DMA_SCR_DIR_P2M |
|
||||
DMA_SCR_MSIZE_8BITS |
|
||||
DMA_SCR_PSIZE_8BITS |
|
||||
DMA_SCR_MINC |
|
||||
I2C_DMA_PRIO);
|
||||
|
||||
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
|
||||
* used.
|
||||
*/
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
/* Now let DMA do all the work, disable i2c interrupts */
|
||||
|
||||
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
|
||||
regval &= ~I2C_CR2_ALLINTS;
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
|
||||
#endif
|
||||
|
||||
/* The user can generate a Stop condition in the DMA Transfer Complete
|
||||
* interrupt routine if enabled. This will be done in the dma rx callback
|
||||
* Start DMA.
|
||||
*/
|
||||
|
||||
stm32_dmastart(priv->rxdma, stm32_i2c_dmarxcallback, priv, false);
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1520,19 +1637,67 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
|
||||
if (priv->dcnt >= 1)
|
||||
{
|
||||
/* Transmitting message. Send byte == write data into write register */
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* if DMA is enabled, only makes sense to make use of it for longer
|
||||
than 1 B transfers.. */
|
||||
|
||||
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++);
|
||||
if (priv->dcnt > 1)
|
||||
{
|
||||
i2cinfo("Starting dma transfer and disabling interrupts\n");
|
||||
|
||||
/* Decrease current message length */
|
||||
/* The DMA must be initialized and enabled before the I2C data transfer.
|
||||
* The DMAEN bit must be set in the I2C_CR2 register before the ADDR event.
|
||||
*/
|
||||
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
|
||||
priv->dcnt--;
|
||||
stm32_dmasetup(priv->txdma, priv->config->base+STM32_I2C_DR_OFFSET,
|
||||
(uint32_t) priv->ptr, priv->dcnt,
|
||||
DMA_SCR_DIR_M2P |
|
||||
DMA_SCR_MSIZE_8BITS |
|
||||
DMA_SCR_PSIZE_8BITS |
|
||||
DMA_SCR_MINC |
|
||||
I2C_DMA_PRIO );
|
||||
|
||||
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
|
||||
* used.
|
||||
*/
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
/* Now let DMA do all the work, disable i2c interrupts */
|
||||
|
||||
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
|
||||
regval &= ~I2C_CR2_ALLINTS;
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
|
||||
#endif
|
||||
|
||||
/* In the interrupt routine after the EOT interrupt, disable DMA
|
||||
* requests then wait for a BTF event before programming the Stop
|
||||
* condition. To do this, we'll just call the ISR again in
|
||||
* dma tx callback, in which point we fall into the msgc==0 case
|
||||
* which ultimately sends the stop..TODO: but we don't explicitly
|
||||
* wait for BTF bit being set...
|
||||
* Start DMA.
|
||||
*/
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
|
||||
stm32_dmastart(priv->txdma, stm32_i2c_dmatxcallback, priv, false);
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_STM32_I2C_DMA */
|
||||
{
|
||||
/* Transmitting message. Send byte == write data into write register */
|
||||
|
||||
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++);
|
||||
|
||||
/* Decrease current message length */
|
||||
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
|
||||
priv->dcnt--;
|
||||
}
|
||||
}
|
||||
else if (priv->dcnt == 0)
|
||||
{
|
||||
|
||||
/* After last byte, check what to do based on next message flags */
|
||||
|
||||
if (priv->msgc == 0)
|
||||
@ -1678,6 +1843,7 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_READ_2, 0);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_STM32_I2C_DMA
|
||||
/* Case total message length >= 3 */
|
||||
|
||||
else if (priv->dcnt >= 4 && priv->total_msg_len >= 3)
|
||||
@ -1757,6 +1923,7 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
|
||||
priv->dcnt = -1;
|
||||
}
|
||||
#endif /* CONFIG_STM32_I2C_DMA */
|
||||
|
||||
/* Error handling for read mode */
|
||||
|
||||
@ -1765,7 +1932,8 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
i2cinfo("I2C read mode no correct state detected\n");
|
||||
i2cinfo(" state %i, dcnt=%i\n", status, priv->dcnt);
|
||||
|
||||
/* set condition to terminate ISR and wake waiting thread */
|
||||
/* Set condition to terminate ISR and wake waiting thread */
|
||||
|
||||
priv->dcnt = -1;
|
||||
priv->msgc = 0;
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_READ_ERROR, 0);
|
||||
@ -1804,9 +1972,9 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0);
|
||||
#else
|
||||
#else
|
||||
/* Read rest of the state */
|
||||
|
||||
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
|
||||
@ -1814,12 +1982,12 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
i2cinfo(" No correct state detected(start bit, read or write) \n");
|
||||
i2cinfo(" state %i\n", status);
|
||||
|
||||
/* set condition to terminate ISR and wake waiting thread */
|
||||
/* Set condition to terminate ISR and wake waiting thread */
|
||||
|
||||
priv->dcnt = -1;
|
||||
priv->msgc = 0;
|
||||
stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Messages handling(2/2)
|
||||
@ -1842,9 +2010,9 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
|
||||
priv->msgv = NULL;
|
||||
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
#ifdef CONFIG_I2C_POLLED
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
#else
|
||||
#else
|
||||
/* Clear all interrupts */
|
||||
|
||||
uint32_t regval;
|
||||
@ -1863,12 +2031,98 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
|
||||
sem_post(&priv->sem_isr);
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: stm32_i2c_dmarxcallback
|
||||
*
|
||||
* Description:
|
||||
* Called when the RX DMA completes
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
{
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
uint32_t regval;
|
||||
#endif
|
||||
|
||||
i2cinfo("DMA rx callback, status = %d \n", status);
|
||||
|
||||
FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)arg;
|
||||
|
||||
priv->dcnt = -1;
|
||||
|
||||
/* The user can generate a Stop condition in the DMA Transfer Complete
|
||||
* interrupt routine if enabled.
|
||||
*/
|
||||
|
||||
stm32_i2c_sendstop(priv);
|
||||
|
||||
/* Let the I2C periph know to stop DMA transfers, also is used by ISR to check
|
||||
* if DMA is done.
|
||||
*/
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
/* Re-enable interrupts */
|
||||
|
||||
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
|
||||
regval |= (I2C_CR2_ITERREN | I2C_CR2_ITEVFEN);
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
|
||||
#endif
|
||||
|
||||
/* let the ISR routine take care of shutting down or switching to next msg */
|
||||
|
||||
stm32_i2c_isr(priv);
|
||||
}
|
||||
#endif /* ifdef CONFIG_STM32_I2C_DMA */
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: stm32_i2c_dmarxcallback
|
||||
*
|
||||
* Description:
|
||||
* Called when the RX DMA completes
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
{
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
uint32_t regval;
|
||||
#endif
|
||||
|
||||
i2cinfo("DMA tx callback, status = %d \n", status);
|
||||
|
||||
FAR struct stm32_i2c_priv_s *priv = (FAR struct stm32_i2c_priv_s *)arg;
|
||||
|
||||
priv->dcnt = 0;
|
||||
|
||||
/* In the interrupt routine after the EOT interrupt, disable DMA requests */
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
|
||||
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
/* re-enable interrupts */
|
||||
|
||||
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
|
||||
regval |= (I2C_CR2_ITERREN | I2C_CR2_ITEVFEN);
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
|
||||
#endif
|
||||
|
||||
/* let the ISR routine take care of shutting down or switching to next msg */
|
||||
|
||||
stm32_i2c_isr(priv);
|
||||
}
|
||||
#endif /* ifdef CONFIG_STM32_I2C_DMA */
|
||||
|
||||
/************************************************************************************
|
||||
* Name: stm32_i2c1_isr
|
||||
*
|
||||
@ -1914,7 +2168,7 @@ static int stm32_i2c3_isr(int irq, void *context, FAR void *arg)
|
||||
return stm32_i2c_isr(&stm32_i2c3_priv);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif /* CONFIG_I2C_POLLED */
|
||||
|
||||
/************************************************************************************
|
||||
* Private Initialization and Deinitialization
|
||||
@ -1972,6 +2226,15 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
|
||||
|
||||
stm32_i2c_setclock(priv, 100000);
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* If, in the I2C_CR2 register, the LAST bit is set, I2C automatically
|
||||
* sends a NACK after the next byte following EOT_1.
|
||||
* Clear DMA en just in case.
|
||||
*/
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, I2C_CR2_LAST);
|
||||
#endif
|
||||
|
||||
/* Enable I2C */
|
||||
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_PE);
|
||||
@ -1991,6 +2254,7 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
|
||||
/* Disable I2C */
|
||||
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, 0);
|
||||
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, 0);
|
||||
|
||||
/* Unconfigure GPIO pins */
|
||||
|
||||
@ -2006,6 +2270,13 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
|
||||
irq_detach(priv->config->er_irq);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* Disable DMA */
|
||||
|
||||
stm32_dmastop(priv->txdma);
|
||||
stm32_dmastop(priv->rxdma);
|
||||
#endif
|
||||
|
||||
/* Disable clocking */
|
||||
|
||||
modifyreg32(STM32_RCC_APB1ENR, priv->config->clk_bit, 0);
|
||||
@ -2035,7 +2306,15 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(count);
|
||||
DEBUGASSERT(count);
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* stop DMA just in case */
|
||||
|
||||
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, I2C_CR2_DMAEN, 0);
|
||||
stm32_dmastop(priv->rxdma);
|
||||
stm32_dmastop(priv->txdma);
|
||||
#endif
|
||||
|
||||
#ifdef I2C1_FSMC_CONFLICT
|
||||
/* Disable FSMC that shares a pin with I2C1 (LBAR) */
|
||||
@ -2246,11 +2525,11 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev)
|
||||
uint32_t frequency;
|
||||
int ret = ERROR;
|
||||
|
||||
ASSERT(dev);
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Our caller must own a ref */
|
||||
|
||||
ASSERT(priv->refs > 0);
|
||||
DEBUGASSERT(priv->refs > 0);
|
||||
|
||||
/* Lock out other clients */
|
||||
|
||||
@ -2412,6 +2691,19 @@ FAR struct i2c_master_s *stm32_i2cbus_initialize(int port)
|
||||
{
|
||||
stm32_i2c_sem_init(priv);
|
||||
stm32_i2c_init(priv);
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
/* Get DMA channels. NOTE: stm32_dmachannel() will always assign the DMA channel.
|
||||
* if the channel is not available, then stm32_dmachannel() will block and wait
|
||||
* until the channel becomes available. WARNING: If you have another device sharing
|
||||
* a DMA channel with SPI and the code never releases that channel, then the call
|
||||
* to stm32_dmachannel() will hang forever in this function! Don't let your
|
||||
* design do that!
|
||||
*/
|
||||
priv->rxdma = stm32_dmachannel(priv->rxch);
|
||||
priv->txdma = stm32_dmachannel(priv->txch);
|
||||
DEBUGASSERT(priv->rxdma && priv->txdma);
|
||||
#endif /* #ifdef CONFIG_STM32_I2C_DMA */
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
@ -2431,7 +2723,7 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
|
||||
FAR struct stm32_i2c_priv_s *priv = (struct stm32_i2c_priv_s *)dev;
|
||||
irqstate_t flags;
|
||||
|
||||
ASSERT(dev);
|
||||
DEBUGASSERT(dev);
|
||||
|
||||
/* Decrement reference count and check for underflow */
|
||||
|
||||
@ -2454,6 +2746,11 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
|
||||
|
||||
stm32_i2c_deinit(priv);
|
||||
|
||||
#ifdef CONFIG_STM32_I2C_DMA
|
||||
stm32_dmafree(priv->rxdma);
|
||||
stm32_dmafree(priv->txdma);
|
||||
#endif
|
||||
|
||||
/* Release unused resources */
|
||||
|
||||
stm32_i2c_sem_destroy(priv);
|
||||
|
@ -889,7 +889,7 @@
|
||||
|
||||
#define SCU_PBCLKCR_PBDIV (1 << 0) /* Bit 0: PB Clock Divider Enable */
|
||||
# define SCU_PBCLKCR_PBDIV_FCPU (0) /* 0=fCPU */
|
||||
# define SCU_PBCLKCR_PBDIV_DIV2 ((1 << 0) /* 1=fCPU/2 */
|
||||
# define SCU_PBCLKCR_PBDIV_DIV2 (1 << 0) /* 1=fCPU/2 */
|
||||
|
||||
/* USB Clock Control */
|
||||
|
||||
|
@ -563,7 +563,7 @@
|
||||
# define USIC_SCTR_TRM_ACTIVE (3 << USIC_SCTR_TRM_SHIFT) /* Active without regard to signal level */
|
||||
#define USIC_SCTR_FLE_SHIFT (16) /* Bits 16-21: Frame Length */
|
||||
#define USIC_SCTR_FLE_MASK (0x3f << USIC_SCTR_FLE_SHIFT)
|
||||
# define USIC_SCTR_FLE(n) ((uint32_t)(n) << USIC_SCTR_FLE_SHIFT)
|
||||
# define USIC_SCTR_FLE(n) ((uint32_t)((n)-1) << USIC_SCTR_FLE_SHIFT)
|
||||
#define USIC_SCTR_WLE_SHIFT (24) /* Bits 24-27: Word Length */
|
||||
#define USIC_SCTR_WLE_MASK (15 << USIC_SCTR_WLE_SHIFT)
|
||||
# define USIC_SCTR_WLE(n) ((uint32_t)((n)-1) << USIC_SCTR_WLE_SHIFT)
|
||||
|
@ -105,13 +105,18 @@
|
||||
#define CLKSET_VALUE (0x00000000)
|
||||
#define SYSCLKCR_VALUE (0x00010001)
|
||||
#define CPUCLKCR_VALUE (0x00000000)
|
||||
#define PBCLKCR_VALUE (0x00000000)
|
||||
#define CCUCLKCR_VALUE (0x00000000)
|
||||
#define WDTCLKCR_VALUE (0x00000000)
|
||||
#define EBUCLKCR_VALUE (0x00000003)
|
||||
#define USBCLKCR_VALUE (0x00010000)
|
||||
#define EXTCLKCR_VALUE (0x01200003)
|
||||
|
||||
#if BOARD_PBDIV == 1
|
||||
# define PBCLKCR_VALUE SCU_PBCLKCR_PBDIV_FCPU
|
||||
#else /* BOARD_PBDIV == 2 */
|
||||
# define PBCLKCR_VALUE SCU_PBCLKCR_PBDIV_DIV2
|
||||
#endif
|
||||
|
||||
#if ((USBCLKCR_VALUE & SCU_USBCLKCR_USBSEL) == SCU_USBCLKCR_USBSEL_USBPLL)
|
||||
# define USB_DIV 3
|
||||
#else
|
||||
@ -387,7 +392,7 @@ void xmc4_clock_configure(void)
|
||||
/* Before scaling to final frequency we need to setup the clock dividers */
|
||||
|
||||
putreg32(SYSCLKCR_VALUE, XMC4_SCU_SYSCLKCR);
|
||||
putreg32(PBCLKCR_VALUE, XMC4_SCU_PBCLKCR);
|
||||
putreg32(PBCLKCR_VALUE, XMC4_SCU_PBCLKCR);
|
||||
putreg32(CPUCLKCR_VALUE, XMC4_SCU_CPUCLKCR);
|
||||
putreg32(CCUCLKCR_VALUE, XMC4_SCU_CCUCLKCR);
|
||||
putreg32(WDTCLKCR_VALUE, XMC4_SCU_WDTCLKCR);
|
||||
|
@ -448,14 +448,14 @@ int xmc4_usic_baudrate(enum usic_channel_e channel, uint32_t baud,
|
||||
|
||||
/* Select and setup the fractional divider */
|
||||
|
||||
regval = USIC_FDR_DM_FRACTIONAL | (clkdiv_min << USIC_FDR_STEP_SHIFT);
|
||||
regval = USIC_FDR_DM_FRACTIONAL | USIC_FDR_STEP(clkdiv_min);
|
||||
putreg32(regval, base + XMC4_USIC_FDR_OFFSET);
|
||||
|
||||
/* Setup and enable the baud rate generator */
|
||||
|
||||
regval = getreg32(base + XMC4_USIC_BRG_OFFSET);
|
||||
regval &= ~(USIC_BRG_DCTQ_MASK | USIC_BRG_PDIV_MASK | USIC_BRG_PCTQ_MASK | USIC_BRG_PPPEN);
|
||||
regval |= (USIC_BRG_DCTQ(oversampling - 1) | USIC_BRG_PDIV(pdiv_int_min - 1));
|
||||
regval |= (USIC_BRG_DCTQ(oversampling - 1) | USIC_BRG_PDIV(pdiv_int_min - 1));
|
||||
putreg32(regval, base + XMC4_USIC_BRG_OFFSET);
|
||||
|
||||
ret = OK;
|
||||
|
@ -7,6 +7,13 @@ README for the XMC4500 Relax
|
||||
|
||||
The current configurations support only the Lite version of the board.
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
2017-03-21: The XMC4500 Relax boots into NSH, provides the NSH prompt,
|
||||
and the LEDs are working. But there is a problem with sserial input.
|
||||
The most likely reason for this is there are no serial RX interripts.
|
||||
|
||||
Serial Console
|
||||
==============
|
||||
|
||||
@ -20,6 +27,9 @@ Serial Console
|
||||
VDD5 - Available on pins 39-40 of either connector X1 or X2
|
||||
|
||||
A TTL to RS-232 convertor or a USB TTL-to-USB serial adaptor is required.
|
||||
The notion of what is TX and what is RX depends on your point of view.
|
||||
With the TTL to RS-232 converter, I connect pin 17 to the pin labeled
|
||||
TX on the converter and pin 16 to the RX pin on the converter.
|
||||
|
||||
LEDs
|
||||
====
|
||||
|
@ -53,16 +53,21 @@
|
||||
|
||||
/* Clocking *************************************************************************/
|
||||
/* Default clock initialization
|
||||
* fPLL = 288MHz => fSYS = 288MHz => fCPU = 144MHz
|
||||
* => fPB = 144MHz
|
||||
* => fCCU = 144MHz
|
||||
* => fETH = 72MHz
|
||||
* => fUSB = 48MHz
|
||||
* => fEBU = 72MHz
|
||||
*
|
||||
* fXTAL = 12Mhz
|
||||
* -> fPLL = (fXTAL / (2 * 1) * 48) = 288MHz
|
||||
* -> fSYS = (fPLL / 1) = 288MHz
|
||||
* -> fCPU = (fSYS / 2) = 144MHz
|
||||
* -> fPERIPH = (fCPU / 1) = 144MHz
|
||||
* -> fCCU = (fSYS / 2) = 144MHz
|
||||
* -> fETH = 72MHz (REVISIT)
|
||||
* -> fUSB = 48MHz (REVISIT)
|
||||
* -> fEBU = 72MHz (REVISIT)
|
||||
*
|
||||
* fUSBPLL Disabled, only enabled if SCU_CLK_USBCLKCR_USBSEL_USBPLL is selected
|
||||
*
|
||||
* fOFI = 24MHz => fWDT = 24MHz
|
||||
* fOFI = 24MHz
|
||||
* -> fWDT = 24MHz (REVISIT)
|
||||
*/
|
||||
|
||||
#undef BOARD_FOFI_CALIBRATION /* Enable factory calibration */
|
||||
@ -79,7 +84,7 @@
|
||||
/* Select the external crystal as the PLL clock source */
|
||||
|
||||
#define BOARD_PLL_CLOCKSRC_XTAL 1 /* PLL Clock source == extnernal crystal */
|
||||
#undef BOARD_PLL_CLOCKSRC_OFI /* PLL Clock source != internal fast oscillator */
|
||||
#undef BOARD_PLL_CLOCKSRC_OFI /* PLL Clock source != internal fast oscillator */
|
||||
|
||||
/* PLL Configuration:
|
||||
*
|
||||
@ -95,16 +100,21 @@
|
||||
#define BOARD_PLL_K2DIV 1
|
||||
#define BOARD_PLL_FREQUENCY 288000000
|
||||
|
||||
/* System frequency is divided down from PLL output */
|
||||
/* System frequency, fSYS, is divided down from PLL output */
|
||||
|
||||
#define BOARD_SYSDIV 1 /* PLL Output divider to get fSYS */
|
||||
#define BOARD_SYS_FREQUENCY 288000000
|
||||
|
||||
/* CPU frequency may be divided down from system frequency */
|
||||
/* CPU frequency, fCPU, may be divided down from system frequency */
|
||||
|
||||
#define BOARD_CPUDIV_ENABLE 1 /* Enable PLL dive by 2 for fCPU */
|
||||
#define BOARD_CPU_FREQUENCY 144000000
|
||||
|
||||
/* The peripheral clock, fPERIPH, derives from fCPU with no division */
|
||||
|
||||
#define BOARD_PBDIV 1 /* No division */
|
||||
#define BOARD_PERIPH_FREQUENCY 144000000
|
||||
|
||||
/* Standby clock source selection
|
||||
*
|
||||
* BOARD_STDBY_CLOCKSRC_OSI - Internal 32.768KHz slow oscillator
|
||||
@ -112,7 +122,7 @@
|
||||
*/
|
||||
|
||||
#define BOARD_STDBY_CLOCKSRC_OSI 1
|
||||
#undef BOARD_STDBY_CLOCKSRC_OSCULP
|
||||
#undef BOARD_STDBY_CLOCKSRC_OSCULP
|
||||
#define BOARD_STDBY_FREQUENCY 32768
|
||||
|
||||
/* USB PLL settings.
|
||||
|
@ -1041,7 +1041,7 @@ FAR struct lcd_dev_s *st7565_initialize(FAR struct st7565_lcd_s *lcd,
|
||||
up_mdelay(2);
|
||||
(void)st7565_send_one_data(priv, ST7565_POWERCTRL_BR);
|
||||
up_mdelay(2);
|
||||
(void)st7565_send_one_data(priv, ST7565_POWERCTRL_BRF);
|
||||
(void)st7565_send_one_data(priv, ST7565_POWERCTRL_INT);
|
||||
|
||||
(void)st7565_send_one_data(priv, ST7565_REG_RES_4_5);
|
||||
(void)st7565_send_one_data(priv, ST7565_SETEVMODE);
|
||||
|
@ -102,8 +102,6 @@
|
||||
*/
|
||||
#define ST7565_POWERCTRL_B 0x2c /* 0x2c: Booster=ON */
|
||||
#define ST7565_POWERCTRL_BR 0x2e /* 0x2e: Booster=ON V/R=ON */
|
||||
#define ST7565_POWERCTRL_BRF 0x2f /* 0x23: Booster=ON V/R=ON V/F=ON */
|
||||
|
||||
#define ST7565_POWERCTRL_INT 0x2f /* 0x2f: Only the internal power supply is used */
|
||||
|
||||
/* Regulation Resistior ratio V0 = (1+Rb/Ra)*Vev */
|
||||
|
@ -263,11 +263,17 @@ if SMP
|
||||
config SMP_NCPUS
|
||||
int "Number of CPUs"
|
||||
default 4
|
||||
range 2 32
|
||||
range 1 32 if DEBUG_FEATURES
|
||||
range 2 32 if !DEBUG_FEATURES
|
||||
---help---
|
||||
This value identifies the number of CPUs supported by the processor
|
||||
that will be used for SMP.
|
||||
|
||||
If CONFIG_DEBUG_FEATURES is enbled, then the value one is permitted
|
||||
for CONFIG_SMP_NCPUS. This is not normally a valid setting for an
|
||||
SMP configuration. However, running the SMP logic in a single CPU
|
||||
configuration is useful during certain testing.
|
||||
|
||||
config SMP_IDLETHREAD_STACKSIZE
|
||||
int "CPU IDLE stack size"
|
||||
default 2048
|
||||
|
@ -136,8 +136,13 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* No, then we would deadlock... return an error (default behavior
|
||||
* is like PTHREAD_MUTEX_ERRORCHECK)
|
||||
/* No, then we would deadlock... return an error (default
|
||||
* behavior is like PTHREAD_MUTEX_ERRORCHECK)
|
||||
*
|
||||
* NOTE: This is non-compliant behavior for the case of a
|
||||
* NORMAL mutex. In that case, it the deadlock condition should
|
||||
* not be detected and the thread should be permitted to
|
||||
* deadlock.
|
||||
*/
|
||||
|
||||
serr("ERROR: Returning EDEADLK\n");
|
||||
@ -169,4 +174,3 @@ int pthread_mutex_lock(FAR pthread_mutex_t *mutex)
|
||||
sinfo("Returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -100,13 +100,22 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
|
||||
|
||||
if (mutex->pid != (int)getpid())
|
||||
{
|
||||
/* No... return an error (default behavior is like PTHREAD_MUTEX_ERRORCHECK) */
|
||||
/* No... return an EPERM error.
|
||||
*
|
||||
* Per POSIX: "EPERM should be returned if the mutex type is
|
||||
* PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, or the
|
||||
* mutex is a robust mutex, and the current thread does not own
|
||||
* the mutex."
|
||||
*
|
||||
* For the case of the non-robust PTHREAD_MUTEX_NORMAL mutex,
|
||||
* the behavior is undefined. Here we treat that type as though
|
||||
* it were PTHREAD_MUTEX_ERRORCHECK type and just return an error.
|
||||
*/
|
||||
|
||||
serr("ERROR: Holder=%d returning EPERM\n", mutex->pid);
|
||||
ret = EPERM;
|
||||
}
|
||||
|
||||
|
||||
/* Yes, the caller owns the semaphore.. Is this a recursive mutex? */
|
||||
|
||||
#ifdef CONFIG_MUTEX_TYPES
|
||||
@ -116,6 +125,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
|
||||
* the mutex lock, just decrement the count of locks held, and return
|
||||
* success.
|
||||
*/
|
||||
|
||||
mutex->nlocks--;
|
||||
}
|
||||
#endif
|
||||
@ -134,6 +144,7 @@ int pthread_mutex_unlock(FAR pthread_mutex_t *mutex)
|
||||
#endif
|
||||
ret = pthread_givesemaphore((FAR sem_t *)&mutex->sem);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ static FAR struct semholder_s *sem_findholder(sem_t *sem,
|
||||
int i;
|
||||
pholder = NULL;
|
||||
|
||||
/* We have two hard-allocated holder structuse in sem_t */
|
||||
/* We have two hard-allocated holder structures in sem_t */
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
@ -338,7 +338,7 @@ static int sem_boostholderprio(FAR struct semholder_s *pholder,
|
||||
if (!sched_verifytcb(htcb))
|
||||
{
|
||||
serr("ERROR: TCB 0x%08x is a stale handle, counts lost\n", htcb);
|
||||
DEBUGASSERT(!sched_verifytcb(htcb));
|
||||
DEBUGPANIC();
|
||||
sem_freeholder(sem, pholder);
|
||||
}
|
||||
|
||||
@ -498,7 +498,7 @@ static int sem_restoreholderprio(FAR struct tcb_s *htcb,
|
||||
if (!sched_verifytcb(htcb))
|
||||
{
|
||||
serr("ERROR: TCB 0x%08x is a stale handle, counts lost\n", htcb);
|
||||
DEBUGASSERT(!sched_verifytcb(htcb));
|
||||
DEBUGPANIC();
|
||||
pholder = sem_findholder(sem, htcb);
|
||||
if (pholder != NULL)
|
||||
{
|
||||
@ -787,7 +787,6 @@ static inline void sem_restorebaseprio_task(FAR struct tcb_s *stcb,
|
||||
FAR sem_t *sem)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = this_task();
|
||||
FAR struct semholder_s *pholder;
|
||||
|
||||
/* Perform the following actions only if a new thread was given a count.
|
||||
* The thread that received the count should be the highest priority
|
||||
@ -831,7 +830,6 @@ static inline void sem_restorebaseprio_task(FAR struct tcb_s *stcb,
|
||||
*/
|
||||
|
||||
sem_findandfreeholder(sem, rtcb);
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -905,14 +903,15 @@ void sem_destroyholder(FAR sem_t *sem)
|
||||
if (sem->hhead != NULL)
|
||||
{
|
||||
serr("ERROR: Semaphore destroyed with holders\n");
|
||||
DEBUGASSERT(sem->hhead != NULL);
|
||||
DEBUGPANIC();
|
||||
(void)sem_foreachholder(sem, sem_recoverholders, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
if (sem->holder[0].htcb != NULL || sem->holder[0].htcb != NULL)
|
||||
if (sem->holder[0].htcb != NULL || sem->holder[1].htcb != NULL)
|
||||
{
|
||||
DEBUGASSERT(sem->holder[0].htcb != NULL || sem->holder[0].htcb != NULL);
|
||||
serr("ERROR: Semaphore destroyed with holder\n");
|
||||
DEBUGPANIC();
|
||||
}
|
||||
|
||||
sem->holder[0].htcb = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user