/***************************************************************************/
/* SmartMedia
/* This .c file implements the control algorithm for a SmartMedia (8 MB) card
/* using an EZUSB microcontroller from Cypress (AN2131QC).  This code was based on the assembly source found at:
/*   URL: http://www2s.biglobe.ne.jp/~elm/reports/mpc/report_e.html
/***************************************************************************/

//Assembler directive to create a .SRC file (needed for inline assembly)
//#pragma SRC

#include <ezusb.h>
#include <EZRegs.h>

//SM Commands
#define READ			0x00
#define RESET			0xff
#define WRITE			0x80
#define PROGRAM			0x10
#define STATUS			0x70
#define ERASE1			0x60
#define	ERASE2			0xD0

//Redirected variable names
#define SM_PINS			PINSB
#define SM_CFG			PORTBCFG
#define SM_OE			OEB
#define SM_OUT			OUTB
#define SM_MEM_LOC		0x2000
#define LED_ADDR		0x21


//xdata unsigned char setit _at_ 0x2800;
//idata unsigned char checkit _at_ 0xFF;
//BYTE xdata Digit[] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e };

//Initialized the ports on the EZUSB microcontroller.
void sm_init()
{
	//Setup the ports for programmable i/o
	PORTACFG = 0x00;
	SM_CFG   = 0x00;
	PORTCCFG = 11000011;

	OEA = 0x00;				//Enable: memory data port pins
	SM_OE = 10110011;		//Enable: memory control
	OEC = 00100000;			//Enable: port for CE
	
    //Disable Iso transfers
	//ISODISAB = 1;

	//Initialize the memory control pins.
	SM_OUT = 10110010;

}
	
	

//Future read function with inline assembly.
/*void sm_read()
{
	//Set RE="L"
	OUTB = PINSB & 11101111; 	 
	
	#pragma ASM
	nop
	mov   	DPTR, 0x2800
	movx  	A, @DPTR
	mov		R6, #FFh
	mov		@R6, A
	#pragma ENDASM

	//Set RE="H"
	OUTB = PINSB | 0001000;
}
*/	


/*Read a byte from the SM card*/
unsigned char sm_read()
{
	unsigned char temp;
	SM_OUT = SM_PINS & 11101111;	//Set RE="L"
	OEA = 0x00;
	temp = PINSA;					//Read
	SM_OUT = SM_PINS | 0001000;
	return temp;
}


/*Write a byte to the SM card*/
void sm_write(unsigned char out)
{
	OEA = 0xff;
	PINSA = out;
	SM_OUT = SM_PINS & 11011111;	//Set WE="L"
	//nop?
	SM_OUT = SM_PINS | 00100000;	//Set WE="H"
	return;
}


/*Setup the card to read out the page*/
void sm_rd_page(unsigned char PageL, unsigned char PageH)
{
	//Command Phase
	OUTC = PINSC & 11011111;		//Set CE="L"
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	sm_write(READ);					//Send READ(1) command

	//Address Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS | 00000001;	//Set ALE="H"
	sm_write(0x00);					//Addr 0
	sm_write(PageL);				//Addr 1
	sm_write(PageH);				//Addr 2

	//Data Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	return;
}


/*Setup to SM card to write a page*/
void sm_wr_set (unsigned char PageL, unsigned char PageH)
{
	//Command Phase
	OUTC = PINSC & 11011111;		//Set CE="L"
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"

	sm_write(WRITE);				//Command: 0x80 - write 

	//Address Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS | 00000001;	//Set ALE="H"
	sm_write(0x00);					//Addr 0
	sm_write(PageL);				//Addr 1
	sm_write(PageH);				//Addr 2
	
	//Data Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	return;
}


/* Locks in the page data to the SM card */
void sm_wr_start()
{
	bit flag = 0;
	unsigned char temp;

	//Command Phase
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	sm_write(PROGRAM);				//Command: 0x10 - Program the card

	//Waiting for ready pin.
	while(flag == 0)
	{
		if ( (SM_PINS & 01000000) == (01000000)) {
			flag = 1;
		}
	}

	sm_write(STATUS);				//Command: 0x70

	//Data Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	temp = sm_read();				//
	OUTC = PINSC | 00100000;		//Set CE="H"
	return;
}

//Setup to erase a block of SM memory
void sm_erase (unsigned char PageL, unsigned char PageH) 
{
	unsigned char temp;
	bit flag = 0;

	//Command Phase
	OUTC = PINSC & 11011111;		//Set CE="L"
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	sm_write(ERASE1);				//Command: 0x60 - auto block erase setup
	
	//Address Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS | 00000001;	//Set ALE="H"
	sm_write(PageL);				//Addr 1
	sm_write(PageH);				//Addr 2

	//Command Phase
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	sm_write(ERASE2);				//Command: 0xD0 - erase command

	//Waiting for ready pin.
	while(flag == 0)
	{
		if ( (SM_PINS & 01000000) == (01000000)) {
			flag = 1;
		}
	}

	sm_write(STATUS);				//Command: 0x70h - status command

	//Data Phase
	SM_OUT = SM_PINS & 11111101;	//Set CLE="L"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	temp = sm_read();				//Right now: WHAT IS THE STATUS READ?
	return;
}


//Reset the SM card
void sm_reset()
{
	bit flag = 0;
	OUTC = PINSC & 11011111;		//Set CE="L"

	//Command Phase
	SM_OUT = SM_PINS | 00000010;	//Set CLE="H"
	SM_OUT = SM_PINS & 11111110;	//Set ALE="L"
	sm_write(RESET);				//Command: 0xFF

	//Waiting for ready pin.
	while(flag == 0)
	{
		if ( (SM_PINS & 01000000) == (01000000)) {
			flag = 1;
		}
	}

	OUTC = PINSC | 00100000;		//Set CE="H"
	return;
}

//Send 512 bytes from the EZUSB to the SM card
void sm_rcv512()
{
	int x = 0;

	sm_reset();				  	//reset the card
	sm_erase(0x00,0x00); 	 	//erase block.
	sm_wr_set(0x00,0x00);	  	//prepare to write to card.

	//iterate through 512 bytes = 1 page.
	for (x=0; x <512; x++) {
		sm_write(0x01);
	}

	sm_wr_start();				//commit data.
	return;
}

//Send 512 bytes from the SM card to the EZUSB
void sm_send512()
{
	int x = 0;
	unsigned char save = 0x00;

	sm_rd_page(0x00,0x00);

	//iterate through the 512 bytes = 1 page.
	for (x=0; x <512; x++) {
		save = sm_read();
	}

	OUTA = save;			//OUTPUT save
	return;
}

//Test program to initialize the SM card, send to the SM card and read it back.
void main()
{
	sm_init();
	sm_rcv512();
	sm_send512();
}

