i2c problem with EEPROM 24AA128

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,366
Good day! I am trying to make an "i2c" interface, but I cant seem to get it to work. I read the datasheet, but Its not working.

Compiler: CCS PIC C v5.061
Simulator: Proteus 8.5

Source code
C:
/*
Description:
Second attempt to make an i2c program, examples and others are taken from the CCS forums, file for reference:

i2c-PCM-programmer-examples-CCS __ View topic - sensor networks.pdf

Original version from PCM programmer, the rest are modified versions
*/

/*
Description:
Second attempt to make an i2c program, examples and others are taken from the CCS forums, file for reference:

i2c-PCM-programmer-examples-CCS __ View topic - sensor networks.pdf
*/

#include <16F690.h>

#define GP0 PIN_C0
#define GP1 PIN_C1
#define GP2 PIN_C2
#define GP3 PIN_C3
#define GP4 PIN_C4
#define GP5 PIN_C5
#define GP6 PIN_C6
#define GP7 PIN_C7

#fuses INTRC_IO, NOWDT, NOPROTECT, BROWNOUT /* Ext. oscilator, no watchdog, no code protect, no brownout (until voltage
rises on power up the PIC is held in reset = inactive) reset */

#use delay(clock=4M) /* Specify clock frequency, to use "delay_()" function */
#use rs232 (baud=9600, xmit=PIN_B5, rcv=PIN_B7, parity=N, bits=8, errors)
#use i2c (master, sda=PIN_C5, scl=PIN_C4) /* Master mode, SDA pin = RB4, SCL pin = RB6, force hardware i2c functions */

#define SLAVE1_WRT_CON_BYTE 0b10100000 /* This byte should contain the control byte from the
datasheet with control code, AN0, AN1, AN2 pins, READ or WRITE bit */
/* bit<0> = 0 for write and 1 for read
bits<1:3> = the values of the AN0:2 pins
bits<4:7> = control code of "1010" for EEPROM24AA128 */
/* !!! Dont forget that these must be put as the most significant bits first,
A0, A1, A2 become A2, A1, A0, making:
10100000 = control 4 bits/A2, A1, A0,/Read or write */
/* HEX = 0xA0 */

#define SLAVE1_READ_CON_BYTE 0b10100001 /* This byte should contain the control byte from the
datasheet with control code, AN0, AN1, AN2 pins, READ or WRITE bit */
/* bit<0> = 0 for write and 1 for read
bits<1:3> = the values of the AN0:2 pins
bits<4:7> = control code of "1010" for EEPROM24AA128 */
/* !!! Dont forget that these must be put as the most significant bits first,
A0, A1, A2 become A2, A1, A0, making:
10100001 = control 4 bits/A2, A1, A0,/Read or write */
/* HEX = A1 */

#define SLAVE1_WRITE_ADDRESS_2_BYTES 0x00A2
#define SLAVE1_READ_ADDRESS_2_BYTES 0x00A3
//====================================

void main()
{
int8 data;

while(1)
{
printf ("Startin i2c module");
/* to write data */
i2c_start();
i2c_write(SLAVE1_WRT_CON_BYTE); /* 1. Following the start condition, the next byte is control code (1010)\chip select (A2, A1, A0), R/W bit (logic low). This indicates to the addressed slave that the address high byte will follow after it has generated an Acknowledge bit */
delay_ms (10); /* delay 10ms for the acknowledge bit to be sent, because we dont record it with the microcontroller */

i2c_write (0x80); /* 2. The next byte is the high order byte of the word address and will be written into the Address Pointer of 24AA128 */

i2c_write (0x00); /* 3. The next byte is the least significant address byte */

i2c_write (0x01); /* 4. After receiving another acknowledge signal from the 24AA128, the master will transmit tha data word to be written into the addressed memory location */
/* After a byte write command, the internal address counter will point
/* to the address location following the one that was just written */
i2c_write (0x02);
delay_ms (10);
i2c_stop (); /* 5. After another acknowledge bit, the master sends the stop condition */
delay_ms (10);

/* to read data subsequently */
i2c_start();
i2c_write(SLAVE1_WRT_CON_BYTE); /* 1. Following the start condition, the next byte is control code (1010)\chip select (A2, A1, A0), R/W bit (logic low). This indicates to the addressed slave that the address high byte will follow after it has generated an Acknowledge bit */
delay_ms (10); /* delay 10ms for the acknowledge bit to be sent, because we dont record it with the microcontroller */

i2c_write (0x80); /* 2. The next byte is the high order byte of the word address and will be written into the Address Pointer of 24AA128 */

i2c_write (0x00); /* 3. The next byte is the least significant address byte */

i2c_write (SLAVE1_READ_CON_BYTE);
delay_ms (10);

data = i2c_read(0);
delay_ms (10);

data = i2c_read (0);

//i2c_stop (); /* 5. After another acknowledge bit, the master sends the stop condition */
//delay_ms (10);

printf("read %X \n\r", data);
delay_ms(1000);
}
}

