cancel
Showing results for 
Search instead for 
Did you mean: 

I2C Slave Problem

andre2399
Associate II
Posted on December 01, 2005 at 06:35

I2C Slave Problem

4 REPLIES 4
andre2399
Associate II
Posted on November 15, 2005 at 13:11

We are using the i2c peripheral in slave mode. After detection of the slave address (which causes the ADSL flag to be set) and the subsequent detection of BTF, one data byte is written into the DR. The master would not acknowledge the reception of that data byte, thus indicating, that no more data is requested. The corresponding parts in our sources (pls. have a glance at them) detect react to the AF as recommended in the STR710 data sheet. So the sda line is released and a stop condition is generated (although we cannot decide, wether this comes from the master or the slave...). The bus is free again.

Now the master issues our slave address again. Although we have done nothing to disable the slave's i2c peripheral and have not changed the slave address, the slave would not acknowledge the reception of the address (and in deed, it is not clocked in, no ADSL,no BTF, no other i2c interrupt).

Where are we wrong? Why does the interface seem to be switched off?

Please, pay attention to the fact, that we have mapped both i2c interrupts (iterr and rx_tx_int) to one single handler function. We've had them separate, but it wouldn't be any better.

Attached you find the parts of our code dealing with the i2c.

----------------------------------------------------------------

void i2c0_init(u32 Baudrate)

