Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

SPI with 8051 and 93C46

Status
Not open for further replies.
increase code memory of 89v51rd2

Hi,
I think your code should work, the leading zeros are acceptable to the chip, so long as DI is not high. Use a pull up to MISO since DO goes tristate at times.

1. You check your device is 93C46 and not 93C46A, the two are slightly different in operation.

2.When you are having hardware SPI, you can send and receive simultaneously 8bits. After writing a desired byte or a dummy byte, always look for SPIF to be true, clear SPIF and read SPIDAT if only required.

3. You can check for ready status after a byte write by sending a zero byte and looking for a nonzero received byte.Reading MISO may not work since the pins are configured as SPI.

4. You can set MISO once only in the beginning if required , mostly even that is not required since configuring as an SPI master will make all SPI bits to their required state. No need to define any output bit in 8051.

5. Check your code carefully.

Regards,
Laktronics
 

93c46 c code void

Hi
I happen to see a application note regarding 93C46 and found that it is a 3 wire serial interface which means DI and DO should be connected together.Which also means MOSI must act as output when writing and as input when reading.I have modified the code to suit this condition.
here it goes(i have given only the read portion)
unsigned char RD_BYTE( char EE_address )
{

unsigned char data1;

SS=0;
SS=1;


SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);

data1=SPI_SlaveReceive();

SS=0;

return data1;
}

unsigned char SPI_SlaveReceive(void)
{
SPI_TX_CHAR(0x00);

/* Wait for reception complete */
while(!(SPSR & (1<<SPSR | 0x80)));
/* Return data register */
MOSI=1;
while(!(SPSR & (1<<SPSR | 0x80)));
return SPDAT;
}
in the main i will be transmitting data1.

Btwn can u suggest any 4 wire serial EEPROM.I think AT25080A/160A or Microchip 25LC080/160 is a good option.Please allow me to donate some points to you because you have really been spending time for me.Thank you.
 

spi transmit byte 8051

Hi,
So far you were on the right track, but now you are deviating from it. 93C46 is always a four wire EEPROM and it can be made three wire ( to save one pin) by shorting the Do and Di pins, you use a resistor in the Do path. But there is no problem in your case since the hardware SPI is always used as four wire. At least Microchip confirms that the leading zeroes of the command will be neglected and I hope it is the same case with other makes also. I there fore think that if you write a proper master SPI program it should work. For checking the ready status, you send an 0x0FF (not Zero as I wrote yesterday) and check the received byte for a nonzero value, instead of reading MISO directly. I am sure it should work alright.

Regards,
Laktronics
 

interfacing 93c46 with 8051

IF i want to use it as a 4 wire i shud connect the ORG to Vcc.then it becomes a 16 bit architecture.Please refer to the datasheet i am attaching in which interface details is explained well.
 

93c46 equivalent

the make of 93C46 is ATMEL and not microchip which is slightly different.in ATMEL make it can be used as 3 wire otherwise we have to configure as 16 bit which will add to our pain only.Moreover i have tried everything but i cant make out why it is not working..
here is my updated code:
unsigned char SPI_SlaveReceive(void)
{

/* Wait for reception complete */
while(!(SPSR & (1<<SPSR | 0x80)));

/* Return data register */



return SPDAT;
}
void RD_BYTE( char EE_address )
{



SS=0;
SS=1;

SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);


SPI_TX_CHAR(0xFF);
P1=P1 | 0x20;
data2=SPI_SlaveReceive();
P1 = (1<<P1_7)|(1<<P1_5)|(1<<P1_4);

SS=0;

DELAY(20);

}

if i try to clear the SPIF flag or poll the status of busy flag the program is getting stuck there.Moreover i did writing and reading between two 89v51rd2 without clearing the SPIF flag and it is working perfectly fine.So i did not clear the SPIF flag.If there is some modifications to the code please let me know.This work is really exceeding its time and i cant guess why but i really cud understand SPI well which is its grey side.
 

93c46 spi interface

Hi Vikky,
I have only experience with Atmel 93C46 and they do operate in 8 bit mode with ORG pin grounded. I have a programmer , which supports these divices in 8 bit mode. I have not tried with leading Zeros since the interface to EEPROMs in the programmer is port bit based and it uses four pin mode only. I will try to change the software to include leading Zeros on Atmel chip and give you a feedback. The acceptability of leading Zeros is mentioned in Microchip data sheet and it sounds logical since a high start bit is required for all commands. Further I believe that all chips with same part number should have same architecture and therefore it should apply for Atmel too, I will try to test it now. All 93C46 ICs as far as I know have ORG pin.

