I2C configuration code

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello,
I am trying to connect a Adafruit BMP280 temperature sensor as slave to the Infineon XMC4800 as master.
I configured the register and write a function to read the register D0 and D1 of the I2C Slave.
However, I got 0xFFFF on the received buffer RBUF so something is wrong.
I think the symbol delay should be 5 us for the standard speed of 100k baud. Did I set the BRG register well ?




#include

#define IIC_CH USIC1_CH1

void IIC_CH_MasterInit(void)
{

// ------------------------------------------------------------
// 1.Enable USICx channel n
// Mode Control RM 18.2.2.2, Kernel State Configuration Register RM 18.11.3.3 :
// BPMODEN MODEN
IIC_CH->KSCFG |= (1 << 1)| (1 << 0);

// ------------------------------------------------------------
// 2.Configure Baud Rate Generator Register (BRG) RM 18.11.6.2
// - PCTQ = 2
// - Speed = 100khz
// - DCTQ : 10 time quanta per symbol : DCTQ + 1
// - PPPEN = 0b : This bit defines the input frequency fPPP. PPPEN = 0b : The 2:1 divider for fPPP is disabled, fPPP = fPIN = 144 mhz .
// ------------------------------------------------------------
// DM = 0b01 STEP = 1023 = 0x3FF = 0b001111111111
IIC_CH->FDR = (1 << 14) | ( 1023 << 0);
// PDIV DCTQ PCTQ
IIC_CH->BRG = (35 << 16) | (9 << 10) | (1<<8) ; //
// ------------------------------------------------------------
// 3.Configure input stages : Input Control Registers RM 18.11.5.1
// - DPOL = 0 : signal not inverted
// - DSEN = 1 : The synchronized signal can be taken as input for the data shift unit.
// - DSEL = 000b : Select input DX0A (because pin P3.15 as input)
// - INSW = 0 : The input of the data shift unit is controlled by the protocol pre-processor.
// ------------------------------------------------------------
// DSEN
IIC_CH->DX0CR = (1 << 6);

// ------------------------------------------------------------
// 4.Configure data format : SCTR Shift Control Register RM 18.11.7.1
// - Data word = 8 bits
// - FLE = 63 : the lengh of the frame is not set, and external fctors can end the transmision, not based on frame length
// - PDL = 0 : This bit defines the output level at the shift data output signal when no data is available for transmission. passive level is 0
// - SDIR = 1 : MSB first
// - TRM = 01b :The shift control signal is considered active if it is at 1-level. This is the setting to be
// programmed to allow data transfers.
// - DSM = 00b : Data Shift Mode : Receive and transmit data is shifted in and out one bit at a time through DX0 and DOUT0
// - DOCFG = 00b : This bit defines the relation between the internal shift data value and the data output signal DOUTx.
// DOUTx = shift data value
// - TRM : Transmission mode : This bit field describes how the shift control signal is interpreted by the DSU. Data transfers are only
// possible while the shift control signal is active.
// 11b=3 : The shift control signal is considered active without referring to the actual signal level. Data
// frame transfer is possible after each edge of the signal.
// WLE = 0x7 FLE (63 = infinite) TRM SDIR
IIC_CH->SCTR = ( 7<<24 ) | ( 63<<16 ) | ( 3<<8 ) | ( 1<<0 );

// ------------------------------------------------------------
// 5.Configure data transfer parameters : TCSR Transmission Control and Status Register RM 18.11.7.2
// - TDSSM = 1b : TBUF Data Single Shot Mode: data in TBUf is considered inactive after being moved into the shift register, send data only once.
// - TDEN = 01b: TBUF Data Enable : A transmission of the data word in TBUF can be started if bit TDV = 1.
// TDEN TDSSM
IIC_CH->TCSR = (1 << 10) |(1 << 8);

// ------------------------------------------------------------
// 5. PCR
// - HDEL : compensate internal delay. Delay requird for hold time
// - ARLIEN : This bit enables the generation of a protocol interrupt if an arbitration lost event is detected.
// HDEL ARLIEN
IIC_CH->PCR = (42 << 26) | (1 <<22 );

// ------------------------------------------------------------
// 7.Enable SSC protocol
// MODE
IIC_CH->CCR = (4 << 0);
}


