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.

Help - Read data from memory (AT89C51 & AT93C46)

Status
Not open for further replies.

Maverickmax

Advanced Member level 1
Joined
Dec 6, 2004
Messages
404
Helped
8
Reputation
16
Reaction score
3
Trophy points
1,298
Activity points
3,689
at93c46 interaction with at89c51

Hello


I am not if my code is correct for reading data from memory. I have attached a read timing diagram. Any help would be greatly appreicated. (Note: I am using AT895C1 to write/read with AT92C46)

Here is my code:


Code:
void read_command(unsigned char ADDRESS)
{
	unsigned char n,i,k,nbit,m,d=0;

	CS=1;  

	//Send 1 twice
	for(i=1; i<=2; i++)
	{
	DIN=1;
	send_clock();	
	}

	DIN=0;
	send_clock();

	n=ADDRESS;

	for(k=1;k<=8;k++)
	{
		nbit= n & 0x80;
		if (nbit != 0)
		DIN=1;
		else
		DIN=0;
		send_clock();
		nbit=nbit <<1;
    }

	for(m=0;m<=8;m++)
	{
	d=d | DOUT;
	d<<1;
	send_clock();
	}

	CS=0;
}
 

Is my code correct or wrong? Please let me know as soon as possible

Kind regards

Maverick Max
 

Hi Maverick Max

you wrote
Code:
for(k=1;k<=8;k++) 
   { 
      nbit= n & 0x80; 
      if (nbit != 0) 
      DIN=1; 
      else 
      DIN=0; 
      send_clock(); 
      nbit=nbit <<1; 
    }

Instead nbit=nbit <<1; don't you think it must be n=n <<1;

Which port of AT89C51 is tied to DOUT of AT93C46 ?
Just because you performed a bitwise operator d=d | DOUT; between an unsigned char and a bit DOUT

Bear in mind that Output data changes are synchronized with the rising edges of serial clock SK. It should be noted that a dummy bit (logic “0”) precedes the 8- or 16-bit data output string (I know you did that because the "m" starts from 0 instead of 1 in the second for loop).
 

    Maverickmax

    Points: 2
    Helpful Answer Positive Rating
silvio said:
Hi Maverick Max

you wrote
Code:
for(k=1;k<=8;k++) 
   { 
      nbit= n & 0x80; 
      if (nbit != 0) 
      DIN=1; 
      else 
      DIN=0; 
      send_clock(); 
      nbit=nbit <<1; 
    }

Instead nbit=nbit <<1; don't you think it must be n=n <<1;

Which port of AT89C51 is tied to DOUT of AT93C46 ?
Just because you performed a bitwise operator d=d | DOUT; between an unsigned char and a bit DOUT

Bear in mind that Output data changes are synchronized with the rising edges of serial clock SK. It should be noted that a dummy bit (logic “0”) precedes the 8- or 16-bit data output string (I know you did that because the "m" starts from 0 instead of 1 in the second for loop).

Oop! Yes, it should be n=n<<1; instead of nbit=nbit<<1;

CS, SK, DIN and DOUT are connected to P3^0, P3^1, P3^2 and P3^3 respectively.

In regards to your last question, are you saying that the DOUT generate logic 0 or 1 when Serial Clock goes high at the same time? Are you insinuateing that the last part of my codes may be wrong? Do I need to improve your code? I look forward to hear your advice asap. By the way I have clicked 'Help me' point for pointing out for my error.

Maverick Max
 

Maverickmax said:
In regards to your last question, are you saying that the DOUT generate logic 0 or 1 when Serial Clock goes high at the same time? Are you insinuateing that the last part of my codes may be wrong?

The last part of your code is OK. Because I didn't know how send_clock(); looks like, I mentioned that the information delivered by AT93C46 through DOUT pin is stable during the rising edge of CK signal.

