/* $Id: logger.c 1.4 2003/05/10 01:57:06 leon Exp leon $ */
/*\
SmartMedia logging via serial port with the AT89C2051 at 11.095MHz
Author: Leon Kos, University of Ljubljana
Compiler: KEIL C 5.0
CODE size: approx 1700 bytes
DATA Size: 23 bytes + stack + 1 bit
64MBytes or more of ASCII log space.
We assume that SmartMedia device is error free :-).
Check 5th byte in spare area for each block to be sure.
Logger works as pass-through serial ascii logger. No flow
control is assumed. Note that at speeds higher then 9600 baud
framing error can occur! I suggest serial RX/TX interrupt redesign.
When escape command is received several buffer operation
can be performed.
The following escape commands are recognised:
@I Print usage statistics
@P Print log. Last page is flushed.
@F Fast print log at 57600 baud.
@E Erase log
\*/
#pragma SYMBOLS
#include <reg51.h>
/* Port 3 SmartMedia control pins */
sbit CE_ = 0xB5;
sbit WE_ = 0xB4;
sbit RE_ = 0XB7;
sbit CLE = 0xB2;
sbit ALE = 0xB3;
#if 1 /* 64MB device */
# define PAGES 131072UL
# define BLOCKS 4096
#else /* 128MB device */
# define PAGES 262144UL
# define BLOCKS 8192
#endif
#define PAGE 528 /* We use also spare area for storage */
#define WRITE(x) {WE_ = 0; P1 = (x); WE_ = 1;}
#define PUTCHAR(c) {while (!TI); TI = 0; SBUF = (c);}
void print(char code *msg)
{
while (*msg)
{
if (*msg == '\n')
PUTCHAR(0x0d);
PUTCHAR(*msg);
msg++;
}
}
void cmd(unsigned char command)
{
CLE = 1;
P1 = command;
WE_ = 0;
WE_ = 1;
CLE = 0;
}
unsigned char status_read(void)
{
unsigned char status;
cmd(0x70);
P1 = 0xff;
RE_ = 0;
status = P1;
RE_ = 1;
return status;
}
void start_address(unsigned long page)
{
ALE = 1;
WRITE(0);
WRITE(page);
WRITE(page>>8);
WRITE(page>>16);
ALE = 0;
}
/* RY/BY and CE_ pin connected together ! */
static void ready_not_busy(void)
{
int i;
CE_ = 1;
for (i = 0; i < 20000; i++)
if (CE_) break;
CE_ = 0;
}
static void print_buffer(void)
{
unsigned long page;
for (page = 0; page < PAGES; page++)
{
int i;
cmd(0x00); /* read the page */
start_address(page);
P1 = 0xff;
ready_not_busy(); /* wait for page transfer */
for (i = 0; i < PAGE; i++)
{
RE_ = 0;
if (P1 == 0xff) /* this is END mark */
{
RE_ = 1;
return;
}
if (P1 != 0x00) /* empty bytes */
PUTCHAR(P1);
RE_ = 1;
}
}
}
/* Fill page with NULs and program it */
void flush(int i)
{
int j;
for (j = i; j < PAGE; j++)
WRITE(0x00);
cmd(0x10);
ready_not_busy();
}
/* Returns first non empty page */
unsigned long append(void)
{
unsigned long page;
for (page = 0; page < PAGES; page++)
{
cmd(0x00); /* read the page */
start_address(page);
P1 = 0xff;
ready_not_busy(); /* wait for page transfer */
RE_ = 0;
if (P1 == 0xff)
{
RE_ = 1;
return page;
}
RE_ = 1;
}
return page; /* overflow ! */
}
void print_long(unsigned long x)
{
char buf[8];
char i = 0;
do /* print long type */
{
buf[i] = x % 10;
x /= 10;
i++;
}
while (x);
while (i--)
PUTCHAR(buf[i] + '0');
}
static void print_info(unsigned long pages)
{
print("\n\nSmartMedia usage information:\n");
print_long(pages);
print(" of total ");
print_long(PAGES);
print(" pages used\n");
pages *= 100;
pages /= PAGES;
print_long(pages);
print("% of pages used\n");
}
void erase_all(void)
{
unsigned int block;
print("Erasing...");
for (block = 0; block < BLOCKS; block++)
{
cmd(0x60); /* Block erase */
ALE = 1;
WRITE(block);
WRITE(block>>8);
WRITE(block>>16);
ALE = 0;
cmd(0xD0);
ready_not_busy();
if (status_read() & 0x01)
PUTCHAR('x');
}
print("DONE\n");
}
#if 0
#include <stdio.h>
static void test_format(void)
{
unsigned int page;
char buf[16];
print("Formating pages...");
for (page = 0; page < 1000; page++)
{
int i;
sprintf(buf, "Page: %04x\r\n", page);
cmd(0x80); /* page program */
start_address(page);
ready_not_busy();
for (i = 0; buf[i]; i++)
WRITE(buf[i]);
for (i = 0; i < PAGE - 12; i++)
WRITE(0x00);
cmd(0x10);
ready_not_busy();
if (status_read() & 0x01)
printf("Failed to program page %04x\n", page);
}
print("DONE\n");
}
#endif
void main()
{
int i;
long page;
bit escape;
/* initialize serial interface */
SCON = 0x50; /* Mode 1: 8bit UART and receiver enable */
PCON &= 0x7F; /* Clear SMOD bit in power ctrl reg */
TMOD &= 0xCF; /* Clear M1 and M0 for timer 1 */
TMOD |= 0x20; /* set M1 for 8 bit autoreload */
TH1 = 0xFD; /* Autoreload value for 9600 baud */
TR1 = 1; /* Start timer 1 */
TI = 1; /* Set transmit indicator to ready */
/* Initialize bus */
CLE = 0;
ALE = 0;
WE_ = 1;
RE_ = 1;
CE_ = 1; /* Chip enable and Ready/Busy pin */
P1 = 0xFF;
CE_ = 0; /* Enable SmartMedia */
cmd(0xFF); /* reset */
ready_not_busy();
page = append();
#if 0
erase_all();
test_format();
print_buffer();
while (1);
#endif
CE_ = 1; /* Disable SmartMedia */
i = 0;
escape = 0; /* escape command received */
while (1)
{
if (RI) /* pull receive buffer */
{
RI = 0;
if (SBUF == '@') /* Escape command issued ? */
{
escape = 1;
continue;
}
if (escape)
{
CE_ = 0;
switch (SBUF)
{
case 'F': /* Fast print */
PCON |= 0x80; /* SMOD = 1; */
TH1 = 0xff; /* 57600 baud */
if (i)
{
flush(i);
page++;
}
print_buffer();
PCON &= 0x7f; /* SMOD = 0; */
TH1 = 0xfd; /* 9600 baud */
i = 0;
break;
case 'P': /* Print */
if (i)
{
flush(i);
page++;
}
print_buffer();
i = 0; /* Start over with new page */
break;
case 'E': /* Erase */
erase_all();
page = 0;
i = 0;
break;
case 'I': /* Print info */
print_info(page);
break;
default:
print("Unknown escape command\n");
}
CE_ = 1;
escape = 0;
continue;
}
while (!TI); /* Wait for transmit to clear */
TI = 0;
SBUF = SBUF; /* Copy RX to TX */
if (page == PAGES)
{
print("\n# SmartMedia logger full!\n");
continue;
}
CE_ = 0;
if (i == 0) /* Begin page write */
{
cmd(0x80);
start_address(page);
ready_not_busy();
}
WRITE(SBUF);
i++;
if (i == PAGE) /* program page */
{
cmd(0x10);
i = 0;
ready_not_busy();
if (status_read() & 0x01)
print("Error programming page!\n");
page ++;
}
CE_ = 1;
}
}
}