Test routine: count = 0x89654321; // unsigned long
Init_i2c(); if(EE_WriteBuffer(0, &count, 4, I2C_ADR_EEPROM0)) DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 1); if(EE_ReadBuffer(0, &okunan, 4, I2C_ADR_EEPROM0)) DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 2); if(count == okunan) DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 3);
void i2c_start(void){ IIC1S_SRW = 0; // R/W bit = 0; IIC1C_IICEN = 0; IIC1C = 0b10011000; IIC1C_MST = 1; // generate START condition}
void Init_i2c(void){ // Bus = 18.432MHz; // mul=4, ICR=0x0D => SCL Div=48, i2c_ Bus Freq = 96Khz, SDA Hold Time = 600ns IIC1F = 0b10001101; IIC1S_SRW = 0; // R/W bit = 0; // Enable i2c module // not generate ACK by master after transfer; // TX mode // Slave mode actually; IIC1C = 0b10011000; }void i2c_start(void){ IIC1C_MST = 1; // generate START condition}void i2c_stop(void){ IIC1C_MST = 0; // generate STOP condition; }void i2c_restart(void){ IIC1C_RSTA = 1; // generate RESTART condition}void i2c_sendbyte(unsigned char data){ IIC1C_TX = 1; // transmit IIC1D = data; while(!IIC1S_IICIF); // wait until Transfer to complete; IIC1S_IICIF = 1;}char i2c_getack(void){ return(!IIC1S_RXAK); // ACK gelmiş ise 1 döner, gelmemişse 0}unsigned char i2c_getbyte(char send_ack){ unsigned char data; IIC1C_TX = 0; // set up to receive; IIC1C_TXAK = send_ack—0:1; data = IIC1D; // dummy read; while(!IIC1S_IICIF); // wait until Transfer to complete; IIC1S_IICIF = 1; data = IIC1D; // read right data; return(data);}/////////////////////////////////////////////////////////////////////////////////// EEPROM RUTINLERI Atmel AT24C512BN-SH-B veya ST M24512-RM/////////////////////////////////////////////////////////////////////////////////unsigned char EE_WaitForACK(unsigned char external_adr){ unsigned char counter = 100; unsigned char ack; unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 ControlByte |= ((external_adr << 1) & 0b00001110); do { i2c_start(); i2c_sendbyte(ControlByte); ack = i2c_getack(); // i2cgetack, ack alınmış ise 1 döner! i2c_stop(); --counter; // her deneme 175uS sürüyor, 29 deneme > 5ms yapar. } while(!ack && (counter != 0)); return(ack);}unsigned char EE_ReadBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF); ControlByte |= ((external_adr << 1) & 0b00001110); i2c_start(); // Control Byte = 1 0 1 0 A2 A1 A0 R/W i2c_sendbyte(ControlByte); if(!i2c_getack()) { i2c_stop(); return(0); } // Address High Byte i2c_sendbyte(AddrHigh); if(!i2c_getack()) { i2c_stop(); return(0); } // Address Low Byte i2c_sendbyte(AddrLow); if(!i2c_getack()) { i2c_stop(); return(0); } // Read i2c_restart(); // Control Byte to read ControlByte |= 0b00000001; // Okuma modu i2c_sendbyte(ControlByte); if(!i2c_getack()) { i2c_stop(); return(0); } do { *Data++ = i2c_getbyte(size != 1); } while(--size); i2c_stop(); return(1);}char EE_WriteBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ unsigned int _PAGE = 0xFFFF; // önceki page do { unsigned int CURRENT_PAGE = Adr & 0b1111111110000000; // page size 128 byte if(CURRENT_PAGE != _PAGE) { // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF); ControlByte |= ((external_adr << 1) & 0b00001110); if(_PAGE != 0xFFFF) { i2c_stop(); if(!EE_WaitForACK(external_adr)) return(0); } i2c_start(); // Control Byte = 1 0 1 0 A2 A1 A0 R/W. i2c_sendbyte(ControlByte); if(!i2c_getack()) { i2c_stop(); return(0); } // Address High Byte i2c_sendbyte(AddrHigh); if(!i2c_getack()) { i2c_stop(); return(0); } // Address Low Byte i2c_sendbyte(AddrLow); if(!i2c_getack()) { i2c_stop(); return(0); } _PAGE = CURRENT_PAGE; } //if(CURRENT_PAGE != _PAGE) i2c_sendbyte(*Data++); if(!i2c_getack()) { i2c_stop(); return(0); } Adr++; } while(--size); i2c_stop(); return(EE_WaitForACK(external_adr));}
Hi All,
I'm using MC9S08QE128, I'm actually using poll and isr iic. I got them to work but after I read from the eeprom, the SDA line won't pull up. Do you guys have any idea? I've included my code just in case. The reading part is in the ISR routine.
The only way to pull it up again is to probe the SCL with the multimeter and then probe the SDA. This seems to bring it up again.
Thank you,
FWFan.
3 years later...
I´m trying to make it work, I read all the messages.
My app: AW60, 24C256 eeprom, IIC polling, 4K7 pull ups, no drive strenght on ports.
So:
First is stopped at:
BRSET IIC1S_IICIF,IIC1S,* ; Branch if flag is set (CF = 1)
Now it stops at:
THIS IS THE COMPLETE ASM CODE:
It stops at WAIT:RXAK whit or whitout the "mad" JUSTRETURN.
Attached code.
Any help??
Thanks,
Gustavo.
Test routine: count = 0x89654321; if(EE_WriteBuffer(0, &count, 4, I2C_ADR_EEPROM0)) ...........1 DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 1); if(EE_ReadBuffer(0, &okunan, 4, I2C_ADR_EEPROM0)) ...........2 DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 2); if(count == okunan) DispMsg(MSG_FILL, 0); else DispMsg(MSG_ERROR_CODE, 3);
void Wait_sh(unsigned char time){ unsigned int i, temp_t = time; for (i=0;i<temp_t;i++) { asm nop; }}void Init_I2C(void){ // Bus = 18.432MHz; // mul=4, ICR=0x0D => SCL Div=48, i2c_ Bus Freq = 96Khz, SDA Hold Time = 600ns IIC1C = 0;/* PTCD_PTCD0 = 0; PTCD_PTCD0 = 0; PTCDD_PTCDD0 = 0; PTCDD_PTCDD0 = 0; PTADS = 0; PTASE = 0;*/ Wait_sh(80); IIC1A = 0; IIC1F = 0b10001101; IIC1C = 0b10000000; Wait_sh(80);}void i2c_start(void){ Init_I2C(); IIC1S = 0b10010010; // clear interrupts IIC1C = 0b10111000; // Start, TX, NOACK Wait_sh(80);}void i2c_stop(void){ IIC1S = 0b10010010; // clear interrupts IIC1C = 0b10000000; Wait_sh(80);}void i2c_restart(void){ IIC1C = 0b10111100; // Start, TX, NOACK, RESTART Wait_sh(80);}char i2c_waitforflag(void){ IIC1SSTR status; Wait_sh(80); do { status.Byte = IIC1S; } while(!status.Bits.TCF); IIC1S = 0b10010010; // clear interrupts return(!status.Bits.RXAK);}char i2c_sendbyte(unsigned char data){ if(IIC1C != 0b10111000) IIC1C = 0b10111000; IIC1D = data; return(i2c_waitforflag());}unsigned char i2c_getbyte(char send_ack){ unsigned char data; if(send_ack) IIC1C = 0b10100000; // RX, SEND_ACK else IIC1C = 0b10101000; // RX, NO_ACK IIC1D; i2c_waitforflag(); data = IIC1D; // read right data; Wait_sh(80); return(data);}
unsigned char EE_WaitForACK(unsigned char control_byte){ unsigned char counter = 200; unsigned char ack; unsigned char ControlByte = control_byte; ControlByte &= 0b11111110; do { i2c_start(); ack = i2c_sendbyte(ControlByte); i2c_stop(); --counter; // her deneme 175uS sürüyor, 29 deneme > 5ms yapar. } while(!ack && (counter != 0)); return(ack);}char EE_ReadBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF); ControlByte |= ((external_adr << 1) & 0b00001110); i2c_start(); // Control Byte = 1 0 1 0 A2 A1 A0 R/W if(!i2c_sendbyte(ControlByte)) { i2c_stop(); return(0); } // Address High Byte if(!i2c_sendbyte(AddrHigh)) { i2c_stop(); return(0); } // Address Low Byte if(!i2c_sendbyte(AddrLow)) { i2c_stop(); return(0); } // Read i2c_restart(); // Control Byte to read ControlByte |= 0b00000001; // Okuma modu if(!i2c_sendbyte(ControlByte)) { i2c_stop(); return(0); } do { *Data++ = i2c_getbyte(size != 1); } while(--size); i2c_stop(); return(1);}char EE_WriteBuffer(unsigned int Adr, unsigned char* Data, unsigned int size, unsigned char external_adr){ unsigned int _PAGE = 0xFFFF; // önceki page // Control Byte = 1 0 1 0 A2 A1 A0 R/W. unsigned char ControlByte = 0b10100000; // Yazma modu, A2, A1, A0 = 0 do { unsigned int CURRENT_PAGE = Adr & 0b1111111110000000; // page size 128 byte if(CURRENT_PAGE != _PAGE) { unsigned char AddrHigh = (Adr >> 8) & 0xFF; unsigned char AddrLow = (Adr & 0xFF); ControlByte |= ((external_adr << 1) & 0b00001110); if(_PAGE != 0xFFFF) { i2c_stop(); if(!EE_WaitForACK(external_adr)) return(0); } //i2c_start(); i2c_start(); // Control Byte = 1 0 1 0 A2 A1 A0 R/W. if(!i2c_sendbyte(ControlByte)) { i2c_stop(); return(0); } // Address High Byte if(!i2c_sendbyte(AddrHigh)) { i2c_stop(); return(0); } // Address Low Byte if(!i2c_sendbyte(AddrLow)) { i2c_stop(); return(0); } _PAGE = CURRENT_PAGE; } //if(CURRENT_PAGE != _PAGE) if(!i2c_sendbyte(*Data++)) { i2c_stop(); return(0); } Adr++; } while(--size); i2c_stop(); return(EE_WaitForACK(ControlByte));}
IIC1D = data;
while (!IIC1S_IICIF); // wait until interrupt flag
IIC1S_IICIF = 1; // clear flag
while (IIC1S_RXAK); // Wait for ACK from slave
So the important aspect appears not that it be necessary to implement interrupts, but that the interrupt flag IICIF should be the flag that is tested and cleared, rather than TCF. If this is correct, the issue appears most likely that the IICIF flag becomes set some time after the TCF flag is set, and the attempt to clear the flags does not clear the IICIF flag (which is obviously a mandatory requirement, although not stated in the data sheet).
The importance of testing the IICIF flag (and not TCF) is suggested by the author of AN3291, in the following thread, that also addresses a bug present in the original release of the application note -http://forums.freescale.com/freescale/board/message?board.id=8BITCOMM&message.id=3785
The application note makes no mention of the need for an extra delay following START or STOP conditions. It might have been more instructive if the reason for the previous suggestion of their inclusion was given, in order to appreciate what the magnitude of the delay might be.
Finally, I notice that your code for the generation of START and STOP seems more complex than the application note would suggest -
IIC1C_TXAK = 0; // RX/TX = 1; MS/SL = 1; TXAK = 0
IIC1C |= 0x30; // generate START
and
IIC1S_IICIF = 1; // clear interrupt flag
IIC1C_MST = 0; // generate STOP
Regards,
Mac
void i2c_clearflags(void){ IIC1S_IICIF = 1; IIC1S_TCF = 0; IIC1S_ARBL = 0;}void i2c_start(void){ i2c_clearflags(); IIC1S_SRW = 0; // master will send data IIC1C = 0b10111000; // Start, TX, NOACK Wait_sh(80);}void i2c_stop(void){ i2c_clearflags(); IIC1S_SRW = 0; // master will send data IIC1C = 0b10000000; Wait_sh(80);}void i2c_restart(void){ i2c_clearflags(); IIC1S_SRW = 0; // master will send data IIC1C = 0b10111100; // Start, TX, NOACK, RESTART Wait_sh(80);}char i2c_waitforflag(void){ IIC1SSTR status; do { status.Byte = IIC1S; } while(!status.Bits.IICIF); i2c_clearflags(); return(!status.Bits.RXAK);}char i2c_sendbyte(unsigned char data){ if(IIC1C != 0b10111000) IIC1C = 0b10111000; IIC1D = data; return(i2c_waitforflag());}unsigned char i2c_getbyte(char send_ack){ unsigned char data; if(IIC1C_TX) { IIC1C_TX = 0; IIC1C_TXAK = 0; data = IIC1D; // initiate first reading sequence } while(!IIC1S_IICIF); i2c_clearflags(); if(send_ack) IIC1C_TXAK = 0; else IIC1C_TXAK = 1; data = IIC1D; // read right data return(data);}