{

//configure the Interrupt to be used

GPIO_Config (GPIO1,1<

GPIO_Config (GPIO1,1<

EIC_IRQChannelPriorityConfig(I2C0_IRQChannel, 0x05);

EIC_IRQChannelConfig(I2C0_IRQChannel, ENABLE);

EIC_IRQChannelPriorityConfig(I2C0ITERR_IRQChannel, 0x05);

EIC_IRQChannelConfig(I2C0ITERR_IRQChannel, ENABLE);

//Configure the I2C0 module

I2C_Init (I2C0);

I2C_FCLKConfig (I2C0);

//Enable the I2C0

I2C_OnOffConfig (I2C0, ENABLE);

//Configure the I2C0 speed

I2C_SpeedConfig (I2C0, Baudrate);

//Configure the I2C0 address (to be used specially when this cell has to be adressed)

I2C_AddressConfig (I2C0,0x30, I2C_Mode7);

//Enable the Acknowledge

I2C_AcknowledgeConfig (I2C0, ENABLE);

// Enable the interrupt generation

I2C_ITConfig (I2C0, ENABLE);

}

----------------------------------------------------------------

void I2C0ITERR_IRQHandler(void)

{

I2C_Interrupt_Process(I2C0);

}

void I2C0_IRQHandler(void)

{

I2C_Interrupt_Process(I2C0);

}

----------------------------------------------------------------

#define I2C_ADSL 0x04

#define I2C_BTF 0x08

#define I2C_BERR 0x02

#define I2C_AF 0x10

#define I2C_STOPF 0x08

void ResetI2C(I2C_TypeDef *I2Cx)

{

u8 temp;

//Reset I2C interface

I2Cx->CR=0x00; // reset the control register

temp=I2Cx->CR; // remove pending interrupts

I2Cx->CR=0x05; // reset I2C

I2Cx->CR=0x25; // set initial value

}

void I2C_Interrupt_Process(I2C_TypeDef *I2Cx)

{

static u8 AddressByte=0;

static u8 TransmitByte=0;

u8 Sr1;

u8 Sr2;

Sr1 = I2Cx->SR1;

Sr2 = I2Cx->SR2;

//----------------------------------we have a BUS error-----------------------------------------------------------------

if (Sr2 & I2C_BERR)

{

ResetI2C(I2Cx); //Reset the I2C interface

return ;

}

//---------------------------------we have a acknowlege failure---------------------------------------------------------

if (Sr2 & I2C_AF)

{

I2Cx->DR=0xFF; // Dummy write to see STOP condition

/*Sr1 = I2Cx->SR1;

I2Cx->CR=I2Cx->CR|0x02; //generates a stop condition

I2Cx->CR=I2Cx->CR&0xFD; //generates the SDA/SCL lines

*/

return ;

}

//--------------------------------test of own address ADSL--------------------------------------------------------------

if (Sr1 & I2C_ADSL)

{

AddressByte=1;

return ;

}

//--------------------------------End of byte transfer BTF--------------------------------------------------------------

if (Sr1 & I2C_BTF)

{

if (AddressByte)

{

u8 Data=I2Cx->DR;

if (Data&0x01) TransmitByte=1;

else TransmitByte=0;

AddressByte=0;

}

else

{ // transmitter mode

if (TransmitByte)

{

u8 Data;

if (!ReadI2CSlaveTransmit(&Data))

{

//buffer is empty - we have to stop the transmission

/*I2Cx->DR=0xFF; // Dummy write to see STOP condition

*/

Sr1 = I2Cx->SR1;

I2Cx->CR=I2Cx->CR|0x02; //generates a stop condition

I2Cx->CR=I2Cx->CR&0xFD; //generates the SDA/SCL lines

}

else

{

I2Cx->DR=Data;

}

}

// receiver mode

else

{

u8 temp=I2Cx->DR;

if (!WriteI2CSlaveReceive(temp))

{

//buffer is full - we have to block the transmission

I2Cx->CR=I2Cx->CR|0x02; //generates a stop condition

I2Cx->CR=I2Cx->CR&0xFD; //generates the SDA/SCL lines

}

}

}

}

//

else

{

if (Sr2 & I2C_STOPF)

{

return ; //stop condition detected

}

else

{

ResetI2C(I2Cx); //Reset the I2C interface

return ;

}

}

}

weigelt
Associate II
Posted on November 17, 2005 at 10:35

u8 disp_send_display(char* temp)

{

u16 len;

u8 i,j;

u8 chks;

len=disp_getMessageLength(temp);

temp[len-2]=MessageNumber;

chks=disp_checksum(temp);

temp[len-1]=chks;

return i2c1_SendBuffer(0x30, (u8*) temp, len , GSTART | GSTOP);

}

void GetDisplayInfo(char * temp, u8 * ResiveBuffer,u8 ResultCode,u32 TimeOut,u32 Loop)

{

u16 iLen=0;

u32 StartTime=0;

Loop++;

do

{

memset((void*)ResiveBuffer,0,MAX_DISPLAY_RESULT_BUFFER); //!< Löschen des Empfangsbuffer

StartTime=GetSystemClock();

disp_send_display(temp);

do

{

//Schauen ob eine Antwort da ist

if (I2C_ReceiveBuffer(I2C1,0x30,ResiveBuffer, 1) && ResiveBuffer[0]==0x42)

{

if (I2C_ReceiveBuffer(I2C1,0x30,&ResiveBuffer[1],3) && ResiveBuffer[1]==ResultCode)

{

iLen=ResiveBuffer[2];

iLen=(iLen<

if (I2C_ReceiveBuffer(I2C1,0x30,&ResiveBuffer[4],iLen+2))

{

return;

}

}

}

}

while((GetSystemClock()-StartTime)*TIMER_RESOLUTION

Loop--;

}

while(Loop);

ResiveBuffer[0]=0;

}

//--------------------------------------------------------------------

int I2C_ReceiveBuffer(I2C_TypeDef *I2Cx,u8 DevAddr, u8* pBuffer, u16 BufLen)

{

u16 TimeOut=GLOBAL_TIMEOUT;

int result,error;

I2C_STARTGenerate (I2Cx, ENABLE); // Generate START-Condition

TimeOut = GLOBAL_TIMEOUT;

do

{

result = result = I2Cx->SR1;

error = I2Cx->SR2;

}

while( --TimeOut && !( result & 0x01 ) && !( error & 0x06 ) );

if(TimeOut==0) return 0;

if( BufLen < 2 ) // disable ACK on just first byte of read

I2C_AcknowledgeConfig( I2Cx, DISABLE );

else

I2C_AcknowledgeConfig( I2Cx, ENABLE );

if(!I2C_AddressSend (I2Cx,DevAddr,I2C_Mode7,I2C_RX)) // Send the slave address

{

return 0; // return 0xFF if timeout occurred

}

TimeOut=GLOBAL_TIMEOUT;

while (I2C_FlagStatus (I2Cx,DIRECT,I2C_ENDAD )==RESET) // Test the end of address transmission

{

TimeOut--;

if(TimeOut==0) return 0; // if a timeout ocurred return 0xFF

}

I2C_FlagClear (I2Cx, I2C_ENDAD); // clear flag

while( BufLen && result)

{

result = Receive_Byte(I2Cx, pBuffer++, BufLen );

BufLen--;

}

return result;

}

u8 i2c1_SendBuffer(u8 DevAddr, u8* pBuffer, u8 BufLen, u8 condition)

{

u16 TimeOut=0xFFFF;

I2C_Tx_Status SendResult;

if(condition&GSTART) // if START condition is needed

{

I2C_STARTGenerate (I2C1, ENABLE); // Generate START-Condition

while (I2C_FlagStatus (I2C1,DIRECT,I2C_SB )==RESET) // Wait til the SB flag is

{ // set to confirm the START generation

TimeOut--;

if(TimeOut==0) return 0xFF; // if a timeout ocurred return 0xFF

}

if(!I2C_AddressSend (I2C1,DevAddr,I2C_Mode7,I2C_TX)) // Send the slave address

{

return I2C_TX_TIMEOUT; // return 0xFF if timeout occurred;

}

while (I2C_FlagStatus (I2C1,DIRECT,I2C_ENDAD )==RESET) // Test the end of address transmission

{

TimeOut--;

if(TimeOut==0) return 0xFF; // if a timeout ocurred return 0xFF

}

I2C_FlagClear (I2C1, I2C_ENDAD); // clear flag

}

SendResult=I2C_BufferSend(I2C1, pBuffer, BufLen); // send buffer

if(condition&GSTOP) // if STOP condition is needed

{

I2C_STOPGenerate (I2C1, ENABLE); //Generate STOP condition

}

if(condition&I2COFF) // if disabling of I2C1 is needed

{

I2C_OnOffConfig (I2C1, DISABLE); // disable I2C1

}

return SendResult; // return result of last transmission

}

weigelt
Associate II
Posted on November 18, 2005 at 09:23

Is it possible to get some sample code for an I2C Slave transmission interrupt handler, particulary showing the howto for the last transmitted byte, which would not be ack'd by the master.

weigelt
Associate II
Posted on November 21, 2005 at 09:40

u8 I2CSlaveReceiveBuff[I2C_SLAVE_RECEIVE_BUFF_LEN];

u8 I2CSlaveTransmitBuff[I2C_SLAVE_TRANSMIT_BUFF_LEN];

u16 I2CSlaveReceiveWP=0;

u16 I2CSlaveTransmitWP=0;

u16 I2CSlaveReceiveRP=0;

u16 I2CSlaveTransmitRP=0;

void InitI2CSlaveReceiveBuffer(void)

{

I2CSlaveReceiveWP=0;

I2CSlaveReceiveRP=0;

}

void InitI2CSlaveTransmitBuffer(void)

{

I2CSlaveTransmitWP=0;

I2CSlaveTransmitRP=0;

}

bool WriteI2CSlaveReceive(u8 Data)

{

return WriteByte(Data,I2CSlaveReceiveBuff,&I2CSlaveReceiveWP,&I2CSlaveReceiveRP,I2C_SLAVE_RECEIVE_BUFF_LEN);

}

bool ReadI2CSlaveReceive(u8* pData)

{

return ReadByte(pData,I2CSlaveReceiveBuff,&I2CSlaveReceiveWP,&I2CSlaveReceiveRP,I2C_SLAVE_RECEIVE_BUFF_LEN);

}

bool ReadByte(u8* Data,u8* Buff,u16* wp,u16* rp,u16 BufferLen)

{

u16 temp=*rp;

if (CurrentDataSize(*wp,temp,BufferLen)>=1)

{

*Data=Buff[temp];

//Der Read Pointer wird um eins erhöht

if (temp>=BufferLen-1) temp=0;

else temp++;

*rp=temp;

return TRUE;

}

//Buffer leer

return FALSE;

}

bool WriteByte(u8 Data,u8* Buff,u16* wp,u16* rp,u16 BufferLen)

{

u16 temp=*wp;

if (CurrentDataFree(temp,*rp,BufferLen)>=1)

{

Buff[temp]=Data;

//Der Write Pointer wird um eins weiter gerückt

if (temp>=BufferLen-1) temp=0;

else temp++;

*wp=temp;

return TRUE;

}

//Buffer voll

return FALSE;

}

u16 CurrentDataFree(u16 wp,u16 rp,u16 BufferLen)

{

return BufferLen-CurrentDataSize(wp,rp,BufferLen)-1;

}

u16 CurrentDataSize(u16 wp,u16 rp,u16 BufferLen)

{

u16 ret; // Returnvalue

if(wp>rp) // vor einem Pufferumbruch

{

ret=(wp-rp); // Anzahl Zeichen im Puffer zurückgeben

}

else if(wp

{

ret=(BufferLen-rp+wp); // Anzahl Zeichen im Puffer zurückgeben

}

else if(wp==rp) // Wenn der Puffer leer ist ...

{

ret=0; // ... melden wir das auch

}

return ret;

}