之所以不能直接在sdram中执行程序是因为sdram必须先进行初始化 *** 作。
如果你的程序很小,可直接放在片内ram中,然后用读写指令拷到初始化完成的sdram中即可。
如果你的程序很大,可建一个二进制的文件存放第二级的代码,把第一级的引导代码在ram中运行之后,先初始化sdram,再去读取那个二进制文件,并把数据写到sdram中,完成后跳转到sdram中运行。
MT48LC2M32的时钟是由DSP给的,给多给少都可以,在硬件允许的范围内,一般是越快越好。你可自行查阅DSP与sdram的时钟频率的上限,以确定给多少。
要想代码在SRAM中运行。有几个步骤需要做。1、中断向量表需要修改,这样才能把中断向量表重新映射一遍。
#ifdef VECT_TAB_SRAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0)
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0)
#endif
2、分散加载要设置,就是设置你的代码段和数据段在ram的运行地址,就是arm手册中的运行域。
3、你的代码相当于boot 和app模式,boot在flash中执行,然后把app从nor flash搬到sram所在地址。
你的运行域地址就是代码搬移到sram所在的地址
你可以自己写一个汇编的程序,把Nand Flash 中的程序搬到SDRAM中。因为S3C2410有Nor Flash和Nand Flash有两种启动方式,所以在搬移过程中略有不同。如果用Nand Flash启动可以使用下面的代码,至于Nor Flash启动就相对简单了,你可以自己研究一下。文件1.head.s
@ 文件 head.s
@ 作用:关闭看门狗、SDRAM 的初始化设置、搬移 Nand Flash 4K 以后
@ 的代码到 SDRAM 的指定位置、执行 SDRAM 中的代码
.text
.global _start
_start:
ldr r0, =0x53000000 @ Close Watch Dog Timer
mov r1, #0x0
str r1, [r0]
bl memory_setup @ Initialize memory setting
bl flash_to_sdram @ Copy code to sdram
ldr sp, =0x34000000 @ Set stack pointer
ldr pc, =main @ execute the code in SDRAM
文件2:flash.s
@ 文件 flash.s
@ 作用:设置 Nand Flash 的控制寄存器、读取 Nand Flash
@ 中的代码到 SDRAM 的指定位置
.equ NFCONF, 0x4e000000
.equ NFCMD, 0x4e000004
.equ NFADDR, 0x4e000008
.equ NFDATA, 0x4e00000c
.equ NFSTAT, 0x4e000010
.equ NFECC, 0x4e000014
.global flash_to_sdram
flash_to_sdram:
@ Save return addr
mov r10,lr
@ Initialize Nand Flash
mov r0,#NFCONF
ldr r1,=0xf830
str r1,[r0]
@ First reset and enable Nand Flash
ldr r1,[r0]
bic r1, r1, #0x800
str r1,[r0]
ldr r2,=NFCMD
mov r3,#0xff
str r3,[r2]
@ for delay
mov r3, #0x0a
1:
subs r3, r3, #1
bne 1b
@ Wait until Nand Flash bit0 is 1
wait_nfstat:
ldr r2,=NFSTAT
ldr r3,[r2]
tst r3,#0x01
beq wait_nfstat
@ Disable Nand Flash
ldr r0,=NFCONF
ldr r1,[r0]
orr r1,r1,#0x8000
str r1,[r0]
@ Initialzie stack
ldr sp,=4096
@ Set arguments and call
@ function nand_read defined in nand_read.c
ldr r0,=0x30000000
mov r1,#4096
mov r2,#1024
bl nand_read
@ return
mov pc,r10
文件3:interrupt.c
/*
* 文件 interrupt.c
* 作用:设置并响应按键中断
*/
#include "printf.h"
#define GPECON (*(volatile unsigned long *)0x56000040)
#define GPEDAT (*(volatile unsigned long *)0x56000044)
#define GPEUP (*(volatile unsigned long *)0x56000048)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068)
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define INTMSK (*(volatile unsigned long *)0X4a000008)
#define PRIORITY (*(volatile unsigned long *)0x4a00000c)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
#define INTPND (*(volatile unsigned long *)0X4a000010)
#define SRCPND (*(volatile unsigned long *)0X4a000000)
#define BIT_EINT0 (0x1 <<0)
#define BIT_EINT2 (0x1 <<2)
#define BIT_EINT8_23 (0x1 <<5)
#define SET_KEY_INTERRUPT_REG() ({ \
GPGCON = (GPGCON &(~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) \
GPGDAT = GPGDAT &(~((1<<6)|(1<<2))) \
GPECON = (GPECON &(~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22))\
GPEDAT = GPEDAT &(~((1<<13)|(1<<11))) \
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) \
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) \
})
__inline void ClearPending(int bit)
{
SRCPND = bit
INTPND = bit
}
void init_irq( ) {
GPFCON = ((0x1<<8) | (0x1 <<10) | (0x1 <<12) | (0x1 <<14)) // Set the led D9~D12 output
/*
GPGCON = (GPGCON &(~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) // GPGCON6,2 set output
// GPGCON6:KSCAN1
// GPGCON2:KSCAN3
GPGDAT = GPGDAT &(~((1<<6)|(1<<2))) // GPGDAT6,2 output 0
GPECON = (GPECON &(~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22)) // GPECON13,11 set output
GPEDAT = GPEDAT &(~((1<<13)|(1<<11))) // GPEDAT13,11 output 0
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) // GPGCON11,3 set EINT
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) // GPFDAT2,0 set EINT
*/
// Use the defined micro instead of above code
SET_KEY_INTERRUPT_REG()
GPFUP |= (1<<0) | (1<<2) // Up
GPGUP |= (1<<3) | (1<<11) // Up
EINTPEND |= (1 <<19) | (1 <<11) // Clear eint 11,19
EINTMASK &= (~((1 <<19) | (1 <<11)))// Enable EINT11,19
ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23)// Enable EINT0,2 and the EINT8_23
INTMSK &= (~0x25)
return
}
int Key_Scan( void )
{
int i
for(i = 0i <1000 i++)
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (0<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 16
else if( (GPFDAT&(1<<2)) == 0 ) return 15
else if( (GPGDAT&(1<<3)) == 0 ) return 14
else if( (GPGDAT&(1<<11)) == 0 ) return 13
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (0<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 11
else if( (GPFDAT&(1<<2)) == 0 ) return 8
else if( (GPGDAT&(1<<3)) == 0 ) return 5
else if( (GPGDAT&(1<<11)) == 0 ) return 2
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (0<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 10
else if( (GPFDAT&(1<<2)) == 0 ) return 7
else if( (GPGDAT&(1<<3)) == 0 ) return 4
else if( (GPGDAT&(1<<11)) == 0 ) return 1
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (0<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 12
else if( (GPFDAT&(1<<2)) == 0 ) return 9
else if( (GPGDAT&(1<<3)) == 0 ) return 6
else if( (GPGDAT&(1<<11)) == 0 ) return 3
else return 0xff
}
void EINT_Handle( void ) {
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((0<<22)|(0<<6)) //GPG11,3 set input
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((0<<4)|(0<<0)) //GPF2, 0 set input
if(INTPND==BIT_EINT8_23) {
if(EINTPEND&(1<<11))
EINTPEND |= 1<<11
if(EINTPEND&(1<<19))
EINTPEND |= 1<<19
ClearPending(BIT_EINT8_23)
}
else if(INTPND==BIT_EINT0) {
ClearPending(BIT_EINT0)
} else if(INTPND==BIT_EINT2) {
ClearPending(BIT_EINT2)
}
int key = Key_Scan()
if( key != 0xff ) {
uart_printf( "K%d is pressed!\n", key )
GPFDAT = ~(key <<4)
}
SET_KEY_INTERRUPT_REG()
return
}
文件4:mem.s
@ 文件 mem.s
@ 作用:SDRAM 的初始化设置
@ 关于初始化的更多细节,请参考我的前一篇随笔
.global memory_setup @ 导出 memory_setup, 使其对链接器可见
memory_setup:
mov r1, #0x48000000
adrl r2, mem_cfg_val
add r3, r1, #13*4
1:
@ write initial values to registers
ldr r4, [r2], #4
str r4, [r1], #4
cmp r1, r3
bne 1b
mov pc, lr
.align 4
mem_cfg_val:
.long 0x22111110 @ BWSCON
.long 0x00000700 @ BANKCON0
.long 0x00000700 @ BANKCON1
.long 0x00000700 @ BANKCON2
.long 0x00000700 @ BANKCON3
.long 0x00000700 @ BANKCON4
.long 0x00000700 @ BANKCON5
.long 0x00018005 @ BANKCON6
.long 0x00018005 @ BANKCON7 9bit
.long 0x008e07a3 @ REFRESH
.long 0x000000b2 @ BANKSIZE
.long 0x00000030 @ MRSRB6
.long 0x00000030 @ MRSRB7
文件5:nand_read.c
/* 文件 nand_read.c
* 作用:从 Nand Flash 中读取一块数据到 SDRAM 中的指定位置
*/
#define NFCONF (*(volatile unsigned long *)0x4e000000)
#define NFCMD (*(volatile unsigned long *)0x4e000004)
#define NFADDR (*(volatile unsigned long *)0x4e000008)
#define NFDATA (*(volatile unsigned long *)0x4e00000c)
#define NFSTAT (*(volatile unsigned long *)0x4e000010)
#define NFECC (*(volatile unsigned long *)0x4e000014)
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK 0x1ff
void wait_idle() {
int i
for (i = 0i <50000++i)
}
int nand_read(unsigned char *buf, unsigned long start_addr, int size){
int i, j
/*
* detect the argument
*/
if ((start_addr &NAND_BLOCK_MASK) || (size &NAND_BLOCK_MASK)) {
return -1
}
/* chip Enable */
NFCONF &= ~0x800
for (i=0i<10i++) {
}
for (i=start_addri <(start_addr + size)i+=NAND_SECTOR_SIZE) {
NFCMD = 0
/* Write Address */
NFADDR = i &0xff
NFADDR = (i >>9) &0xff
NFADDR = (i >>17) &0xff
NFADDR = (i >>25) &0xff
wait_idle()
for(j=0j <NAND_SECTOR_SIZEj++) {
*buf++ = (NFDATA &0xff)
}
}
NFCONF |= 0x800 /* chip disable */
return 0
}
文件6:sdram.c
/* 文件 sdram.c
* 作用:循环点 FS2410 开发板上的 D9、D10、D11、D12
* 四个发光二极管。
*/
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
int main()
{
int i,j
while(1) {
for (i = 0i <4++i) {
GPFCON = 0x1<<(8+i*2)
GPFDAT = 0x0
// for delay
for(j=0j<50000++j)
}
}
}
文件7:nand.lds
SECTIONS {
first 0x00000000 : { head.o mem.o flash.o nand_read.o }
second 0x30000000 : AT(4096) { sdram.o }
}
文件8:Makefile
sdram:head.s flash.s mem.s sdram.c
arm-linux-gcc -c -o head.o head.s
arm-linux-gcc -c -o mem.o mem.s
arm-linux-gcc -c -o flash.o flash.s
arm-linux-gcc -c -o nand_read.o nand_read.c
arm-linux-gcc -c -o sdram.o sdram.c
arm-linux-ld -Tnand.lds head.o mem.o flash.o nand_read.o sdram.o -o sdram_tmp.o
arm-linux-objcopy -O binary -S sdram_tmp.o sdram
clean:
rm -f *.o
rm -f sdram
好了,你把这些文件拷下去,执行make命令就能生成可执行的二进制代码sdram,把sdram烧写到板子上就能运行了。祝你好运
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)