In the mean time, please let me know which C Compiler you are using.

Regards,
Laktronics
 

hardware spi 8051

Hi laktronics,
i do agree that with ORG grounded they operate in 8 bit mode.but DI and DO should be connected together.Please go through the application note which i have attached in my previous post.SO what i did was made MOSI as input after writing the address in the read mode.after reading the data from DI pin i again configured MOSI as output.Should i change anything further in read mode.I am getting undefined data as my O/P.Any change in circuit required??
The compiler i am using is SDCC C compiler.
 

#include<p89v51rd2.h>

Hi Vikky,
From your own App. Note
The ORG (internal ORGanization) pin selects 8 bit data when grounded and 16 bit data when floating or tied to Vcc.... 8bit or 16 bit data may be selected in either the 3-wire or 4-wire configuration
.

So, it clearly shows the selection of 3/4 wire does not affect 8bit/16bit operation.

Another good news for you , Atmel 93C46 does work with leading Zeros on my programmer in 4-WIRE mode. So, it boils down to your software only. Stream line your software keeping the following in mind:

1.You need only one basic full duplex (simultaneous send / receive ) fuction for SPI. All other functions can just call and recall this function with changing data to perform read/erase/ write operations. In your caseCPU is the Master and EEPROM is the slave.

2. Even to receive a byte you need to send a dummy byte and when SPIF is set after sending 8 bits you simply read the byte and clear SPIF. Can't you define SPIF as D7 bit of SPSR and use SPIF for checking the status or clearing it when Set? I do not quite understand your usage of (1<< ...). And, MISO has to be equated to one to make it an input only once in the beginning of the program. There is no special definition to be given for output pins in 8051 as in the case of PIC controllers.

3. Similarly even if you do not want to receive a byte, whenever you send a byte you always receive a byte back and SPIF will be set . You should clear it as otherwise when you really want to read a byte next time you will be mislead with the already set SPIF.

4. I expect that you can send a series of Dummy FFs and read the busy status( as a returned byte) after any write/erase commands. The bytes will be zero when busy and nonzero when ready. However if this logic fails for some reason, you can give the required amount of delay after erase/ write commands before giving any other commands.

Regards,
Laktronics
 

application note atmel 93c46

Thanks a ton...that was a good news...id didnt notice that statement.Now i have taken care of your instructions and modified my code for 4 wire...See if there is anything wrong.Regarding SPIF i cant help it because if i use SPIF directly and control some error is shown in my compiler so i am going for this usage.So back to 4 wire and please check my modified code for 4 wire.
#include<p89v51rd2.h>
#include<delay.h>

#include<uart.h>

#define MOSI P1_5
#define MISO P1_6
#define SCK P1_7
#define SS P1_4

unsigned char DAT,d,data2;


void SPI_MasterInit(void)
{
/* Set MOSI and SCK and SS(-) as output , all others input */
P1 = (1<<P1_7)|(1<<P1_5)|(1<<P1_4);
/* Enable SPI, Master, set clock rate fck/128 */
SPCR = 0x52;

}
unsigned char SPI_TX_CHAR(unsigned char d)
{

SPDAT=d;

while(!(SPSR & (1<<SPSR | 0x80)));


return SPDAT;//Return data register

}//I am using this as a commen function for all my operations


void ERASE()
{
SS=0;
SS=1;
SPI_TX_CHAR(0x03);
SPI_TX_CHAR(0xFF);

SS=0;
//Pulled low between Last DI bit
SS=1;
SS=0;
DELAY(20);
}
void EWDS()
{
SS=0;
SS=1;
SPI_TX_CHAR(0x02);
SPI_TX_CHAR(0x00);
SS=0;

}

void EWEN()
{
SS=0;
SS=1;
// Make sure CS is high
// Start bit is bit1,
SPI_TX_CHAR(0x02);
// 00 is opcode for EWEN
SPI_TX_CHAR(0x60); // 0110 (6) required for
// EWEN 0's are don't cares
SS=0; // for 5 lsb address bits
DELAY(20); // Bring chip select line low to begin
// EEPROM internal write cycle
} // MUST wait 5 ms for internal cycle to complete



