|
|
View previous topic :: View next topic |
Author |
Message |
skywest
Joined: 16 Aug 2014 Posts: 7
|
I2c eeprom - works fine but odd problem with code or me? |
Posted: Thu Jun 28, 2018 8:56 am |
|
|
I have been testing CCS with I2c and a 24LC64 eeprom.
The I2c is working perfectly, I can write a byte to a memory location and read it back. Using a logic analyser, I can see that this works correctly. I am sending some debugging data over rs232 to a terminal and I am unsure whether the problem lies here or in my code. (I could just be dim today).
The program calls LCWrite and stores a character in location 5, it then calls LCRead to read location 5 which it does correctly. The value read is then returned to the main function where it always ends up as [00h], I guess this is Null. Where am I being dim?
Here's the terminal output when the program is run, the last item is always zero when it should be 'Z'):
Writing data Z 5 (store character 'Z' to location 5)
Reading data from 5 (read fromn location 5)
data is Z (the data read is 'Z')
Returned Data is [00] (the value returned to the main function)
_____________________________________________________
And here's the code:
Code: |
#include <24LC64.h>
#use rs232(uart1, baud = 9600,xmit=PIN_C6,rcv=PIN_C7))
#use I2C(master,sda=PIN_C4,scl=PIN_C3)
#use delay(clock = 20000000)
BYTE LCRead(unsigned int);
void LCWrite(unsigned int , BYTE );
byte sendchar='Z';
byte recvchar='X';
unsigned int Addr=5;
//********************************************
void main()
{
LCWrite(Addr,sendchar);
recvchar=LCRead(Addr);
printf("%s %c","\nReturned Data is ",recvchar); // always gets null incorrectly
}
//*******************************************
void LCWrite(unsigned int Addr, BYTE data)
{
BYTE AddrHi,AddrLo;
AddrHi=(BYTE) (Addr/256);
AddrLo=(BYTE) (Addr-(Addr*256));
printf("%s %c %u","\nWriting data ",data,Addr); //reports correctly
i2c_start();
i2c_write(0xA0); // Device address
i2c_write(AddrHi);
i2c_write(AddrLo);
i2c_write(data);
i2c_stop();
delay_ms(20);
}
//***************************************
BYTE LCRead(unsigned int Addr)
{
BYTE data='_';
BYTE AddrHi,AddrLo;
AddrHi=(BYTE)(Addr/256);
AddrLo=(BYTE) (Addr-(AddrHi*256));
printf("%s %u","\nReading data from",Addr); // reports correctly
i2c_start();
i2c_write(0xA0);
i2c_write(AddrHi);
i2c_write(AddrLo);
i2c_start();
i2c_write(0xA1); // Device address
data=i2c_read();
i2c_stop();
delay_ms(10);
printf("%s %c","\ndata is",data); // reports the correctly read character
return(data); // always ends up as null in the main function
} |
|
|
|
HnC
Joined: 28 Jun 2018 Posts: 2 Location: India
|
Re: I2c eeprom - works fine but odd problem with code or me? |
Posted: Thu Jun 28, 2018 9:46 am |
|
|
Maybe casting from byte to char is needed. _________________ HnC |
|
|
skywest
Joined: 16 Aug 2014 Posts: 7
|
|
Posted: Thu Jun 28, 2018 10:02 am |
|
|
Thanks, yes I have tried that, no luck there. As the printf in i2cRead displays the correctly read value, something is going wrong when it returns that value to the main function where it ends up as null. I've tried using pointers etc, nothing changes. I'm missing something simple. |
|
|
HnC
Joined: 28 Jun 2018 Posts: 2 Location: India
|
|
Posted: Thu Jun 28, 2018 10:25 am |
|
|
skywest wrote: | Thanks, yes I have tried that, no luck there. As the printf in i2cRead displays the correctly read value, something is going wrong when it returns that value to the main function where it ends up as null. I've tried using pointers etc, nothing changes. I'm missing something simple. |
zip and post complete project files. I will test it here by debugging. _________________ HnC |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: I2c eeprom - works fine but odd problem with code or me? |
Posted: Thu Jun 28, 2018 10:40 am |
|
|
skywest wrote: |
unsigned int Addr=5;
|
This is wrong. You're using an 18F4520 (I asssume this from your
previous thread on May 13). For the PCH compiler, an unsigned int
holds 8 bits, which is 0 to 255. Your address requires 16 bits, so you
should use int16.
skywest wrote: |
void main()
{
LCWrite(Addr,sendchar);
recvchar=LCRead(Addr);
printf("%s %c","\nReturned Data is ",recvchar); // always gets null incorrectly
} |
You need to put while(TRUE); at the end of main(). If you don't, the PIC
will hit a hidden Sleep instruction (inserted by the compiler) and the PIC
will shut down before it sends all the serial data. Your output will appear
to be cut off.
skywest wrote: |
void LCWrite(unsigned int Addr, BYTE data)
{
|
Again, fix the 'Addr' declaration.
skywest wrote: |
BYTE AddrHi,AddrLo;
AddrHi=(BYTE) (Addr/256);
AddrLo=(BYTE) (Addr-(Addr*256)); |
This is overly complicated.
It could be done like this:
Code: | AddrHi = (Addr >> 8);
AddrLo = (int8)Addr; |
or, by using the CCS make8() function:
Code: |
AddrHi = make8(Addr, 1);
AddrHi = make8(Addr, 0);
|
skywest wrote: |
delay_ms(20);
|
It doesn't take 20 ms to do a write operation. Per the 24LC64 data sheet,
it takes a maxium of 5 ms.
Regarding the read routine:
skywest wrote: |
BYTE LCRead(unsigned int Addr)
{
|
Fix the size for 'Addr'.
Quote: | AddrHi=(BYTE)(Addr/256);
AddrLo=(BYTE) (Addr-(AddrHi*256)); |
Simplify this.
Quote: | printf("%s %u","\nReading data from",Addr); |
The %u must be changed to %lu when you change 'Addr' to int16.
Quote: |
i2c_start();
i2c_write(0xA0);
i2c_write(AddrHi);
i2c_write(AddrLo);
i2c_start();
i2c_write(0xA1); // Device address
data=i2c_read();
i2c_stop();
delay_ms(10);
|
The last i2c_read() in a read operation must do a NACK. This is specified
in CCS by using a 0 parameter in i2c_read(). Edit that line to fix this.
Also, there is no delay required after a read. You are just slowing down
your code. Remove the delay. |
|
|
skywest
Joined: 16 Aug 2014 Posts: 7
|
|
Posted: Thu Jun 28, 2018 11:54 am |
|
|
Thanks, that's really useful stuff and seems to reflect many of the software issues I have been seeing.
This is based old code I wrote in 2003, I'm trying to port from my old compiler (wiz c) which was used with an 18f452. Worked fine there, but I guess that was because it was an 18f452?.
What has been throwing me, is that when I stick a logic analyser on the bus, it is perfect, the write is good and the timing protocol is perfect, correct data is read back. Weird.
Anyway, I will make all the changes you suggest and hopefully it will fix it up. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Jun 28, 2018 12:02 pm |
|
|
No. The same problems would have been there on the 452. Were you using the same size EEPROM?. The code would have basicically 99% worked for something like a 2408 rather than a 64. |
|
|
skywest
Joined: 16 Aug 2014 Posts: 7
|
|
Posted: Thu Jun 28, 2018 12:58 pm |
|
|
Yes, in fact the devices I'm using I have pulled from those old boards. Worked fine and also similar for reading and writing a DS1307 registers and it's internal memory. Just for interest, this is the working wiz-C code I'm trying to port. I'll make your suggested changes to the CCS code tomorrow, I think that will move me forward.
Code: |
//***********************************************************
// Read Data From memory
//***********************************************************
BYTE LCRead(unsigned int Addr)
{
BYTE AddrHi,AddrLo,data;
AddrHi=(BYTE)(Addr/256);
AddrLo=(BYTE) (Addr-(AddrHi*256));
QuickStop();
TRISC&=~(1<<SDABit);
IIWrite(0xA0,IISTART|IIACK);
IIWrite(AddrHi,IIACK);
IIWrite(AddrLo,IIACK|IISTOP);
IIWrite(0xA1,IISTART|IIACK);
TRISC|=(1<<SDABit);
data=IIRead(!IIACK|IISTOP);
Wait(READDELAY);
return(data);
}
// *************************************************************
// write data to memory
//***********************************************************
void LCWrite(unsigned int Addr, BYTE data)
{
BYTE AddrHi,AddrLo;
AddrHi=(BYTE) (Addr/256);
AddrLo=(BYTE) (Addr-(Addr*256));
QuickStop();
TRISC&=~(1<<SDABit);
IIWrite(0xA0,IISTART|IIACK);
IIWrite(AddrHi,IIACK);
IIWrite(AddrLo,IIACK);
IIWrite(data,IIACK|IISTOP);
Wait(WRITEDELAY);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Jun 28, 2018 1:10 pm |
|
|
OK. Obviously the default size for an integer in Wiz-C is an int16. That would then have allowed the code to 99% possibly work, however the old code must have had something that generated the NACK. Missed in translation somewhere.
Yes. That is what this does:
(!IIACK|IISTOP)
The !IIACK tells the command to send a NACK. 'Not acknowledge'. |
|
|
skywest
Joined: 16 Aug 2014 Posts: 7
|
|
Posted: Thu Jun 28, 2018 2:54 pm |
|
|
Thanks so much Ttelmah for all your help.
Changed the ints to 16 bit
Added the NACK
Added the while(TRUE);
Now works fine.! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Thu Jun 28, 2018 3:41 pm |
|
|
just a comment... but CCS does supply several 'drivers', 2432.c comes to mind as a possible 'look see how it's done' ?
Jay |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|