2005-11-30 09:35 PM
2005-11-15 04:11 AM
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 ; } } }2005-11-17 01:35 AM
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 }2005-11-18 12:23 AM
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.
2005-11-21 12:40 AM
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; }