SPI 16F887 SPI1_Read doesn't work

General discussion on mikroC PRO for PIC.
Post Reply
Author
Message
Anoniem
Posts: 6
Joined: 28 Feb 2016 20:54

SPI 16F887 SPI1_Read doesn't work

#1 Post by Anoniem » 06 Apr 2021 16:39

Hello

I have SRAM 23LC1024 chip and I want to write a value to the SRAM chip and then read it.
But it doesn't seem to work...
Can you help?

Here is my code:

sbit Chip_Select at RD2_bit;
sbit Chip_Select_Direction at TRISD2_bit;

unsigned char read_bytes = 0;
const char READ = 0x03;
const char WRITE = 0x02;


void InitMain()
{
Chip_Select_Direction = 0; // Set CS# pin as Output
Chip_Select = 1; // Deselect DAC

SPI1_Init();
//Delay_ms(100);
}

void Write_SRAM(long int Address, unsigned char Data)
{
Chip_Select = 0;
SPI1_Write(WRITE);
SPI1_Write((Address >> 16) & 0xFF); //24 bit adress
SPI1_Write((Address >> 8) & 0xFF);
SPI1_Write(Address & 0xFF);
SPI1_Write(Data);
Chip_Select = 1;
}

int Read_SRAM(long int Address)
{
Chip_Select = 0;
SPI1_Write(READ);

SPI1_Write((Address >> 16) & 0xFF);
SPI1_Write((Address >> 8) & 0xFF);
SPI1_Write(Address & 0xFF);
read_bytes = SPI1_Read(0);

Chip_Select = 1;

return read_bytes;
}

void main()
{
long int Address = 0x000;
unsigned char Data = 0x05;
unsigned char Data2;
unsigned char txt[4];

ANSEL = 0;
ANSELH = 0;
/*
TRISC3_bit = 0; //SCK
TRISC4_bit = 1; //SDI
TRISC5_bit = 0; //SDA
*/
UART1_Init(9600);
delay_ms(100);

InitMain();

Write_SRAM(Address, Data);

Data2 = Read_SRAM(Address);

ByteToStr(Data2, txt);

while (1)
{
UART1_Write(txt);

Delay_ms(1000);
}
}

User avatar
filip
mikroElektronika team
Posts: 11874
Joined: 25 Jan 2008 09:56

Re: SPI 16F887 SPI1_Read doesn't work

#2 Post by filip » 08 Apr 2021 10:00

Hi,

The SPI library fro the 16F887 works OK. maybe there is an issue with the communication with the SRAM 23LC1024.

Regards,
Filip.

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#3 Post by tejcasrejca » 30 Nov 2023 08:15

I know this is old topic ... but anyway I am trying to do the same thing and it does'nt work.
I looked on web for example on how to save and write to SPI eeprom and I found that
you need to write to buffer before data are sent to eeprom.
Does MikroE library takes care of that and I don't need that in my code?
I am using PIC16F1789 and eeprom is ST95020WP.
So this code shoul work:
//RC3 is SCK
//RC4 is SDI
//RC5 is SDO
//RB4 is SS


sbit CS at RB4_bit;
void spi_eeprom_write(unsigned int address,unsigned int value)
{
SPI1_Write(0x02); // write command for writing data
SPI1_Write(address >> 8);
SPI1_Write(address);
SPI1_Write(value); //write value
CS = 1; // disable
}

unsigned char spi_eeprom_read(unsigned int address) //
{
CS = 0; // enable
SPI1_Write(0x03); // write instruction for read data
SPI1_Write(address >> 8);
SPI1_Write(address);
value = SPI1_Read(0); //read byte
CS = 1; // disable
return value;
}

Thank you for your ansver.
Last edited by tejcasrejca on 01 Dec 2023 08:55, edited 1 time in total.

User avatar
IvanJeremic
mikroElektronika team
Posts: 316
Joined: 05 Sep 2022 14:32

Re: SPI 16F887 SPI1_Read doesn't work

#4 Post by IvanJeremic » 30 Nov 2023 09:48

Hi,

Did you initialize the SPI before calling the write and read functions?

You can see from the previous answer how he used the SPI interface.

You can also find in the help section in the compiler how to use the SPI functions.

There are also some example in the project explorer.

Regards,

Ivan.

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#5 Post by tejcasrejca » 01 Dec 2023 10:05

It is best if I show you all of my code for testing.

//PIC16F1789 and ST95020 SPI eeprom
//RC3 is SCK to Pin 6 on ST95020
//RC4 is SDI to Pin 2 on ST95020
//RC5 is SDO to Pin 5 on ST95020
//RB4 is SS to Pin 1 on ST95020
//WP and HOLD on ST95020 are tied to +5V

