jz2440内存实验(八)

前面花了大量力气去看芯片手册和SDRAM相关的管脚定义相关的内容。
下面就应该把这个内存芯片给用起来,跑一段程序看看。

在(四)中提到,机器初始化需要做的工作:
1.关闭看门狗
2.初始化时钟
3.初始化内存 
4.为C语言初始化堆栈。


这里因为位对汇编语言的熟悉程序不够,且不说不是不够,是根本不想花时间研究指令怎么用。
还有更多的是对于debug汇编语言的恐慌,所以原则是尽量少用汇编。

废话不多说了,那么怎么去实验呢?

1.为C语言初始化堆栈
2.关看门狗
3.初始化时钟(忽略)
4.初始化SDRAM
5.拷贝有关代码到内存
6.跳转到内存中执行代码


head.S
.global _start
_start:
    ldr sp, =4096                            @ 设置堆栈指针
    bl  disable_watch_dog               @ 关闭WATCHDOG,否则CPU会不断重启
    bl  memsetup                             @ 设置存储控制器
    bl  copy_code_to_sdram              @ 复制代码到SDRAM中

    ldr sp, =0x34000000                 @ 重设栈指针,指向SDRAM顶端
    ldr pc, =0x30000000                 @ 跳到SDRAM中继续执行
                                                      @ 这里如何寻找main函数呢?这里提一个问题!

halt_loop:
    b   halt_loop




disable_watch_dog
memsetup
copy_code_to_sdram
这些代码都放到C语言实现了。

SP PC分别代表堆栈和CPU运行代码的位置,我们全部都转移到SDRAM上

下面看一下代码的实现:

init.c
unsigned long  addr_sdram_stack = 0x34000000;
unsigned long  addr_sdram_base = 0x30000000;
/* WATCHDOG寄存器 */
#define P_WTCON           ((volatile unsigned long *)0x53000000)
/* 存储控制器的寄存器起始地址 */
#define MEM_CTL_BASE    0x48000000
/*
 * 关闭WATCHDOG,否则CPU会不断重启
 */
void disable_watch_dog(void)
{
//      ClearBit(*P_WTCON,5);
//        setNbit(*P_WTCON,1,5,0x0);
      *P_WTCON = 0;
}



void memsetup(void)
{
    /* SDRAM 13个寄存器的值 */
    unsigned long  const    mem_cfg_val[]={ 0x22011110,     //BWSCON
                                            0x00000700,     //BANKCON0
                                            0x00000700,     //BANKCON1
                                            0x00000700,     //BANKCON2
                                            0x00000700,     //BANKCON3 
                                            0x00000700,     //BANKCON4
                                            0x00000700,     //BANKCON5
                                            0x00018005,     //BANKCON6
                                            0x00018005,     //BANKCON7
                                            0x008C07A3,     //REFRESH
                                            0x000000B1,     //BANKSIZE
                                            0x00000030,     //MRSRB6
                                            0x00000030,     //MRSRB7
                                    };
    int     i = 0;
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
    for(; i < 13; i++)
        p[i] = mem_cfg_val[i];
}


void copy_code_to_sdram(void)
{
    unsigned int *pdwSrc  = (unsigned int *)2048;
    unsigned int *pdwDest = (unsigned int *)addr_sdram_base;

    while (pdwSrc < (unsigned int *)4096) //2k-4k复制
    {
        *pdwDest = *pdwSrc;
        pdwDest++;
        pdwSrc++;
    }
}

这样我们跳入到sdram的代码就是这些了,
然后我们用之前写过的非常老土的一个小程序验证一下。

leds.c
#define GPBCON      (*(volatile unsigned long *)0x56000050)
#define GPBDAT      (*(volatile unsigned long *)0x56000054)

int main()
{
    GPBCON = 0x00000100;    // 设置GPB4为输出口, 位[8:7]=0b01
    GPBDAT = 0x00000000;    // GPB4输出0,LED1点亮

    return 0;
}




Makefile
objs := head.o init.o leds.o
memory.bin : $(objs)
        arm-linux-ld -Tmem.lds -o mem.elf $^
        arm-linux-objcopy -O binary -S mem.elf $@
        arm-linux-objdump -D -m arm mem.elf > mem.dis

#$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件
%.o:%.c
        arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.S
        arm-linux-gcc -Wall -O2 -c -o $@ $<
clean:
        rm -f *.dis *.bin *.elf *.o ../../pub/*.o



这里我们将链接地址改了一下,前面也看到过,我们嫌弃复制一大堆运行的过的代码很LOW,我们不复制初始化的代码。

为了达成这个效果,我们将代码分开存放。
从Makefile arm-linux-ld -T mem.lds -o mem.elf $^

SECTIONS {
  firtst    0x00000000 : { head.o init.o ../../pub/bit.o}
  second    0x30000000 : AT(2048) { leds.o }
}

我们将程序分开存放 初始化代码放到0地址

我们应用程序放到  0x30000000 也就是sdram的开始地址


实验看看效果,果然灯亮了。



我们在head.S中只是随意的设置了,入口地址。我们反汇编看一下main函数的地址。


这个我们看到确实是3000 0000,要是我们加一些函数呢?
我们随便加了一个空函数,我们发现地址变了。

我们测试一下修改head.S 设置pc的地址为0x3000 0004,应该不成问题!

那么我们能不要人工计算这个,很麻烦。也容易弄错。

bl main  发现这样出错了!
: relocation truncated to fit: R_ARM_PC24 main
bl、b等指令 跳转范围在32MB, 显然就算可以调整过去这样的代码还是有很大的风险。

这里我想到一个取巧的办法:
我的main函数的.C文件不会有其他函数出现。
比如我引用的一个其他函数.abc 我们放到另外的文件里,然后修改一些链接规则

SECTIONS {
  firtst    0x00000000 : { head.o init.o ../../pub/bit.o }
  second    0x30000000 : AT(2048) { leds.o }
  third     :{1.o}
}

记得在MakeFile编译一下新加的文件哦。

PS:想找一个办法自动定位出main的链接地址,那么写程序就方便很多,不需要偷偷摸摸的另外在单独函数中弄,目前还没看到好的办法,暂时先这样吧。
后面才发现使用 ldr pc,=main 就好了,之前可能Makefile没有写好,报错了,以为不行。





 




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值