又裸奔了两天,把mini2440上面的nandflash(型号是K9F1G08U0C 128M*8bit)的简单的页读写和擦除操作调通了,代码先记录下来,复杂的nandflash操作以后有时间再说,现在能够实现代码的搬移已经够了。
head.s
@this is a test program of nandflash, the properties of com0 is the same as usual (115200,8, 1, n, n)
.text
.global _start
_start:
b Reset
b . @undefined instruction
b . @swi
b . @pregetch instruction
b . @data abort
b . @Reserved
b HandleIRQ @irq
b . @fiq
Reset:
ldr sp, =4096 @set the stack pointer of sys mode to 4096
bl disable_watchdog
bl init_led
bl init_sdram
bl copy_sdram
ldr pc, =on_sdram
on_sdram:
msr cpsr_c, #0xd2 @set cpu to irq mode
ldr sp, =0x31000000 @set the stack pointer of irq mode to sdram
msr cpsr_c, #0xdf @reset cpu to sys mode
ldr sp, =0x32000000
bl init_clock
mov r0, #1
mov r1, #10
bl blink
bl init_timer0
mov r0, #2
mov r1, #10
bl blink
bl init_com0
mov r0, #3
mov r1, #10
bl blink
bl init_nandflash
bl init_irq
msr cpsr_c, #0x5f @enable irq
bl main
b .
.ltorg
.ltorg
.ltorg
HandleIRQ:
sub lr, lr, #4
stmdb sp!, {r0-r12, lr}
ldr lr, =next
ldr pc, =interrupt_func
next:
ldmia sp!, {r0-r12, pc}^ @return to main
.ltorg
.ltorg
init.c
#define GPBCON (*((volatile unsigned long*)(0x56000010)))
#define GPBDAT (*((volatile unsigned long*)(0x56000014)))
#define WTCON (*((volatile unsigned long*)(0x53000000)))
#define LOCKTIME (*((volatile unsigned long*)(0x4C000000)))
#define CLKDIVN (*((volatile unsigned long*)(0x4C000014)))
#define MPLLCON (*((volatile unsigned long*)(0x4C000004)))
#define TCFG0 (*((volatile unsigned long*)(0x51000000)))
#define TCFG1 (*((volatile unsigned long*)(0x51000004)))
#define TCNTB0 (*((volatile unsigned long*)(0x5100000C)))
#define TCON (*((volatile unsigned long*)(0x51000008)))
#define INTMSK (*((volatile unsigned long*)(0X4A000008)))
#define INTSUBMASK (*((volatile unsigned long*)(0X4A00001C)))
#define GPHCON (*((volatile unsigned long*)(0x56000070)))
#define GPHUP (*((volatile unsigned long*)(0x56000078)))
//control register of com0
#define ULCON0 (*((volatile unsigned long*)(0x50000000)))
#define UCON0 (*((volatile unsigned long*)(0x50000004)))
#define UFCON0 (*((volatile unsigned long*)(0x50000008)))
#define UMCON0 (*((volatile unsigned long*)(0x5000000C)))
#define UBRDIV0 (*((volatile unsigned long*)(0x50000028)))
//initilize GPB to output mode
void init_led()
{
GPBCON &= (~(0xff<<10));
GPBCON |= (0X55<<10);
}
void delay(int times)
{
int i, j;
for(i=0; i<times; i++)
{
for(j=0; j<1000; j++);
}
}
//blink function is used to debug
void blink(int number, int delay_num)
{
GPBDAT |= (0X0F<<5);
GPBDAT &= (~(number<<5));
delay(delay_num);
GPBDAT |= (0X0F<<5);
delay(delay_num);
}
void disable_watchdog()
{
WTCON = 0;
}
void init_clock()
{
LOCKTIME = 0xffffffff;
CLKDIVN = 0X03; //fclk:hclk:pclk=1:2:4
__asm__
(
"mrc p15, 0, r1, c1, c0, 0\n"
"orr r1, r1, #0xc0000000\n"
"mcr p15, 0, r1, c1, c0, 0\n"
);
MPLLCON = (92<<12)|(1<<4)|(2<<0); //fclk=200M, hclk=100M, pclk=50M
}
void init_sdram()
{
volatile unsigned long *p = (volatile unsigned long *)(0x48000000);
p[0] = 0x22011110; //BWSCON
p[1] = 0x00000700; //BANKCON0
p[2] = 0x00000700; //BANKCON1
p[3] = 0x00000700; //BANKCON2
p[4] = 0x00000700; //BANKCON3
p[5] = 0x00000700; //BANKCON4
p[6] = 0x00000700; //BANKCON5
p[7] = 0x00018005; //BANKCON6
p[8] = 0x00018005; //BANKCON7
p[9] = 0x008C04F4; //REFRESH value is different than before, because the clock is different
p[10] = 0x000000B1; //BANKSIZE
p[11] = 0x00000030; //MRSRB6
p[12] = 0x00000030; //MRSRB7
}
void copy_sdram()
{
unsigned long* src = (unsigned long *)(0);
unsigned long* des = (unsigned long *)(0x30000000);
int i;
for(i=0; i<1024; i++)
{
des[i] = src[i];
}
}
void init_timer0()
{
TCFG0 = 99; //set prescaler value to 100
TCFG1 = 0x03; //set MUX to 16
TCNTB0 = 15625;
TCON = (1<<1);
TCON = 0x09; //start timer0
}
void init_irq()
{
//enable interrupt of rxd0 txd0
INTSUBMASK &= (~(0b11));
//enable interrupt of uart0
INTMSK &= (~(1<<28));
}
void init_com0()
{
//set gph[2:3] used as txd and rxd for com0
GPHCON &= (~(0xff<<4));
GPHCON |= (0x0a<<4);
//disable pull up functon for gph[2:3]
GPHUP = 0x0c;
//set properties of com0
ULCON0 = 0b00000011;
//enable the rxd and txd, and interrupt will happen when con0 received data or the send buffer is empty in non-fifo mode
UCON0 = 0b00000101;
//disable fifo
UFCON0 = 0x00;
//disable fifo
UMCON0 = 0x00;
//set baud-rate to 115200
UBRDIV0 = (int)(50000000/(115200*16)) -1;
}
com0.c
#define UTRSTAT0 (*((volatile unsigned long*)(0x50000010)))
#define UTXH0 (*((volatile unsigned long*)(0x50000020)))
#define URXH0 (*((volatile unsigned long*)(0x50000024)))
#define SUBSRCPND (*((volatile unsigned long*)(0X4A000018)))
#define SRCPND (*((volatile unsigned long*)(0X4A000000)))
#define INTPND (*((volatile unsigned long*)(0X4A000010)))
extern void blink(int, int);
void put_char(char ch)
{
while (!(UTRSTAT0 & (1<<2)));
UTXH0 = ch;
}
unsigned char get_char()
{
while (!(UTRSTAT0 & (1<<0)));
return URXH0;
}
void put_string(char *string)
{
int i = 0;
while(string[i] != '\0')
put_char(string[i++]);
}
void com0_read(char *ch)
{
*ch = URXH0;
}
void com0_write(char ch)
{
UTXH0 = ch;
}
//the function to serve the uart0 interrupt
void interrupt_func()
{
char ch;
//rxd sub interrupt
if(SUBSRCPND & (1<<0))
{
blink(15, 1);
com0_read(&ch);
com0_write(ch);
}
else if(SUBSRCPND & (1<<1)) //txd interrupt
{
blink(10, 1);
}
//clear the interrupt of uart0
SUBSRCPND = SUBSRCPND;
SRCPND |= (1<<28);
INTPND = INTPND;
}
nandflash.c
#define NFCONF (*((volatile unsigned long*)(0x4E000000)))
#define NFCONT (*((volatile unsigned long*)(0x4E000004)))
#define NFCMMD (*((volatile unsigned char*)(0x4E000008)))
#define NFADDR (*((volatile unsigned char*)(0x4E00000C)))
#define NFDATA (*((volatile unsigned char*)(0x4E000010)))
#define NFSTAT (*((volatile unsigned long*)(0x4E000020)))
#define GPACON (*((volatile unsigned char*)(0x56000000)))
#define TACLS 1
#define TWPRH0 1
#define TWPRH1 1
//command
#define READ1 0x00
#define READ2 0X30
#define RESET 0xff
#define RANDOM_READ1 0x05
#define RANDOM_READ2 0xe0
#define WRITE1 0x80
#define WRITE2 0x10
#define RADOM_WRITE 0X85
#define ERASE1 0X60
#define ERASE2 0xd0
#define STATUS 0X70
void nandflash_reset();
void init_nandflash();
void nandflash_select_chip();
void nandflash_deselect_chip();
void nandflash_wait_ready();
extern void put_string(char *);
extern void delay(int);
//initilize the nandflash
void init_nandflash()
{
//make gpa[17:22] used for nandflash controler
GPACON |= (0x3f<<17);
NFCONF = (TACLS<<12)|(TWPRH0<<8)|(TWPRH1<<4);
NFCONT = (1<<4)|(1<<1)|(1<<0);
put_string("init nandflash over!\r\n");
nandflash_reset();
}
//reset the nandflash
void nandflash_reset()
{
nandflash_select_chip();
NFCMMD = RESET;
nandflash_wait_ready();
nandflash_deselect_chip();
}
void nandflash_select_chip()
{
NFCONT &= (~(1<<1));
delay(3);
}
void nandflash_deselect_chip()
{
NFCONT |= (1<<1);
delay(3);
}
void nandflash_wait_ready()
{
while(1)
{
if( (NFSTAT&(1<<0)) )
break;
delay(1);
}
}
void nandflash_read_page(unsigned int page_num, unsigned int length, unsigned char *buffer)
{
int i;
nandflash_select_chip();
NFCMMD = READ1;
NFADDR = 0x00;
NFADDR = 0x00;
NFADDR = (unsigned char)(page_num&0xff);
NFADDR = (unsigned char)((page_num>>8)&0xff);
NFCMMD = READ2;
nandflash_wait_ready();
for(i=0; i<length;i++)
{
buffer[i] = NFDATA;
}
nandflash_deselect_chip();
}
unsigned char nandflash_write_page(unsigned int page_num, unsigned int length, unsigned char *buffer)
{
int i;
unsigned char status;
nandflash_select_chip();
NFCMMD = WRITE1;
delay(3);
NFADDR = 0x00;
NFADDR = 0x00;
NFADDR = (unsigned char)(page_num&0xff);
NFADDR = (unsigned char)((page_num>>8)&0xff);
delay(3);
for(i=0; i<length;i++)
{
NFDATA = buffer[i];
}
delay(3);
NFCMMD = WRITE2;
delay(30);
nandflash_wait_ready();
delay(20);
NFCMMD = STATUS;
delay(3);
status = NFDATA;
nandflash_deselect_chip();
if(status & 0x01)
{
put_string("write error!\r\n");
return 0;
}
else
{
put_string("write compelete!\r\n");
return 1;
}
}
unsigned char nandflash_erase_block(unsigned int block_num)
{
unsigned char status;
nandflash_select_chip();
NFCMMD = ERASE1;
NFADDR = ((block_num<<6)&0b11000000);
NFADDR = ((block_num>>2)&0xff);
NFCMMD = ERASE2;
delay(30);
nandflash_wait_ready();
delay(20);
NFCMMD = STATUS;
delay(3);
status = NFDATA;
nandflash_deselect_chip();
if(status & 0x01)
{
put_string("erase error!\r\n");
return 0;
}
else
{
put_string("erase compelete!\r\n");
return 1;
}
nandflash_deselect_chip();
}
main.c
extern void put_char(char);
extern unsigned char get_char();
extern void put_string(char *);
extern void blink(int, int);
extern void put_string(char*);
extern void delay(int);
extern void nandflash_read_page(unsigned int page_num, unsigned int length, unsigned char *buffer);
extern unsigned char nandflash_erase_block(unsigned int block_num);
extern unsigned char nandflash_write_page(unsigned int page_num, unsigned int length, unsigned char *buffer);
void change_num_string(unsigned char num, char *buffer)
{
unsigned char num1, num0;
num1 = num%16;
num0 = num/16;
if(num1 <= 9)
buffer[1] = num1+'0';
else
buffer[1] = num1-10+'A';
if(num0 <= 9)
buffer[0] = num0+'0';
else
buffer[0] = num0-10+'A';
buffer[2] = '\0';
}
int main(void)
{
int i;
unsigned char read_buffer[20];
unsigned char write_buffer[20];
char num[3];
for(i=0; i<20; i++)
{
write_buffer[i] = i;
}
if(!nandflash_erase_block(1))
{
return -1;
}
if(!nandflash_write_page(64, 20, write_buffer))
{
return -1;
}
nandflash_read_page(64, 20, read_buffer);
for(i=0; i<20; i++)
{
change_num_string(read_buffer[i], num);
put_string("0x");
put_string(num);
put_string("\r\n");
}
while(1);
return 0;
}
运行结果:
总结:
以后调裸机程序一定要好好看datasheet里面的时序图然后再写程序,要不然效率极低,调试太蛋疼。