void I2C_PinsInit(void)
{
/*
* The pins used for SDA and SCL have to be set to open-drain mode to support the
wired-AND structure of the IIC bus lines.
*/

// Data Input (DX0) : USIC1_CH1.DX0A : Pin 3.15 : Shift data input for IIC SDA
// Data Output : USIC1_CH1.DOUT0 : Pin P3.15 : Shift data output for IIC SDA

// OUTPUT P3.15 -> IOCR12, PC15 (bits [31:27])
// Alternate function 2 in Open drain (cf RM p 2814 26.10.1 Port I/O Function Table ) -> 0b11010 = 0x1A
PORT3->IOCR12 |= (0x1A << 27);


// USIC1_CH1.SCLKOUT : Pin P0.13 : Shift clock output for IIC SCL
// OUTPUT P0.13 -> IOCR12, PC13 (bits [15:11])
// Alternate function 2 in Open drain (cf RM p 2814 26.10.1 Port I/O Function Table ) -> 11010b = 0x1A
PORT0->IOCR12 |= (0x1A << 11);


}


void I2C_SDA_Input(void)
{
PORT3->IOCR12 = 0;
}

void I2C_SDA_Output(void)
{
PORT3->IOCR12 |= (0x1A << 27);
}


uint32_t I2C_ReadMode(uint8_t SlaveAddress, uint8_t RegisterAddress)
{
uint32_t slaveResponse;
uint8_t Rbuf_buffer;
uint16_t sendData;
// bus idle : SDA high and CLK high
// TBUF[10:8] : TDF code and TBUF[7:0] : slave address (7 bits) and read/write control (last bit) or data

// ======================= Read Mode =======================

// Clear PSR register
IIC_CH->TCSR = 0xFF;

//1. Send Start condition and slave address
// TDF code : 0b100 = 4
// TBUF[7:0] : slave address (7 bits) and Write Mode (last bit = 0)
I2C_SDA_Output(); // put SDA pin P3.15 in output mode

sendData = SlaveAddress;
// Add write mode
sendData = (sendData << 1);
// Add TDF code
sendData |= (4 << 8);


IIC_CH->TBUF[0] = sendData;
while( !((IIC_CH->TCSR & 0x80)>>7) ); // wait until TCSR.TDV = 1

// Wait until the last bit in TBUF is shifted :
while ( !( (IIC_CH->PSR & 0x1000) >> 12) ); //PSR.TSIF (bit 12)
I2C_SDA_Input(); // put SDA pin P3.15 in input mode to receive ACK
// While ACKS is not received yet, wait
while ( !( (IIC_CH->PSR & 0x200) >> 9) ); //PSR.ACK (bit 9)
// Clear flags TSIF ACKS
IIC_CH->PSCR = (1<<12) | (1<<9);

I2C_SDA_Output();

//2. Master sends Register address, receives and checks the acknowledge bit sent by the slave
// TDF code : 000
IIC_CH->TBUF[0] = RegisterAddress;
while( !((IIC_CH->TCSR & 0x80)>>7) ); // wait until TCSR.TDV = 1

// Wait until the last bit in TBUF is shifted :
while ( !( (IIC_CH->PSR & 0x1000) >> 12) ); //PSR.TSIF (bit 12)
I2C_SDA_Input();
// While ACKS is not received yet, wait
while ( !( (IIC_CH->PSR & 0x200) >> 9) ); //PSR.ACK (bit 9)
// Clear flags TSIF ACKS
IIC_CH->PSCR = (1<<12) | (1<<9);
I2C_SDA_Output();

//3. Master sends repeated start condition
// TDF code : 0b101 = 5
// TBUF[7:0] : slave address (7 bits) and Read Mode (last bit = 1)
sendData = SlaveAddress;
// Add read mode by shifting and replacing the last bit by 1 :
sendData = (sendData << 1);
sendData |= (1 << 0); //Read Mode
sendData |= (5 << 8); // TDF code
IIC_CH->TBUF[0] = sendData;
while( !((IIC_CH->TCSR & 0x80)>>7) ); // wait until TCSR.TDV = 1

// Wait until the last bit in TBUF is shifted :
while ( !( (IIC_CH->PSR & 0x1000) >> 12) ); //PSR.TSIF (bit 12)
I2C_SDA_Input();
// While ACK is not received yet, wait
while ( !( (IIC_CH->PSR & 0x200) >> 9) ); //PSR.ACK (bit 9)
// Clear flags TSIF ACKS
IIC_CH->PSCR = (1<<12) | (1<<9);

//4.1 Master receives data byte and send acknowledge. The content of TBUF[7:0] is ignored.
// TDF code : 0b010 = 2
IIC_CH->TBUF[0] |= (2 << 8);
while( !((IIC_CH->TCSR & 0x80)>>7) ); // wait until TCSR.TDV = 1

// AIF and RIF indicates whether a received event has occurred
while( !( ((IIC_CH->PSR & 0x8000)>>15) | ((IIC_CH->PSR & 0x4000)>>14) ) ); // !(PSR.AIF+PSR.RIF)
// clear flags AIF RIF
IIC_CH->PSCR = (1<<15) | (1<<14);
slaveResponse = IIC_CH->RBUF; // read the received buffer
slaveResponse = (slaveResponse & 0xFF);//additional information is monitored at the bit positions RBUF[12:8] : delete them

//5. The slave continues to send data from the other register until not acknowledge from the master and stop condition : repeat step 4.1
// Receive data byte and send not-acknowledge to stop the communication :
// TDF code : 0b011 = 3
IIC_CH->TBUF[0] |= (3 << 8);

// AIF and RIF indicates whether a received event has occurred
while( !( ((IIC_CH->PSR & 0x8000)>>15) | ((IIC_CH->PSR & 0x4000)>>14) ) ); // !(PSR.AIF+PSR.RIF)
// Clear flags AIF RIF
IIC_CH->PSCR = (1<<15) | (1<<14);
Rbuf_buffer = IIC_CH->RBUF; // read the received buffer
Rbuf_buffer = (Rbuf_buffer & 0xFF);//additional information is monitored at the bit positions RBUF[12:8] : delete them

// Concatenate the 2 slave response
slaveResponse |= (Rbuf_buffer << 8);

//5.1 Send stop condition
// TDF code : 0b110 = 6
I2C_SDA_Output();
IIC_CH->TBUF[0] |= (6 << 8);


return slaveResponse;
}

