1446 lines
42 KiB
C
1446 lines
42 KiB
C
/* -----------------------------------------------------------------------------
|
|
* Copyright (c) 2013-2015 ARM Ltd.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied warranty.
|
|
* In no event will the authors be held liable for any damages arising from
|
|
* the use of this software. Permission is granted to anyone to use this
|
|
* software for any purpose, including commercial applications, and to alter
|
|
* it and redistribute it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software in
|
|
* a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*
|
|
*
|
|
* $Date: 21. October 2015
|
|
* $Revision: V2.1
|
|
*
|
|
* Driver: Driver_I2C1, Driver_I2C2
|
|
* Configured: via RTE_Device.h configuration file
|
|
* Project: I2C Driver for STMicroelectronics STM32F10x
|
|
* --------------------------------------------------------------------------
|
|
* Use the following configuration settings in the middleware component
|
|
* to connect to this driver.
|
|
*
|
|
* Configuration Setting Value I2C Interface
|
|
* --------------------- ----- -------------
|
|
* Connect to hardware via Driver_I2C# = 1 use I2C1
|
|
* Connect to hardware via Driver_I2C# = 2 use I2C2
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
/* History:
|
|
* Version 2.1
|
|
* Corrected invalid __I2C_DMA field in I2C_DMA_TxEvent and I2C_DMA_RxEvent functions (corrected from instance into reg)
|
|
* Version 2.0
|
|
* Updated to the CMSIS Driver API V2.02
|
|
* Version 1.2
|
|
* Bugfix (corrected I2C register access)
|
|
* Version 1.1
|
|
* Based on API V1.10 (namespace prefix ARM_ added)
|
|
* Version 1.0
|
|
* Initial release
|
|
*/
|
|
|
|
|
|
#include "I2C_STM32F10x.h"
|
|
|
|
#define ARM_I2C_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2,1) /* driver version */
|
|
|
|
|
|
/* Driver Version */
|
|
static const ARM_DRIVER_VERSION DriverVersion = {
|
|
ARM_I2C_API_VERSION,
|
|
ARM_I2C_DRV_VERSION
|
|
};
|
|
|
|
/* Driver Capabilities */
|
|
static const ARM_I2C_CAPABILITIES DriverCapabilities = { 0U };
|
|
|
|
|
|
#if defined(USE_I2C1)
|
|
/* Function prototypes */
|
|
void I2C1_EV_IRQHandler (void);
|
|
void I2C1_ER_IRQHandler (void);
|
|
|
|
/* I2C1 DMA */
|
|
#if defined(I2C1_RX_DMA_Instance) && defined(I2C1_TX_DMA_Instance)
|
|
static const I2C_DMA I2C1_RX_DMA = {
|
|
I2C1_RX_DMA_Instance,
|
|
I2C1_RX_DMA_Number,
|
|
I2C1_RX_DMA_Channel,
|
|
I2C1_RX_DMA_Priority
|
|
};
|
|
static const I2C_DMA I2C1_TX_DMA = {
|
|
I2C1_TX_DMA_Instance,
|
|
I2C1_TX_DMA_Number,
|
|
I2C1_TX_DMA_Channel,
|
|
I2C1_TX_DMA_Priority
|
|
};
|
|
#endif
|
|
|
|
/* I2C1 Information (Run-Time) */
|
|
static I2C_INFO I2C1_Info;
|
|
|
|
/* I2C1 Resources */
|
|
static I2C_RESOURCES I2C1_Resources = {
|
|
I2C1,
|
|
#if defined(I2C1_RX_DMA_Instance) && defined(I2C1_TX_DMA_Instance)
|
|
&I2C1_RX_DMA,
|
|
&I2C1_TX_DMA,
|
|
#else
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
{
|
|
I2C1_SCL_GPIOx,
|
|
I2C1_SDA_GPIOx,
|
|
I2C1_SCL_GPIO_Pin,
|
|
I2C1_SDA_GPIO_Pin,
|
|
I2C1_AF_REMAP,
|
|
},
|
|
I2C1_EV_IRQn,
|
|
I2C1_ER_IRQn,
|
|
RCC_APB_I2C1_MASK,
|
|
&I2C1_Info
|
|
};
|
|
|
|
#endif /* USE_I2C1 */
|
|
|
|
#if defined(USE_I2C2)
|
|
/* Function prototypes */
|
|
void I2C2_EV_IRQHandler (void);
|
|
void I2C2_ER_IRQHandler (void);
|
|
|
|
/* I2C2 DMA */
|
|
#if defined(I2C2_RX_DMA_Instance) && defined(I2C2_TX_DMA_Instance)
|
|
static const I2C_DMA I2C2_RX_DMA = {
|
|
I2C2_RX_DMA_Instance,
|
|
I2C2_RX_DMA_Number,
|
|
I2C2_RX_DMA_Channel,
|
|
I2C2_RX_DMA_Priority
|
|
};
|
|
static const I2C_DMA I2C2_TX_DMA = {
|
|
I2C2_TX_DMA_Instance,
|
|
I2C2_TX_DMA_Number,
|
|
I2C2_TX_DMA_Channel,
|
|
I2C2_TX_DMA_Priority
|
|
};
|
|
#endif
|
|
|
|
/* I2C2 Information (Run-Time) */
|
|
static I2C_INFO I2C2_Info;
|
|
|
|
/* I2C2 Resources */
|
|
static I2C_RESOURCES I2C2_Resources = {
|
|
I2C2,
|
|
#if defined(I2C2_RX_DMA_Instance) && defined(I2C2_TX_DMA_Instance)
|
|
&I2C2_RX_DMA,
|
|
&I2C2_TX_DMA,
|
|
#else
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
{
|
|
I2C2_SCL_GPIOx,
|
|
I2C2_SDA_GPIOx,
|
|
I2C2_SCL_GPIO_Pin,
|
|
I2C2_SDA_GPIO_Pin,
|
|
I2C2_AF_REMAP,
|
|
},
|
|
I2C2_EV_IRQn,
|
|
I2C2_ER_IRQn,
|
|
RCC_APB_I2C2_MASK,
|
|
&I2C2_Info
|
|
};
|
|
|
|
#endif /* USE_I2C2 */
|
|
|
|
|
|
/**
|
|
\fn ARM_DRV_VERSION I2C_GetVersion (void)
|
|
\brief Get driver version.
|
|
\return \ref ARM_DRV_VERSION
|
|
*/
|
|
static ARM_DRIVER_VERSION I2CX_GetVersion (void) {
|
|
return DriverVersion;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn ARM_I2C_CAPABILITIES I2C_GetCapabilities (void)
|
|
\brief Get driver capabilities.
|
|
\return \ref ARM_I2C_CAPABILITIES
|
|
*/
|
|
static ARM_I2C_CAPABILITIES I2CX_GetCapabilities (void) {
|
|
return DriverCapabilities;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_Initialize (ARM_I2C_SignalEvent_t cb_event, I2C_RESOURCES *i2c)
|
|
\brief Initialize I2C Interface.
|
|
\param[in] cb_event Pointer to \ref ARM_I2C_SignalEvent
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref ARM_I2C_STATUS
|
|
*/
|
|
static int32_t I2C_Initialize (ARM_I2C_SignalEvent_t cb_event, I2C_RESOURCES *i2c) {
|
|
|
|
if (i2c->info->flags & I2C_INIT) { return ARM_DRIVER_OK; }
|
|
|
|
GPIO_AFConfigure(i2c->io.remap);
|
|
|
|
/* Configure SCL Pin */
|
|
GPIO_PortClock (i2c->io.scl_port, true);
|
|
GPIO_PinConfigure(i2c->io.scl_port, i2c->io.scl_pin, GPIO_AF_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
/* Configure SDA Pin */
|
|
GPIO_PortClock (i2c->io.sda_port, true);
|
|
GPIO_PinConfigure(i2c->io.sda_port, i2c->io.sda_pin, GPIO_AF_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
|
|
/* Initialize DMA Channels */
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
DMA_ChannelInitialize(i2c->dma_rx->dma_num, i2c->dma_rx->channel);
|
|
DMA_ChannelInitialize(i2c->dma_tx->dma_num, i2c->dma_tx->channel);
|
|
}
|
|
#endif
|
|
|
|
/* Reset Run-Time information structure */
|
|
memset (i2c->info, 0x00, sizeof (I2C_INFO));
|
|
|
|
i2c->info->cb_event = cb_event;
|
|
i2c->info->flags = I2C_INIT;
|
|
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_Uninitialize (I2C_RESOURCES *i2c)
|
|
\brief De-initialize I2C Interface.
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_Uninitialize (I2C_RESOURCES *i2c) {
|
|
|
|
/* Unconfigure SCL Pin */
|
|
GPIO_PinConfigure(i2c->io.scl_port, i2c->io.scl_pin, GPIO_IN_ANALOG,
|
|
GPIO_MODE_OUT2MHZ);
|
|
/* Unconfigure SDA Pin */
|
|
GPIO_PinConfigure(i2c->io.sda_port, i2c->io.sda_pin, GPIO_IN_ANALOG,
|
|
GPIO_MODE_OUT2MHZ);
|
|
GPIO_AFConfigure(AFIO_I2C1_NO_REMAP);
|
|
|
|
/* Uninitialize DMA Channels */
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
DMA_ChannelUninitialize(i2c->dma_rx->dma_num, i2c->dma_rx->channel);
|
|
DMA_ChannelUninitialize(i2c->dma_tx->dma_num, i2c->dma_tx->channel);
|
|
}
|
|
#endif
|
|
|
|
i2c->info->flags = 0U;
|
|
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t ARM_I2C_PowerControl (ARM_POWER_STATE state, I2C_RESOURCES *i2c)
|
|
\brief Control I2C Interface Power.
|
|
\param[in] state Power state
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_PowerControl (ARM_POWER_STATE state, I2C_RESOURCES *i2c) {
|
|
|
|
switch (state) {
|
|
case ARM_POWER_OFF:
|
|
/* Enable I2C clock */
|
|
RCC->APB1ENR |= i2c->apb_mask;
|
|
|
|
/* Disable I2C peripheral */
|
|
i2c->reg->CR1 = 0;
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
/* Abort DMA channels */
|
|
DMA_ChannelDisable (i2c->dma_rx->reg);
|
|
DMA_ChannelDisable (i2c->dma_tx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Disable I2C IRQ */
|
|
NVIC_DisableIRQ(i2c->ev_irq_num);
|
|
NVIC_DisableIRQ(i2c->er_irq_num);
|
|
|
|
/* Disable peripheral clock */
|
|
RCC->APB1ENR &= ~i2c->apb_mask;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
i2c->info->status.direction = 0U;
|
|
i2c->info->status.general_call = 0U;
|
|
i2c->info->status.arbitration_lost = 0U;
|
|
i2c->info->status.bus_error = 0U;
|
|
|
|
i2c->info->flags &= ~I2C_POWER;
|
|
break;
|
|
|
|
case ARM_POWER_LOW:
|
|
return ARM_DRIVER_ERROR_UNSUPPORTED;
|
|
|
|
case ARM_POWER_FULL:
|
|
if ((i2c->info->flags & I2C_INIT) == 0U) {
|
|
return ARM_DRIVER_ERROR;
|
|
}
|
|
if ((i2c->info->flags & I2C_POWER) != 0U) {
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* Enable I2C clock */
|
|
RCC->APB1ENR |= i2c->apb_mask;
|
|
|
|
/* Clear and Enable I2C IRQ */
|
|
NVIC_ClearPendingIRQ(i2c->ev_irq_num);
|
|
NVIC_ClearPendingIRQ(i2c->er_irq_num);
|
|
NVIC_EnableIRQ(i2c->ev_irq_num);
|
|
NVIC_EnableIRQ(i2c->er_irq_num);
|
|
|
|
/* Reset the peripheral */
|
|
RCC->APB1RSTR |= i2c->apb_mask;
|
|
__NOP(); __NOP(); __NOP(); __NOP();
|
|
RCC->APB1RSTR &= ~i2c->apb_mask;
|
|
|
|
/* Enable event and error interrupts */
|
|
i2c->reg->CR2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN;
|
|
/* Disable buffer interrupts */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITBUFEN;
|
|
|
|
/* Enable clock stretching */
|
|
i2c->reg->CR1 &= ~I2C_CR1_NOSTRETCH;
|
|
|
|
/* Enable I2C peripheral */
|
|
i2c->reg->CR1 |= I2C_CR1_PE;
|
|
|
|
/* Enable acknowledge */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
|
|
/* Ready for operation */
|
|
i2c->info->flags |= I2C_POWER;
|
|
break;
|
|
}
|
|
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_MasterTransmit (uint32_t addr,
|
|
const uint8_t *data,
|
|
uint32_t num,
|
|
bool xfer_pending,
|
|
I2C_RESOURCES *i2c)
|
|
\brief Start transmitting data as I2C Master.
|
|
\param[in] addr Slave address (7-bit or 10-bit)
|
|
\param[in] data Pointer to buffer with data to send to I2C Slave
|
|
\param[in] num Number of data bytes to send
|
|
\param[in] xfer_pending Transfer operation is pending - Stop condition will not be generated
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_MasterTransmit (uint32_t addr,
|
|
const uint8_t *data,
|
|
uint32_t num,
|
|
bool xfer_pending,
|
|
I2C_RESOURCES *i2c) {
|
|
|
|
if ((data == NULL) || (num == 0U)) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
|
|
if ((addr & ~(ARM_I2C_ADDRESS_10BIT | ARM_I2C_ADDRESS_GC)) > 0x3FFU) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
|
|
if (i2c->info->status.busy) {
|
|
return (ARM_DRIVER_ERROR_BUSY);
|
|
}
|
|
|
|
if ((i2c->info->xfer.ctrl & XFER_CTRL_XPENDING) == 0U) {
|
|
/* New transfer */
|
|
while (i2c->reg->SR2 & I2C_SR2_BUSY) {
|
|
; /* Wait until bus released */
|
|
}
|
|
}
|
|
|
|
i2c->info->status.busy = 1U;
|
|
i2c->info->status.mode = 1U;
|
|
i2c->info->status.direction = 0U;
|
|
i2c->info->status.bus_error = 0U;
|
|
i2c->info->status.arbitration_lost = 0U;
|
|
|
|
i2c->info->xfer.num = num;
|
|
i2c->info->xfer.cnt = 0U;
|
|
i2c->info->xfer.data = (uint8_t *)data;
|
|
i2c->info->xfer.addr = (uint16_t)(addr);
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
if (xfer_pending) {
|
|
i2c->info->xfer.ctrl |= XFER_CTRL_XPENDING;
|
|
}
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if (i2c->dma_tx) {
|
|
/* Configure and enable DMA channel */
|
|
DMA_ChannelConfigure (i2c->dma_tx->reg,
|
|
(i2c->dma_rx->priority << DMA_PRIORITY_POS)|
|
|
DMA_MEMORY_DATA_8BIT |
|
|
DMA_PERIPHERAL_DATA_8BIT |
|
|
DMA_MEMORY_INCREMENT |
|
|
DMA_READ_MEMORY |
|
|
DMA_TRANSFER_COMPLETE_INTERRUPT,
|
|
(uint32_t)&(i2c->reg->DR),
|
|
(uint32_t)data,
|
|
num);
|
|
DMA_ChannelEnable (i2c->dma_tx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Generate start and enable event interrupts */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
i2c->reg->CR1 |= I2C_CR1_START;
|
|
i2c->reg->CR2 |= I2C_CR2_ITEVTEN;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_MasterReceive (uint32_t addr,
|
|
uint8_t *data,
|
|
uint32_t num,
|
|
bool xfer_pending,
|
|
I2C_RESOURCES *i2c)
|
|
\brief Start receiving data as I2C Master.
|
|
\param[in] addr Slave address (7-bit or 10-bit)
|
|
\param[out] data Pointer to buffer for data to receive from I2C Slave
|
|
\param[in] num Number of data bytes to receive
|
|
\param[in] xfer_pending Transfer operation is pending - Stop condition will not be generated
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_MasterReceive (uint32_t addr,
|
|
uint8_t *data,
|
|
uint32_t num,
|
|
bool xfer_pending,
|
|
I2C_RESOURCES *i2c) {
|
|
|
|
if ((data == NULL) || (num == 0U)) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
if ((addr & ~(ARM_I2C_ADDRESS_10BIT | ARM_I2C_ADDRESS_GC)) > 0x3FFU) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
|
|
if (i2c->info->status.busy) {
|
|
return (ARM_DRIVER_ERROR_BUSY);
|
|
}
|
|
|
|
if ((i2c->info->xfer.ctrl & XFER_CTRL_XPENDING) == 0U) {
|
|
/* New transfer */
|
|
while (i2c->reg->SR2 & I2C_SR2_BUSY) {
|
|
; /* Wait until bus released */
|
|
}
|
|
}
|
|
|
|
i2c->info->status.busy = 1U;
|
|
i2c->info->status.mode = 1U;
|
|
i2c->info->status.direction = 1U;
|
|
i2c->info->status.bus_error = 0U;
|
|
i2c->info->status.arbitration_lost = 0U;
|
|
|
|
i2c->info->xfer.num = num;
|
|
i2c->info->xfer.cnt = 0U;
|
|
i2c->info->xfer.data = data;
|
|
i2c->info->xfer.addr = (uint16_t)(addr);
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
if (xfer_pending) {
|
|
i2c->info->xfer.ctrl |= XFER_CTRL_XPENDING;
|
|
}
|
|
|
|
/* Enable acknowledge generation */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if (i2c->dma_rx) {
|
|
/* Configure and enable DMA channel */
|
|
DMA_ChannelConfigure (i2c->dma_rx->reg,
|
|
(i2c->dma_rx->priority << DMA_PRIORITY_POS)|
|
|
DMA_MEMORY_DATA_8BIT |
|
|
DMA_PERIPHERAL_DATA_8BIT |
|
|
DMA_MEMORY_INCREMENT |
|
|
DMA_PERIPHERAL_TO_MEMORY |
|
|
DMA_TRANSFER_COMPLETE_INTERRUPT,
|
|
(uint32_t)&(i2c->reg->DR),
|
|
(uint32_t)data,
|
|
num);
|
|
|
|
DMA_ChannelEnable (i2c->dma_rx->reg);
|
|
|
|
/* Permit generation of a NACK on the last received data */
|
|
i2c->reg->CR2 |= I2C_CR2_LAST;
|
|
}
|
|
#endif
|
|
|
|
/* Generate start and enable event interrupts */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
i2c->reg->CR1 |= I2C_CR1_START;
|
|
i2c->reg->CR2 |= I2C_CR2_ITEVTEN;
|
|
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_SlaveTransmit (const uint8_t *data, uint32_t num, I2C_RESOURCES *i2c)
|
|
\brief Start transmitting data as I2C Slave.
|
|
\param[in] data Pointer to buffer with data to send to I2C Master
|
|
\param[in] num Number of data bytes to send
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_SlaveTransmit (const uint8_t *data, uint32_t num, I2C_RESOURCES *i2c) {
|
|
|
|
if ((data == NULL) || (num == 0U)) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
|
|
if (i2c->info->status.busy) {
|
|
return (ARM_DRIVER_ERROR_BUSY);
|
|
}
|
|
|
|
i2c->info->status.bus_error = 0U;
|
|
i2c->info->status.general_call = 0U;
|
|
|
|
i2c->info->xfer.num = num;
|
|
i2c->info->xfer.cnt = 0U;
|
|
i2c->info->xfer.data = (uint8_t *)data;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if (i2c->dma_tx) {
|
|
/* Configure and enable DMA channel */
|
|
DMA_ChannelConfigure (i2c->dma_tx->reg,
|
|
(i2c->dma_tx->priority << DMA_PRIORITY_POS)|
|
|
DMA_MEMORY_DATA_8BIT |
|
|
DMA_PERIPHERAL_DATA_8BIT |
|
|
DMA_MEMORY_INCREMENT |
|
|
DMA_READ_MEMORY |
|
|
DMA_TRANSFER_COMPLETE_INTERRUPT,
|
|
(uint32_t)&(i2c->reg->DR),
|
|
(uint32_t)data,
|
|
num);
|
|
DMA_ChannelEnable (i2c->dma_tx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Enable acknowledge */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
|
|
/* Enable event interrupts */
|
|
i2c->reg->CR2 |= I2C_CR2_ITEVTEN;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_SlaveReceive (uint8_t *data, uint32_t num, I2C_RESOURCES *i2c)
|
|
\brief Start receiving data as I2C Slave.
|
|
\param[out] data Pointer to buffer for data to receive from I2C Master
|
|
\param[in] num Number of data bytes to receive
|
|
\param[in] i2c Pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_SlaveReceive (uint8_t *data, uint32_t num, I2C_RESOURCES *i2c) {
|
|
|
|
if ((data == NULL) || (num == 0U)) {
|
|
return ARM_DRIVER_ERROR_PARAMETER;
|
|
}
|
|
|
|
if (i2c->info->status.busy) {
|
|
return (ARM_DRIVER_ERROR_BUSY);
|
|
}
|
|
|
|
i2c->info->status.bus_error = 0U;
|
|
i2c->info->status.general_call = 0U;
|
|
|
|
i2c->info->xfer.num = num;
|
|
i2c->info->xfer.cnt = 0U;
|
|
i2c->info->xfer.data = data;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
/* Enable acknowledge generation */
|
|
i2c->reg->CR2 |= I2C_CR2_LAST;
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if (i2c->dma_rx) {
|
|
/* Configure and enable DMA channel */
|
|
DMA_ChannelConfigure (i2c->dma_rx->reg,
|
|
(i2c->dma_rx->priority << DMA_PRIORITY_POS)|
|
|
DMA_MEMORY_DATA_8BIT |
|
|
DMA_PERIPHERAL_DATA_8BIT |
|
|
DMA_MEMORY_INCREMENT |
|
|
DMA_PERIPHERAL_TO_MEMORY |
|
|
DMA_TRANSFER_COMPLETE_INTERRUPT,
|
|
(uint32_t)&(i2c->reg->DR),
|
|
(uint32_t)data,
|
|
num);
|
|
|
|
DMA_ChannelEnable (i2c->dma_rx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Enable acknowledge */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
|
|
/* Enable event interrupts */
|
|
i2c->reg->CR2 |= I2C_CR2_ITEVTEN;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_GetDataCount (void)
|
|
\brief Get transferred data count.
|
|
\return number of data bytes transferred; -1 when Slave is not addressed by Master
|
|
*/
|
|
static int32_t I2C_GetDataCount (I2C_RESOURCES *i2c) {
|
|
return ((int32_t)i2c->info->xfer.cnt);
|
|
}
|
|
|
|
|
|
/**
|
|
\fn int32_t I2C_Control (uint32_t control, uint32_t arg, I2C_RESOURCES *i2c)
|
|
\brief Control I2C Interface.
|
|
\param[in] control operation
|
|
\param[in] arg argument of operation (optional)
|
|
\param[in] i2c pointer to I2C resources
|
|
\return \ref execution_status
|
|
*/
|
|
static int32_t I2C_Control (uint32_t control, uint32_t arg, I2C_RESOURCES *i2c) {
|
|
uint32_t state;
|
|
uint32_t i, j, pclk;
|
|
uint32_t ccr;
|
|
uint32_t trise;
|
|
|
|
if ((i2c->info->flags & I2C_POWER) == 0U) {
|
|
/* I2C not powered */
|
|
return ARM_DRIVER_ERROR;
|
|
}
|
|
|
|
switch (control) {
|
|
case ARM_I2C_OWN_ADDRESS:
|
|
/* Enable/Disable General call */
|
|
if (arg & ARM_I2C_ADDRESS_GC) {
|
|
i2c->reg->CR1 |= I2C_CR1_ENGC;
|
|
} else {
|
|
i2c->reg->CR1 &= ~I2C_CR1_ENGC;
|
|
}
|
|
/* Set own address and its length */
|
|
i2c->reg->OAR1 = ((arg << 1) & 0x03FFU) |
|
|
(1U << 14) |
|
|
((arg & ARM_I2C_ADDRESS_10BIT) ? (1U << 15) : (0U));
|
|
break;
|
|
|
|
case ARM_I2C_BUS_SPEED:
|
|
pclk = RTE_PCLK1;
|
|
|
|
switch (arg) {
|
|
case ARM_I2C_BUS_SPEED_STANDARD:
|
|
/* Clock = 100kHz, Rise Time = 1000ns */
|
|
if (pclk > 42000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; }
|
|
if (pclk < 2000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; }
|
|
ccr = (pclk / 100000U) / 2U;
|
|
trise = (pclk / 1000000U) + 1U;
|
|
break;
|
|
case ARM_I2C_BUS_SPEED_FAST:
|
|
/* Clock = 400kHz, Rise Time = 300ns */
|
|
if (pclk > 42000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; }
|
|
if (pclk < 4000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; }
|
|
if ((pclk >= 10000000U) && ((pclk % 10000000U) == 0U)) {
|
|
ccr = I2C_CCR_FS | I2C_CCR_DUTY | ((pclk / 400000U) / 25U);
|
|
} else {
|
|
ccr = I2C_CCR_FS | ((pclk / 400000U) / 3U);
|
|
}
|
|
trise = (pclk / 333333U) + 1U;
|
|
break;
|
|
default:
|
|
return ARM_DRIVER_ERROR_UNSUPPORTED;
|
|
}
|
|
|
|
i2c->reg->CR1 &= ~I2C_CR1_PE; /* Disable I2C peripheral */
|
|
i2c->reg->CR2 &= ~I2C_CR2_FREQ;
|
|
i2c->reg->CR2 |= pclk / 1000000U;
|
|
i2c->reg->CCR = ccr;
|
|
i2c->reg->TRISE = trise;
|
|
i2c->reg->CR1 |= I2C_CR1_PE; /* Enable I2C peripheral */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK; /* Enable acknowledge */
|
|
break;
|
|
|
|
case ARM_I2C_BUS_CLEAR:
|
|
i2c->reg->CR1 &= ~I2C_CR1_PE;
|
|
|
|
SystemCoreClockUpdate();
|
|
|
|
/* Frequency is set to approx. standard speed (100kHz) */
|
|
pclk = SystemCoreClock / 100000 / 4;
|
|
|
|
GPIO_PinWrite (i2c->io.scl_port, i2c->io.scl_pin, 1);
|
|
GPIO_PinWrite (i2c->io.sda_port, i2c->io.sda_pin, 1);
|
|
|
|
|
|
/* Configure SCL Pin as GPIO */
|
|
GPIO_PinConfigure(i2c->io.scl_port, i2c->io.scl_pin, GPIO_OUT_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
|
|
/* Configure SDA Pin as GPIO */
|
|
GPIO_PinConfigure(i2c->io.sda_port, i2c->io.sda_pin, GPIO_OUT_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
|
|
for (i = 0U; i < 9U; i++) {
|
|
if (GPIO_PinRead (i2c->io.sda_port, i2c->io.sda_pin)) {
|
|
/* Break if slave released SDA line */
|
|
break;
|
|
}
|
|
/* Clock high */
|
|
GPIO_PinWrite (i2c->io.scl_port, i2c->io.scl_pin, 1);
|
|
for (j = 0; j < pclk; j++);
|
|
|
|
/* Clock low */
|
|
GPIO_PinWrite (i2c->io.scl_port, i2c->io.scl_pin, 0);
|
|
for (j = 0; j < pclk; j++);
|
|
}
|
|
/* Check SDA state */
|
|
state = GPIO_PinRead (i2c->io.sda_port, i2c->io.sda_pin);
|
|
|
|
/* Generate STOP condition - SDA goes high while SCL is high */
|
|
GPIO_PinWrite (i2c->io.sda_port, i2c->io.sda_pin, 0);
|
|
for (j = 0; j < pclk; j++);
|
|
GPIO_PinWrite (i2c->io.scl_port, i2c->io.scl_pin, 1);
|
|
for (j = 0; j < pclk; j++);
|
|
GPIO_PinWrite (i2c->io.sda_port, i2c->io.sda_pin, 1);
|
|
|
|
/* Configure SCL Pin as I2C peripheral pin */
|
|
GPIO_PinConfigure(i2c->io.scl_port, i2c->io.scl_pin, GPIO_AF_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
|
|
/* Configure SDA Pin as I2C peripheral pin */
|
|
GPIO_PinConfigure(i2c->io.sda_port, i2c->io.sda_pin, GPIO_AF_OPENDRAIN,
|
|
GPIO_MODE_OUT50MHZ);
|
|
|
|
i2c->reg->CR1 |= I2C_CR1_PE;
|
|
|
|
/* Send event */
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_BUS_CLEAR);
|
|
}
|
|
|
|
return (state) ? ARM_DRIVER_OK : ARM_DRIVER_ERROR;
|
|
|
|
case ARM_I2C_ABORT_TRANSFER:
|
|
/* Disable DMA requests and I2C interrupts */
|
|
i2c->reg->CR2 &= ~(I2C_CR2_DMAEN | I2C_CR2_ITBUFEN | I2C_CR2_ITEVTEN);
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
DMA_ChannelDisable(i2c->dma_rx->reg);
|
|
DMA_ChannelDisable(i2c->dma_tx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Generate stop */
|
|
/* Master generates stop after the current byte transfer */
|
|
/* Slave releases SCL and SDA after the current byte transfer */
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
|
|
i2c->info->xfer.num = 0U;
|
|
i2c->info->xfer.cnt = 0U;
|
|
i2c->info->xfer.data = NULL;
|
|
i2c->info->xfer.addr = 0U;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
i2c->info->status.direction = 0U;
|
|
i2c->info->status.general_call = 0U;
|
|
i2c->info->status.arbitration_lost = 0U;
|
|
i2c->info->status.bus_error = 0U;
|
|
|
|
/* Disable and reenable peripheral to clear some flags */
|
|
i2c->reg->CR1 &= ~I2C_CR1_PE;
|
|
i2c->reg->CR1 |= I2C_CR1_PE;
|
|
/* Enable acknowledge */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
break;
|
|
|
|
default: return ARM_DRIVER_ERROR;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
\fn ARM_I2C_STATUS I2C_GetStatus (I2C_RESOURCES *i2c)
|
|
\brief Get I2C status.
|
|
\param[in] i2c pointer to I2C resources
|
|
\return I2C status \ref ARM_I2C_STATUS
|
|
*/
|
|
static ARM_I2C_STATUS I2C_GetStatus (I2C_RESOURCES *i2c) {
|
|
return (i2c->info->status);
|
|
}
|
|
|
|
|
|
/**
|
|
\fn void I2C_EV_IRQHandler (I2C_RESOURCES *i2c)
|
|
\brief I2C Event Interrupt handler.
|
|
\param[in] i2c Pointer to I2C resources
|
|
*/
|
|
static void I2C_EV_IRQHandler (I2C_RESOURCES *i2c) {
|
|
I2C_TRANSFER_INFO *tr = &i2c->info->xfer;
|
|
uint8_t data;
|
|
uint16_t sr1, sr2;
|
|
uint32_t event;
|
|
|
|
sr1 = (uint16_t)i2c->reg->SR1;
|
|
|
|
if (sr1 & I2C_SR1_SB) {
|
|
/* (EV5): start bit generated, send address */
|
|
|
|
if (tr->addr & ARM_I2C_ADDRESS_10BIT) {
|
|
/* 10-bit addressing mode */
|
|
data = (uint8_t)(0xF0U | ((tr->addr >> 7) & 0x06U));
|
|
}
|
|
else {
|
|
/* 7-bit addressing mode */
|
|
data = (uint8_t)tr->addr << 1;
|
|
data |= (uint8_t)i2c->info->status.direction;
|
|
}
|
|
i2c->reg->DR = data;
|
|
}
|
|
else if (sr1 & I2C_SR1_ADD10) {
|
|
/* (EV9): 10-bit address header sent, send device address LSB */
|
|
i2c->reg->DR = (uint8_t)tr->addr;
|
|
|
|
if (i2c->info->status.direction) {
|
|
/* Master receiver generates repeated start in 10-bit addressing mode */
|
|
tr->ctrl |= XFER_CTRL_RSTART;
|
|
}
|
|
}
|
|
else if (sr1 & I2C_SR1_ADDR) {
|
|
/* (EV6): addressing complete */
|
|
if (tr->ctrl & XFER_CTRL_ADDR_DONE) {
|
|
/* Restart condition, end previous transfer */
|
|
i2c->info->status.busy = 0U;
|
|
|
|
event = ARM_I2C_EVENT_TRANSFER_DONE;
|
|
|
|
if (tr->cnt < tr->num) {
|
|
event |= ARM_I2C_EVENT_TRANSFER_INCOMPLETE;
|
|
}
|
|
|
|
if (i2c->info->status.general_call) {
|
|
event |= ARM_I2C_EVENT_GENERAL_CALL;
|
|
}
|
|
|
|
if (i2c->info->cb_event != NULL) {
|
|
i2c->info->cb_event (event);
|
|
}
|
|
}
|
|
|
|
if ((i2c->info->status.mode != 0U) && (i2c->info->status.direction != 0U)) {
|
|
/* Master mode, receiver */
|
|
if (tr->num == 1U) {
|
|
i2c->reg->CR1 &= ~I2C_CR1_ACK;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
i2c->reg->SR1;
|
|
i2c->reg->SR2;
|
|
|
|
if (tr->ctrl & XFER_CTRL_RSTART) {
|
|
tr->ctrl &= ~XFER_CTRL_RSTART;
|
|
/* Generate repeated start */
|
|
i2c->reg->CR1 |= I2C_CR1_START;
|
|
}
|
|
else {
|
|
if (tr->num == 1U) {
|
|
if ((tr->ctrl & XFER_CTRL_XPENDING) == 0U) {
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
}
|
|
}
|
|
else if (tr->num == 2U) {
|
|
i2c->reg->CR1 &= ~I2C_CR1_ACK;
|
|
i2c->reg->CR1 |= I2C_CR1_POS;
|
|
|
|
/* Wait until BTF == 1 */
|
|
tr->ctrl |= XFER_CTRL_WAIT_BTF;
|
|
}
|
|
else {
|
|
if (tr->num == 3U) {
|
|
/* Wait until BTF == 1 */
|
|
tr->ctrl |= XFER_CTRL_WAIT_BTF;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Master transmitter or slave mode */
|
|
sr2 = (uint16_t)i2c->reg->SR2;
|
|
|
|
if (i2c->info->status.mode == 0U) {
|
|
/* Slave mode */
|
|
|
|
if (sr2 & I2C_SR2_GENCALL) {
|
|
i2c->info->status.general_call = 1U;
|
|
} else {
|
|
i2c->info->status.general_call = 0U;
|
|
}
|
|
|
|
if (sr2 & I2C_SR2_TRA) {
|
|
i2c->info->status.direction = 0U;
|
|
} else {
|
|
i2c->info->status.direction = 1U;
|
|
}
|
|
|
|
event = 0U;
|
|
|
|
if (tr->data == NULL) {
|
|
if (i2c->info->status.direction) {
|
|
event |= ARM_I2C_EVENT_SLAVE_RECEIVE;
|
|
}
|
|
else {
|
|
event |= ARM_I2C_EVENT_SLAVE_TRANSMIT;
|
|
}
|
|
}
|
|
|
|
if (i2c->info->status.general_call) {
|
|
event |= ARM_I2C_EVENT_GENERAL_CALL;
|
|
}
|
|
|
|
if ((event != 0U) && (i2c->info->cb_event != NULL)) {
|
|
i2c->info->cb_event (event);
|
|
}
|
|
|
|
i2c->info->status.busy = 1U;
|
|
}
|
|
}
|
|
|
|
tr->ctrl |= XFER_CTRL_ADDR_DONE | XFER_CTRL_XACTIVE;
|
|
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
/* Enable DMA data transfer */
|
|
i2c->reg->CR2 |= I2C_CR2_DMAEN;
|
|
}
|
|
else {
|
|
/* Enable IRQ data transfer */
|
|
i2c->reg->CR2 |= I2C_CR2_ITBUFEN;
|
|
}
|
|
|
|
}
|
|
else if (sr1 & I2C_SR1_STOPF) {
|
|
/* STOP condition detected */
|
|
tr->data = NULL;
|
|
tr->ctrl = 0U;
|
|
|
|
/* Reenable ACK */
|
|
i2c->reg->CR1 |= I2C_CR1_ACK;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
|
|
event = ARM_I2C_EVENT_TRANSFER_DONE;
|
|
if (tr->cnt < tr->num) {
|
|
event |= ARM_I2C_EVENT_TRANSFER_INCOMPLETE;
|
|
}
|
|
if (i2c->info->status.general_call) {
|
|
event |= ARM_I2C_EVENT_GENERAL_CALL;
|
|
}
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (event);
|
|
}
|
|
}
|
|
else if (tr->ctrl & XFER_CTRL_XACTIVE) {
|
|
/* BTF, RxNE or TxE interrupt */
|
|
if (tr->ctrl & XFER_CTRL_DMA_DONE) {
|
|
/* BTF triggered this event */
|
|
if (i2c->info->status.mode) {
|
|
if (i2c->info->xfer.ctrl & XFER_CTRL_XPENDING) {
|
|
/* Disable event interrupt */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
}
|
|
else {
|
|
/* Generate stop condition */
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
}
|
|
tr->data = NULL;
|
|
tr->ctrl &= ~XFER_CTRL_XACTIVE;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_TRANSFER_DONE);
|
|
}
|
|
}
|
|
}
|
|
else if (sr1 & I2C_SR1_TXE) {
|
|
if (i2c->info->status.mode) {
|
|
/* Master transmitter */
|
|
if (tr->ctrl & XFER_CTRL_WAIT_BTF) {
|
|
if (sr1 & I2C_SR1_BTF) {
|
|
/* End master transmit operation */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITBUFEN;
|
|
|
|
if (tr->ctrl & XFER_CTRL_XPENDING) {
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
}
|
|
else {
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
}
|
|
|
|
tr->data = NULL;
|
|
tr->ctrl &= ~XFER_CTRL_XACTIVE;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_TRANSFER_DONE);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
i2c->reg->DR = tr->data[tr->cnt];
|
|
|
|
tr->cnt++;
|
|
if (tr->cnt == tr->num) {
|
|
tr->ctrl |= XFER_CTRL_WAIT_BTF;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Slave transmitter */
|
|
if (tr->data == NULL) {
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_SLAVE_TRANSMIT);
|
|
}
|
|
}
|
|
|
|
if (tr->data) {
|
|
i2c->reg->DR = tr->data[tr->cnt];
|
|
|
|
tr->cnt++;
|
|
if (tr->cnt == tr->num) {
|
|
tr->data = NULL;
|
|
}
|
|
}
|
|
else {
|
|
/* Master requests more data as we have */
|
|
i2c->reg->DR = (uint8_t)0xFF;
|
|
}
|
|
}
|
|
}
|
|
else if (sr1 & I2C_SR1_RXNE) {
|
|
if (i2c->info->status.mode) {
|
|
/* Master receiver */
|
|
if (tr->ctrl & XFER_CTRL_WAIT_BTF) {
|
|
if (sr1 & I2C_SR1_BTF) {
|
|
if ((tr->num == 2U) || (tr->cnt == (tr->num - 2U))) {
|
|
/* Two bytes remaining */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITBUFEN;
|
|
|
|
if (tr->ctrl & XFER_CTRL_XPENDING) {
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
}
|
|
else {
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
}
|
|
|
|
/* Read data N-1 and N */
|
|
tr->data[tr->cnt++] = (uint8_t)i2c->reg->DR;
|
|
tr->data[tr->cnt++] = (uint8_t)i2c->reg->DR;
|
|
|
|
tr->data = NULL;
|
|
tr->ctrl &= ~XFER_CTRL_XACTIVE;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
i2c->reg->CR1 &= ~I2C_CR1_POS;
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_TRANSFER_DONE);
|
|
}
|
|
}
|
|
else {
|
|
/* Three bytes remaining */
|
|
i2c->reg->CR1 &= ~I2C_CR1_ACK;
|
|
/* Read data N-2 */
|
|
tr->data[tr->cnt++] = (uint8_t)i2c->reg->DR;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
tr->data[tr->cnt++] = (uint8_t)i2c->reg->DR;
|
|
|
|
if (tr->num == 1U) {
|
|
/* Single byte transfer completed */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITBUFEN;
|
|
|
|
if (tr->ctrl & XFER_CTRL_XPENDING) {
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
}
|
|
/* (STOP was already sent during ADDR phase) */
|
|
|
|
tr->data = NULL;
|
|
tr->ctrl &= ~XFER_CTRL_XACTIVE;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_TRANSFER_DONE);
|
|
}
|
|
}
|
|
else {
|
|
if (tr->cnt == (tr->num - 3U)) {
|
|
/* N > 2 byte reception, begin N-2 data reception */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITBUFEN;
|
|
/* Wait until BTF == 1 */
|
|
tr->ctrl |= XFER_CTRL_WAIT_BTF;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Slave receiver */
|
|
data = (uint8_t)i2c->reg->DR;
|
|
|
|
if (tr->data == NULL) {
|
|
/* Receive buffer full: Disable ACK */
|
|
i2c->reg->CR1 &= ~I2C_CR1_ACK;
|
|
}
|
|
else {
|
|
if (tr->cnt < tr->num) {
|
|
tr->data[tr->cnt] = data;
|
|
|
|
tr->cnt++;
|
|
if (tr->cnt == tr->num) {
|
|
tr->data = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
\fn void I2C_ER_IRQHandler (I2C_RESOURCES *i2c)
|
|
\brief I2C Error Interrupt handler.
|
|
\param[in] i2c Pointer to I2C resources
|
|
*/
|
|
static void I2C_ER_IRQHandler (I2C_RESOURCES *i2c) {
|
|
uint32_t sr1 = i2c->reg->SR1;
|
|
uint32_t evt = 0U;
|
|
uint32_t err = 0U;
|
|
|
|
if (sr1 & I2C_SR1_SMBALERT) {
|
|
/* SMBus alert */
|
|
err |= I2C_SR1_SMBALERT;
|
|
}
|
|
if (sr1 & I2C_SR1_TIMEOUT) {
|
|
/* Timeout - SCL remained LOW for 25ms */
|
|
err |= I2C_SR1_TIMEOUT;
|
|
}
|
|
if (sr1 & I2C_SR1_PECERR) {
|
|
/* PEC Error in reception */
|
|
err |= I2C_SR1_PECERR;
|
|
}
|
|
if (sr1 & I2C_SR1_OVR) {
|
|
/* Overrun/Underrun */
|
|
err |= I2C_SR1_OVR;
|
|
}
|
|
|
|
if (sr1 & I2C_SR1_AF) {
|
|
/* Acknowledge failure */
|
|
err |= I2C_SR1_AF;
|
|
|
|
/* Reset the communication */
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
i2c->info->xfer.data = NULL;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
evt = ARM_I2C_EVENT_TRANSFER_DONE;
|
|
|
|
if ((i2c->info->xfer.ctrl & XFER_CTRL_ADDR_DONE) == 0U) {
|
|
/* Addressing not done */
|
|
evt |= ARM_I2C_EVENT_ADDRESS_NACK;
|
|
}
|
|
}
|
|
|
|
if (sr1 & I2C_SR1_ARLO) {
|
|
/* Arbitration lost */
|
|
err |= I2C_SR1_ARLO;
|
|
|
|
/* Switch to slave mode */
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
i2c->info->status.arbitration_lost = 1U;
|
|
|
|
i2c->info->xfer.data = NULL;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
|
|
evt = ARM_I2C_EVENT_TRANSFER_DONE | ARM_I2C_EVENT_ARBITRATION_LOST;
|
|
}
|
|
|
|
if (sr1 & I2C_SR1_BERR) {
|
|
/* Bus error - misplaced start/stop */
|
|
err |= I2C_SR1_BERR;
|
|
|
|
i2c->info->status.bus_error = 1U;
|
|
|
|
if (i2c->info->status.mode == 0U) {
|
|
/* Lines are released in slave mode */
|
|
i2c->info->status.busy = 0U;
|
|
|
|
i2c->info->xfer.data = NULL;
|
|
i2c->info->xfer.ctrl = 0U;
|
|
}
|
|
|
|
evt = ARM_I2C_EVENT_TRANSFER_DONE | ARM_I2C_EVENT_BUS_ERROR;
|
|
|
|
}
|
|
/* Abort DMA channels */
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
if ((i2c->dma_rx != NULL) && (i2c->dma_tx != NULL)) {
|
|
DMA_ChannelDisable(i2c->dma_tx->reg);
|
|
DMA_ChannelDisable(i2c->dma_rx->reg);
|
|
}
|
|
#endif
|
|
|
|
/* Clear error flags */
|
|
i2c->reg->SR1 &= ~err;
|
|
|
|
if ((evt != 0) && (i2c->info->cb_event != NULL)) {
|
|
if (i2c->info->xfer.cnt < i2c->info->xfer.num) {
|
|
evt |= ARM_I2C_EVENT_TRANSFER_INCOMPLETE;
|
|
}
|
|
i2c->info->cb_event (evt);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(USE_I2C1_DMA) || defined(USE_I2C2_DMA)
|
|
/**
|
|
\fn void I2C_DMA_TxEvent (uint32_t event, I2C_RESOURCES *i2c)
|
|
\brief I2C DMA Transmit Event handler
|
|
\param[in] i2c Pointer to I2C resources
|
|
*/
|
|
static void I2C_DMA_TxEvent (uint32_t event, I2C_RESOURCES *i2c) {
|
|
i2c->reg->CR2 &= ~I2C_CR2_DMAEN;
|
|
|
|
DMA_ChannelDisable(i2c->dma_tx->reg);
|
|
|
|
i2c->info->xfer.cnt = i2c->info->xfer.num - DMA_ChannelTransferItemCount(i2c->dma_tx->reg);
|
|
i2c->info->xfer.data = NULL;
|
|
|
|
if (i2c->info->status.mode) {
|
|
/* Master transmitter: Wait for BTF in I2C EV IRQ handler */
|
|
i2c->info->xfer.ctrl |= XFER_CTRL_DMA_DONE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
\fn void I2C_DMA_RxEvent (uint32_t event, I2C_RESOURCES *i2c)
|
|
\brief I2C DMA Receive Event handler
|
|
\param[in] i2c Pointer to I2C resources
|
|
*/
|
|
static void I2C_DMA_RxEvent (uint32_t event, I2C_RESOURCES *i2c) {
|
|
i2c->reg->CR2 &= ~I2C_CR2_DMAEN;
|
|
|
|
DMA_ChannelDisable(i2c->dma_rx->reg);
|
|
|
|
i2c->info->xfer.cnt = i2c->info->xfer.num - DMA_ChannelTransferItemCount(i2c->dma_rx->reg);
|
|
i2c->info->xfer.data = NULL;
|
|
|
|
if (i2c->info->status.mode) {
|
|
/* Master mode */
|
|
if (i2c->info->xfer.ctrl & XFER_CTRL_XPENDING) {
|
|
/* Transfer pending */
|
|
i2c->reg->CR2 &= ~I2C_CR2_ITEVTEN;
|
|
}
|
|
else {
|
|
if (i2c->info->xfer.num != 1U) {
|
|
i2c->reg->CR1 |= I2C_CR1_STOP;
|
|
}
|
|
}
|
|
|
|
i2c->info->status.busy = 0U;
|
|
i2c->info->status.mode = 0U;
|
|
|
|
if (i2c->info->cb_event) {
|
|
i2c->info->cb_event (ARM_I2C_EVENT_TRANSFER_DONE);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#if defined(USE_I2C1)
|
|
/* I2C1 Driver wrapper functions */
|
|
static int32_t I2C1_Initialize (ARM_I2C_SignalEvent_t cb_event) {
|
|
return I2C_Initialize(cb_event, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_Uninitialize (void) {
|
|
return I2C_Uninitialize(&I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_PowerControl (ARM_POWER_STATE state) {
|
|
return I2C_PowerControl(state, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_MasterTransmit (uint32_t addr, const uint8_t *data, uint32_t num, bool xfer_pending) {
|
|
return I2C_MasterTransmit(addr, data, num, xfer_pending, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_MasterReceive (uint32_t addr, uint8_t *data, uint32_t num, bool xfer_pending) {
|
|
return I2C_MasterReceive(addr, data, num, xfer_pending, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_SlaveTransmit (const uint8_t *data, uint32_t num) {
|
|
return I2C_SlaveTransmit(data, num, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_SlaveReceive (uint8_t *data, uint32_t num) {
|
|
return I2C_SlaveReceive(data, num, &I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_GetDataCount (void) {
|
|
return I2C_GetDataCount(&I2C1_Resources);
|
|
}
|
|
static int32_t I2C1_Control (uint32_t control, uint32_t arg) {
|
|
return I2C_Control(control, arg, &I2C1_Resources);
|
|
}
|
|
static ARM_I2C_STATUS I2C1_GetStatus (void) {
|
|
return I2C_GetStatus(&I2C1_Resources);
|
|
}
|
|
void I2C1_EV_IRQHandler (void) {
|
|
I2C_EV_IRQHandler(&I2C1_Resources);
|
|
}
|
|
void I2C1_ER_IRQHandler (void) {
|
|
I2C_ER_IRQHandler(&I2C1_Resources);
|
|
}
|
|
|
|
#if defined(USE_I2C1_DMA)
|
|
void I2C1_RX_DMA_Handler (uint32_t event) {
|
|
I2C_DMA_RxEvent (event, &I2C1_Resources);
|
|
}
|
|
|
|
void I2C1_TX_DMA_Handler (uint32_t event) {
|
|
I2C_DMA_TxEvent (event, &I2C1_Resources);
|
|
}
|
|
#endif
|
|
|
|
/* I2C1 Driver Control Block */
|
|
ARM_DRIVER_I2C Driver_I2C1 = {
|
|
I2CX_GetVersion,
|
|
I2CX_GetCapabilities,
|
|
I2C1_Initialize,
|
|
I2C1_Uninitialize,
|
|
I2C1_PowerControl,
|
|
I2C1_MasterTransmit,
|
|
I2C1_MasterReceive,
|
|
I2C1_SlaveTransmit,
|
|
I2C1_SlaveReceive,
|
|
I2C1_GetDataCount,
|
|
I2C1_Control,
|
|
I2C1_GetStatus
|
|
};
|
|
#endif
|
|
|
|
|
|
#if defined(USE_I2C2)
|
|
/* I2C2 Driver wrapper functions */
|
|
static int32_t I2C2_Initialize (ARM_I2C_SignalEvent_t cb_event) {
|
|
return I2C_Initialize(cb_event, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_Uninitialize (void) {
|
|
return I2C_Uninitialize(&I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_PowerControl (ARM_POWER_STATE state) {
|
|
return I2C_PowerControl(state, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_MasterTransmit (uint32_t addr, const uint8_t *data, uint32_t num, bool xfer_pending) {
|
|
return I2C_MasterTransmit(addr, data, num, xfer_pending, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_MasterReceive (uint32_t addr, uint8_t *data, uint32_t num, bool xfer_pending) {
|
|
return I2C_MasterReceive(addr, data, num, xfer_pending, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_SlaveTransmit (const uint8_t *data, uint32_t num) {
|
|
return I2C_SlaveTransmit(data, num, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_SlaveReceive (uint8_t *data, uint32_t num) {
|
|
return I2C_SlaveReceive(data, num, &I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_GetDataCount (void) {
|
|
return I2C_GetDataCount(&I2C2_Resources);
|
|
}
|
|
static int32_t I2C2_Control (uint32_t control, uint32_t arg) {
|
|
return I2C_Control(control, arg, &I2C2_Resources);
|
|
}
|
|
static ARM_I2C_STATUS I2C2_GetStatus (void) {
|
|
return I2C_GetStatus(&I2C2_Resources);
|
|
}
|
|
void I2C2_EV_IRQHandler (void) {
|
|
I2C_EV_IRQHandler(&I2C2_Resources);
|
|
}
|
|
void I2C2_ER_IRQHandler (void) {
|
|
I2C_ER_IRQHandler(&I2C2_Resources);
|
|
}
|
|
|
|
#if defined(USE_I2C2_DMA)
|
|
void I2C2_RX_DMA_Handler (uint32_t event) {
|
|
I2C_DMA_RxEvent (event, &I2C2_Resources);
|
|
}
|
|
|
|
void I2C2_TX_DMA_Handler (uint32_t event) {
|
|
I2C_DMA_TxEvent (event, &I2C2_Resources);
|
|
}
|
|
#endif
|
|
|
|
|
|
/* I2C2 Driver Control Block */
|
|
ARM_DRIVER_I2C Driver_I2C2 = {
|
|
I2CX_GetVersion,
|
|
I2CX_GetCapabilities,
|
|
I2C2_Initialize,
|
|
I2C2_Uninitialize,
|
|
I2C2_PowerControl,
|
|
I2C2_MasterTransmit,
|
|
I2C2_MasterReceive,
|
|
I2C2_SlaveTransmit,
|
|
I2C2_SlaveReceive,
|
|
I2C2_GetDataCount,
|
|
I2C2_Control,
|
|
I2C2_GetStatus
|
|
};
|
|
#endif
|