Hello. I need some help. I'm trying to write, read and erase an external EEPROM (25AA040 MICROCHIP) via SPI from XC164CS board, for example, one byte at 0x00 adress of the eeprom, but i don't know how to do it. Into the datasheet, I can see some instructions but i don't know what to do with them: img28.imagevenue.com/img.php Could anyone help me? Thank you very much. :)
I never worked with SPI but rather with I2C, so I don't know for sure. I think that your datasheet might tell you what you need to place on the data bus and what you need to place on the address bus in order to communicate with your device. A simple assignment into a memory mapped region will get the job done.
Perhaps you would like to look at the application note on the Infineon web site...
Interfacing the XC16x Microcontroller to a Serial SPI EEPROM -description (ap1609510_XC16x_SPI_EEPROM.pdf)
There is a pdf with code.
www.infineon.com/.../channel.html
Hello Chris, I have seen your program in the website of Infineon, and its compiler is Tasking and mine is Keil uVision. Do you have the same proyect but for my compiler? Thanks
Pfff, i'm so desperated. This program is very difficult to understand... I have been so long trying to undestand it. Is there any simple program that might help me? Thanks
Hi
I am not sure what are the difficulties but I modified some code I made previously to Keil. I then tested it on an XC164CS starterkit without issue. If you want to post your email then I will send it to you. However I am not sure if it is easier to understand though...
The program is in a few files which are to many to post here but listed below is from the main file if this is interesting to you.
const S8 txBuf[] = "Welcome to XC164CS Serial EEPROM reading/writing"; const U16 txSize = (sizeof(txBuf) - 1); S8 rxBuf[64]; /**/ void main (void) { U16 address = 0; /* EEPROM address for string */ SSC0_Init(); /* initialize the SSC peripheral */ PSW_IEN = 1; /* globally enable interrupts */ /* write bytes to the EEPROM */ EepromWriteEnable(); while(EepromBusy()); /* max page size if 64 bytes in a write */ EepromWrite(address, (U8*) &txBuf[0], (U16) txSize); while(EepromBusy()); /* wait for WRITE command to complete */ while((EepromReadStatus() & RDY_) == true); /* read back the bytes we wrote to the EEPROM */ EepromRead(address, &rxBuf[0], (U16) txSize); while(1){ _nop_(); /* loop forever */ } }
Hi Chris, my email is iker@leako.com. Send me please the program that you have and I will create a simple project in uVision with it. I only want to understand EepromWriteEnable, EepromWrite, and EepromRead functions. Thank you very much Crhis. You are teaching me a lot. ;-)
Hi John,
The Keil project was sent to your email address.
-Chris
Thanks Chris. You are GOD!. Inmediately IÂ'm going to study the proyect and attempt to understand it. I will comment you the results. Give me some time :)
Hi Chris, I have 3 questions about the project:
First one: I suppose the program writes and reads this array: txBuf[] = "Welcome to XC164CS Serial EEPROM reading/writing" into EEPROM. Isn't it? How can I check if this program writes and reads correctly?
Second one: How does the "EepromStartTx" function work? It doesnÂ't have any "for" loop to send each byte of txBuf[] to SSC0_TB?
Third one:Is SSC0 interrupt system similar to ASC0? Thanks. I go on studying.
Other question: Is there any time to comply with this?
void SSC0_viTx(void) interrupt SSC0TINT ... if ((eeprom.cmd == WRITE) && (eeprom.bytesTx == START_TX_MSG)) ...
eeprom.bytesTx is going to take as maximum, 2, isn't it?
There are two functions to read/write the serial EEPROM
U8 EepromRead(U16 address, S8 *des, U16 cnt); U8 EepromWrite(U16 address, S8 *src, U16 cnt);
Each has three parameters, the address, a pointer to first element of data (to read/write) and the number of bytes elements to read or write from the serial EEPROM.
In the example the txbuf[] is a constant string which is written to the serial EEPROM. Again it is an argument so you can write what you want. In this example the SSC0 is assumed to be exclusively used for communication to the serial EEPROM. In addition it also puts the command and address into the data stream that the serial EEPROM sees. The EepromRead routine also strips out the address and command from the data receive stream so the data the application sees is strictly application data (protocol overhead of the serial EEPROM has been removed). In other words the driver is hiding some details from the application which is what I wanted.
How can I check if this program writes and reads correctly?. You read back what you wrote and if they are the same then you were successful. You could also add more checks to make sure that a write actually started by querying the serial EEPROM. Hook up a LSA and look at the SPI data streams...
How does the "EepromStartTx" function work? It only starts the transmission and the interrupts serve to fill the rest of the data. No for is used as it is interrupt driven in the background.
Is SSC0 interrupt system similar to ASC0? They are similar in that they are both interrupts and relate to a serial protocol. The user's manual explains how they each behave.
Hi, I tested the program by using the uVision Debugger in evaluation mode. I don't understand why the program enters into the receive interrupt while the message array is being written in EEPROM. I am trying to visualize what I read from EEPROM ("Welcome to XC164CS Serial EEPROM reading/writing") in hyperterminal through ASC0. How could I transfer the read data from EEPROM to new array in order to send this array afterwards for ASC0? How would you do this? Thanks
In any case, I think that the program doesn't read properly the written data because when it gets EepromRead function, the receive interrupt is executed only once. Correct me if I am wrong.
Chris, Have you tested this program by using keils ulink2?
I tested it with ULINK and Lauterbach. Everything works as expected.
What hardware are you using? The hardware I used was the Starter kit which uses SSC0 and P3.6 for the chip select.
I don't have any type of hardware to test the programs :(. I can only use the ASC0 and hyperterminal to show the bytes I read/write from EEPROM and for every tests. In my project we don't have much money to buy debuggers, such as uLink jejeje.
Hello Chris, Despite I have tried so much, I am not able to read what I have written in the EEPROM. I am trying to store everything I receive from EEPROM in an array located in reception interruption. I only get as answer [00][FF]. What could it be the problem? Thank you.
John, Despite our desire to help you, we are not mind readers. Please post the core of your code - just the essentials so that it can be analyzed.
Tamir, if you want, I will send you the keil proyect to your mail right?
John, I don't have your hardware so sending me your code is not going to help a lot. Besides I am at work and I don't time too much time...Just post a couple of code snippets: your peripheral configuration, ISRs, and buffers that interact with incoming data. Are you sure your external bus interface is correctly configured? Did you try to minimize the scope of the program to the absolute minimum, so that you can rule out external interferences? That can you and us, too.
Hello John,
I don't see the same issue so something must be different in your implementation. What pins are connected from the serial EERPOM to what pins of the XC164CS. What about the WR and HOLD pins (they are tied high in my configuration)?
The read and write routines are completely interrupt driven and are the same implementation only the instruction (sent to the serial EEPROM) is changed.
You would need to isolate your problem/issue and properly communicate the defect for someone else to understand what the cause might be and provide suggestions.
If you run the code using the simulator you will see that the interrupts are more than two. You would not have the correct data but the transfers should work.
void SSC0_viRx(void) interrupt SSC0RINT { if (eeprom.bytesRx < eeprom.rxCnt) { eeprom.bytesRx++; if ((eeprom.cmd == READ) && (eeprom.bytesRx >= START_RX_MSG)) { *eeprom.rxptr++ = (S8) (SSC0_RB); } else { eeprom.data = (S8) (SSC0_RB); /* */ my_array[j] = SSC0_RB; j++; if (j == NUMBER) { flag = 1; ASC0_TBIC_IR = 1; } } if (eeprom.bytesRx >= eeprom.rxCnt) { eeprom.busy = false; CS_EEPROM = high; } } } void ASC0_viTxBuffer(void) interrupt ASC0_TBINT using RB_LEVEL14 { if ((j > 0) && (flag == 1)) { j--; ASC0_TBUF = mi_array[j]; if (j == 0) flag = 0; } }
void SSC0_viRx(void) interrupt SSC0RINT { if (eeprom.bytesRx < eeprom.rxCnt) { eeprom.bytesRx++; if ((eeprom.cmd == READ) && (eeprom.bytesRx >= START_RX_MSG)) { *eeprom.rxptr++ = (S8) (SSC0_RB); } else { eeprom.data = (S8) (SSC0_RB); /* */ my_array[j] = SSC0_RB; j++; if (j == NUMBER) { flag = 1; ASC0_TBIC_IR = 1; } } if (eeprom.bytesRx >= eeprom.rxCnt) { eeprom.busy = false; CS_EEPROM = high; } } } void ASC0_viTxBuffer(void) interrupt ASC0_TBINT using RB_LEVEL14 { if ((j > 0) && (flag == 1)) { j--; ASC0_TBUF = my_array[j]; if (j == 0) flag = 0; } }
You have changed the behavior of the interrupt service routines as I defined them (Which is fine but I think you missed what was going on). Concerning the receive interrupt you are unloading the data stream in the wrong place. Concerning the transmit interrupt you aren't sending any more bytes which is a problem.
Remember you still need to transmit to read.
Have a look again to the differences...
void SSC0_viTx(void) interrupt SSC0TINT { if (eeprom.bytesTx < eeprom.txCnt) { eeprom.bytesTx++; if (TxMode == WRITE) { /* write mode */ if ((eeprom.cmd == WRITE) && (eeprom.bytesTx == START_TX_MSG)) { eeprom.txptr = eeprom.baseptr; /* switch pointer to data */ } SSC0_TB = *eeprom.txptr++; /* write user data */ } else { /* ok READ mode */ if ((eeprom.cmd == READ) && (eeprom.bytesTx >= START_TX_MSG)) { SSC0_TB = 0; /* when reading data just send zeros */ } else { SSC0_TB = *eeprom.txptr++; /* send command and address */ } } } } void SSC0_viRx(void) interrupt SSC0RINT { if (eeprom.bytesRx < eeprom.rxCnt) { eeprom.bytesRx++; if ((eeprom.cmd == READ) && (eeprom.bytesRx >= START_RX_MSG)) { /* data stream read here! */ *eeprom.rxptr++ = (S8) (SSC0_RB); /* read user data */ } else { eeprom.data = (S8) (SSC0_RB); /* used for non-user data */ } if (eeprom.bytesRx >= eeprom.rxCnt) { eeprom.busy = false; /* indicate the resource is free */ CS_EEPROM = high; /* all data sent, release /CS */ } } }
Ok after I sent the last post I realized you posting the code for the ASC0 interrupt (not the SSC ts interrupt) to send the data that was read from the serial EEPROM. So my comments to the SSC0 interrupt are still valid.
Ok, I just obey you and it is the result :)
... #define NUMBER 48 const S8 txBuf[] = "Welcome to XC164CS Serial EEPROM reading/writing"; ... void SSC0_viRx(void) interrupt SSC0RINT { if (eeprom.bytesRx < eeprom.rxCnt) { eeprom.bytesRx++; if ((eeprom.cmd == READ) && (eeprom.bytesRx >= START_RX_MSG)) { ///////////////////////////////////////////////// my_array[j] = SSC0_RB; j++; if (j == NUMBER) { flag = 1; ASC0_TBIC_IR = 1; } ///////////////////////////////////////////////// *eeprom.rxptr++ = (S8) (SSC0_RB); /* read user data */ } else { eeprom.data = (S8) (SSC0_RB); /* used for non-user data */ } if (eeprom.bytesRx >= eeprom.rxCnt) { eeprom.busy = false; /* indicate the resource is free */ CS_EEPROM = high; /* all data sent, release /CS */ } } } void ASC0_viTxBuffer(void) interrupt ASC0_TBINT using RB_LEVEL14 { if ((j > 0) && (flag == 1)) { j--; ASC0_TBUF = my_array[j]; if (j == 0) flag = 0; } }
Hyperterminal: img171.imagevenue.com/img.php
It's succesfull :)
Now, I would like to read SC461CX only. What parameters do I have to introduce in the readEeprom function?
View all questions in Keil forum