Led Sign with MMC Memory Card
History
At the beginning this project was to buy a led sign to interface with my home automation network. This automation network display information like temperature, wind speed, humidity, etc. I had bought on EBay a LED Sign but when I received it I got a surprise! There was no serial port to program messages... After a couple of days, I look inside to see how it was built. The principle of operation is simple you have just 160 bits shift register with drivers for LEDs. I removed the old CPU from the LED sign and connected a couple of wires to the shift register (column driver) and the row driver to an ATMega128. The main reason why I chose to use an ATMega128 was the need of a large amount of RAM. I decided to use a MMC memory card to store all the messages for 3 reasons: low cost, SPI interface and a lot of space for messages.
Features
|
|
3 Colors messages |
|
|
5 Scrolling speed |
|
|
Serial port for uploading messages |
Pictures
Click to enlarge
|
Surgery |
New CPU Board |
What it's look like |
Sources codes & Schematics
-LED Board Shematic in PDF format
//**************************************
// Moving Sign V:1.0
// Version 1.0 Dec 2003
// Sylvain Bissonnette
//
// Clock : 16Mhz
// Stack : 32
//**************************************
//**************************************
// I N C L U D E
//**************************************
#include <macros.h>
#include <stdlib.h>
#include <iom128v.h>
#include <STRING.H>
//**************************************
// D E F I N E
//**************************************
#define VERSION 10
#define TRUE 0x01
#define FALSE 0x00
#define SERIALPORT PORTA
#define SERIALDDR DDRA
#define SERIALBIT 0x01
#define SERIALCLK 0x02
#define ROWPORT PORTC
#define ROWDDR DDRC
#define SPIDDR DDRB
#define SPIPORT PORTB
#define SPIPIN PINB
#define SCLK 0x02
#define MOSI 0x04
#define MISO 0x08
#define CS 0x01
#define MMCPOWER 0x10
#define RED 0
#define GREEN 1
#define AMBER 2
/*--------------------------------------------------------------------------------------------------
Character generator
This table defines the standard ASCII characters in a 5x7 dot format.
--------------------------------------------------------------------------------------------------*/
static const char FontLookup [][5] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp
{ 0x00, 0x00, 0x2f, 0x00, 0x00 }, // !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
{ 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
{ 0xc4, 0xc8, 0x10, 0x26, 0x46 }, // %
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
{ 0x14, 0x08, 0x3E, 0x08, 0x14 }, // *
{ 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x00, 0x50, 0x30, 0x00 }, // ,
{ 0x10, 0x10, 0x10, 0x10, 0x10 }, // -
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x32, 0x49, 0x59, 0x51, 0x3E }, // @
{ 0x7E, 0x11, 0x11, 0x11, 0x7E }, // A
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F
{ 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M
{ 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // back slash
{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, // ]
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // '
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x0C, 0x52, 0x52, 0x52, 0x3E }, // g
{ 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x20, 0x40, 0x44, 0x3D, 0x00 }, // j
{ 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k
{ 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // p
{ 0x08, 0x14, 0x14, 0x18, 0x7C }, // q
{ 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // y
{ 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, // |
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
{ 0x04, 0x02, 0x04, 0x08, 0x04 }, // ~
{ 0x00, 0x00, 0x36, 0x00, 0x00 }, // ¦
{ 0x0e, 0x51, 0x31, 0x11, 0x08 }, // Ç
{ 0x3c, 0x41, 0x40, 0x21, 0x7c }, // ü
{ 0x38, 0x54, 0x56, 0x55, 0x18 }, // é
{ 0x20, 0x56, 0x55, 0x56, 0x78 }, // â
{ 0x20, 0x55, 0x54, 0x55, 0x78 }, // ä
{ 0x20, 0x55, 0x56, 0x54, 0x78 }, // à
{ 0x08, 0x08, 0x2a, 0x1c, 0x08 }, // Right Arrow (chr 134)
{ 0x0e, 0x51, 0x31, 0x11, 0x08 }, // ç
{ 0x38, 0x56, 0x55, 0x56, 0x18 }, // ê
{ 0x38, 0x55, 0x54, 0x55, 0x18 }, // ë
{ 0x38, 0x55, 0x56, 0x54, 0x18 }, // è
{ 0x00, 0x45, 0x7c, 0x41, 0x00 }, // ï
{ 0x00, 0x46, 0x7d, 0x42, 0x00 }, // î
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 141)
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 142)
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 143)
{ 0x7c, 0x54, 0x56, 0x55, 0x44 }, // É
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 145)
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 146)
{ 0x38, 0x46, 0x45, 0x46, 0x38 }, // ô
{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, // free (chr 148)
{ 0x38, 0x45, 0x46, 0x44, 0x38 }, // ò
{ 0x3c, 0x42, 0x41, 0x22, 0x7c }, // û
{ 0x3c, 0x41, 0x42, 0x20, 0x7c } // ù
};
//**************************************
// P R O T O T Y P E
//**************************************
void main(void);
void GetNextPage(unsigned char First);
void uart1_rx_isr(void);
void Analyse(void);
void TxString(const char *ch);
void TxChar(char ch);
void ClrSCR(void);
void WriteString(int x,const unsigned char *ptr,unsigned char color);
void WriteChar(int ptr,unsigned char ch,unsigned char color);
int DoDisplay(void);
void SendOnBit(void);
void SendOffBit(void);
void Delay_1ms(int Del);
int MMCInit(void);
void MMCInfo(void);
int MMCReadSector(unsigned long lba, unsigned char * s);
int MMCWriteSector(unsigned long lba, unsigned char *s);
unsigned char MMCGet(void);
unsigned char MMCDataToken(void);
void MMCCommand(unsigned char command, unsigned int px, unsigned int py);
unsigned char SpiByte(unsigned char byte);
//******************************************************************
//* Global Variable
//******************************************************************
char Red[512];
char Green[512];
char GreenT[512];
char RedT[512];
int MsgLen;
unsigned char Speed = 3;
unsigned char MaxPage = 0;
unsigned char NewData = FALSE;
char RxBuffer[100];
//**************************************
// M A I N
//**************************************
void main(void)
{
WDR();
WDTCR = 0x0f; // Watch Dog enable
ROWDDR = 0xff;
SERIALDDR |= SERIALBIT + SERIALCLK;
UCSR1B = 0x00; //disable while setting baud rate
UCSR1A = 0x00;
UCSR1C = 0x06;
UBRR1L = 0x33; //set baud rate lo for 19200 at 16Mhz
UBRR1H = 0x00; //set baud rate hi
UCSR1B = 0x98;
SEI();
ClrSCR();
while (MMCInit() != 0);
cstrcpy(&RxBuffer[0],"<99MMC: ~GInit OK ~AVer:1.0>\0");
Analyse();
MMCReadSector(0,&GreenT[0]);
MaxPage = GreenT[0];
GetNextPage(TRUE);
while(1)
{
if (DoDisplay()) GetNextPage(FALSE);
if (NewData == TRUE)
{
Analyse();
NewData = FALSE;
}
WDR();
}
}
//**************************************
// void uart1_rx_isr(void)
//**************************************
#pragma interrupt_handler uart1_rx_isr:31
void uart1_rx_isr(void)
{
static char *Ptr = &RxBuffer[0];
unsigned char ch;
ch = UDR1;
if (Ptr > &RxBuffer[100]) Ptr = &RxBuffer[0];
if (ch == '<') Ptr = &RxBuffer[0];
*Ptr++ = ch;
if (ch == '>') NewData = TRUE;
}
//**************************************
// void Analyse(void)
//**************************************
void Analyse(void)
{
char *Ptr = &RxBuffer[0];
unsigned char Page;
int x = 0;
unsigned char Color = AMBER;
unsigned char Spd = 3;
unsigned char Row;
Row = ROWPORT;
ROWPORT = 0x00;
ClrSCR();
Ptr++;
Page = (((*Ptr)-0x30) * 10) + ((*(Ptr+1)-0x30));
Ptr++;
Ptr++;
if ((Page == 99) && (*Ptr == 'D'))
{
for (x=0;x<512;x++) GreenT[x] = 0x00;
MMCWriteSector(0,&GreenT[0]);
MaxPage = 0;
TxString("Delete ALL\n\r\0");
ROWPORT = Row;
return;
}
if ((Page > 99) || (Page < 0))
{
ROWPORT = Row;
return;
}
if (Page > (MaxPage+1))
{
ROWPORT = Row;
return;
}
while (*Ptr != '>')
{
if (*Ptr == '~')
{
Ptr++;
if (*Ptr == 'R') Color = RED;
if (*Ptr == 'G') Color = GREEN;
if (*Ptr == 'A') Color = AMBER;
if (*Ptr == '1') Spd = 1;
if (*Ptr == '2') Spd = 2;
if (*Ptr == '3') Spd = 3;
if (*Ptr == '4') Spd = 4;
if (*Ptr == '5') Spd = 5;
Ptr++;
}
else WriteChar(x++,*Ptr++,Color);
}
GreenT[510] = Spd;
RedT[510] = (x*6)>>8;
RedT[511] = (x*6);
MMCWriteSector((Page*2)+1, &RedT[0]);
MMCWriteSector((Page*2)+2, &GreenT[0]);
if ((Page > MaxPage) && (Page != 99))
{
for (x=0;x<512;x++) GreenT[x] = 0x00;
GreenT[0] = Page;
MMCWriteSector(0,&GreenT[0]);
MaxPage = Page;
}
ROWPORT = Row;
}
//**************************************
// void TxString(unsigned char *ch)
//**************************************
void TxString(const char *ch)
{
while(*ch != 0x00) TxChar(*ch++);
}
//**************************************
// void TxChar(unsigned char ch)
//**************************************
void TxChar(unsigned char ch)
{
while (!(UCSR1A & 0x20)) WDR(); // Wait for empty transmit buffer
UDR1 = ch; // Write char
}
//**************************************
// void GetNextPage(void)
//**************************************
void GetNextPage(unsigned char First)
{
static int Page = 0;
WDR();
if (First == TRUE) // Retrive the First time init message of status
{
MMCReadSector((99*2)+1, &Red[0]);
MMCReadSector((99*2)+2, &Green[0]);
Speed = Green[510];
MsgLen = (Red[510]<<8) + Red[511];
}
else
{
MMCReadSector((Page*2)+1, &Red[0]);
MMCReadSector((Page*2)+2, &Green[0]);
Speed = Green[510];
if (Speed > 5) Speed = 1;
MsgLen = (Red[510]<<8) + Red[511];
Page++;
if (Page > MaxPage) Page = 0;
}
}
//**************************************
// void ClrSCR(void)
//**************************************
void ClrSCR(void)
{
int i;
for (i=0;i<510;i++)
{
WDR();
RedT[i] = 0x00;
GreenT[i] = 0x00;
}
}
//**************************************
// void WriteString(unsigned char ptr,unsigned char color)
//**************************************
void WriteString(int x,const unsigned char *ptr,unsigned char color)
{
while(*ptr != 0x00) WriteChar(x++,*ptr++,color);
}
//**************************************
// void WriteChar(unsigned char x,unsigned char ch,unsigned char color)
//**************************************
void WriteChar(int x,unsigned char ch,unsigned char color)
{
unsigned char i;
x *= 6;
if (x > 509) return; // Max of 85 char per page 85*6 = 510
for (i=0;i<5;i++)
{
WDR();
if (color == RED) RedT[x++] = FontLookup[ch - 32][i];
if (color == GREEN) GreenT[x++] = FontLookup[ch - 32][i];
if (color == AMBER)
{
RedT[x] = FontLookup[ch - 32][i];
GreenT[x++] = FontLookup[ch - 32][i];
}
}
RedT[x] = 0x00;
GreenT[x++] = 0x00;
}
//**************************************
// void DoDisplay(void)
//**************************************
int DoDisplay(void)
{
unsigned char Row;
unsigned char Col;
unsigned char RowMask;
int i,j;
static int Pos = 80;
char GreenT[80];
char RedT[80];
char SHIFT[160];
WDR();
// Clear Buffer's
for (i=0;i<80;i++)
{
GreenT[i] = 0x00;
RedT[i] = 0x00;
}
// Do Scrolling Right to Left
if (Pos >= 0)
{
j = 0;
for (i=Pos;i<80;i++)
{
GreenT[i] = Green[j];
RedT[i] = Red[j];
j++;
}
}
else
{
j = 0;
for (i=abs(Pos);i<(80+abs(Pos));i++)
{
GreenT[j] = Green[i];
RedT[j] = Red[i];
j++;
}
}
Pos--;
if (Pos < 0-MsgLen)
{
Pos = 80;
return 1;
}
// Append Red & Green to the Real shifting buffer
j = 0;
for (i=0;i<80;i++)
{
if ((!(i % 8)) && (i != 0)) j +=8;
SHIFT[j] = GreenT[i];
SHIFT[j+8] = RedT[i];
j++;
}
// Do the Row/Column display
for (i=0;i<Speed;i++)
{
RowMask = 0x40;
for (Row=0;Row<7;Row++)
{
WDR();
for (Col=0;Col<160;Col++)
{
if ((SHIFT[Col] & RowMask) == RowMask) SendOnBit();
else SendOffBit();
}
ROWPORT = RowMask;
Delay_1ms(1);
ROWPORT = 0x00;
RowMask = RowMask >> 1;
}
}
return 0;
}
//**************************************
// void SendOnBit(void)
//**************************************
void SendOnBit(void)
{
SERIALPORT |= SERIALBIT;
SERIALPORT |= SERIALCLK;
SERIALPORT &= ~SERIALCLK;
}
//**************************************
// void SendOffBit(void)
//**************************************
void SendOffBit(void)
{
SERIALPORT &= ~SERIALBIT;
SERIALPORT |= SERIALCLK;
SERIALPORT &= ~SERIALCLK;
}
//**************************************
// void Delay_1ms(void)
//**************************************
void Delay_1ms(int Del)
{
int i;
while (Del--)
{
for (i=0;i<2000;i++) WDR();
}
}
/*************************************************************
* MMC Init function
*
* - flushes card receive buffer
* - selects card
* - sends the reset command
* - sends the initialization command, waits for card ready
*************************************************************/
int MMCInit(void)
{
unsigned int i;
unsigned char Byte;
SPIDDR = SCLK + MOSI + CS + MMCPOWER;
SPIPORT = 0x00;
Delay_1ms(500);
SPIPORT |= MMCPOWER;
SPIPORT |= CS;
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0); /* enable SPI as master, set clk divider */
Delay_1ms(250);
/* start off with 80 bits of high data with card deselected */
for(i=0;i<10;i++)
SpiByte(0xff);
SPIPORT &= ~CS; /* select card */
/* now send CMD0 - go to idle state */
MMCCommand(0,0,0);
if (MMCGet() != 1)
{
SPIPORT |= CS;
return -1; // MMC Not detected
}
/* send CMD1 until we get a 0 back, indicating card is done initializing */
i = 0xffff;
while ((SpiByte(0xff) != 0) && (--i))
{
MMCCommand(1,0,0);
WDR();
}
if (i == 0)
{
SPIPORT |= CS;
return -2; // Init Fail
}
SPIPORT |= CS;
return 0;
}
/************************************************************
* void MMCInfo(void)
*
* - gets and prints formatted CID and CSD info from card
************************************************************/
void MMCInfo(void)
{
int i;
MMCCommand(10,0,0);
if (MMCDataToken() != 0xfe) TxString("MMC: error during CID read\n\r\0");
else TxString("MMC: CID read\n\r\0");
// Skip 3 byte Manufacturer ID
SpiByte(0xff);
SpiByte(0xff);
SpiByte(0xff);
TxString("MMC: Product Name : ");
for (i=0;i<7;i++) TxChar(SpiByte(0xff));
TxString("\n\r\0");
for (i=0;i<9;i++) SpiByte(0xff); // Read 9 left byte
SPIPORT |= CS;
}
/************************************************************
* int MMCReadSector(unsigned long lba, unsigned char * s)
*
* - reads a sector from the card (512 bytes)
* - takes sector # as param
************************************************************/
int MMCReadSector(unsigned long lba, char *s)
{
unsigned int i;
MMCCommand(17,(lba>>7) & 0xffff, (lba<<9) & 0xffff);
if (MMCDataToken() != 0xfe)
{
SEI();
return -1;
}
for (i=0;i<512;i++) /* read the sector */
{
*s++ = SpiByte(0xff);
}
SpiByte(0xff); /* checksum -> don't care about it for now */
SpiByte(0xff); /* checksum -> don't care about it for now */
SPIPORT |= CS;
return 0;
}
/************************************************************
* int MMCWriteSector(unsigned long lba, unsigned char * s)
*
* - reads a sector from the card (512 bytes)
* - takes sector # as param
************************************************************/
int MMCWriteSector(unsigned long lba, char *s)
{
unsigned int i;
MMCCommand(24, (lba>>7)& 0xffff, (lba<<9)& 0xffff);
if (MMCGet() == 0xff) return -1;
SpiByte(0xfe); // Send Start Byte
for (i=0;i<512;i++) /* read the sector */
{
SpiByte(*s++);
}
SpiByte(0xff); /* checksum -> don't care about it for now */
SpiByte(0xff); /* checksum -> don't care about it for now */
SpiByte(0xff); /* Read "data response byte" */
i = 0xffff;
while ((SpiByte(0xff) == 0x00) && (--i)); /* wait for write finish */
if (i == 0) return -1; // Error
SPIPORT |= CS;
return 0;
}
/************************************************************
* unsigned char MMCGet(void)
*
* - pings the card until it gets a non-0xff value
* - returns one byte of read info
************************************************************/
unsigned char MMCGet(void)
{
unsigned int i = 0xffff;
unsigned char Byte = 0xff;
while((Byte == 0xff) && (--i)) Byte = SpiByte(0xff);
return Byte;
}
/************************************************************
* int MMCDataToken(void)
*
* - pings the card until it gets data token
* - returns one byte of read info (data token)
************************************************************/
unsigned char MMCDataToken(void)
{
unsigned int i = 0xffff;
unsigned char Byte = 0xff;
while((Byte != 0xfe) && (--i)) Byte = SpiByte(0xff);
return Byte;
}
/************************************************************
* void MMCCommand(unsigned char command, unsigned int px, unsigned int py)
*
* - send one byte of 0xff, then issue command + params + (fake) crc
* - eat up the one command of nothing after the CRC
************************************************************/
void MMCCommand(unsigned char command, unsigned int px, unsigned int py)
{
SPIPORT &= ~CS;
SpiByte(0xff);
SpiByte(command | 0x40);
SpiByte((unsigned char)((px >> 8)&0x0ff)); /* high byte of param y */
SpiByte((unsigned char)(px & 0x00ff)); /* low byte of param y */
SpiByte((unsigned char)((py >> 8)&0x0ff)); /* high byte of param x */
SpiByte((unsigned char)(py & 0x00ff)); /* low byte of param x */
SpiByte(0x95); /* correct CRC for first command in SPI */
/* after that CRC is ignored, so no problem with */
/* always sending 0x95 */
SpiByte(0xff);
}
/*****************************************************
* Main SPI routine
* - transmits a byte and receives a byte simultaneously
* - received byte is returned
* - if you only want to read a byte, put a dummy
* (say 0xff) in the transmit slot
****************************************************/
unsigned char SpiByte(unsigned char byte)
{
WDR();
SPDR = byte; /* put byte to send in SPDR, which initiates xmit */
while(!(SPSR & (1<<SPIF)));/* wait for completion */
return SPDR; /* return with byte shifted in from slave */
}