Hi David,
True, I need to tidy up my use of global and local variables. The I2C frequency being used is 400 kHz. I don’t have an Arduino so I cannot test it the EEPROM on that. However, I have successfully used I2C on the Wixel for reading/writing to a real time clock (DS1307). I have not tried an oscilloscope yet, however I suspect that my problem is with the EEPROM rather than the Wixel’s I2C given that the RTC works. I also suspect that the write operation is failing as the read outputs FF which are the default values stored on the EEPROM. Full code and wiring diagram are as follows:
// EEPROM MEMORY USING I2C BASED ON PREVIOUS CODE WRITTEN FOR DS1307 REAL TIME CLOCK (RTC)
// NOTE: To access the I2C functions in this code, copy "options.mk" from <serial_i2c> directory into the directory of this C code
/* Dependencies ***************************************************************/
#include <cc2511_map.h>
#include <board.h>
#include <time.h>
#include <gpio.h>
#include <i2c.h>
#include <wixel.h>
#include <usb.h>
#include <usb_com.h>
#include <string.h>
#include <stdlib.h>
/* Global Constants & Variables ***********************************************/
int32 CODE param_I2C_SCL_pin = 10;
int32 CODE param_I2C_SDA_pin = 11;
int32 CODE param_I2C_freq_kHz = 400;
int32 CODE param_I2C_timeout_ms = 10;
uint8 XDATA report[128]; //Big buffer for holding report (string input). DM changed back to 128
uint16 DATA reportLength = 0; //Length (in bytes) of report currently in buffer, if zero then buffer is empty
uint16 DATA reportBytesSent = 0; //Number of bytes in current report that have already been sent to computer via USB
uint8 byteCommand[32]={0}; // variables to store bytes received from USB
uint8 byteCommandCounter = 0; // variables to store bytes received from USB
void frequentTasks(void);
void delaySeconds(uint8);
void putchar(char);
void processBytesFromUsb(void);
void sendReportToUsb(void);
void processUserCommand(void);
unsigned char tsec,cmin,tmin,thour,tday,tdate,tmonth,tyear;
uint8 second, minute, hour, date, month, year; // change to day and date instead of ...OfWeek, OfMonth
uint16 byte,hex;
uint8 i2cbyte,dec,time,logValue,mem1,mem2;
unsigned char dsec,dmin,dhour,dday,ddate,dmonth,dyear;
uint8 nsec,nmin,nhour,nday,ndate,nmonth,nyear;
uint8 hexToDec(uint16);
uint16 decToHex(uint8);
unsigned char MSB, LSB;
unsigned char DS1307_WA=0xD0; // 0xD0 = 11010000 in binary. I2C address of DS1307 is 1101000, subsequent 0 denotes write direction
unsigned char DS1307_RA=0xD1; // 0xD1 = 11010001 in binary. I2C address of DS1307 is 1101000, subsequent 1 denotes read direction
unsigned char EEPROM1k_b0_WA=0xA0; // 0xA0 = 10100000 is write address for EEPROM 24LC1025. 1010 is the chips control byte, 0 is the first 512kb sector, next tow 0s denote A1 and A0 at GND, final 0 denotes write direction
unsigned char EEPROM1k_b0_RA=0xA1; // 0xA1 = 10100001 is read address for EEPROM 24LC1025 first 512kb sector
unsigned char EEPROM1k_b1_WA=0xA8; // 0xA0 = 10101000 is write address for EEPROM 24LC1025. 1010 is the chips control byte, 1 is the second 512kb sector, next tow 0s denote A1 and A0 at GND, final 0 denotes write direction
unsigned char EEPROM1k_b1_RA=0xA9; // 0xA1 = 10101001 is read address for EEPROM 24LC1025 second 512kb sector
unsigned char EEPROM256_WA=0xA4; // 10100100 is write address for EEPROM 24LC256 (if pins set to same as 1kB)
unsigned char EEPROM256_RA=0xA4; // 10100101 is read address for EEPROM 24LC256 (if pins set to same as 1kB)
uint16 intlMemAddr=0x0001; // overall counter for internal address location. 16 bit value, will be split into MSB and LSB.
/* ************************************** RTC FUNCTIONS ******************************************************************************/
void Write_DS1307(unsigned char Addr, unsigned char Data)
{
i2cStart();
i2cWriteByte(DS1307_WA);
i2cWriteByte(Addr); // Addr is the registor address (i.e. 0x00 to 0x07) specified at input
i2cWriteByte(Data);
i2cStop();
}
Read_DS1307(unsigned char Addr)
{
i2cStart();
i2cWriteByte(DS1307_WA);
i2cWriteByte(Addr);
i2cStart();
i2cWriteByte(DS1307_RA);
i2cbyte=i2cReadByte(1); // If 1, a NACK will be sent to the slave device instead of an ACK after this byte is received. (This is used to signal conclusion of a transfer from the slave to the master.)
i2cStop();
return(i2cbyte); //byte from ReadByte
}
void displayTime(void)
{
nsec=hexToDec(Read_DS1307(0x00));
nmin=hexToDec(Read_DS1307(0x01));
nhour=hexToDec(Read_DS1307(0x02) & 0b111111); // "& 0b111111" allows 24-hour clock to be read properly
//dday=hexToDec(Read_DS1307(0x03)); // day, a number in range 1-7 representing day of week, is neglected here as unnecessary
ndate=hexToDec(Read_DS1307(0x04));
nmonth=hexToDec(Read_DS1307(0x05));
nyear=hexToDec(Read_DS1307(0x06));
printf("%02u/%02u/%02u %02u:%02u:%02u \r\n",ndate,nmonth,nyear,nhour,nmin,nsec);
}
uint8 hexToDec(uint16 hexValue)
{
uint8 truncValueHex = hexValue / 16;
uint8 decCalc = hexValue - (truncValueHex * 6);
return decCalc;
}
uint16 decToHex(uint8 decValue)
{
uint8 truncValueDec = decValue / 10;
uint16 hexCalc = (16*truncValueDec)+decValue%10;
return hexCalc;
}
// --- --- --- --- --- --- EEPROM FUNCTIONS --- --- --- --- --- --- --- --- --- --- --- --- --- --- /
void writeByteEEPROM(uint16 eeaddress, unsigned char mData)
{
uint8 rdata=mData;
i2cStart();
i2cWriteByte(EEPROM256_WA); // control byte address of EEPROM 24LC1025 - need something to check use of b0 or b1
delayMs(5);
MSB=eeaddress >> 8;
i2cWriteByte(MSB); // takes the first 8 bits (MSB) of the 16-bit intlAddr
delayMs(5);
LSB=eeaddress & 0xFF;
i2cWriteByte(LSB); // compares the 16-bit intlAddr (xxxxxxxxXXXXXXXX) with 11111111 (0xFF), thus extracting the second 8-bits (LSB)
delayMs(5);
i2cWriteByte(rdata); // data byte to be saved
delayMs(5);
i2cStop();
printf("%u was written to address %x, MSB %x and LSB %x \r\n", rdata, eeaddress, MSB, LSB);
}
// page write: writes up to 128 bytes. After receipt of each byte, seven lower address pointer bits are incremented by 1
uint8 readByteEEPROM(uint16 eeaddress) // void was uint16 intlMemAddr
{
i2cStart();
i2cWriteByte(EEPROM256_WA);
MSB=eeaddress>>8;
i2cWriteByte(MSB);
delayMs(5);
LSB=eeaddress&0xFF;
i2cWriteByte(LSB);
delayMs(5);
i2cStart();
i2cWriteByte(EEPROM256_RA);
delayMs(5);
i2cbyte=i2cReadByte(1);
i2cStop();
printf("%x read from address %u", i2cbyte, eeaddress);
return(i2cbyte);
}
void writeReadEEPROMtest(void) // an example function to write 0x77 to address 0001000100010001; does not work as 0xFF or 255 is read back
{
i2cStart();
i2cWriteByte(0xA0); delayMs(5); // writes 1010-0000 for control byte write
i2cWriteByte(0x11); delayMs(5); // writes 0001-0001 for address high byte
i2cWriteByte(0x11); delayMs(5); // writes 0001-0001 for address low byte
i2cWriteByte(0x77); delayMs(5); // writes 0111-0111 (dec 119) for data to be stored
i2cStop();
printf("Value 0x77 or decimal 119 written to memory location 0001000100010001 \r\n");
delaySeconds(2);
i2cStart();
i2cWriteByte(0xA1); delayMs(5); // // writes 1010-0001 for control byte read
mem1=i2cReadByte(1);
i2cStop();
printf("Current address should have been read to yield %x \r\n", mem1);
i2cStart();
i2cWriteByte(0xA0); delayMs(5); // writes 1010-0001 for control byte write
i2cWriteByte(0x11); delayMs(5); // writes 0001-0001 for address high byte
i2cWriteByte(0x11); delayMs(5); // writes 0001-0001 for address low byte
i2cStart();
i2cWriteByte(0xA1); delayMs(5); // // writes 1010-0001 for control byte read
mem2=i2cReadByte(1);
i2cStop();
printf("Specific address (0001000100010001) should have been read to yield %x \r\n",mem2);
}
//****************************** MAIN() FUNCTION ************************************************************************************************/
void main()
{
systemInit();
usbInit();
i2cPinScl = param_I2C_SCL_pin;
i2cPinSda = param_I2C_SDA_pin;
i2cSetFrequency(param_I2C_freq_kHz); // sets frequency to 400 kHz as per 24LC1025 specs
i2cSetTimeout(param_I2C_timeout_ms);
while(1)
{
frequentTasks();
}
}
//******************************* OTHER NON-I2C FUNCTIONS ***************************************************************************************/
void frequentTasks() //function for calling the services below, needs to be iterated every 50 ms to keep everything running smoothly
{
boardService();
usbComService();
processBytesFromUsb();
sendReportToUsb();
}
void putchar(char c) //populates report buffer to be later sent from HyterTerminal via USB
{
report[reportLength] = c;
reportLength++;
}
void delaySeconds(uint8 seconds) //enables seconds delay, allowing USB comms every 50 milliseconds
{
while(seconds--)
{
uint8 i;
for(i=1;i<=20;i++)
{
delayMs(50);
frequentTasks();
}
}
}
void sendReportToUsb()
{
uint8 bytesToSend;
// Send the report to USB in chunks.
if (reportLength > 0)
{
bytesToSend = usbComTxAvailable();
if (bytesToSend > reportLength - reportBytesSent)
{
// Send the last part of the report.
usbComTxSend(report+reportBytesSent, reportLength - reportBytesSent);
reportLength = 0;
}
else
{
usbComTxSend(report+reportBytesSent, bytesToSend);
reportBytesSent += bytesToSend;
}
}
}
void processBytesFromUsb()
{
uint8 bytesInRxBuffer = usbComRxAvailable();
uint8 byteReceived;
while(bytesInRxBuffer)
{
byteReceived = usbComRxReceiveByte();
if (byteReceived==0x0D) // run when carriage return (ENTER key) entered by user
{
byteCommand[byteCommandCounter] = byteReceived;
processUserCommand();
memset(&byteCommand[0], 0, sizeof(byteCommand)); // set all elements in byteCommand to null
byteCommandCounter = 0; //reset byteCommandCounter
}
else if (byteReceived==0x03) //this is the CTRL+C character which will serve as an interupt to other while loop
{
// if necessary, reset all pins etc
printf("\r\n>> Reset \r\n>>");
while(1)
{
frequentTasks();
}
}
else // populate byteCommand byte by byte from USB RX buffer
{
byteCommand[byteCommandCounter] = byteReceived;
printf("%c", byteCommand[byteCommandCounter]);
byteCommandCounter++;
}
bytesInRxBuffer--;
}
}
void processUserCommand() // recognises the commands typed into HyperTerminal
{
char * cmd;
char delims[] = ", \r";
cmd = strtok(byteCommand,delims); // parse command
printf("\r\n");
if(!strcmp(byteCommand, "\r"))
{
}
else if (!strcmp(cmd, "showtime")) // prints date and time to Hyperterminal, updated every second
{
while(1)
{
displayTime();
delaySeconds(1);
frequentTasks();
}
}
else if ((!strcmp(cmd, "settime"))) // for example: settime 12 02 16 14 32 - set system time to 16/02/2012 14:32
{
cmd = strtok(NULL,delims); // "strtok" returns a pointer to token in a string
year=decToHex((atoi(cmd))); // "atoi" converts string to integer
Write_DS1307(0x06,year);
cmd = strtok(NULL,delims);
month=decToHex((atoi(cmd)));
Write_DS1307(0x05,month);
cmd = strtok(NULL,delims);
date=decToHex((atoi(cmd)));
Write_DS1307(0x04,date);
cmd = strtok(NULL,delims); //day (i.e. 1-7 representing Mon-Sun, register 0x03, is ignored as being unnecessary)
hour=decToHex((atoi(cmd)));
Write_DS1307(0x02,hour);
cmd = strtok(NULL,delims);
minute=decToHex((atoi(cmd)));
Write_DS1307(0x01,minute);
cmd = strtok(NULL,delims);
second=decToHex((atoi(cmd)));
Write_DS1307(0x00,second);
displayTime();
}
else if (!strcmp(cmd, "test")) // function to write 0x77 to address 0001000100010001 and read back from this address
{
writeReadEEPROMtest();
}
else
{
printf(">> Invalid Command\r\n");
}
printf(">> ");
}
Following your advice of simplicity, I have written a specific function to write a value to a specified address and read back from that address (writeReadEEPROMtest). However the value is not being written. Compared to Arduino code that I see online, there’s a Wire.begin() function in the main() or an if(wire.available) function in the write function - these seem to be part of Arduino’s wire library. Is something like this necessary for me and if so is there an equivalent in Wixel’s I2C library?
On a side note, I am going to order the EEPROM chip used by the other author (M24C02) to see if that works any easier for me.
Thanks for your help.