int main(void)
{
DAVE_STATUS_t status;
uint32_t result = 5;
status = DAVE_Init(); /* Initialization of DAVE APPs */

if(status == DAVE_STATUS_FAILURE)
{
XMC_DEBUG("DAVE APPs initialization failed\n");

while(1U)
{

}
}


I2C_PinsInit();
IIC_CH_MasterInit();

while(1U)
{
//BMP280 address, register
result = I2C_ReadMode(0x77, 0xD0 );

}
}



Thank you for having a look in this code,
Nicolas
0 Likes
4 Replies
Not applicable
Hello,
I tried with the I2C master Apps, to read one register ( 8 bits9, with this code :


int main(void)
{
DAVE_STATUS_t status;

uint8_t rx_data;
// Slave address 0x77
uint8_t registerD0 = 0xD0;




status = DAVE_Init(); /* Initialization of DAVE APPs */

while(1U)
{
I2C_MASTER_Transmit(&I2C_MASTER_0,true,0x77,&registerD0,1,false);
while(I2C_MASTER_IsTxBusy(&I2C_MASTER_0));


I2C_MASTER_Receive(&I2C_MASTER_0,true,0x77,&rx_data,1,true,true);
while(I2C_MASTER_IsRxBusy(&I2C_MASTER_0));

}
}



The protocol to read a register is described on this picture :
2261.attach

Do you se any mistakes on the code ?
Because I got nothing.


Thank you,
Nicolas
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hi Nicolas,

I´ve took a quick look to the BMP280 specification and it seems to me that you´re providing wrong slave address in your code. In the Chapter 5.2.2 I2C read of the mentioned document, it´s stated:
"To be able to read registers, first the register address must be sent in write mode (slave address 111011X0). Then either a stop or a repeated start condition must be generated. After this the slave is addressed in read mode (RW = ‘1’) at address 111011X1, after which the slave sends out data from auto-incremented register addresses until a NOACKM and stop condition occurs.
These "X" mentioned above are determined by the state of SDO pin (it´s explained in the specification).

Can you please modify your code and provide me with the feedback?

Best regards,
Deni
0 Likes
Not applicable
Hello,

What I understand from the Infineon Library for I2C_MASTER_Transmit and I2C_MASTER_Received is I should provide the address of the slave and the function will add the last bit for write or read.
I am using the adafruit BMP280 and the SDO pin is connected to Vddio (so X is a 1), and the slave address is 0x77.
SO in write mode it is 0xEE and in read mode 0xEF.

I checked it with an Arduino, the sensor is working well.

I tried another program using the library functions, because according to this post ( https://www.infineonforums.com/threads/4326-DAVE-I2C-Driver-DMA-Support-missing-Direct-mode-busy-loo...) , there is a bug in I2C_MASTER_Transmit().

The following code is working, I obtain 0x58 in RBUF.






#include //Declarations from DAVE Code Generation (includes SFR declaration)

/**

* @brief main() - Application entry point
*
* Details of function

* This routine is the application entry point. It is invoked by the device startup code. It is responsible for
* invoking the APP initialization dispatcher routine - DAVE_Init() and hosting the place-holder for user application
* code.
*/


uint8_t data_received = 0;
int main(void)
{
DAVE_STATUS_t status;

status = DAVE_Init(); /* Initialization of DAVE APPs */

if(status == DAVE_STATUS_FAILURE)
{
/* Placeholder for error handler code. The while loop below can be replaced with an user error handler. */
XMC_DEBUG("DAVE APPs initialization failed\n");

while(1U)
{

}
}

//-------------------------------------------------------
// reinitialize PSR register
USIC1_CH1->PSR = 0;

/* Placeholder for user application code. The while loop below can be replaced with user application code. */
while(1U)
{
uint8_t SLAVE_ADDRESS = 0xEE;
// 0x77 : BMP address
// 0xEE : Write BMP address
// 0xEF : Read BMP address
I2C_MASTER_SendStart(&I2C_MASTER_0, SLAVE_ADDRESS, XMC_I2C_CH_CMD_WRITE);
while(I2C_MASTER_GetFlagStatus(&I2C_MASTER_0, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
// wait for ACKS
}
I2C_MASTER_ClearFlag(&I2C_MASTER_0,XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

// write to address 0xD0
I2C_MASTER_TransmitByte(&I2C_MASTER_0, 0xD0);
while(I2C_MASTER_GetFlagStatus(&I2C_MASTER_0, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
// wait for ACKS
}
I2C_MASTER_ClearFlag(&I2C_MASTER_0,XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

// read
SLAVE_ADDRESS = 0xEF;
I2C_MASTER_SendRepeatedStart(&I2C_MASTER_0, SLAVE_ADDRESS, XMC_I2C_CH_CMD_READ);
while(I2C_MASTER_GetFlagStatus(&I2C_MASTER_0, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
// wait for ACKS
}
I2C_MASTER_ClearFlag(&I2C_MASTER_0,XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

data_received = I2C_MASTER_GetReceivedByte(&I2C_MASTER_0);
// send NOACKM and then Stop condition
XMC_I2C_CH_MasterReceiveNack(&I2C_MASTER_0);
I2C_MASTER_SendStop(&I2C_MASTER_0);


}
}

0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hi Nicolas,

you got it right, but as you mentioned, our function sets the first bit if the read mode is used, so you don´t need to distinguish two slave addresses. You just need to define that slave address is 0xEE (note that LSB is 0), and in case of read mode these lines of the code will set the proper slave address.

if (command == XMC_I2C_CH_CMD_READ)
{
tmp |= 0x1U;
}
0 Likes