MC9S08QG8: Help getting SPI to work with external EEPROM

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MC9S08QG8: Help getting SPI to work with external EEPROM

2,905 Views
comp_e
Contributor I
Hi, this is my first post and I am in need of some assistance.  I am trying to use Microchip 25AA512 EEPROM via spi and am running into quite a few problems.

Datasheet for EEPROM: http://ww1.microchip.com/downloads/en/DeviceDoc/22021E.pdf
Datasheet for  S08QG8: http://ww1.microchip.com/downloads/en/DeviceDoc/22021E.pdf

The problem I'm getting is a lack of response from the EEPROM.  I'm sending out what I believe to be the correct code to start it up, however I don't get any response back from the chip.  I have verified this fact vie logic analyzer attached to all EEPROM perifrials.  Below is the initialization code I have written.  However, I am using beans and have uploaded the entire project in a zip file (project is called newproject).

Thank you to anyone who can help me figure this out.  (My guess is that it may be due to timing, but then again, this is the first time I've ever used a MC so I can't be all that sure).

/** EEprom power up follows the initialization sequence
 *  specified in the EEprom data sheet for 25AA512 EEPROM
 *  Each Send is required.  Also, assume that !CS is tied
 *  to ground, !HOLD and !WP are tied high.  This is done
 *  off chip (these pins are not hooked up to the mcu and
 *  require no mcu pins to be set: done to maximize usabl
 *  i/o pins).  All EEprom OP-Codes are defined.
 *
 *  SPI hardware settings are managed by the SWSPI bean.
 * 
 *  - SPI1_SendChar(char ch)
 *  - SPI1_RecvChar(char *ch)
 * 
 */
void powerUpEEprom(void) {
       
    SPI2_Init();
    PTBD_PTBD6 = 0;
    waitAbit();
   
    /*
    #define READ    0x03          // Read  from mem array beg. at selected address
    #define WRITE   0x02          // Write to mem array beg. at selected address
    #define WREN    0x06          // Set   the latch (enable write operations)
    #define WRDI    0x04          // Reset the latch (disable write operations)
    #define RDSR    0x05          // Read         – STATUS register
    #define WRSR    0x01          // Write        – STATUS register
    #define PE      0x42          // Page Erase   – erase one page in mem array
    #define SE      0xD8          // Sector Erase – erase one sector in mem array
    #define CE      0xC7          // Chip Erase   – erase all sectors in mem array
    */
    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, WRDI);     // data = 0

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, WRSR);     // data = 4

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, WRITE);    // data = 1

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, PE);

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, SE);

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, CE);

    while(SPIS_SPTEF != 1);
    SPIS;
    data = getReg8(SPID);
    setReg8(SPID, WREN);
   
    while(SPIS_SPTEF != 1);
    SPIS;
    SPID;
    setReg8(SPID, 0x00);
    while(SPIS_SPTEF != 1);
   
    //PULSE TO LATCH WRITE ENABLE
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;PTBD_PTBD6 = 1;
    PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;
    PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;PTBD_PTBD6 = 0;
   


    while(SPIS_SPTEF != 1);
    SPIS;
    SPID;
    setReg8(SPID, RDSR);              // Check write enable set correctly (Read Status Reg on EEPROM)
   
    while(SPIS_SPRF != 1);
    setReg8(SPID, 0x00);
    while(SPIS_SPRF != 1);            // Wait for eeprom to send status
    data = getReg8(SPID);             // Save Status
}

FreeRTOS-3.2.4-HCS08_Files.zip
Message Edited by dkindler on 2009-08-20 03:32 PM
Labels (1)
0 Kudos
7 Replies

577 Views
comp_e
Contributor I

I hate it when people post questions, figure things out and then don't post the solution!!

 

I was able to get this working and have provided the .h and .c code used in order to make everything run.  This EEPROM is incredibly finicky.  I was able to get it to work at 2000KHz and 12.5KHz.

 

The code and a more detailed description is posted on my website @

 

http://comp-e.com/using-spi-eeprom-25aa512-on-an-hcs08-microcontroller

 

Message Edited by comp-e on 2009-03-15 05:29 PM
0 Kudos

577 Views
bigmac
Specialist III

Hello,

 

I think that a few comments about the code posted on your website are in order. One of your preliminary comments:

You will notice that slave select pin is not used. Because I only used this one chip, I tied the SS, WP, and HOLD pins to hi/low as per my needs.

Tying the SS (or CS) pin low is not an option for an EEPROM device. The line must be lowered prior to the commencement of a command sequence (to indicate that a command byte will follow), and raised at the completion of the command sequence. For a write or erase command, execution will not commence until this occurs.

 

There still seems to be some confusion over the role of the SPI flags SPTEF and SPRF. My understanding is that many of the time delays that you have introduced should not be necessary, but were required because of improper handling of the SPRF flag. The amount of delay would also have been dependent on the SPI clock rate chosen. With appropriate handling of SPRF, the clock rate should be non-critical, provided it is less than the maximum limit specified for the EEPROM.

 

Now for some comments on snippets of your code, to outline some of the perceived problems -

 

Snippet 1:

 

void SPI_WREN(void)
{
CS_ON;
delay(2); // Probably unnecessary for EEPROM

while (!(SPIS & 0x20)); // Wait until ready to send

// SPTEF should normally be already set here

 

SPID = WREN; // Send byte value

delay(1);

// Delay is needed for completion of SPI transfer prior to raising CS

// A better solution is to test the SPRF flag

while (!(SPIS & 0x80)); // Wait until transfer is complete

(void)SPID; // Clears SPRF - prevents overrun on next transfer

 

CS_OFF;
delay(1);
// Unnecessary
}