Schematic

Arakal_I2C.jpg

Moderators note : made code and schematic directly viewable
 
Last edited by a moderator:

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,366
Thats only if I use the hardware built-in option. Otherwise I can specify, whichever pin I want. The RS232 is already tested and working, I just dont know if there is anything wrong with the sequence with which I write and read to EEPROM.
 

ErnieM

Joined Apr 24, 2011
8,415
It's hard to track down all your errors without knowing what your library code is doing for you. These routines need to be "bit banging" ones where they wiggle the I/O pins directly, and since I2C needs open collector drives they should be hitting the TRIS registers too. Do check that.

The write sequence you have seems OK, though the only delay you need is after then bytes are sent. Don't delay within the write cycles.

The read has one obvious problem. Line 92 should be either a RESTART command or a STOP and START sequence. This is not obvious, but you write the address, then read the data there. No delay is needed for reads.

Do be careful with the START and STOP commands.

Also check what your library does with the ACK signal. After the master reads a byte it needs to ACK this to advance the memory pointer. No ACK, the slave thinks the transaction is complete.
 

JohnInTX

Joined Jun 26, 2012
4,787
Thats only if I use the hardware built-in option. Otherwise I can specify, whichever pin I want. The RS232 is already tested and working, I just dont know if there is anything wrong with the sequence with which I write and read to EEPROM.
If that is the case then what are these two lines doing? To me, it seems that it is using the hardware pins.
C:
#use rs232 (baud=9600, xmit=PIN_B5, rcv=PIN_B7, parity=N, bits=8, errors)
#use i2c (master, sda=PIN_C5, scl=PIN_C4) /* Master mode, SDA pin = RB4, SCL pin = RB6, force hardware i2c functions */
Also, RS232 connections usually have PIC TX -> Terminal RX and PIC RX->Terminal TX.

As @ErnieM says, what it does with ACK is important. I don't understand using a delay() to wait for ACK. The PIC is the master here so it has to generate the I2C clock, something it can't do when using a delay() and bit-banging I2C. If you are able to relocate the I2C pins with the library, you are indeed bit-banging since the 16F690 can't relocate the hardware MSSP pins. In any I2C, you have to pay attention to ACK/NAK, if for no other reason but to see if you actually have addressed the slave EEPROM.

If it were me, I would wire it up in a more normal manner first i.e.
SDA/SCL on the specified pins
TX->RX
RX<-TX

If you insist on pioneering with your pinout, I'd at least look at the assembler output of the compiler to see if indeed it is relocating pins or if it's using the MSSP.
Just thinking out loud..
 

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,366
I need to know if the bytes sent are according to the procedure for the I2C standard, according to the datasheet of EEPROM 24AA128, because despite reading the datasheet, the program does not work.

The functions do this:

  1. i2c_start(); /* the start condition according to the datasheet of EEPROM 24AA128 is sent to the EEPROM */
  2. i2c_write(SLAVE1_WRT_CON_BYTE); /* just sends a byte on the bus with the value in the brackets */

  3. i2c_write (0x80); /* sends a byte on the bus with the value in the brackets */

  4. i2c_write (0x00); /* sends a byte on the bus with the value in the brackets */

  5. i2c_write (0x01); /* sends a byte on the bus with the value in the brackets */

  6. i2c_write (0x02); /* sends a byte on the bus with the value in the brackets */
  7. delay_ms (10);
  8. i2c_stop (); /* stop condition according to the datasheet of EEPROM 24AA128 */
 

ErnieM

Joined Apr 24, 2011
8,415
Put that delay AFTER the stop command.

Up until the stop is issued the EEPROM Keeps the data in a buffer. It only gets written after the stop.

Writing takes time, and other commands are basically ignored till it is complete.

Next, do tell how and what your library does with ACK.

(Edit to remove horrible auto-correct)
 
Last edited:

Thread Starter

ArakelTheDragon

Joined Nov 18, 2016
1,366
For theese 2 lines:.
#use rs232 (baud=9600, xmit=PIN_B5, rcv=PIN_B7, parity=N, bits=8, errors)
#use i2c (master, sda=PIN_C5, scl=PIN_C4)

As far as I understand, I can use hardware "i2c" or software "i2c", so if I use the software version, I can pick whichever pins I want. I will try with different pins though.
 
Top