/* $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; } } }