#include "__T6963C.h"
sbit T6963C_ctrlcd at RE2_bit; // CD command/data signals pin8 PIC RE2
sbit T6963C_ctrlrd at RA7_bit; // RD read signal pin 6 PIC RA7
sbit T6963C_ctrlwr at RA6_bit; // WR write signal pin 5 PIC RA6
sbit T6963C_ctrlrst at RE1_bit; // RST reset signal pin 10 prej RC4
sbit T6963C_ctrlcd_Direction at TRISE2_bit; // CD command/data signal
sbit T6963C_ctrlrd_Direction at TRISA7_bit; // RD read signal
sbit T6963C_ctrlwr_Direction at TRISA6_bit; // WR write signal
sbit T6963C_ctrlrst_Direction at TRISE1_bit; // RST reset signal
// Signals not used by library, they are set in main function
sbit T6963C_ctrlce at RE0_bit; // CE signal pin 7 PIC RE0
sbit T6963C_ctrlfs at RC0_bit; // FS signal pin 19 PIC RC0
sbit T6963C_ctrlce_Direction at TRISE0_bit; // CE signal direction
sbit T6963C_ctrlfs_Direction at TRISC0_bit; // FS signal direction

sbit CS at RB4_bit;

int stevec, tlong, value, address;

void spi_eeprom_write(unsigned int address,unsigned int value)
{
CS = 0; // enable
SPI1_Write(0x02); // write command for writing data
SPI1_Write(address >> 8);
SPI1_Write(address);
SPI1_Write(value); //write value
CS = 1; // disable
}

unsigned char spi_eeprom_read(unsigned int address) //
{
CS = 0; // enable
SPI1_Write(0x03); // write instruction for read data
SPI1_Write(address >> 8);
SPI1_Write(address);
value = SPI1_Read(0); //read byte
CS = 1; // disable
return value;
}


void main() {
OSCCON = 0b11111000; //16MHz internal oscilator
CM1CON0 = 0x00; // Disable comparators
CM1CON1 = 0x00;
CM2CON0 = 0x00;
CM2CON1 = 0x00;
CM3CON0 = 0x00;
CM3CON1 = 0x00;
DAC1CON0 = 0x00;
DAC1CON1 = 0x00;

PORTA = 0b00111111;
TRISA = 0b00111111;
PORTB = 0b11000000;
TRISB = 0b11000000;

PORTC = 0b11010000;
TRISC.RC0 = 0; // output signal FS for LCD
TRISC.RC1 = 0; // output for PWM2
TRISC.RC2 = 0; // output for PWM1
TRISC.RC3 = 0; // SCL as output
TRISC.RC4 = 1; // SDI as input
TRISC.RC5 = 0; // SDO ničla ker je nastavljen kot izhod
TRISC.RC6 = 1; // input for key
TRISC.RC7 = 1; // input for key

TRISD = 0x00; // Port D as output
PORTE = 0b00001000;
TRISE = 0b00001000; // Port E as input

ANSELA = 0b00000000; // no analog inputs
ANSELB = 0b00000000;
ANSELC = 0b00000000;
ANSELD = 0b00000000;
ANSELE = 0x00;
APFCON1 = 0b00000000;
APFCON2 = 0b00000100; // SS on pin RB4

T6963C_ctrlce_Direction = 0;
T6963C_ctrlce = 0; // Enable T6963C
T6963C_ctrlfs_Direction = 0; // set font
T6963C_ctrlfs = 0;
delay_ms(1);
T6963C_init(240, 64, 8); // Initialize T6963C
T6963C_text(1);
T6963C_cursor(0); // cursor = off
T6963C_panelFill(0); //Clear LCD screen

value = 28; //some randome value for testing
address = 0;

SPI1_Init();

spi_eeprom_write(0x58, value); //some random address for testing
delay_ms(10);

while (1) {
stevec = spi_eeprom_read(0x58); //save to stevec

tlong = stevec / 10;
T6963C_write_char(48+tlong, 10, 0, T6963C_ROM_MODE_XOR);
tlong = stevec % 10;
T6963C_write_char(48+tlong, 11, 0, T6963C_ROM_MODE_XOR);
}
}

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#6 Post by tejcasrejca » 19 Dec 2023 20:50

Can anyone help me with this?

User avatar
IvanJeremic
mikroElektronika team
Posts: 316
Joined: 05 Sep 2022 14:32

Re: SPI 16F887 SPI1_Read doesn't work

#7 Post by IvanJeremic » 21 Dec 2023 16:40

Hi,

Sorry for the delay.

