Có anh nào làm giao tiếp MMC/SD dùng SPI1 cho lpc2148 chưa vậy, mình đang làm về cái này mà không biết vì sao ko debug được, còn chạy thì không có tín hiệu gì hết, nó bị lỗi gì trong file startup.s mà không chạy được. Anh em coi code của mình xem có cách nào sửa chữa không, giúp mình với nhé.
code :http://www.mediafire.com/?zz2znwu4zom
mmc.c
mmc.h
startup.s
code :http://www.mediafire.com/?zz2znwu4zom
mmc.c
//------------------------------------------------------------------------------
// MMC.C 20060406 CHG
//------------------------------------------------------------------------------
// Simple read/write interface to MMC/SD cards.
// Uses either SPI0 or SPI1 (SSP) on a Philips LPC2xxx ARM processor
//------------------------------------------------------------------------------
#include <LPC213X.H>
#include "LPC214x.H" // LPC2148 MPU Register
#include "mmc.h"
#include "stdio.h"
#define MMC_CMD_SIZE 6 // The SPI data is 8 bit long, the MMC use 48 bits, 6 bytes
#define MMC_DATA_SIZE 512 // 512 bytes per block (sector)
#define MAX_TIMEOUT 0xFF // just a raw number used for some of the timeout checks..
// Returncodes not currently used/implemented
//#define DATA_TOKEN_TIMEOUT 8
//#define SELECT_CARD_TIMEOUT 9
//#define SET_RELATIVE_ADDR_TIMEOUT 10
#define RS 2
#define RW 3
#define EN 4
#define BUSYBIT 17
#define LCDPORT 14
// khai bao cac ham
void delay(unsigned long count1) ;
int readpinport1(unsigned int portpin);
int outpinport1(unsigned int portpin,unsigned int val);
void WAIT_LCD(void);
void write_nibble(unsigned int pos,unsigned char val);
void WR_LCD( unsigned char TXT,unsigned int RSbit);//RSbit=0 cmd,=1 data
void INT_LCD(void);
void SET_POS(unsigned int pos);
void CLR_LCD (void);
void HOME_LCD (void);
void WR_STR(unsigned char *str);
//void putlcd(unsigned char *hienthi);
/* end pototype section */
void putlcd(unsigned char *hienthi)
{
IODIR0|= 15<<LCDPORT;//set output pin at LCD data bus
IODIR0|=1<<RS; //set output
IODIR0|=1<<RW; //set output
IODIR0|=1<<EN; //set output
INT_LCD();
CLR_LCD();
HOME_LCD();
WR_STR(hienthi);
}
// cac function
//-------------delay-------------------------
void delay(unsigned long count1)
{
while(count1 > 0) {count1--;} // Loop Decrease Counter
}
//-------------read pin function-------------
int readpinport1(unsigned int portpin)
{
unsigned long p;
IODIR0&=~(1<<portpin); //set input
p=IO0PIN; //doc trang thai port 0
p=(p&(1<<portpin))>>portpin;// kiem tra bit p0.5
return (p) ;
}
//----------------write pin------------------
//out
int outpinport1(unsigned int portpin,unsigned int val)
{
// IODIR1|=1<<portpin; //set output
if (val)
IOSET0|=1<<portpin;
else
IOCLR0|=1<<portpin;
return (1) ;
}
//---------------write Nibble byte-----------------
void write_nibble(unsigned int pos,unsigned char val)
{
unsigned long p;
//IODIR1|=15<<pos;//set output pin
p=IO0PIN;
p=(p|15<<pos);
p&= (val<<pos)|(~(15<<pos));
//k=(val<<pos)|(~(15<<pos));
//v= p&k;
IO0PIN=p;
//p&=(~(15<<pos))|(val<<pos) ;
//IO1PIN=p;
}
//----------WAIT_LCD function----------------------
void WAIT_LCD(void)
{
delay(100000);
/*outpinport1(BUSYBIT,1);
outpinport1(RW,1);
outpinport1(EN,1);
outpinport1(RS,0);
while(readpinport1(BUSYBIT));
outpinport1(EN,0);
outpinport1(RW,0);*/
}
//----------write LCD Nibble Mode------------------
void WR_LCD( unsigned char TXT,unsigned int RSbit)
{
unsigned int temp;
outpinport1(RS,RSbit);
outpinport1(RW,0);
//write 4 bit high
outpinport1(EN,1);
temp=(TXT&0xF0)>>4;
write_nibble(LCDPORT,temp);
delay(10000);
outpinport1(EN,0);
//delay(10000);
//write 4 bit low
outpinport1(EN,1);
temp=TXT&0x0F;
write_nibble(LCDPORT,temp);
delay(10000);
outpinport1(EN,0);
WAIT_LCD();
}
//---------------INT LCD Function----------------
void INT_LCD(void)
{
//function set 8 col 2 row, 5x7 dot format,NIBBLE MODE
WR_LCD(0x28,0);
// Dislay ON/OFF CURSOR Shift
// dislay ON, Cursor Underline on, cursor blink off
WR_LCD(0x0E,0);
// increment (dich fai) , Dislay Shift Off
WR_LCD(0x06,0);
}
//-------------CLR LCD fuction---------------------
void CLR_LCD (void)
{
WR_LCD(0x01,0);
}
//------------Home LCD function---------------------
void HOME_LCD (void)
{
WR_LCD(0x02,0);
}
//-------- Set Pos function----------------------------
void SET_POS(unsigned int pos)
{
if (pos<=15)
WR_LCD(0x80+pos-1,0);
else
WR_LCD(0x80+pos+0x40-17,0);
}
//--------Write String to LCD------------------------
void WR_STR(unsigned char *str)
{
while (*str != '\0')
{
WR_LCD(*str,1);
++str;
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//
// Basic SPI functions to transport data to/from the card
//
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//------------------------------------------------------------------------------
// Send a buffer to the card
//------------------------------------------------------------------------------
static void sendMMCSPI(unsigned char *buf, unsigned int Length) {
unsigned char Dummy;
if ( Length == 0 )
return;
#ifdef SPI0
while ( Length != 0 ) {
S0SPDR = *buf;
while ( !(S0SPSR & 0x80) );
Length--;
buf++;
}
Dummy=S0SPDR;
#else
while ( Length != 0 ) {
// as long as TNF bit is set, TxFIFO is not full, I can write
while (!(SSPSR & 0x02));
SSPDR = *buf;
// Wait until the Busy bit is cleared
while (!(SSPSR & 0x04));
Dummy = SSPDR; // Flush the RxFIFO
Length--;
buf++;
}
#endif
return;
}
//------------------------------------------------------------------------------
// SPI Receive Byte, receive one byte only, return Data byte
// (used a lot to check the status from the card)
//------------------------------------------------------------------------------
static unsigned char receiveMMCSPI( void ) {
unsigned char data;
#ifdef SPI0
// write dummy byte out to generate clock, then read data from MISO
S0SPDR = 0xFF;
// Wait until the Busy bit is cleared
while (!(S0SPSR & 0x80));
// Grab the received data
data = S0SPDR;
#else
// write dummy byte out to generate clock, then read data from MISO
SSPDR = 0xFF;
// Wait until the Busy bit is cleared
while (SSPSR & 0x10);
// Grab the received data
data = SSPDR;
#endif
return (data);
}
//------------------------------------------------------------------------------
// SPI Receive, receive a number of bytes
//------------------------------------------------------------------------------
static void receiveBlockMMCSPI(unsigned char *buf, unsigned int Length) {
unsigned int i;
for (i = 0; i < Length; i++) {
*buf = receiveMMCSPI();
buf++;
}
return;
}
//-----------------------------------------------------------------------------
// initMMCSPI()
// Initializes the SPI port for the SD/MMC card
// This function must be called before the initMMC() is called
//-----------------------------------------------------------------------------
void initMMCSPI(void ) {
unsigned char i, Dummy;
// Configure PIN connect block */
// SSEL0/1 is NOT set to SSEL0/1, so enable/disable of the card is total manually done !
#ifdef SPI0
// Using SPI0 which has no FIFO
PINSEL0|= 0x1500; //Enable SPI0 pins (except SSEL)
IO_DIR |= CS;
IO_SET = CS;
S0SPCR = 0x00000020; // Configure as SPI Master
S0SPCCR = 0x00000008; // Set bit timing
Dummy = S0SPDR; // clear the RxFIFO
#else
// Using SPI1 (SSP port) which has a 8 byte FIFO
SSPCR1 = 0x00; // SSP master (off) in normal mode */
PINSEL1 |= 0x00A8; // Enable SPI1 pins (except SSEL)
IO_DIR |= CS;
IO_SET = CS;
// Set PCLK 1/2 of CCLK
VPBDIV = 0x02;
// Set data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15
SSPCR0 = 0x0707;
// SSPCPSR clock prescale register, master mode, minimum divisor is 0x02
SSPCPSR = 0x2;
// Device select as master, SSP Enabled, normal operational mode
SSPCR1 = 0x02;
// clear the RxFIFO
for ( i = 0; i < 8; i++ ) Dummy = SSPDR;
#endif
return;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//
// SD/MMC functions
//
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//------------------------------------------------------------------------------
// Repeatedly reads the MMC until we get the response we want or timeout
//------------------------------------------------------------------------------
static int mmc_response( unsigned char response) {
unsigned int count = 0xFFF;
while((receiveMMCSPI() != response) && count) count--;
if (count == 0)
return 1; // Failure, loop was exited due to timeout
else
return 0; // Normal, loop was exited before timeout
}
//------------------------------------------------------------------------------
// Repeatedly reads the MMC until we get a non-zero value (after
// a zero value) indicating the write has finished and card is no
// longer busy.
//------------------------------------------------------------------------------
static int mmc_wait_for_write_finish(void) {
unsigned int count = 0xFFFF; // The delay is set to maximum considering the longest data block length to handle
unsigned char result = 0;
while((result == 0) && count) {
result = receiveMMCSPI();
count--;
}
if (count == 0)
return 1; // Failure, loop was exited due to timeout
else
return 0; // Normal, loop was exited before timeout
}
//------------------------------------------------------------------------------
// write a block of data based on the length that has been set
// in the SET_BLOCKLEN command.
// Send the WRITE_SINGLE_BLOCK command out first, check the
// R1 response, then send the data start token(bit 0 to 0) followed by
// the block of data. When the data write finishs, the response should come back
// as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating
// that MMC card is in idle state again.
//------------------------------------------------------------------------------
int writeBlockMMC(unsigned int blocknum, unsigned char *Buffer) {
unsigned char Status;
unsigned char CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};
unsigned char MMCStatus = 0;
IO_CLR = CS;
// As we need to send a 32 bit address, we adjust the block number to 512 bytes alignment
// and uses that as the address..
blocknum <<= 9;
CMD[1] = ((blocknum & 0xFF000000) >>24 );
CMD[2] = ((blocknum & 0x00FF0000) >>16 );
CMD[3] = ((blocknum & 0x0000FF00) >>8 );
// send mmc CMD24(WRITE_SINGLE_BLOCK) to write the data to MMC card
sendMMCSPI(CMD, MMC_CMD_SIZE );
// if mmc_response returns 1 then we failed to get a 0x00 response
if((mmc_response(0x00))==1) {
MMCStatus = WRITE_BLOCK_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Set bit 0 to 0 which indicates the beginning of the data block
CMD[0] = 0xFE;
sendMMCSPI(CMD, 1);
// send data
sendMMCSPI(Buffer, MMC_DATA_SIZE );
//Send dummy checksum
// when the last check sum is sent, the response should come back
// immediately. So, check the SPI FIFO MISO and make sure the status
// return 0xX5, the bit 3 through 0 should be 0x05
CMD[0] = 0xFF;
CMD[1] = 0xFF;
sendMMCSPI( CMD, 2 );
Status = receiveMMCSPI();
if ((Status & 0x0F) != 0x05) {
MMCStatus = WRITE_BLOCK_FAIL;
IO_SET = CS;
return MMCStatus;
}
// if the status is already zero, the write hasn't finished yet and card is busy
if(mmc_wait_for_write_finish()==1) {
MMCStatus = WRITE_BLOCK_FAIL;
IO_SET = CS;
return MMCStatus;
}
IO_SET = CS;
receiveMMCSPI();
return 0;
}
//------------------------------------------------------------------------------
// Reads a 512 Byte block from the MMC
// Send READ_SINGLE_BLOCK command first, wait for response 0x00 followed by 0xFE.
// Then call receiveBlockMMCSPI() to read the data block back followed by the checksum.
//------------------------------------------------------------------------------
int readBlockMMC(unsigned int blocknum, unsigned char *Buffer) {
unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
unsigned char MMCStatus = 0;
IO_CLR = CS;
// As we need to send a 32 bit address, we adjust the block number to 512 bytes alignment
// and uses that as the address..
blocknum <<= 9;
CMD[1] = ((blocknum & 0xFF000000) >>24 );
CMD[2] = ((blocknum & 0x00FF0000) >>16 );
CMD[3] = ((blocknum & 0x0000FF00) >>8 );
if (CMD[1]==0x20) {
printf("Hit, CMD[1]=%i\n", CMD[1]);
}
// send MMC CMD17(READ_SINGLE_BLOCK) to read the data from MMC card
sendMMCSPI(CMD, MMC_CMD_SIZE );
// if mmc_response returns 1 then we failed to get a 0x00 response
if((mmc_response(0x00))==1) {
MMCStatus = READ_BLOCK_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// wait for data token
if((mmc_response(0xFE))==1) {
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
IO_SET = CS;
printf("%i::readBlockMMC, blocknum=%i, CMD[1]=%i, CMD[2]=%i, CMD[3]=%i\n", __LINE__, blocknum, CMD[1],CMD[2],CMD[3]);
return MMCStatus;
}
// Get the block of data based on the length
receiveBlockMMCSPI(Buffer, MMC_DATA_SIZE);
// CRC bytes that are not needed
receiveMMCSPI();
receiveMMCSPI();
IO_SET = CS;
receiveMMCSPI();
return 0;
}
//------------------------------------------------------------------------------
// Initialises the MMC into SPI mode and sets block size(512),
// returns 0 on success (card found and initialized)
//------------------------------------------------------------------------------
int initMMC() {
unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
unsigned int i;
unsigned char dummy=0xFF;
unsigned char MMCStatus = 0;
IO_SET = CS;
// initialise the MMC card into SPI mode by sending 80 clks
for(i=0; i<10; i++) sendMMCSPI( &dummy, 1 );
IO_CLR = CS;
// send CMD0(RESET or GO_IDLE_STATE) command, all the arguments are 0x00 for the reset command, precalculated checksum
sendMMCSPI( CMD, MMC_CMD_SIZE );
// if = 1 then there was a timeout waiting for 0x01 from the MMC
if(mmc_response(0x01) == 1) {
MMCStatus = IDLE_STATE_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Send some dummy clocks after GO_IDLE_STATE
IO_SET = CS;
receiveMMCSPI();
IO_CLR = CS;
// must keep sending command until zero response
i = MAX_TIMEOUT;
do {
// send mmc CMD1(SEND_OP_COND) to bring out of idle state
// all the arguments are 0x00 for command one
CMD[0] = 0x41;
CMD[5] = 0xFF;
sendMMCSPI( CMD, MMC_CMD_SIZE );
i--;
} while ((mmc_response(0x00) != 0) && (i>0));
// timeout waiting for 0x00 from the MMC
if (i == 0) {
MMCStatus = OP_COND_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Send some dummy clocks after SEND_OP_COND
IO_SET = CS;
receiveMMCSPI();
IO_CLR = CS;
// send MMC CMD16(SET_BLOCKLEN) to set the block length
CMD[0] = 0x50;
CMD[1] = 0x00; // 4 bytes from here is the block length
// LSB is first
// 00 00 00 10 set to 16 bytes
// 00 00 02 00 set to 512 bytes
CMD[2] = 0x00;
// high block length bits - 512 bytes
CMD[3] = 0x02;
// low block length bits
CMD[4] = 0x00;
// checksum is no longer required but we always send 0xFF
CMD[5] = 0xFF;
sendMMCSPI(CMD, MMC_CMD_SIZE);
if((mmc_response(0x00))==1) {
MMCStatus = SET_BLOCKLEN_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
IO_SET = CS;
receiveMMCSPI();
return 0;
}
int main()
{
unsigned char *buf;
unsigned char *str;
str = "ky thuat may ";
initMMC();
writeBlockMMC(100,str);
readBlockMMC(100, buf);
putlcd(buf);
}
// MMC.C 20060406 CHG
//------------------------------------------------------------------------------
// Simple read/write interface to MMC/SD cards.
// Uses either SPI0 or SPI1 (SSP) on a Philips LPC2xxx ARM processor
//------------------------------------------------------------------------------
#include <LPC213X.H>
#include "LPC214x.H" // LPC2148 MPU Register
#include "mmc.h"
#include "stdio.h"
#define MMC_CMD_SIZE 6 // The SPI data is 8 bit long, the MMC use 48 bits, 6 bytes
#define MMC_DATA_SIZE 512 // 512 bytes per block (sector)
#define MAX_TIMEOUT 0xFF // just a raw number used for some of the timeout checks..
// Returncodes not currently used/implemented
//#define DATA_TOKEN_TIMEOUT 8
//#define SELECT_CARD_TIMEOUT 9
//#define SET_RELATIVE_ADDR_TIMEOUT 10
#define RS 2
#define RW 3
#define EN 4
#define BUSYBIT 17
#define LCDPORT 14
// khai bao cac ham
void delay(unsigned long count1) ;
int readpinport1(unsigned int portpin);
int outpinport1(unsigned int portpin,unsigned int val);
void WAIT_LCD(void);
void write_nibble(unsigned int pos,unsigned char val);
void WR_LCD( unsigned char TXT,unsigned int RSbit);//RSbit=0 cmd,=1 data
void INT_LCD(void);
void SET_POS(unsigned int pos);
void CLR_LCD (void);
void HOME_LCD (void);
void WR_STR(unsigned char *str);
//void putlcd(unsigned char *hienthi);
/* end pototype section */
void putlcd(unsigned char *hienthi)
{
IODIR0|= 15<<LCDPORT;//set output pin at LCD data bus
IODIR0|=1<<RS; //set output
IODIR0|=1<<RW; //set output
IODIR0|=1<<EN; //set output
INT_LCD();
CLR_LCD();
HOME_LCD();
WR_STR(hienthi);
}
// cac function
//-------------delay-------------------------
void delay(unsigned long count1)
{
while(count1 > 0) {count1--;} // Loop Decrease Counter
}
//-------------read pin function-------------
int readpinport1(unsigned int portpin)
{
unsigned long p;
IODIR0&=~(1<<portpin); //set input
p=IO0PIN; //doc trang thai port 0
p=(p&(1<<portpin))>>portpin;// kiem tra bit p0.5
return (p) ;
}
//----------------write pin------------------
//out
int outpinport1(unsigned int portpin,unsigned int val)
{
// IODIR1|=1<<portpin; //set output
if (val)
IOSET0|=1<<portpin;
else
IOCLR0|=1<<portpin;
return (1) ;
}
//---------------write Nibble byte-----------------
void write_nibble(unsigned int pos,unsigned char val)
{
unsigned long p;
//IODIR1|=15<<pos;//set output pin
p=IO0PIN;
p=(p|15<<pos);
p&= (val<<pos)|(~(15<<pos));
//k=(val<<pos)|(~(15<<pos));
//v= p&k;
IO0PIN=p;
//p&=(~(15<<pos))|(val<<pos) ;
//IO1PIN=p;
}
//----------WAIT_LCD function----------------------
void WAIT_LCD(void)
{
delay(100000);
/*outpinport1(BUSYBIT,1);
outpinport1(RW,1);
outpinport1(EN,1);
outpinport1(RS,0);
while(readpinport1(BUSYBIT));
outpinport1(EN,0);
outpinport1(RW,0);*/
}
//----------write LCD Nibble Mode------------------
void WR_LCD( unsigned char TXT,unsigned int RSbit)
{
unsigned int temp;
outpinport1(RS,RSbit);
outpinport1(RW,0);
//write 4 bit high
outpinport1(EN,1);
temp=(TXT&0xF0)>>4;
write_nibble(LCDPORT,temp);
delay(10000);
outpinport1(EN,0);
//delay(10000);
//write 4 bit low
outpinport1(EN,1);
temp=TXT&0x0F;
write_nibble(LCDPORT,temp);
delay(10000);
outpinport1(EN,0);
WAIT_LCD();
}
//---------------INT LCD Function----------------
void INT_LCD(void)
{
//function set 8 col 2 row, 5x7 dot format,NIBBLE MODE
WR_LCD(0x28,0);
// Dislay ON/OFF CURSOR Shift
// dislay ON, Cursor Underline on, cursor blink off
WR_LCD(0x0E,0);
// increment (dich fai) , Dislay Shift Off
WR_LCD(0x06,0);
}
//-------------CLR LCD fuction---------------------
void CLR_LCD (void)
{
WR_LCD(0x01,0);
}
//------------Home LCD function---------------------
void HOME_LCD (void)
{
WR_LCD(0x02,0);
}
//-------- Set Pos function----------------------------
void SET_POS(unsigned int pos)
{
if (pos<=15)
WR_LCD(0x80+pos-1,0);
else
WR_LCD(0x80+pos+0x40-17,0);
}
//--------Write String to LCD------------------------
void WR_STR(unsigned char *str)
{
while (*str != '\0')
{
WR_LCD(*str,1);
++str;
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//
// Basic SPI functions to transport data to/from the card
//
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//------------------------------------------------------------------------------
// Send a buffer to the card
//------------------------------------------------------------------------------
static void sendMMCSPI(unsigned char *buf, unsigned int Length) {
unsigned char Dummy;
if ( Length == 0 )
return;
#ifdef SPI0
while ( Length != 0 ) {
S0SPDR = *buf;
while ( !(S0SPSR & 0x80) );
Length--;
buf++;
}
Dummy=S0SPDR;
#else
while ( Length != 0 ) {
// as long as TNF bit is set, TxFIFO is not full, I can write
while (!(SSPSR & 0x02));
SSPDR = *buf;
// Wait until the Busy bit is cleared
while (!(SSPSR & 0x04));
Dummy = SSPDR; // Flush the RxFIFO
Length--;
buf++;
}
#endif
return;
}
//------------------------------------------------------------------------------
// SPI Receive Byte, receive one byte only, return Data byte
// (used a lot to check the status from the card)
//------------------------------------------------------------------------------
static unsigned char receiveMMCSPI( void ) {
unsigned char data;
#ifdef SPI0
// write dummy byte out to generate clock, then read data from MISO
S0SPDR = 0xFF;
// Wait until the Busy bit is cleared
while (!(S0SPSR & 0x80));
// Grab the received data
data = S0SPDR;
#else
// write dummy byte out to generate clock, then read data from MISO
SSPDR = 0xFF;
// Wait until the Busy bit is cleared
while (SSPSR & 0x10);
// Grab the received data
data = SSPDR;
#endif
return (data);
}
//------------------------------------------------------------------------------
// SPI Receive, receive a number of bytes
//------------------------------------------------------------------------------
static void receiveBlockMMCSPI(unsigned char *buf, unsigned int Length) {
unsigned int i;
for (i = 0; i < Length; i++) {
*buf = receiveMMCSPI();
buf++;
}
return;
}
//-----------------------------------------------------------------------------
// initMMCSPI()
// Initializes the SPI port for the SD/MMC card
// This function must be called before the initMMC() is called
//-----------------------------------------------------------------------------
void initMMCSPI(void ) {
unsigned char i, Dummy;
// Configure PIN connect block */
// SSEL0/1 is NOT set to SSEL0/1, so enable/disable of the card is total manually done !
#ifdef SPI0
// Using SPI0 which has no FIFO
PINSEL0|= 0x1500; //Enable SPI0 pins (except SSEL)
IO_DIR |= CS;
IO_SET = CS;
S0SPCR = 0x00000020; // Configure as SPI Master
S0SPCCR = 0x00000008; // Set bit timing
Dummy = S0SPDR; // clear the RxFIFO
#else
// Using SPI1 (SSP port) which has a 8 byte FIFO
SSPCR1 = 0x00; // SSP master (off) in normal mode */
PINSEL1 |= 0x00A8; // Enable SPI1 pins (except SSEL)
IO_DIR |= CS;
IO_SET = CS;
// Set PCLK 1/2 of CCLK
VPBDIV = 0x02;
// Set data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15
SSPCR0 = 0x0707;
// SSPCPSR clock prescale register, master mode, minimum divisor is 0x02
SSPCPSR = 0x2;
// Device select as master, SSP Enabled, normal operational mode
SSPCR1 = 0x02;
// clear the RxFIFO
for ( i = 0; i < 8; i++ ) Dummy = SSPDR;
#endif
return;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//
// SD/MMC functions
//
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++
//------------------------------------------------------------------------------
// Repeatedly reads the MMC until we get the response we want or timeout
//------------------------------------------------------------------------------
static int mmc_response( unsigned char response) {
unsigned int count = 0xFFF;
while((receiveMMCSPI() != response) && count) count--;
if (count == 0)
return 1; // Failure, loop was exited due to timeout
else
return 0; // Normal, loop was exited before timeout
}
//------------------------------------------------------------------------------
// Repeatedly reads the MMC until we get a non-zero value (after
// a zero value) indicating the write has finished and card is no
// longer busy.
//------------------------------------------------------------------------------
static int mmc_wait_for_write_finish(void) {
unsigned int count = 0xFFFF; // The delay is set to maximum considering the longest data block length to handle
unsigned char result = 0;
while((result == 0) && count) {
result = receiveMMCSPI();
count--;
}
if (count == 0)
return 1; // Failure, loop was exited due to timeout
else
return 0; // Normal, loop was exited before timeout
}
//------------------------------------------------------------------------------
// write a block of data based on the length that has been set
// in the SET_BLOCKLEN command.
// Send the WRITE_SINGLE_BLOCK command out first, check the
// R1 response, then send the data start token(bit 0 to 0) followed by
// the block of data. When the data write finishs, the response should come back
// as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating
// that MMC card is in idle state again.
//------------------------------------------------------------------------------
int writeBlockMMC(unsigned int blocknum, unsigned char *Buffer) {
unsigned char Status;
unsigned char CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};
unsigned char MMCStatus = 0;
IO_CLR = CS;
// As we need to send a 32 bit address, we adjust the block number to 512 bytes alignment
// and uses that as the address..
blocknum <<= 9;
CMD[1] = ((blocknum & 0xFF000000) >>24 );
CMD[2] = ((blocknum & 0x00FF0000) >>16 );
CMD[3] = ((blocknum & 0x0000FF00) >>8 );
// send mmc CMD24(WRITE_SINGLE_BLOCK) to write the data to MMC card
sendMMCSPI(CMD, MMC_CMD_SIZE );
// if mmc_response returns 1 then we failed to get a 0x00 response
if((mmc_response(0x00))==1) {
MMCStatus = WRITE_BLOCK_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Set bit 0 to 0 which indicates the beginning of the data block
CMD[0] = 0xFE;
sendMMCSPI(CMD, 1);
// send data
sendMMCSPI(Buffer, MMC_DATA_SIZE );
//Send dummy checksum
// when the last check sum is sent, the response should come back
// immediately. So, check the SPI FIFO MISO and make sure the status
// return 0xX5, the bit 3 through 0 should be 0x05
CMD[0] = 0xFF;
CMD[1] = 0xFF;
sendMMCSPI( CMD, 2 );
Status = receiveMMCSPI();
if ((Status & 0x0F) != 0x05) {
MMCStatus = WRITE_BLOCK_FAIL;
IO_SET = CS;
return MMCStatus;
}
// if the status is already zero, the write hasn't finished yet and card is busy
if(mmc_wait_for_write_finish()==1) {
MMCStatus = WRITE_BLOCK_FAIL;
IO_SET = CS;
return MMCStatus;
}
IO_SET = CS;
receiveMMCSPI();
return 0;
}
//------------------------------------------------------------------------------
// Reads a 512 Byte block from the MMC
// Send READ_SINGLE_BLOCK command first, wait for response 0x00 followed by 0xFE.
// Then call receiveBlockMMCSPI() to read the data block back followed by the checksum.
//------------------------------------------------------------------------------
int readBlockMMC(unsigned int blocknum, unsigned char *Buffer) {
unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
unsigned char MMCStatus = 0;
IO_CLR = CS;
// As we need to send a 32 bit address, we adjust the block number to 512 bytes alignment
// and uses that as the address..
blocknum <<= 9;
CMD[1] = ((blocknum & 0xFF000000) >>24 );
CMD[2] = ((blocknum & 0x00FF0000) >>16 );
CMD[3] = ((blocknum & 0x0000FF00) >>8 );
if (CMD[1]==0x20) {
printf("Hit, CMD[1]=%i\n", CMD[1]);
}
// send MMC CMD17(READ_SINGLE_BLOCK) to read the data from MMC card
sendMMCSPI(CMD, MMC_CMD_SIZE );
// if mmc_response returns 1 then we failed to get a 0x00 response
if((mmc_response(0x00))==1) {
MMCStatus = READ_BLOCK_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// wait for data token
if((mmc_response(0xFE))==1) {
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
IO_SET = CS;
printf("%i::readBlockMMC, blocknum=%i, CMD[1]=%i, CMD[2]=%i, CMD[3]=%i\n", __LINE__, blocknum, CMD[1],CMD[2],CMD[3]);
return MMCStatus;
}
// Get the block of data based on the length
receiveBlockMMCSPI(Buffer, MMC_DATA_SIZE);
// CRC bytes that are not needed
receiveMMCSPI();
receiveMMCSPI();
IO_SET = CS;
receiveMMCSPI();
return 0;
}
//------------------------------------------------------------------------------
// Initialises the MMC into SPI mode and sets block size(512),
// returns 0 on success (card found and initialized)
//------------------------------------------------------------------------------
int initMMC() {
unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};
unsigned int i;
unsigned char dummy=0xFF;
unsigned char MMCStatus = 0;
IO_SET = CS;
// initialise the MMC card into SPI mode by sending 80 clks
for(i=0; i<10; i++) sendMMCSPI( &dummy, 1 );
IO_CLR = CS;
// send CMD0(RESET or GO_IDLE_STATE) command, all the arguments are 0x00 for the reset command, precalculated checksum
sendMMCSPI( CMD, MMC_CMD_SIZE );
// if = 1 then there was a timeout waiting for 0x01 from the MMC
if(mmc_response(0x01) == 1) {
MMCStatus = IDLE_STATE_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Send some dummy clocks after GO_IDLE_STATE
IO_SET = CS;
receiveMMCSPI();
IO_CLR = CS;
// must keep sending command until zero response
i = MAX_TIMEOUT;
do {
// send mmc CMD1(SEND_OP_COND) to bring out of idle state
// all the arguments are 0x00 for command one
CMD[0] = 0x41;
CMD[5] = 0xFF;
sendMMCSPI( CMD, MMC_CMD_SIZE );
i--;
} while ((mmc_response(0x00) != 0) && (i>0));
// timeout waiting for 0x00 from the MMC
if (i == 0) {
MMCStatus = OP_COND_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
// Send some dummy clocks after SEND_OP_COND
IO_SET = CS;
receiveMMCSPI();
IO_CLR = CS;
// send MMC CMD16(SET_BLOCKLEN) to set the block length
CMD[0] = 0x50;
CMD[1] = 0x00; // 4 bytes from here is the block length
// LSB is first
// 00 00 00 10 set to 16 bytes
// 00 00 02 00 set to 512 bytes
CMD[2] = 0x00;
// high block length bits - 512 bytes
CMD[3] = 0x02;
// low block length bits
CMD[4] = 0x00;
// checksum is no longer required but we always send 0xFF
CMD[5] = 0xFF;
sendMMCSPI(CMD, MMC_CMD_SIZE);
if((mmc_response(0x00))==1) {
MMCStatus = SET_BLOCKLEN_TIMEOUT;
IO_SET = CS;
return MMCStatus;
}
IO_SET = CS;
receiveMMCSPI();
return 0;
}
int main()
{
unsigned char *buf;
unsigned char *str;
str = "ky thuat may ";
initMMC();
writeBlockMMC(100,str);
readBlockMMC(100, buf);
putlcd(buf);
}
//-----------------------------------------------------------------------------
// MMC.H 20060407 CHG
//-----------------------------------------------------------------------------
// Simple read/write interface to MMC/SD cards.
// Uses either SPI0 or SPI1 (SSP) on a Philips LPC2xxx ARM processor
//-----------------------------------------------------------------------------
#ifndef _MMC_H_
#define _MMC_H_
#define IDLE_STATE_TIMEOUT 1
#define OP_COND_TIMEOUT 2
#define SET_BLOCKLEN_TIMEOUT 3
#define WRITE_BLOCK_TIMEOUT 4
#define WRITE_BLOCK_FAIL 5
#define READ_BLOCK_TIMEOUT 6
#define READ_BLOCK_DATA_TOKEN_MISSING 7
//-----------------------------------------------------------------------------
// Define I/O pins for the interface
//-----------------------------------------------------------------------------
#define IO_DIR IODIR0 // The GPIO registers used for accessing the CS pin to the SD Card
#define IO_SET IOSET0
#define IO_CLR IOCLR0
// Educationboard from Embedded Artists
#define CS (1<<20) // P0.11 is CS
// LPC2148 Small board on prototype board from Embedded Artists
//#define CS (1<<22) // P0.22 is CS
// Keil MCB2140
//#define CS (1<<20) // P0.20 is CS
//-----------------------------------------------------------------------------
// Define which SPI port to use
//-----------------------------------------------------------------------------
#define SPI1 // Remove this to use SPI1 (SSP) port instead
//------------------------------------------------------------------------------
// Reads a 512 Byte block from the MMC
// Send READ_SINGLE_BLOCK command first, wait for response 0x00 followed by 0xFE.
// Then call receiveBlockMMCSPI() to read the data block back followed by the checksum.
//------------------------------------------------------------------------------
int readBlockMMC(unsigned int blocknum, unsigned char *Buffer);
//------------------------------------------------------------------------------
// write a block of data based on the length that has been set
// in the SET_BLOCKLEN command.
// Send the WRITE_SINGLE_BLOCK command out first, check the
// R1 response, then send the data start token(bit 0 to 0) followed by
// the block of data. When the data write finishs, the response should come back
// as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating
// that MMC card is in idle state again.
//------------------------------------------------------------------------------
int writeBlockMMC(unsigned int blocknum, unsigned char *Buffer);
//-----------------------------------------------------------------------------
// initMMCSPI()
// Initializes the SPI port for the SD/MMC card
// This function must be called before the initMMC() is called
//-----------------------------------------------------------------------------
void initMMCSPI(void);
//------------------------------------------------------------------------------
// Initialises the MMC into SPI mode and sets block size(512),
// returns 0 on success (card found and initialized)
//------------------------------------------------------------------------------
int initMMC(void);
#endif
// MMC.H 20060407 CHG
//-----------------------------------------------------------------------------
// Simple read/write interface to MMC/SD cards.
// Uses either SPI0 or SPI1 (SSP) on a Philips LPC2xxx ARM processor
//-----------------------------------------------------------------------------
#ifndef _MMC_H_
#define _MMC_H_
#define IDLE_STATE_TIMEOUT 1
#define OP_COND_TIMEOUT 2
#define SET_BLOCKLEN_TIMEOUT 3
#define WRITE_BLOCK_TIMEOUT 4
#define WRITE_BLOCK_FAIL 5
#define READ_BLOCK_TIMEOUT 6
#define READ_BLOCK_DATA_TOKEN_MISSING 7
//-----------------------------------------------------------------------------
// Define I/O pins for the interface
//-----------------------------------------------------------------------------
#define IO_DIR IODIR0 // The GPIO registers used for accessing the CS pin to the SD Card
#define IO_SET IOSET0
#define IO_CLR IOCLR0
// Educationboard from Embedded Artists
#define CS (1<<20) // P0.11 is CS
// LPC2148 Small board on prototype board from Embedded Artists
//#define CS (1<<22) // P0.22 is CS
// Keil MCB2140
//#define CS (1<<20) // P0.20 is CS
//-----------------------------------------------------------------------------
// Define which SPI port to use
//-----------------------------------------------------------------------------
#define SPI1 // Remove this to use SPI1 (SSP) port instead
//------------------------------------------------------------------------------
// Reads a 512 Byte block from the MMC
// Send READ_SINGLE_BLOCK command first, wait for response 0x00 followed by 0xFE.
// Then call receiveBlockMMCSPI() to read the data block back followed by the checksum.
//------------------------------------------------------------------------------
int readBlockMMC(unsigned int blocknum, unsigned char *Buffer);
//------------------------------------------------------------------------------
// write a block of data based on the length that has been set
// in the SET_BLOCKLEN command.
// Send the WRITE_SINGLE_BLOCK command out first, check the
// R1 response, then send the data start token(bit 0 to 0) followed by
// the block of data. When the data write finishs, the response should come back
// as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating
// that MMC card is in idle state again.
//------------------------------------------------------------------------------
int writeBlockMMC(unsigned int blocknum, unsigned char *Buffer);
//-----------------------------------------------------------------------------
// initMMCSPI()
// Initializes the SPI port for the SD/MMC card
// This function must be called before the initMMC() is called
//-----------------------------------------------------------------------------
void initMMCSPI(void);
//------------------------------------------------------------------------------
// Initialises the MMC into SPI mode and sets block size(512),
// returns 0 on success (card found and initialized)
//------------------------------------------------------------------------------
int initMMC(void);
#endif
;/************************************************** ***************************/
;/* STARTUP.S: Startup file for Philips LPC2000 */
;/************************************************** ***************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/************************************************** ***************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2007 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/************************************************** ***************************/
;/*
; * The STARTUP.S code is executed after CPU Reset. This file may be
; * translated with the following SET symbols. In uVision these SET
; * symbols are entered under Options - ASM - Define.
; *
; * REMAP: when set the startup code initializes the register MEMMAP
; * which overwrites the settings of the CPU configuration pins. The
; * startup and interrupt vectors are remapped from:
; * 0x00000000 default setting (not remapped)
; * 0x80000000 when EXTMEM_MODE is used
; * 0x40000000 when RAM_MODE is used
; *
; * EXTMEM_MODE: when set the device is configured for code execution
; * from external memory starting at address 0x80000000.
; *
; * RAM_MODE: when set the device is configured for code execution
; * from on-chip RAM starting at address 0x40000000.
; *
; * EXTERNAL_MODE: when set the PIN2SEL values are written that enable
; * the external BUS at startup.
; */
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
;// <h> Stack Configuration (Stack Sizes in Bytes)
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
;// </h>
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
;// <h> Heap Configuration
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
; VPBDIV definitions
VPBDIV EQU 0xE01FC100 ; VPBDIV Address
;// <e> VPBDIV Setup
;// <i> Peripheral Bus Clock Rate
;// <o1.0..1> VPBDIV: VPB Clock
;// <0=> VPB Clock = CPU Clock / 4
;// <1=> VPB Clock = CPU Clock
;// <2=> VPB Clock = CPU Clock / 2
;// <o1.4..5> XCLKDIV: XCLK Pin
;// <0=> XCLK Pin = CPU Clock / 4
;// <1=> XCLK Pin = CPU Clock
;// <2=> XCLK Pin = CPU Clock / 2
;// </e>
VPBDIV_SETUP EQU 0
VPBDIV_Val EQU 0x00000000
; Phase Locked Loop (PLL) definitions
PLL_BASE EQU 0xE01FC080 ; PLL Base Address
PLLCON_OFS EQU 0x00 ; PLL Control Offset
PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset
PLLSTAT_OFS EQU 0x08 ; PLL Status Offset
PLLFEED_OFS EQU 0x0C ; PLL Feed Offset
PLLCON_PLLE EQU (1<<0) ; PLL Enable
PLLCON_PLLC EQU (1<<1) ; PLL Connect
PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier
PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider
PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status
;// <e> PLL Setup
;// <o1.0..4> MSEL: PLL Multiplier Selection
;// <1-32><#-1>
;// <i> M Value
;// <o1.5..6> PSEL: PLL Divider Selection
;// <0=> 1 <1=> 2 <2=> 4 <3=> 8
;// <i> P Value
;// </e>
PLL_SETUP EQU 1
PLLCFG_Val EQU 0x00000024
; Memory Accelerator Module (MAM) definitions
MAM_BASE EQU 0xE01FC000 ; MAM Base Address
MAMCR_OFS EQU 0x00 ; MAM Control Offset
MAMTIM_OFS EQU 0x04 ; MAM Timing Offset
;// <e> MAM Setup
;// <o1.0..1> MAM Control
;// <0=> Disabled
;// <1=> Partially Enabled
;// <2=> Fully Enabled
;// <i> Mode
;// <o2.0..2> MAM Timing
;// <0=> Reserved <1=> 1 <2=> 2 <3=> 3
;// <4=> 4 <5=> 5 <6=> 6 <7=> 7
;// <i> Fetch Cycles
;// </e>
MAM_SETUP EQU 1
MAMCR_Val EQU 0x00000002
MAMTIM_Val EQU 0x00000004
; External Memory Controller (EMC) definitions
EMC_BASE EQU 0xFFE00000 ; EMC Base Address
BCFG0_OFS EQU 0x00 ; BCFG0 Offset
BCFG1_OFS EQU 0x04 ; BCFG1 Offset
BCFG2_OFS EQU 0x08 ; BCFG2 Offset
BCFG3_OFS EQU 0x0C ; BCFG3 Offset
;// <e> External Memory Controller (EMC)
EMC_SETUP EQU 0
;// <e> Bank Configuration 0 (BCFG0)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG0_SETUP EQU 0
BCFG0_Val EQU 0x0000FBEF
;// <e> Bank Configuration 1 (BCFG1)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG1_SETUP EQU 0
BCFG1_Val EQU 0x0000FBEF
;// <e> Bank Configuration 2 (BCFG2)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG2_SETUP EQU 0
BCFG2_Val EQU 0x0000FBEF
;// <e> Bank Configuration 3 (BCFG3)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG3_SETUP EQU 0
BCFG3_Val EQU 0x0000FBEF
;// </e> End of EMC
; External Memory Pins definitions
PINSEL2 EQU 0xE002C014 ; PINSEL2 Address
PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3,
; D0..31, A2..23, JTAG Pins
PRESERVE8
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup External Memory Pins
IF EF:EXTERNAL_MODE
LDR R0, =PINSEL2
LDR R1, =PINSEL2_Val
STR R1, [R0]
ENDIF
; Setup External Memory Controller
IF EMC_SETUP <> 0
LDR R0, =EMC_BASE
IF BCFG0_SETUP <> 0
LDR R1, =BCFG0_Val
STR R1, [R0, #BCFG0_OFS]
ENDIF
IF BCFG1_SETUP <> 0
LDR R1, =BCFG1_Val
STR R1, [R0, #BCFG1_OFS]
ENDIF
IF BCFG2_SETUP <> 0
LDR R1, =BCFG2_Val
STR R1, [R0, #BCFG2_OFS]
ENDIF
IF BCFG3_SETUP <> 0
LDR R1, =BCFG3_Val
STR R1, [R0, #BCFG3_OFS]
ENDIF
ENDIF ; EMC_SETUP
; Setup VPBDIV
IF VPBDIV_SETUP <> 0
LDR R0, =VPBDIV
LDR R1, =VPBDIV_Val
STR R1, [R0]
ENDIF
; Setup PLL
IF PLL_SETUP <> 0
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55
; Configure and Enable PLL
MOV R3, #PLLCFG_Val
STR R3, [R0, #PLLCFG_OFS]
MOV R3, #PLLCON_PLLE
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
; Wait until PLL Locked
PLL_Loop LDR R3, [R0, #PLLSTAT_OFS]
ANDS R3, R3, #PLLSTAT_PLOCK
BEQ PLL_Loop
; Switch to PLL Clock
MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC)
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
ENDIF ; PLL_SETUP
; Setup MAM
IF MAM_SETUP <> 0
LDR R0, =MAM_BASE
MOV R1, #MAMTIM_Val
STR R1, [R0, #MAMTIM_OFS]
MOV R1, #MAMCR_Val
STR R1, [R0, #MAMCR_OFS]
ENDIF ; MAM_SETUP
; Memory Mapping (when Interrupt Vectors are in RAM)
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control
IF EF:REMAP
LDR R0, =MEMMAP
IF EF:EXTMEM_MODE
MOV R1, #3
ELIF EF:RAM_MODE
MOV R1, #2
ELSE
MOV R1, #1
ENDIF
STR R1, [R0]
ENDIF
; Initialise Interrupt System
; ...
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
IF EF:__MICROLIB
EXPORT __initial_sp
ELSE
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
ENDIF
; Enter the C code
IMPORT __main
LDR R0, =__main
BX R0
IF EF:__MICROLIB
EXPORT __heap_base
EXPORT __heap_limit
ELSE
; User Initial Stack & Heap
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + USR_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
END
;/* STARTUP.S: Startup file for Philips LPC2000 */
;/************************************************** ***************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/************************************************** ***************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2007 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/************************************************** ***************************/
;/*
; * The STARTUP.S code is executed after CPU Reset. This file may be
; * translated with the following SET symbols. In uVision these SET
; * symbols are entered under Options - ASM - Define.
; *
; * REMAP: when set the startup code initializes the register MEMMAP
; * which overwrites the settings of the CPU configuration pins. The
; * startup and interrupt vectors are remapped from:
; * 0x00000000 default setting (not remapped)
; * 0x80000000 when EXTMEM_MODE is used
; * 0x40000000 when RAM_MODE is used
; *
; * EXTMEM_MODE: when set the device is configured for code execution
; * from external memory starting at address 0x80000000.
; *
; * RAM_MODE: when set the device is configured for code execution
; * from on-chip RAM starting at address 0x40000000.
; *
; * EXTERNAL_MODE: when set the PIN2SEL values are written that enable
; * the external BUS at startup.
; */
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
;// <h> Stack Configuration (Stack Sizes in Bytes)
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
;// </h>
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
;// <h> Heap Configuration
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
; VPBDIV definitions
VPBDIV EQU 0xE01FC100 ; VPBDIV Address
;// <e> VPBDIV Setup
;// <i> Peripheral Bus Clock Rate
;// <o1.0..1> VPBDIV: VPB Clock
;// <0=> VPB Clock = CPU Clock / 4
;// <1=> VPB Clock = CPU Clock
;// <2=> VPB Clock = CPU Clock / 2
;// <o1.4..5> XCLKDIV: XCLK Pin
;// <0=> XCLK Pin = CPU Clock / 4
;// <1=> XCLK Pin = CPU Clock
;// <2=> XCLK Pin = CPU Clock / 2
;// </e>
VPBDIV_SETUP EQU 0
VPBDIV_Val EQU 0x00000000
; Phase Locked Loop (PLL) definitions
PLL_BASE EQU 0xE01FC080 ; PLL Base Address
PLLCON_OFS EQU 0x00 ; PLL Control Offset
PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset
PLLSTAT_OFS EQU 0x08 ; PLL Status Offset
PLLFEED_OFS EQU 0x0C ; PLL Feed Offset
PLLCON_PLLE EQU (1<<0) ; PLL Enable
PLLCON_PLLC EQU (1<<1) ; PLL Connect
PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier
PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider
PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status
;// <e> PLL Setup
;// <o1.0..4> MSEL: PLL Multiplier Selection
;// <1-32><#-1>
;// <i> M Value
;// <o1.5..6> PSEL: PLL Divider Selection
;// <0=> 1 <1=> 2 <2=> 4 <3=> 8
;// <i> P Value
;// </e>
PLL_SETUP EQU 1
PLLCFG_Val EQU 0x00000024
; Memory Accelerator Module (MAM) definitions
MAM_BASE EQU 0xE01FC000 ; MAM Base Address
MAMCR_OFS EQU 0x00 ; MAM Control Offset
MAMTIM_OFS EQU 0x04 ; MAM Timing Offset
;// <e> MAM Setup
;// <o1.0..1> MAM Control
;// <0=> Disabled
;// <1=> Partially Enabled
;// <2=> Fully Enabled
;// <i> Mode
;// <o2.0..2> MAM Timing
;// <0=> Reserved <1=> 1 <2=> 2 <3=> 3
;// <4=> 4 <5=> 5 <6=> 6 <7=> 7
;// <i> Fetch Cycles
;// </e>
MAM_SETUP EQU 1
MAMCR_Val EQU 0x00000002
MAMTIM_Val EQU 0x00000004
; External Memory Controller (EMC) definitions
EMC_BASE EQU 0xFFE00000 ; EMC Base Address
BCFG0_OFS EQU 0x00 ; BCFG0 Offset
BCFG1_OFS EQU 0x04 ; BCFG1 Offset
BCFG2_OFS EQU 0x08 ; BCFG2 Offset
BCFG3_OFS EQU 0x0C ; BCFG3 Offset
;// <e> External Memory Controller (EMC)
EMC_SETUP EQU 0
;// <e> Bank Configuration 0 (BCFG0)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG0_SETUP EQU 0
BCFG0_Val EQU 0x0000FBEF
;// <e> Bank Configuration 1 (BCFG1)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG1_SETUP EQU 0
BCFG1_Val EQU 0x0000FBEF
;// <e> Bank Configuration 2 (BCFG2)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG2_SETUP EQU 0
BCFG2_Val EQU 0x0000FBEF
;// <e> Bank Configuration 3 (BCFG3)
;// <o1.0..3> IDCY: Idle Cycles <0-15>
;// <o1.5..9> WST1: Wait States 1 <0-31>
;// <o1.11..15> WST2: Wait States 2 <0-31>
;// <o1.10> RBLE: Read Byte Lane Enable
;// <o1.26> WP: Write Protect
;// <o1.27> BM: Burst ROM
;// <o1.28..29> MW: Memory Width <0=> 8-bit <1=> 16-bit
;// <2=> 32-bit <3=> Reserved
;// </e>
BCFG3_SETUP EQU 0
BCFG3_Val EQU 0x0000FBEF
;// </e> End of EMC
; External Memory Pins definitions
PINSEL2 EQU 0xE002C014 ; PINSEL2 Address
PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3,
; D0..31, A2..23, JTAG Pins
PRESERVE8
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup External Memory Pins
IF EF:EXTERNAL_MODE
LDR R0, =PINSEL2
LDR R1, =PINSEL2_Val
STR R1, [R0]
ENDIF
; Setup External Memory Controller
IF EMC_SETUP <> 0
LDR R0, =EMC_BASE
IF BCFG0_SETUP <> 0
LDR R1, =BCFG0_Val
STR R1, [R0, #BCFG0_OFS]
ENDIF
IF BCFG1_SETUP <> 0
LDR R1, =BCFG1_Val
STR R1, [R0, #BCFG1_OFS]
ENDIF
IF BCFG2_SETUP <> 0
LDR R1, =BCFG2_Val
STR R1, [R0, #BCFG2_OFS]
ENDIF
IF BCFG3_SETUP <> 0
LDR R1, =BCFG3_Val
STR R1, [R0, #BCFG3_OFS]
ENDIF
ENDIF ; EMC_SETUP
; Setup VPBDIV
IF VPBDIV_SETUP <> 0
LDR R0, =VPBDIV
LDR R1, =VPBDIV_Val
STR R1, [R0]
ENDIF
; Setup PLL
IF PLL_SETUP <> 0
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55
; Configure and Enable PLL
MOV R3, #PLLCFG_Val
STR R3, [R0, #PLLCFG_OFS]
MOV R3, #PLLCON_PLLE
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
; Wait until PLL Locked
PLL_Loop LDR R3, [R0, #PLLSTAT_OFS]
ANDS R3, R3, #PLLSTAT_PLOCK
BEQ PLL_Loop
; Switch to PLL Clock
MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC)
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
ENDIF ; PLL_SETUP
; Setup MAM
IF MAM_SETUP <> 0
LDR R0, =MAM_BASE
MOV R1, #MAMTIM_Val
STR R1, [R0, #MAMTIM_OFS]
MOV R1, #MAMCR_Val
STR R1, [R0, #MAMCR_OFS]
ENDIF ; MAM_SETUP
; Memory Mapping (when Interrupt Vectors are in RAM)
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control
IF EF:REMAP
LDR R0, =MEMMAP
IF EF:EXTMEM_MODE
MOV R1, #3
ELIF EF:RAM_MODE
MOV R1, #2
ELSE
MOV R1, #1
ENDIF
STR R1, [R0]
ENDIF
; Initialise Interrupt System
; ...
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
IF EF:__MICROLIB
EXPORT __initial_sp
ELSE
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
ENDIF
; Enter the C code
IMPORT __main
LDR R0, =__main
BX R0
IF EF:__MICROLIB
EXPORT __heap_base
EXPORT __heap_limit
ELSE
; User Initial Stack & Heap
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + USR_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
END
Comment