CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Hardware SPI <-> 25LC320 EEPROM question

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

Hardware SPI <-> 25LC320 EEPROM question
PostPosted: Wed Sep 13, 2006 1:54 pm     Reply with quote

A long time ago I tried using the built in h/w SPI module to communicate with an EEPROM and eventually gave up. I ended up bit-banging the comms, and was able to get everything to work.

NOTE: My hardware is working. I used the '25320.c' driver to verify this.

Now I'm coming back to the h/w SPI module and I'm trying to get it to work.....and can't. This is just one of those things that I want to make work not because I need it but because I want it.

My almost complete code listing follows. I say almost complete because I'm not including the lcd driver file as it is not relevant.

Code:
#include <18F4680.h>
#device adc=8
#FUSES WDT
#FUSES WDT64                    //Watch Dog Timer uses 1:64 Postscale
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV43                   //Brownout reset at 4.3V
#FUSES PUT                      //Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES BBSIZ4K                  //4K words Boot Block size
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=20000000,RESTART_WDT)

int8 i, j;

// Microchip 25LC320 SPI EEPROM

// /CS:  pin A5
// MISO: pin C5
// MOSI: pin C4
// SCK:  pin C3

#define CHIP_SELECT PIN_A5
#define WREN 0x06 // write enable
#define RDSR 0x05 // read status register
#define WRSR 0x01 // write status register
#define READ_EE 0x03 // read instruction
#define WRITE_EE 0x02 // write instruction

void enable_eeprom_write(void) {
   // send the WREN (write enable) command to EEPROM
   output_low(CHIP_SELECT);
   spi_write(WREN);
   output_high(CHIP_SELECT);
}

int1 check_eeprom_status(void) {
   int8 data;
   // checks the status of the WIP (write in progress) status bit
   // returns 1 if ready, 0 if not
   output_low(CHIP_SELECT);
   spi_write(RDSR);
   data = spi_read(0);
   output_high(CHIP_SELECT);
   printf(lcd_putc,"\nStatus = %u",data);
   return (!bit_test(data, 0));
}

void init_eeprom(void) {
   // initializes the block protect bits in the eeprom's status register
   enable_eeprom_write();
   
   output_low(CHIP_SELECT);
   spi_write(WRSR);
   spi_write(0x80); // sets bank protect bits to 0, and enables external WP line
   output_high(CHIP_SELECT);
}

void write_byte_to_eeprom(int16 address, int8 data) {
   int1 eeprom_ready;
   // check status and keep looping until it is ready
   eeprom_ready = check_eeprom_status();
   while(!eeprom_ready) {
      restart_wdt();
      eeprom_ready = check_eeprom_status();
   }
   
   // eeprom no longer busy, so enable writes
   enable_eeprom_write();
   
   output_low(CHIP_SELECT);
   spi_write(WRITE_EE);
   spi_write(address >> 8); // address MSB
   spi_write(address); // address LSB
   spi_write(data);
   output_high(CHIP_SELECT);
}

int8 read_data_from_eeprom(int16 address) {
   int8 data;
   int1 eeprom_ready;
   // check status and keep looping until it is ready
   eeprom_ready = check_eeprom_status();
   while(!eeprom_ready) {
      restart_wdt();
      eeprom_ready = check_eeprom_status();
   }
   
   // eeprom no longer busy
   
   output_low(CHIP_SELECT);
   spi_write(READ_EE);
   spi_write(address >> 8); // address MSB
   spi_write(address); // address LSB
   data = spi_read(0);
   output_high(CHIP_SELECT);
   
   return (data);
}

void main() {

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);
   setup_wdt(WDT_ON);
   setup_timer_0(RTCC_OFF);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   setup_oscillator(False);
   
   set_tris_e(0x00);
   lcd_init();
   lcd_putc("\fReady...");
   
   set_tris_a(0x00); // all out
   output_high(PIN_A5); // deselect EEPROM
   
   delay_ms(250);
   
   init_eeprom();
   lcd_putc("\fInit successful");
   restart_wdt();
   write_byte_to_eeprom(0, 0xcc);
   restart_wdt();
   write_byte_to_eeprom(12, 0xab);
     
   lcd_putc("\fData written");
   
   while (TRUE) {
      restart_wdt();
      for (i = 0; i < 20; i++) {
         delay_ms(500);
         j = read_ext_eeprom(i);
         printf(lcd_putc,"\f%x from %u",j,i);
         restart_wdt();
      }
   }
}