You can take a look at the examples for the clicks below:
https://www.mikroe.com/eeprom-2-click
https://www.mikroe.com/eeprom-4-click
https://www.mikroe.com/eeprom-7-click

They should be similar to what you are trying to do.

Regards,

Ivan.

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#8 Post by tejcasrejca » 27 Dec 2023 16:33

Thoose are for mikrobus examples and are totaly different from help file.
Is there and other example for storing a single variable on external eeprom?
For I2C you have beatifull example and know how to use it.

Tejca

User avatar
IvanJeremic
mikroElektronika team
Posts: 316
Joined: 05 Sep 2022 14:32

Re: SPI 16F887 SPI1_Read doesn't work

#9 Post by IvanJeremic » 28 Dec 2023 12:40

Hi,

The MikroBUS does not change much, SPI initialized just like when using some other header.

Also i found this code, maybe it will be of help to you:

Code: Select all

/*
        SPI_EEPROM.C
        SPI EEPROM LIBRARY FOR 25LC** SERIES EEPROMS

        If #HOLD not used, set #define NOTHOLD = 0
        
        SPI inits:  I make a habit of setting SPI in every routine
        as I have many SPI devices on my bus. I use all SPI_Read()'s
        because they are queued up, as SPI_Write()'s can overwrite
        each other.
        
        I insert asm_nop's for breakpoints for debugging


        ** STRUCTURE / ARRAY FUNCTIONS **
        These routines let you copy an entire structure to/from
        the spi_eeprom with one command.  For large structs/arrays
        THIS CAN TAKE TIME! We must write ONE byte at a time &
        allow EEPROM to finish it's write!
        
        Since we want to read/write ONE BYTE at a time, we have
        declared a "char *" as the pointer to the variable:

          void spi_eeprom_array_xxxxx(char *ptr,int num,int addr)

        So this means we have to typecast the address we pass
        to routines as a CHAR* (pointer to ONE BYTE). We typecast
        the address by using syntax (char*)(&variable).

        PARAMETERS:
        pointer to object (&foo = address of 1st byte of foo)
        number of bytes (using 'sizeof' will always be correct!)
        address to write to (up to you to keep from overlapping!)

        STRUCTURES/ARRAYS
        EXAMPLE: a structure with any data (even other structs)
        
        struct FOO
        {
               char proportional_val;
               char offset_val;
               float pid_val;
               int whatmeworry[10];
        }foo;

        // store starting at EEPROM address 0
        spi_eeprom_write_array((char*)&foo,sizeof(foo),0);
        // read (say on power up to restore all values at once)
        spi_eeprom_read_array((char*)&foo,sizeof(foo),0);

        example: floats to/from eeprom at address 0:
        spi_eeprom_write_array((char*)&floatname,sizeof(float),0);
        spi_eeprom_read_array((char*)&floatname,sizeof(float),0);

*/

#define NOTHOLD  1       // using #hold pin

// for simplicity define the instructions
#define READ      0x03   // read data
#define WRITE     0x02   // Write data
#define WREN      0x06   // Set write enable latch
#define WRDI      0x04   // Reset write enable latch
#define RDSR      0x05   // read STATUS register
#define WRSR      0x01   // write STATUS register

unsigned char val;

// function prototypes (can copy to *.h file)
void spi_eeprom_write_byte(int, unsigned char);
unsigned char spi_eeprom_read_byte(int);
unsigned char spi_eeprom_ready(void);

// define your #CS & #HOLD (if used) here!
sbit  SPI_EEPROM_CS  at RB4_bit;
sbit  SPI_EEPROM_CS_Direction at TRISB4_bit;

#ifdef NOTHOLD
  sbit  SPI_EEPROM_HOLD  at RB3_bit;
  sbit  SPI_EEPROM_HOLD_Direction at TRISB3_bit;
#endif

void spi_eeprom_init(void)
{
      SPI_EEPROM_CS_Direction = 0;   // output
      SPI_EEPROM_CS = 1;             // disable

      // just setting inactive, can implement in each routine if used
      #ifdef NOTHOLD
      SPI_EEPROM_HOLD_Direction = 0; // output
      SPI_EEPROM_HOLD = 1;           // hold active
      #endif
      asm nop;
}


void spi_eeprom_write_byte(int address, unsigned char value)
{
      unsigned char tempchar = 0;
      
      while(spi_eeprom_ready());      // wait if writing

      SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE,
                         _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);

       SPI_EEPROM_CS = 0;             // enable
       tempchar = SPI1_Read(WREN);    // enable write
       SPI_EEPROM_CS = 1;             // disable
       Delay_us(100);
       SPI_EEPROM_CS = 0;             // enable
       //write instruction
       tempchar = SPI1_Read(WRITE);   // write
       // write address
       tempchar = SPI1_Read((unsigned char)address >> 8);
       tempchar = SPI1_Read((unsigned char)address & 0x0F);
       //write byte
       tempchar = SPI1_Read(value);
       SPI_EEPROM_CS = 1;             // disable
       asm nop;
}