void WR_BYTE( char EE_address,char EE_data)
{
SS=0;
SS=1;
EWEN();
SS=0;
SS=1;
// Set chip sele//ct high
SPI_TX_CHAR(0x02); // start bit is bit 1,
// Note: 01 is op-code for write, since everything is right justified
// the 1 falls into the second byte in the leftmost position(bit 7).
// The EE_address must be ORed with b'1000 0000'.

SPI_TX_CHAR( EE_address );

// Address location
SPI_TX_CHAR(EE_data);
SS=0;
SS=1;
// Must set chip select low to start
DELAY(20); // internal programming cycle.
}


void RD_BYTE( char EE_address )
{



SS=0;
SS=1; // Set chip select high
SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);
data2=SPI_TX_CHAR(0xFF);//here i am sending a dummy data and expecting data from EEPROM which i am storing in data2 and displaying in hyperterminal.
TX_CHAR(data2);

SS=0;
DELAY(20);
//return data1;
}

void main()
{
//unsigned char data2;
SS=0;
UART_INIT(9600,0);

SPI_MasterInit();
ERASE();




while(1)
{

WR_BYTE(0x8C,'B');

DELAY(20);
RD_BYTE(0x0C);

TX_CHAR(data2);

}

}

I am getting !!! on my hyperterminal...any correction in this code?

Added after 4 hours 12 minutes:

Hi Laktronics,
Atlast i am able to read something from the EEPROM.Now the new problem is there is a shift.
for eg whenever i try to read K i get %.when i try 2 read V i get +.and for H i get $.If i try to compare it with ascii sheet i found it two characters are sharing the same ascii character and increase is proportional.for eg.j and k are ssharing %.L,M are sharing &.N,O are sharing '.how to get rid of this new problem...any way out??

Added after 1 hours 33 minutes:

Hi Laktronics,
there is an interesting observation....The last bit is not getting inside.
for eg
for letter K the data received must be 01001100 but i am getting 00100101
for letter L the data received must be 01001100 but i am getting 00100110
for letter N the data received must be 01001110 but i am getting 00100111.
the lsb is not fully getting inside.

Added after 55 minutes:

i feel the dummy bit(logical 0)preceding the 8 bit string in the read mode is creating the problem because you can find an extra zero in the MSB which is not needed.Now the question will be how to avoid this zero....I am giving the code below.

#include<p89v51rd2.h>
#include<delay.h>

#include<uart.h>

#define MOSI P1_5
#define MISO P1_6
#define SCK P1_7
#define SS P1_4

unsigned char DAT,d,data2;


void SPI_MasterInit(void)
{
/* Set MOSI and SCK and SS(-) as output , all others input */
P1 = (1<<P1_7)|(1<<P1_5)|(1<<P1_4);
/* Enable SPI, Master, set clock rate fck/128 */
SPCR = 0x50;

}
unsigned char SPI_TX_CHAR(unsigned char d)
{

SPDAT=d;
while(!(SPSR & (1<<SPSR | 0x80)));

SPSR=SPSR & 0x7F;

// Return data register
return SPDAT;

}

void ERASE()
{
SS=0;
SS=1;
SPI_TX_CHAR(0x03);
SPI_TX_CHAR(0xFF);

SS=0;
//Pulled low between Last DI bit
SS=1;
while(MISO==0);
//TX_CHAR('U');
SS=0;
}
void EWDS()
{
SS=0;
SS=1;
SPI_TX_CHAR(0x02);
SPI_TX_CHAR(0x00);
SS=0;

}

void EWEN()
{
SS=0;
SS=1;
// Make sure CS is high
// Start bit is bit1,
SPI_TX_CHAR(0x02);
// 00 is opcode for EWEN
SPI_TX_CHAR(0x60); // 0110 (6) required for
// EWEN 0's are don't cares
SS=0; // for 5 lsb address bits
DELAY(20); // Bring chip select line low to begin
// EEPROM internal write cycle
} // MUST wait 5 ms for internal cycle to complete



void WR_BYTE( char EE_address,char EE_data)
{
SS=0;
SS=1;
EWEN();
SS=0;
SS=1;
// Set chip sele//ct high
SPI_TX_CHAR(0x02); // start bit is bit 1,
// Note: 01 is op-code for write, since everything is right justified
// the 1 falls into the second byte in the leftmost position(bit 7).
// The EE_address must be ORed with b'1000 0000'.

SPI_TX_CHAR( EE_address );

// Address location
SPI_TX_CHAR(EE_data);
SS=0;
SS=1;
while(MISO==0);
//TX_CHAR('S'); // Data
SS=0;
// TX_CHAR('B'); // Must set chip select low to start
DELAY(20); // internal programming cycle.
}


