Skip to main content
Visitor II
December 1, 2005
Question

I2C Slave Problem

  • December 1, 2005
  • 4 replies
  • 1483 views
Posted on December 01, 2005 at 06:35

I2C Slave Problem

    This topic has been closed for replies.

    4 replies

    andre2399Author
    Visitor II
    November 15, 2005
    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 ;

    }

    }

    }

    Visitor II
    November 17, 2005
    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

    }

    Visitor II
    November 18, 2005
    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.

    Visitor II
    November 21, 2005
    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;

    }