/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
static volatile uint32_t ticks = 0;
static volatile int32_t Ret = I2C_OK;
/*****************************************************************************
* Define EEPROM
****************************************************************************/
#define DEFAULT_I2C I2C0
#define I2C_DEFAULT_SPEED 400000
#define DATA_SIZE 6
#define I2C_SLAVE_EEPROM_ADDR 0x50
#define BYTE_ADDR 0x00
/* Data area for slave operations */
static uint8_t sendData[DATA_SIZE] = {BYTE_ADDR,0x48,0x45,0x4c,0x4c,0x4f}; //Byte d'addresse + "HELLO"
static uint8_t receiveData[DATA_SIZE];
/* Xfer structure for slave operations */
static I2C_M_SETUP_Type TransferCfg;
/*****************************************************************************
* Private functions
****************************************************************************/
/********************************************************************//**
* @brief Send a byte
* @param[in] databyte: number of byte
* @return None
*********************************************************************/
static void I2C_SendByte ( uint8_t databyte, Bool ack)
{
/* Write data to DAT */
LPC_I2C->DAT = databyte & I2C_I2DAT_BITMASK;
if (ack)
{
/* Set AA bit */
LPC_I2C->CONSET = I2C_I2CONSET_AA;
/* Clear the SI flag */
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
}
else
{
/* Set STO and AA bits */
LPC_I2C->CONSET = I2C_I2CONSET_AA|I2C_I2CONSET_STO;
/* Clear the SI flag */
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
}
}
/********************************************************************//**
* @brief Get a byte
* @param[out] retdat pointer to return data
* @param[in] ack assert acknowledge or not, should be: TRUE/FALSE
* @return None
*********************************************************************/
static void I2C_GetByte (uint8_t *retdat, Bool ack)
{
*retdat = (uint8_t) (LPC_I2C->DAT & I2C_I2DAT_BITMASK);
if (ack)
{
LPC_I2C->CONSET = I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
}
else
{
LPC_I2C->CONCLR = I2C_I2CONCLR_AAC|I2C_I2CONCLR_SIC;
}
}
/********************************************************************//**
* @brief Wait for interupt
* @param[in] timeout timeout value
* @return None
*********************************************************************/
/*********************************************************************//**
* @brief Reset I2C Block
* @param[in] None
* @return None
**********************************************************************/
__INLINE void I2C_Reset(void)
{
/* Reset STA, STO, SI */
LPC_I2C->CONCLR = I2C_CON_SI | I2C_CON_STO | I2C_CON_STA;
/* Enable Slave I2C operation */
LPC_I2C->CONSET = I2C_I2CONSET_I2EN;
}
static __INLINE void I2C_WaitInt(uint32_t timeout)
{
uint32_t tm = timeout;
// Wait for sending ends
while ((!(LPC_I2C->CONSET & I2C_I2CONSET_SI)) && tm )
{
tm--;
}
}
static void Init_I2C_PinMux(void)
{
Chip_IOCON_PinMuxSet(LPC_IOCON, IOCON_PIO0_4, IOCON_FUNC1 | IOCON_SFI2C_EN);
Chip_IOCON_PinMuxSet(LPC_IOCON, IOCON_PIO0_5, IOCON_FUNC1 | IOCON_SFI2C_EN);
}
/* Initialize the I2C bus */
static void I2C_Init(I2C_ID_T id, int speed)
{
/* Select port function */
Init_I2C_PinMux();
uint32_t temp;
#if 1
LPC_SYSCTL->PRESETCTRL |= (0x1<<1);
#else
LPC_SYSCTL->PRESETCTRL |= (0x1<<0);
#endif
//Enable clock
LPC_SYSCTL->SYSAHBCLKCTRL |= (1 << SYSCTL_CLOCK_I2C);
/* Set clock rate */
temp = SystemCoreClock / speed;
I2C_DEV->SCLH = (uint32_t)(temp/2);
I2C_DEV->SCLL = (uint32_t)(temp - I2C_DEV->SCLH);
/* Initialize I2C Interrupt */
NVIC_EnableIRQ(I2C0_IRQn);
NVIC_SetPriority(I2C0_IRQn, 0);
/* Set I2C operation to default */
I2C_DEV->CONCLR = (I2C_CON_AA | I2C_CON_SI | I2C_CON_STA | I2C_CON_I2EN);
I2C_Reset();
}
/*****************************************************************************
* Public functions
****************************************************************************/
/********************************************************
* Generate a start condition on I2C bus
********************************************************/
void I2C_Start (void)
{
volatile uint32_t timeout = 0;
restart:
timeout = 0;
// Enter to Master Mode
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
LPC_I2C->CONSET = I2C_I2CONSET_STA;
// Wait for complete
/* while(1)
{
if((LPC_I2C->STAT == I2C_I2STAT_M_TX_START) ||(LPC_I2C->STAT == I2C_I2STAT_M_TX_RESTART))
break;
timeout++;
if(timeout > 0x1000)
{
I2C_Reset();
goto restart;
}
}*/
}
/********************************************************
* Generate a stop condition on I2C bus
********************************************************/
void I2C_Stop (void)
{
/* Set STO and AA bits */
LPC_I2C->CONSET = I2C_I2CONSET_AA|I2C_I2CONSET_STO;
/* Clear the SI flag */
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
while(LPC_I2C->CONSET & I2C_I2CONSET_STO)
{
if(LPC_I2C->CONSET & I2C_I2CONSET_SI)
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
}
}
/*********************************************************************//**
* @brief Handle I2C Master states.
* @param[in] CodeStatus I2C state
* @param[in] TransferCfg Pointer to a I2C_S_SETUP_Type structure that
* contains specified information about the
* configuration for master transfer.
* @return It can be
* - I2C_OK
* - I2C_BYTE_RECV
* - I2C_BYTE_SENT
* - I2C_SEND_END
* - I2C_RECV_END
* - I2C_ERR
* - I2C_NAK_RECV
**********************************************************************/
int32_t I2C_MasterHanleStates(uint32_t PreStatus,uint32_t CodeStatus, I2C_M_SETUP_Type *TransferCfg)
{
uint8_t tmp;
switch(CodeStatus)
{
case 0x08: /*!< A start condition has been transmitted */
case 0X10: /*!< A repeat start condition has been transmitted */
// Send data first
if(TransferCfg->tx_count < TransferCfg->tx_length)
{
/* Send slave address + WR direction bit = 0 */
I2C_SendByte((TransferCfg->sl_addr7bit << 1), TRUE);
}
else
{
/* Send slave address + RD direction bit = 1 */
I2C_SendByte(((TransferCfg->sl_addr7bit << 1) | 0x01), TRUE);
}
// Initialize Master data counter
TransferCfg->tx_count == 0;
// Clear STA bit
LPC_I2C->CONCLR = I2C_I2CONCLR_STAC;
return I2C_BYTE_SENT;
case 0x18: /*!< SLA+W has been transmitted, ACK has been received */
case 0x28: /*!< Data has been transmitted, ACK has been received */
/* Load DAT with next data byte from Master Transmit buffer*/
/* Increment the Master data counter*/
/* Increment Master Transmit buffer pointer*/
if(TransferCfg->tx_count > (TransferCfg->tx_length - 2))
{
I2C_SendByte(TransferCfg->tx_data[TransferCfg->tx_count++], FALSE); // the next byte is the last byte, send STOP
return I2C_SEND_END;
}
else
{
I2C_SendByte(TransferCfg->tx_data[TransferCfg->tx_count++], TRUE);
return I2C_BYTE_SENT;
}
case 0x30: /*!< Data has been transmitted, NACK has been received */
I2C_Stop();
if(TransferCfg->tx_count < TransferCfg->tx_length)
{
I2C_Start();
return I2C_OK;
}
else
return I2C_SEND_END;
case 0x40: /*!< SLA+R has been transmitted, ACK has been received */
LPC_I2C->CONSET = I2C_I2CONSET_AA;
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
return I2C_BYTE_RECV;
case 0x50: /*!< Data has been received, ACK has been returned */
case 0x58: /*!< Data has been received, NACK has been returned */
if (TransferCfg->rx_length)
{
if(TransferCfg->rx_count >= TransferCfg->rx_length)
return I2C_RECV_END;
if((TransferCfg->rx_length == 1)||(TransferCfg->rx_count > (TransferCfg->rx_length - 2)) )
{
I2C_GetByte( &tmp, FALSE); // the next byte is the last byte, send NACK
}
else
{
I2C_GetByte( &tmp, TRUE);
}
TransferCfg->rx_data[TransferCfg->rx_count++] = tmp;
if(TransferCfg->rx_count >= TransferCfg->rx_length)
return I2C_RECV_END;
}
else
{
if(TransferCfg->tx_count < TransferCfg->tx_length)
I2C_Start();
else
return I2C_SEND_END;
}
return I2C_BYTE_RECV;
case 0x48: /*!< SLA+R has been transmitted, NACK has been received */
case 0x20: /*!< SLA+W has been transmitted, NACK has been received */
I2C_Stop();
return I2C_ERR;
case 0x38: /*!< Arbitration lost in SLA+R/W or Data bytes */
if(TransferCfg->tx_count < TransferCfg->tx_length)
I2C_Start();
else
return I2C_SEND_END;
return I2C_OK;
/*case I2C_I2STAT_S_RX_ARB_LOST_M_SLA: //!< Arbitration lost in SLA+R/W as master
case I2C_I2STAT_S_RX_ARB_LOST_M_GENCALL: //!< Arbitration lost in SLA+R/W (GENERAL CALL) as master
I2C_Stop();
I2C_Start();
return I2C_BYTE_RECV;*/
case I2C_I2STAT_BUS_ERROR: /*!< Bus Error */
/* Set STO and AA bits */
LPC_I2C->CONSET = I2C_I2CONSET_AA|I2C_I2CONSET_STO;
/* Clear the SI flag */
LPC_I2C->CONCLR = I2C_I2CONCLR_SIC;
if((TransferCfg->tx_count <= TransferCfg->tx_length)||(TransferCfg->rx_count < TransferCfg->rx_length))
{
I2C_Start();
if((PreStatus == I2C_BYTE_SENT)&& TransferCfg->tx_count) // sending failed
{
TransferCfg->tx_count--;
}
}
return I2C_OK;
case I2C_I2STAT_NO_INF: /*!< No relevant information */
default:
return I2C_OK;
}
}
/*********************************************************************//**
* @brief Transmit and Receive data in master mode
* @param[in] TransferCfg Pointer to a I2C_M_SETUP_Type structure that
* contains specified information about the
* configuration for master transfer.
* @return SUCCESS or ERROR
*
* Note:
* - In case of using I2C to transmit data only, either transmit length set to 0
* or transmit data pointer set to NULL.
* - In case of using I2C to receive data only, either receive length set to 0
* or receive data pointer set to NULL.
* - In case of using I2C to transmit followed by receive data, transmit length,
* transmit data pointer, receive length and receive data pointer should be set
* corresponding.
**********************************************************************/
void I2C_MasterTransmitData(I2C_ID_T id, I2C_M_SETUP_Type *TransferCfg)
{
const uint32_t timeout_max = 0x1000;
uint32_t timeout = 0x100000;
uint32_t flag= 0;
// Reset I2C setup value to default state
TransferCfg->sl_addr7bit = I2C_SLAVE_EEPROM_ADDR;
TransferCfg->rx_data = NULL;
TransferCfg->rx_length = 0;
TransferCfg->tx_data = sendData;
TransferCfg->tx_length = DATA_SIZE;
TransferCfg->retransmissions_count = 0;
TransferCfg->tx_count = 0;
TransferCfg->rx_count = 0;
/* First Start condition*/
I2C_Start();
while(flag != 1)
{
if( Ret & (I2C_BYTE_SENT|I2C_BYTE_RECV))
{
I2C_WaitInt(timeout_max);
timeout = timeout_max;
if(!(LPC_I2C->CONSET & I2C_I2CONSET_SI))
{
flag = 0;
}
}
else if ((Ret & I2C_SEND_END) || (Ret & I2C_RECV_END))// If no need to wait for data from Slave// If no need to wait for data from Slave
{
if((TransferCfg->tx_count >= TransferCfg->tx_length) && (TransferCfg->rx_count >= TransferCfg->rx_length))
{
flag = 1;
}
}
else if (I2C_CheckError(Ret))
{
if(I2C_CheckError(Ret) || (timeout == 0))
{
if (++TransferCfg->retransmissions_count > TransferCfg->retransmissions_max)
{
flag = 0;
}
I2C_Start();
timeout = timeout_max;
}
}
}
}
void SysTick_Handler(void)
{
ticks++;
}
void I2C_IRQHandler(void)
{
Ret = I2C_MasterHanleStates(Ret, LPC_I2C->STAT & I2C_STAT_CODE_BITMASK, &TransferCfg);
}
/**
* @briefMain program body
* @returnint
*/
int main(void)
{
SystemCoreClockUpdate();
Board_Init();
I2C_Init(I2C0, I2C_DEFAULT_SPEED);
I2C_MasterTransmitData(I2C0, &TransferCfg);
return 0;
} |