unsigned char spi_eeprom_read_byte(int address)
{
      unsigned char tempchar = 0;


      while(spi_eeprom_ready());     // wait if writing

     SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE,
                        _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);

     SPI_EEPROM_CS = 0;             // enable
     tempchar = SPI1_Read(READ);    //write instruction
     // write address
     tempchar = SPI1_Read((unsigned char)address >> 8);
     tempchar = SPI1_Read((unsigned char)address & 0x0F);
     //read byte
     tempchar = SPI1_Read(0);
     SPI_EEPROM_CS = 1;             // disable
     asm nop;
     return tempchar;
}


char spi_eeprom_ready(void)
{
      unsigned char tempchar = 0xFF;  // set to non-zero to be sure we read
                                      // real data (all 0's is normal)

     SPI1_Init_Advanced(_SPI_MASTER_OSC_DIV64, _SPI_DATA_SAMPLE_MIDDLE,
                        _SPI_CLK_IDLE_LOW, _SPI_LOW_2_HIGH);

     SPI_EEPROM_CS = 0;             // enable
     tempchar = SPI1_Read(RDSR);    //write instruction
     tempchar = SPI1_Read(0);       //read byte
     SPI_EEPROM_CS = 1;             // disable
     asm nop;
     if(tempchar & 0x01)            // test WIP bit
     {
          return 1;
     }
     else
     {
          return 0;
     }
}


/************************************
  STRUCT/ARRAY FUNCTIONS
*************************************/
void spi_eeprom_read_array(char *ptr,int num,int addr) 
{
     int count;
     for (count=0;count<num;count++)
     {
        ptr[count]=spi_eeprom_read_byte(addr+count);
     }
     asm nop;   // breakpoint to look at debugger
}

void spi_eeprom_write_array(char *ptr,int num,int addr) 
{
     int count;
     for (count=0;count<num;count++)
     {
        spi_eeprom_write_byte(addr+count,ptr[count]);
     }
     asm nop;   // breakpoint to look at debugger
}
Regards,

Ivan.

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#10 Post by tejcasrejca » 30 Dec 2023 17:25

Thank you for the code.
And quick look at the code something feels unlogical or am I missing something.
Especialy this part. SPI1_Read si for reading and WREN is write enable latch.
tempchar = SPI1_Read(WREN);
Is this OK?

arslanbikmambetov37@gmail.com
Posts: 1
Joined: 05 Jan 2024 10:14

Re: SPI 16F887 SPI1_Read doesn't work

#11 Post by arslanbikmambetov37@gmail.com » 05 Jan 2024 11:18

tejcasrejca wrote:
01 Dec 2023 10:05
value = 28; //some randome value for testing
address = 0;

SPI1_Init();

spi_eeprom_write(0x58, value); //some random address for testing
delay_ms(10);
Hi, according to the datasheet for the used memory chip, I think that there is a need to initialize SPI1_Init() in an advanced mode.

tejcasrejca
Posts: 6
Joined: 16 Dec 2013 16:50

Re: SPI 16F887 SPI1_Read doesn't work

#12 Post by tejcasrejca » 11 Feb 2024 09:01

Hello guys. Sorry it took me so long to write back.
I have finaly made it and it works now.
The biggest problem that I had was with hardware.
JLCPCB made a mistake - I was missing 1,5mm of a track and I totaly overlooked it.
Its a good thing that I have a osciloscope to check if the signals are getting to the eeprom.
The second one was that I have overlooked the size of my eeprom becos it has only 255 byte addresses so
I did'nt need the line (Address >> 8).
This is all I need to write and read to eeprom.

void Write_SPI(int Address, char stevec) {
Chip_Select = 0;
SPI1_Write(WREN);
Chip_Select = 1;
delay_ms(1);
Chip_Select = 0;
SPI1_Write(write);
SPI1_Write(Address);
SPI1_Write(stevec);
Chip_Select = 1;
}

char Read_SPI(int Address) {
Chip_Select = 0;
SPI1_Write(read);
SPI1_Write(Address);
stevec = SPI1_Read(0);
Chip_Select = 1;
return stevec;
}

Anyway thank you all who have tryed to help me and If we ever meet I would buy you a beer.
Cheers

Post Reply

Return to “mikroC PRO for PIC General”