Snippet 2:

 

byte SPI_RDSR(void)
{
CS_ON;

delay(2); // Probably unnecessary for EEPROM

while (!(SPIS & 0x20)); // Wait until ready to send

// SPTEF should normally be already set here

SPID = RDSR; // Send byte value

while (!(SPIS & 0x20)); // Wait until ready to send

// SPTEF should again be set because of double buffering
SPID = DUMMY; // Send byte value
delay(1); // Unnecessary
while (!(SPIS & 0x80)); // Wait until ready to send

// SPRF will become set on completion of the first byte transfer

// SPID will contain the result of this transfer (invalid value)

// On completion of the second transfer, an overrun state will remain until SPRF is cleared

// The result of the second transfer will be lost

 

delay(4); // Unnecessary with appropriate SPRF handling

CS_OFF;
delay(1); // Unnecessary
return SPID; // This read will clear both SPRF and the overrun state

}

 

There are many other instances throughout the code with similar issues. The cardinal rule for SPI master transfers -

Wait until each byte transfer is complete, and then always clear the SPRF flag to prevent an overrun condition.

If this is strictly followed, there should be few timing issues. While I have not used the 25AA512 device, I have used smaller capacity SPI EEPROM devices - I cannot see that there are more severe timing requirements for the larger device, and I do not know of any special power-up requirements.

 

See what you make of the attached experimental code.

 

Regards,

Mac

Message Edited by bigmac on 2009-03-19 03:42 PM
0 Kudos

577 Views
comp_e
Contributor I

I did retain control of the CS pin but the SS pin was tied since I didn't have a need for it.

 

I will try out your code as it's quite a bit cleaner, but I did try to follow your previous suggestion.  Problem was, when I hooked it up to the logic analyzer the while( ... ) was clearing before the 8 clock tics finished going out.

0 Kudos

577 Views
bigmac
Specialist III

Hello, 


comp-e wrote:

I did retain control of the CS pin but the SS pin was tied since I didn't have a need for it. 

 


 

With the SPI configuration you have used, the SS pin function at the MCU does not exist.  That pin will operate as GPIO, so there is no reason for tying anywhere.  There is also no reason that the pin could not have been allocated to the CS output line function.

 

The reason for the ambiguity is that the labels SS and CS are often used to represent the same signal.


... Problem was, when I hooked it up to the logic analyzer the while( ... ) was clearing before the 8 clock tics finished going out.


For those instances where a flag is cleared by means of a read process, such as for SPRF, you may find that the debugger is unintentionally clearing the flag because it is reading the appropriate registers during the monitoring process, during single stepping.  I suspect that this was a possible reason for your problem.

 

This can be avoided by not single stepping through the function, but using a break point at the conclusion of the function.

 

Regards,

Mac

0 Kudos

577 Views
comp_e
Contributor I
Thanks so much.  I was going over the timing diagrams for the EEPROM and couldn't quite make out if they were implying that chip select needed to go high after every transmission.  This does lead to one problem though and it may be a fundamental issue in which this mcu implements spi.  This particular eeprom clocks in on low clock pulses, which is fine because i just change cpol in the spic1 register.  However, I need to set chip select high after i'm done transmitting and assume that I still need a clock pulse.  Usually one would just transmit the dummy 0x00 to continu clocking the eeprom.  However, the use of cpol results in a deformed clock pulse in which one gets the following wave form.

(low high low high low high low high low high low high low high low high low low high....)

Will this clock 'deformity' prevent me from latching say, the write enable signal?

0 Kudos

577 Views
bigmac
Specialist III
Hello,

The settings for both CPHA and CPOL will need to be adjusted to suit the EEPROM device - this can be ascertained from the datasheets.  Look at the waveform diagrams for both the EEPROM and the MCU to see what MCU configuration will match the EEPROM requirements.

The CS signal should be set low prior to each command byte being sent, and should not be raised again prior to the transfer of the last byte of the command sequence being completed.  At this point, no further clock pulses should be present.

Regards,
Mac

Just had a quick look at the datasheet.  It would appear that the positive edge of the clock is used to latch each data bit, and the device requires settings of either CPHA=0, CPOL=0, or alternatively CPHA=1, CPOL=1.  In the first case, the static state for the clock will be low, and high for the second alternative.




Message Edited by bigmac on 2009-02-17 01:47 PM
0 Kudos

577 Views
bigmac
Specialist III
Hello, and welcome to the forum.

I think there are some problems with the code for your basic SPI transfers.
  1. You will need to manipulate the device CS signal to "frame" each command sequence.  CS will normally be allocated to a GPIO pin.
  2. To initiate any SPI transfer, the SPID register needs to be written.
  3. Before reading the returned byte value within SPID, you need to wait until the SPI transfer is complete, and the SPRF flag is set.
The following function represents the basic SPI transfer process for a single byte.

byte SPI_trans( byte val)
{
   while (!SPIS_SPTEF);  // Wait until ready to send
   SPID = val;           // Send byte value
   while (!SPIS_SPRF);   // Wait until transfer complete
   return SPID;
}

To send a byte value, and ignore the return value -
(void) SPI_trans( WREN);  // Write enable

To read the returned value as a result of sending a dummy byte -
data = SPI_trans( 0);

If you use the forum search engine below, you might find some sample code specifically for serial EEPROM devices.

Regards,
Mac

0 Kudos