unsigned char RD_BYTE( char EE_address )
{

unsigned char data1;

SS=0;
SS=1; // Set chip select high
SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);
data1=SPI_TX_CHAR(0x00);

SS=0;

return data1;
}

void main()
{
P1_6=1;
unsigned char data2;
SS=0;
UART_INIT(9600,0);

SPI_MasterInit();
ERASE();



while(1)
{


WR_BYTE(0xEF,'K');


data2=RD_BYTE(0x6F);

TX_CHAR(data2);


}



}

Added after 27 minutes:

Hi laktronics,
I have found a solution.but it does not apply to every cases.I am doing a left shift so that a 0 lands up in the last bit and i am getting the right output but this is possible only in even cases.if get a odd number which has a 1 in the last bit this is not possible and i will have the problem facing me.anything coming to your mind?
 

Hi Vikky,
Good work Vikky, I have not been comming back since I could not get a ready solution to your problem and I am sure that it would have helped you to learn things by yourselves.

Now, coming back to your problem, it appears that the system is picking up the leading Zero that precedes the data byte. If you look at the timing diagram on page 44 of the CPU manual, you can see that SPI Mode 0 expects the MISO input to be ready when the clock goes positive, where as the EEPROM shifts out the data after a short delay from the positive edge of the pulse. So, after sending the read command with SPCR=0x52, you change SPCR =0x56 (SPI Mode1) before reading the data byte from EEPROM. This will ensure that the Master strobs data on the falling edge of the clock and by then the EEPROM will output the data to MISO, triggered by the positive edge of the clock. As far as I can see , reloading the SPCR should not affect anything else.

After reading the byte, in the same function set SPCR back to 0x52 before leaving the function.

I hope it should solve your problem.

Regards,
Laktronics
 

Hi Laktronics
i found your guidance very useful.Without i would not have reached so far.Thanks a million for it.Meanwhile i modified my code for transmission.other part of code remains the same.but i am getting a undefined data.see my modification and c if there is any correction.

unsigned char SPI_TX_CHAR(unsigned char d)
{

SPDAT=d;
SPCR=0X56;
while(!(SPSR & (1<<SPSR | 0x80)));

SPSR=SPSR & 0x7F;
SPCR=0X52;
// Return data register
return SPDAT;

}

Added after 17 minutes:

Hi Laktronics
My code is now working perfectly fine thanks to your wonderful idea.In the process i could also learn more.I would be expecting your guidance also in future.
Thank you again for spending your time for me.
 

Hi Vikky,
What ever is working it is all due to your efforts only. I do not quite understand the final modification you have done, I was suggesting you to modify as follows:, and not to modify the basic SPI TX/RX code.

unsigned char RD_BYTE( char EE_address )
{

unsigned char data1;

SS=0;
SS=1; // Set chip select high
SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);

SPCR = 0x56

data1=SPI_TX_CHAR(0x00);

SPCR = 0x52
SS=0;

return data1;

}

Regards,
Laktronics
 

Hi Laktronics,l
later on i wrote the code the same way you wrote.it worked.I didnt post the modified code.Thanks for guiding me.Please keep in touch.
 

Hi,
Good, Thank you for the info.
Regards,
Laktronics
 

Hi Laktronics
there is a small change to the code.I have to bring back to mode 0 in TX/RX code itself otherwise it is not working.The one below is the working one.
unsigned char RD_BYTE( char EE_address )
{

unsigned char data1;

SS=0;
SS=1; // Set chip select high
SPI_TX_CHAR(0x03); // Start bit is bit 1// bit 7 must be 0 - can

SPI_TX_CHAR(EE_address);

SPCR = 0x56

data1=SPI_TX_CHAR(0x00);

SS=0;

return data1;

}
unsigned char SPI_TX_CHAR(unsigned char d)
{

SPDAT=d;

while(!(SPSR & (1<<SPSR | 0x80)));

SPSR=SPSR & 0x7F;
SPCR=0X52;
// Return data register
return SPDAT;

}

I just wanted to give this info

With Thanks & Regards

Vikky
 

Hi Vikky,
I thought both should have the same effect, I do not know why they behave different. If you come to know the answer please let me know.

Regards,
Laktronics
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top