Regarding my observation to the bitwise operator, I apologize it's my mistake.
Usualy I do bitwise operator with a mask. But I've notice that no matter the position of the bit DOUT (P3^3) it will always fall into LSB of the mask during statement (d=d | DOUT;) with the others bits (up to MSB) padded with "0" logic. Thus your code it's correct (just because after d=d | DOUT; follows d<<1;
 

Hi Silivo

send_clock() would look like:

Code:
void send_clock()
{
    PULSE_CLOCK=1;
    PULSE_CLOCK=0;
}

Would you write the code different from mine? In order to improve my programming skill.

By the way, my codes will write simple number, let say five, into my memory device. Then it read the content of memory at the first address from memory and send the content to P1 which automatically set any eight of LEDs on such as 0000110 which help me to know that it works or not. Wish me a good luck.....

Maverick Max


I will update my progress
 

Here is my updated software.....

Who ever spot my error, will be donated with whopping 20 points!!!

Code:
// header files
#include "main.h"
#include "port.h"
#include "delay_loop.h"

//global variables



//Function Prototypes

void write_command(unsigned char DATA);
void read_command(unsigned char ADDRESS);

void send_clock();
void process(unsigned char byte);
void EW_enable();
void EW_disable();
//void Erase_command();


void send_clock()
{
	PULSE_CLOCK=1;
	PULSE_CLOCK=0;
}

void process(unsigned char byte)
{
	unsigned char k,nbit;
	
	for(k=1;k<=8;k++)
	
	{
		nbit= byte & 0x80;
		if (nbit != 0)
		DIN=1;
		else
		DIN=0;
		send_clock();
		byte=byte <<1;
    }
}


void read_command(unsigned char ADDRESS)
{
	unsigned char i,m,d=0,loop=8;

	CS=1;  

	//Send two 1s (Dummies data)
	for(i=1; i<=2; i++)
	{
	DIN=1;
	send_clock();	
	}

	process(ADDRESS);

	for(m=0;m<=8;m++)
	{
	d=d | DOUT;
	send_clock();

		if(loop !=0)
		{
			d=d<<1;
		}
		loop--;
	}

	CS=0;
	CS=1;
	CS=0;

	P1=d;  //Send result to P1 (leds)

}

void write_command(unsigned char DATA)
{
	unsigned char const location=0x00;
	
	CS=1;  

	// Transmit 1,1,0	
	DIN=1;
	send_clock();	
	DIN=0;
	send_clock();
	DIN=1;
	send_clock();	

	process(location); //Select address 
	process(DATA);	  //Write data
	
	CS=0;
	CS=1;
	CS=0;
	
}


void EW_enable()
{

   CS=1;
   DIN=1;
   send_clock();
   DIN=0;
   send_clock();
   process(0x7F); 
   CS=0;
   CS=1;
}


void EW_disable()
{
   CS=1;
   DIN=1;
   send_clock();
   DIN=0;
   send_clock();
   process(0x30); 
   CS=0;
   CS=1;
}
/*
void Erase_command()
{
   CS=1;
   DIN=1;
   send_clock();
   DIN=1;
   send_clock();
   DIN=1;
   send_clock();
   process(0x00); 	 //Erase Data at address 0x00
   CS=0;
   CS=1;
}
*/

void main(void)
{
	int s=1;	

  while(1)
  {
  	if(s==1)
  	{
  		P1=0;
		CS=0;
		DIN=0;
		DOUT=0;
		PULSE_CLOCK=0;

		EW_enable();
		write_command(0xFF);
		Delay_Loop(200);
		read_command(0x00);				//Read data at address 0x00
		EW_disable();
  	}
	s--;
  }

}
 

Since I could not get any message (0xFF) from my 8 LEDs to confirm that the memory device has been read. So I assume that my codes may be wrong but I cannot be certain at this stage. Can you please give me any advice to iron this problem out?

Maverick Max
 

Hi Maverickmax


Here are the mistakes (assuming ORG pin is tied to GND) :

In the main loop DOUT = 1 ( P3^3 should be input port, isn't ? )
In the EW_disable(), process(0x30) shouldn't be process(0x1F) ?

You have used process function for sending both data and address.
But address has 7 bits and data has 8 bits.
Now look at Erase_command() (I know it has been commented out, but..)
You sent 11100000000 (0x700) instead 1110000000 ( 0x380 )
Don't you think that AT93C46 will be a little bit confused regarding your request ?

Thus Erase_command() may look like bellow :
Code:
void Erase_command() 
{ 
   CS=1; 
   DIN=1; 
   send_clock();
   DIN=1; 
   send_clock(); 
   process(0x80);     //Erase Data at address 0x00 
   CS=0; 
   CS=1; 
} 
*/
Same comments for write_command. You sent 10100000000 (0x500) followed by 0xFF as data

You should sent :
1 - Start Bit
01 - Op Code for write
0000000 - Adress A6 - A0
11111111 - Data FF as per your wish

If you want to keep process function for sending both address (7 bits) and data (8 bits), the write_command may look like :
Code:
void write_command(unsigned char DATA) 
{ 
   unsigned char const location=0x80; // the 2nd OP CODE bit is now the MSBit of address 0000000 (7 bits of "0")
    
   CS=1;  

   // Transmit 1,0,1    
   DIN=1; 
   send_clock();    
   DIN=0; 
   send_clock(); 
   // DIN=1; 
   // send_clock();    

   process(location); //Select address 
   process(DATA);     //Write data 
    
   CS=0;   //let's say that minimum tCS is attempt (1 us AT89C51 machine cycle)
   CS=1;   //you can wait now until DOUT goes high as a result of succesful writing 
   CS=0; 
    
}
Why did you choose the "loop' variable inside read_command ?
The for loop isn't enough to retrieve the 8 bits data ?
Did you afraid of the first "0" dummy bit ?
Since you performed left shifting, when the LSB from AT93C46 goes into AT89C51, the first "0" dummy bit has left the "d" variable.
Remeber that you set a counter "m" for the for loop starting from 0 and not 1 (I know you noticed that 9 bits must be retrieved , one dummy "0' bit and 8 data bits)

Last tips : Be selective ! Don't write 0xFF as test just because this is the default erased value.
Choose 0x55 or alternatively 0xAA in order to be sure that the cell has been really written.
 

Hi

I have your comment constructive and I have modifed my codes and I hope it is better than my last one.

Hope you agree with me unless you find more error in my revised code

Code:
// header files
#include "main.h"
#include "port.h"
#include "delay_loop.h"

//global variables

unsigned char const ADDRESS=0xF0;		// 1111000X
unsigned char const DATA=0x55;			// 10101010

//Port configurations

sbit CS = P3^0;
sbit SK = P3^1;
sbit DIN = P3^2;
sbit DOUT = P3^3;
sbit ERROR = P3^4;


//Function Prototypes

void outdata(unsigned char byte, int const loop);
void indata();
void status();
void EW_enable();
void write_command();
void read_command();
void Erase_command();
void EW_disable();

// Transmit data to AT93C46
void outdata(unsigned char byte, int const loop)
{
	unsigned char l,nbit;
	
	for(l=1;l<=loop;l++)
	
	{
		SK=0;		  		// Drop SK
		nbit= byte & 0x80;
		if (nbit != 0)
		DIN=1;
		else
		DIN=0;
		byte=byte <<1;
		SK=1;			   // Raise SK
    }
	SK=0;				   // Drop SK
}

void indata()
{
   	unsigned char m,d=0,cycle=8;

	// Dummy bit (0)
	
	SK=0;
	SK=1;
	if(DOUT == 0)
	{
		for(m=1;m<=9;m++)
		{
			SK=0; // Drop SK
			d=d | DOUT;
		
			if(cycle !=0)
			{
				d=d<<1;
			}
			cycle--;
			SK=1;	 // Raise SK
		}
		SK=0; // Drop SK
		P1=d; // Display 8-bits of DATA
	}
	else
	{
	ERROR=1;
	}
}

// read status after either writing or erasing process
void status()
{
	DOUT=1;	// Float pin
	CS=1;	// Raise CS
	Delay_Loop(100);  // 50uS delay
	if(DIN !=1)
	{
		ERROR=1;	// Display Error
	}
	CS=0;	
}

// Enable Write/Erase Programming mode
void EW_enable()
{
   CS=1;	// Raise CS   
   outdata(0x80,3); // Transmit start bit (1) and op-code (00)
   outdata(0xC0,7);   // Transmit 7 bits of address - 11XXXXX (X - don't care)
   CS=0; // Drop CS
}

void write_command()
{
	CS=1;  // Raise CS
	outdata(0xA0,3); // Transmit start bit (1) and op-code (01)
	outdata(ADDRESS,7);	 // Write 7-bits of address (0xF0- 1111000X)
	outdata(DATA,8);	 // Write DATA - (0x55 - 10101010)
	CS=0;
	status();	
}


void read_command()
{
	CS=1; 
	outdata(0xC0,3); // Transmit dummy bit (1) and op-code (10)
	outdata(ADDRESS,7); // Transmit 7-bits of address (0xF0 - 1111000X)
	indata(); // Read dummy bit (0) and 8 bit of DATA
	CS=0; // Drop CS
}

void Erase_command()
{
	outdata(0xE0,3); // Transmit start bit (1) and dummy bit (11)
	outdata(ADDRESS,7); // Send 7 bits of ADDRESS (0xF0 - 1111000X)
	CS=0;
	status();
}

void EW_disable()
{
   CS=1;	// Raise CS   
   outdata(0x80,3); // Transmit start bit (1) and op-code (00)
   outdata(0x00,7);   // Transmit 7 bits of address - 00XXXXX (X - don't care)
   CS=0; // Drop CS
	
}

void main(void)
{
		int s=1;

		//Output
		P1=0;
		CS=0;
		DIN=0;
		SK=0;
		ERROR=0;

		//Input
		DOUT=1;


		while(1)
		{
			if(s==1)
			{
			EW_enable();
			write_command();
			Delay_Loop(1000);
			read_command();	
			Erase_command();			
			EW_disable();
			}
		//	--s;
		}
}

Max

Added after 2 hours 52 minutes:

It is getting there but I still keep getting slightly error as LEDs display 11010101. It should be 01010101 (0x55).

However when I tried to use data as 0xAA and I get a strange result on LED - 00000000

Maverick Max
 

Hi Maverickmax,

I'm quite sure I'm not a good teacher (in fact it's not my goal to be), but definitely you're a good "student"
I like the introduction of "loop" argument in function outdata and Ready/Busy status check inside status function.
However be aware that the small delay of 50 uS inside status function and the Delay_Loop(1000); between write command and read command it's not enough if you plan to update few memory location shortly one after another.
Bear in mind that wryte cycle time tWP is typical 3 ms and maximum 10 ms starting with the write of the LSBit.
Hence I'm quite sure that after 50 us delay you'll always step over
Code:
if(DIN !=1) 
   { 
      ERROR=1;   // Display Error 
   }

The best solution is to use a TimeOut code (do not wait more than 10 ms inside indata() function if Ready flag didn't came out)

I don't understand why you check the "0" dummy bit at the begining of indata() function.
Are you afraid that AT93C46 will not deliver on DOUT ? Why did you use "cycle" inside indata() function ? It's not nice to use a counter "m" and inside for loop to check "cycle" just because you don't want to shift "d" when "m" get 9
Try this:
Code:
void indata() 
{ 
      unsigned char m,d=0; 

      SK=0;    // Drop SK
      for(m=1;m<=9;m++) // 9 bits including "0" dummy bit
      { 
         SK=1;    // Raise SK, data will be available after max. 250 ns (tPDO)
         d=d<<1;  // make room for the current read bit
         d=d | DOUT;   
         SK=0;    // Drop SK
      } 
      P1=d; // Display 8-bits of DATA 
}
 

silvio said:
Hi Maverickmax,

The best solution is to use a TimeOut code (do not wait more than 10 ms inside indata() function if Ready flag didn't came out)

I am slightly confused with your suggestion regarding time out in the indata() because I think you meant timeout algorithm in outdata function prototype.

You see my comment was actually mistake as it should be 10mS like you said above.

What I would have done in my status function prototype:

Code:
// read status after either writing or erasing process
void status()
{
   unsigned long time_out 160U; // Generate approximately 10mS delay
   DOUT=1;   // Float pin
   CS=1;   // Raise CS
   while((--time_out !=0) && (DOUT!=0));  // Wait for 10mS or Ready (DOUT==1)
   if(DOUT !=1)
   {
      ERROR=1;   // Nofity the current status - Error
   }
  else
 {
     ERROR=0;  // Nofity the current status - Ok
 }
   CS=0;   // Drop CS
}

Maverick Max[/code]

Added after 1 hours 33 minutes:

Here is my updated information:

It seemed that I have forgotten to add CS=1; in Erase_command();

Maverick Max
 

Hi

When I read the Erase command from AT93C46 as shown below:

ERASE (ERASE): The Erase (ERASE) instruction programs all bits in the specified
memory location to the logical “1” state. The self-timed erase cycle starts once the
ERASE instruction and address are decoded. The DO pin outputs the READY/BUSY
status of the part if CS is brought high after being kept low for a minimum of 250 ns (tCS). A logic “1” at pin DO indicates that the selected memory location has been erased, and the part is ready for another instruction.


Am I right that when erase process completes, all of bits in DOUT indicates "1" states?

The reason that I asked about this is that everytime I erase the data and read the same address and 0xFF which is completely opposite to what I expected because I expected to receive 0x00 instead of 0xFF. Unless there is problem in my erase_command function prototype!

Maverick Max[/i]
 

Maverickmax said:
Am I right that when erase process completes, all of bits in DOUT indicates "1" states?

YES. Try to read a "virgin" AT93C46 no matter the address. You'll get 0xFF. This is the default value of an erased memory cell.
 

    Maverickmax

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top