Here's the problem....The code hangs in the while (!eeprom_ready) loop because it reads 0xff from the EEPROM. Again, using the routines in the 25320.c driver from CCS, everything works.

What am I missing? Do I have to manually set the CLK and MOSI lines either high or low before I attempt communications with the chip? Do I have to manually set the port direction bits (I thought the MSSP module took control of them)?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Sep 13, 2006 2:19 pm     Reply with quote

Here is a hardware SPI driver for the 25LC640. This should help
you to write a driver for the 25LC320.

The test program fills up the EEPROM with random numbers and then
reads back the data and compares it to the original data. Any errors
found are reported. The dots show the progress in writing or reading.
Example of good output:
Code:

writing................................
reading................................
done


Note: The \WP and \HOLD pins are both connected to +5v.

Here is the test program that calls the driver:
Code:
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define SPI_MODE_0_0 0x4000
#define SPI_MODE_0_1 0x0000
#define SPI_MODE_1_0 0x0010
#define SPI_MODE_1_1 0x4010

/*
// If your hardware SPI pins are different than the
// ones used on the 16F877, then define them here
// and un-comment this section.
#define EEPROM_SELECT PIN_C2
#define EEPROM_CLK    PIN_C3
#define EEPROM_DI     PIN_C5
#define EEPROM_DO     PIN_C4
*/

#include <25LC640_Hardware_SPI.c>

#include <STDLIB.H>
//========================
void main()
{
int8 data;
int8 wrote;
int16 addr;
int16 errors = 0;
     
init_ext_eeprom();
     
// Fill eeprom with random data.
printf("\n\r");
printf("writing");

srand(0x55);

for(addr = 0; addr < EEPROM_SIZE; addr++)
   {
    write_ext_eeprom(addr, (int8)rand());
    if((int8)addr == 0)
       putc('.');
   }

// Read the eeprom and check for errors.
printf("\n\r");
printf("reading");

srand(0x55);

for(addr = 0; addr < EEPROM_SIZE; addr++)
   {
    data = read_ext_eeprom(addr);
    wrote = (int8)rand();
    if(data != wrote)
      {
       printf("%lx: read %x, should be %x\n\r", addr, data, wrote);
       errors++;
       if(errors >= 10)
          break;
      }

    if((int8)addr == 0)
       putc('.');
   }

printf("\n\r");
printf("done\n\r");

while(1);
}



Here is the hardware SPI driver for the 25LC640:
Code:

#ifndef EEPROM_SELECT
#define EEPROM_SELECT PIN_C2
#define EEPROM_CLK    PIN_C3
#define EEPROM_DI     PIN_C5
#define EEPROM_DO     PIN_C4
#endif

#define EEPROM_ADDRESS long int
#define EEPROM_SIZE    8192

void init_ext_eeprom()
{
output_high(EEPROM_SELECT);   
setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_16 );
}

//--------------------------------
int1 ext_eeprom_ready(void)
{
int8 data;

output_low(EEPROM_SELECT);
spi_write(0x05);
data = spi_read(0);
output_high(EEPROM_SELECT);
return(!bit_test(data, 0));
}

//--------------------------------
void write_ext_eeprom(EEPROM_ADDRESS address, BYTE data)
{
while(!ext_eeprom_ready());

output_low(EEPROM_SELECT);
spi_write(0x06);
output_high(EEPROM_SELECT);

output_low(EEPROM_SELECT);
spi_write(0x02);
spi_write(address >> 8);
spi_write(address);
spi_write(data);
output_high(EEPROM_SELECT);
}
//--------------------------------

BYTE read_ext_eeprom(EEPROM_ADDRESS address)
{
int8 data;

while(!ext_eeprom_ready());

output_low(EEPROM_SELECT);
spi_write(0x03);
spi_write(address >> 8);
spi_write(address);

data = spi_read(0);
output_high(EEPROM_SELECT);

return(data);
}
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Wed Sep 13, 2006 2:57 pm     Reply with quote

Solved. Thanks PCM.

The issue is my prototyping board, an ME Labs LAB-X1. It has a socket for an 8 pin DIP SPI EEPROM. It has the MOSI and MISO lines reversed. Confused

I pulled the EEPROM out of the socket and placed it in a separate protoboard and it works just fine now that pin C5 -> EEPROM's SI and pin C4 <- EEPROM's SO.

Geez. All this time wasted for something so simple and so obvious. Reinforced lesson: never trust that a commercial product is wired correctly.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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