S5PV210裸机(二):看门狗,栈,icache,SoC时钟,重加载,led

本文详细介绍了看门狗的作用、如何在汇编和C中设置栈,初始化ICache,以及SoC时钟系统的设计,包括时钟的来源、分频和设置过程,还涉及了重定位、链接、长跳转和短跳转等概念,以及LED操作和MKV210平台的示例代码和Makefile配置。
摘要由CSDN通过智能技术生成

看门狗
        电子设备会跑飞或者死机,需要设备自动复位,看门狗是SoC内部定时器,规定时间内需要重新置位,如果没有系统会被强制复位
WTCON(0xE2700000),bit5是开关:0关,1开

 

汇编设置栈和调用C
        C运行过程中局部变量需要栈,如果汇编没有设置栈地址,局部变量会落空,程序崩溃
系统在复位后默认是SVC模式,设置栈时不设置所有栈而是设置自己模式下的栈
        CPU启动,外部DRRAM未初始化,内部SRAM使用,SRAM内存做SVC栈

        SVC栈置为0xd0037D80(满减栈)

初始化iCache
        cache是内存高速缓存,打开icache后程序运行加快
        容量:CPU < 寄存器 < cache < DDR
        速度:CPU >  寄存器 > cache > DDR

        汇编读写cp15开关icache
                mrc p15,0,r0,c1,c0,0      // 读出cp15的c1到r0中
                bic r0, r0, #(1<<12)      // bit12 置0  关icache
                orr r0, r0, #(1<<12)      // bit12 置1  开icache
                mcr p15,0,r0,c1,c0,0

重定位和链接
        位置无关编码(PIC):汇编源文件编码成二进制可执行程序时编码方式与位置(内存地址)无关
        位置有关编码:汇编源码编码成二进制可执行程序后和内存地址是有关
        链接地址:链接时指定的地址,Makefile中-Ttext或链接脚本指定
        运行地址:程序实际运行地址,运行时被加载到的内存位置
        位置有关代码执行时运行地址和编译链接地址必须相同
        重定位是在运行地址处执行位置无关码,位置无关码从运行地址拷贝到链接地址处
        注意:210运行时地址是0xd0020010,指定的链接地址与运行地址不同时,内部SRAM射到0x0地址,故程序运行正常

        长跳转与短跳转     
                长跳转:ldr pc, = func
                短跳转:bl func
                链接地址和运行地址相同,短跳转和长跳转无差异
                链接地址和运行地址不同,短跳转在运行地址,长跳转在链接地址处

        adr与伪指令ldr
                ldr是长加载,adr是短加载
                adr加载运行时地址,ldr加载链接地址
                adr和ldr可以判断是否需要重定位

        程序段
                代码段:(.text)文本段
                数据段:(.data)
                bss段:  (.bss),ZI段
                自己定义段

        链接脚本
                链接脚本:段名,地址(作为链接地址的内存地址)
                        SECTIONS {}          整个链接脚本
                        .                               当前位置
                        =                              赋值

SoC时钟
        时钟是同步工作系统的同步节拍,SoC内部器件需要同步时钟系统指挥
        210获得时钟:外部晶振+内部时钟发生器+内部PLL产生高频时钟(1GHz、1.2GHz)+内部分频器分频

        210的时钟
                时钟域:MSYS、DSYS、PSYS
                MSYS: CPU(Cortex-A8内核)、DRAM控制器(DMC0和DMC1)、IRAM&IROM等
                DSYS: 都是和视频显示、编解码等有关的模块等
                PSYS: 和内部的各种外设时钟有关,譬如串口、SD接口、I2C、AC97、USB等
                时钟来源:晶振+时钟发生器+PLL+分频电路
                210外部有4个晶振接口,接晶振后上电相应模块振荡产生原始时钟,原始时钟经过筛选进入PLL电路生成高频时钟,再经分频到各模块

        PLL
                PLL:APLL、MPLL、VPLL
                        APLL:Cortex-A8内核 MSYS域
                        MPLL&EPLL:DSYS PSYS
                        VPLL:Video视频相关模块

        210时钟域
                MSYS
                        ARMCLK:cpu内核时钟(主频)
                        HCLK_MSYS:MSYS域高频时钟(DMC0和DMC1)
                        PCLK_MSYS:MSYS域低频时钟
                        HCLK_IMEM:iMEM(iROM和iRAM)
                DSYS
                        HCLK_DSYS:DSYS域高频时钟
                        PCLK_DSYS:DSYS域低频时钟
                PSYS
                        HCLK_PSYSPSYS域的高频时钟
                        PCLK_PSYS:PSYS域的低频时钟
                SCLK_ONENAND
                注意:210内部外设接在(内部AMBA总线)总线上,AMBA总线高频分支AHB,低频分支APB

        时钟典型值
                210上电默认外部晶振+内部时钟发生器产生24MHz时钟给ARMCLK,iROM初始化时钟系统
                freq(ARMCLK)         = 1000 MHz
                freq(HCLK_MSYS)      = 200 MHz
                freq(HCLK_IMEM)      = 100 MHz
                freq(PCLK_MSYS)      = 100 MHz
                freq(HCLK_DSYS)      = 166 MHz
                freq(PCLK_DSYS)      = 83 MHz
                freq(HCLK_PSYS)      = 133 MHz
                freq(PCLK_PSYS)      = 66 MHz
                freq(SCLK_ONENAND)   = 133 MHz, 166 MHz

        时钟设置寄存器

                  锁存寄存器,频率设置寄存器(CON、SRC、DIV,CON决定PLL倍频,SRC决定来源,DIV决定分频),其他寄存器(开关控制器,开关和分频状态寄存器)
                         锁存寄存器:xPLL_LOCK:控制PLL锁存周期


                        频率设置寄存器              

                         xPLL_CON/xPLL_CON0/xPLL_CON1:打开/关闭PLL电路,设置PLL倍频参数,查看PLL锁定状态


                CLK_SRCn(n:0~6):设置时钟来源(MUX开关)


              

       CLK_DIVn:各模块分频器参数配置

                         其他寄存器

                        CLK_SRC_MASKn:MUX(n选1),默认进开关开放

                         CLK_GATE_x:分频出开关控制

 


                        CLK_DIV_STATn和CLK_MUX_STATn:查看DIV和MUX状态(完成或进行)
              

 

        时钟设置
                选择不使用PLL,24MHz原始时钟接入绕过APLL(走FINAPLL)
                设置锁定时间,默认0x0FFF,时钟系统有变化时缓冲时间
                设置分频系统
                设置PLL的倍频,ARMCLK(1GHz)
                打开PLL

        寄存器设置
                CLK_SRC设置MUX开关,设置全0(bit0和bit4为0),APLL和MPLL禁用
                CLK_LOCK设置PLL锁定延时,推荐值为0xFFF或0xFFFF
                CLK_DIV寄存器设置为0x14131440  00010100000100110001010001000000

                PCLK_PSYS = HCLK_PSYS / 2
                HCLK_PSYS = MOUT_PSYS / 5
                PCLK_DSYS = HCLK_DSYS / 2
                HCLK_DSYS = MOUT_DSYS / 4
                PCLK_MSYS = HCLK_MSYS /4
                HCLK_MSYS = ARMCLK / 5
                SCLKA2M = SCLKAPLL /5
                ARMCLK = MOUT_MSYS / 1

        APLL和MPLL设置M、P、S

 

 

LED 

demo: 

        关看门狗,初始化栈,初始化icache,初始化时钟,重加载方式实现流水灯

代码示例:

        start.S

#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80

.global _start

_start:

        //close WatchDog
        ldr r0,=WTCON
        ldr r1,=0x0
        str r1,[r0]

        //init SVC stack
        ldr sp,=SVC_STACK

        //init clock
        bl init_clock

        //init icache
        mrc p15,0,r0,c1,c0,0
        bic r0,r0,#(1<<12)      //close icache
        orr r0,r0,#(1<<12)      //open icache
        mcr p15,0,r0,c1,c0,0 


        //judge reload
        adr r0,_start
        ldr r1,=_start
        ldr r2,=bss_start
        cmp r0,r1
        beq clear_bss

        //reload
copy_operation_to_link:
        ldr r3,[r0],#4
        str r3,[r1],#4
        cmp r1,r2
        bne copy_operation_to_link

        //judge bss
        ldr r0,=bss_start
        ldr r1,=bss_end
        mov r2,#0
        cmp r0,r1
        beq run_to_func

        //clear bss
clear_bss:
        str r2,[r0],#4
        cmp r1,r0
        bne clear_bss

run_to_func:
        //long jump
        ldr pc,=led_blink

        //short jump
        //bl led_blink

        b .

        led.c

#define GPJ0CON   0xE0200240
#define GPJ0DAT   0xE0200244

#define rGPJ0CON *((volatile  unsigned int *) GPJ0CON)
#define rGPJ0DAT *((volatile  unsigned int *) GPJ0DAT)

//dealy time

void dealy_time()
{
        volatile unsigned int num = 900000;
        while(num--);
}

//led blink

void led_blink()
{
                //set jpio output
                rGPJ0CON = 0x11111111;

                while(1)
                {
                        //led off
                        rGPJ0DAT = ((0<<3)|(0<<4)|(0<<5));
                        //dealy time
                        dealy_time();
                        //led on
                        rGPJ0DAT = ((1<<3)|(1<<4)|(1<<5));
                        //dealy time
                        dealy_time();
                }
}

clock_init.c

//register base address
#define CLOCK_BASE              0xE0100000

//register offsect
#define APLL_LOCK_OFFSECT       0x0
#define MPLL_LOCK_OFFSECT       0x8
#define APLL_CON0_OFFSECT       0x0100
#define MPLL_CON_OFFSECECT      0x0108
#define CLOCK_SRC0_OFFSECT      0x0200
#define CLOCK_DIV0_OFFSECT      0x0300

//register define
#define rAPLL_LOCK      *((volatile unsigned int *) (CLOCK_BASE + APLL_LOCK_OFFSECT))
#define rMPLL_LOCK      *((volatile unsigned int *) (CLOCK_BASE + MPLL_LOCK_OFFSECT))
#define rAPLL_CON0      *((volatile unsigned int *) (CLOCK_BASE + APLL_CON0_OFFSECT))
#define rMPLL_CON       *((volatile unsigned int *) (CLOCK_BASE + MPLL_CON_OFFSECECT))
#define rCLOCK_SRC0     *((volatile unsigned int *) (CLOCK_BASE + CLOCK_SRC0_OFFSECT))
#define rCLOCK_DIV0     *((volatile unsigned int *) (CLOCK_BASE + CLOCK_DIV0_OFFSECT))

//APLL_CON param
#define APLL_MDIV       0x007D
#define APLL_PDIV       0x0003
#define APLL_SDIV       0x0001

//MPLL_CON param
#define MPLL_MDIV       0x029B
#define MPLL_PDIV       0x000C
#define MPLL_SDIV       0x0001

//set PLL_CON param
#define SET_PLL_DIV(mdiv,pdiv,sdiv) (1<<31 |mdiv << 16 |pdiv << 8 |sdiv)
#define APLL_DIV        SET_PLL_DIV(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_DIV        SET_PLL_DIV(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)

//init clock
void init_clock()
{
        //close clock
        rCLOCK_SRC0 = 0x0;

        //set clock peroid
        rAPLL_LOCK = 0x0000FFFF;
        rMPLL_LOCK = 0x0000FFFF;

        //set PLL is set multiple
        //FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
        rAPLL_CON0 = APLL_DIV;
        //FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
        rMPLL_CON  = MPLL_DIV;

        //set PLL_DIV is set diversion
        rCLOCK_DIV0 = 0x14131440;

        //open clock
        rCLOCK_SRC0 = 0x10000111;
}

        link.lds

SECTIONS
{
        . = 0xd0024000;

        .text :
        {
                start.o
                *(.text)
        }

        .data :
        {
                *(.data)
        }

        bss_start = .;

        .bss :
        {
                *(.bss)
        }

        bss_end = .;
}

        Makefile

CC      =       arm-linux-gcc
LD      =       arm-linux-ld
OBJCOPY =       arm-linux-objcopy
OBJDUMP =       arm-linux-objdump

#预处理器的flag,flag就是编译器可选的选项
CPPFLAGS  := -nostdlib -nostdinc 
#C编译器的flag
CFLAGS    := -Wall -O2 -fno-builtin

export CC LD OBJCOPY OBJDUMP CPPFLAGS CFLAGS

objs    := start.o clock.o led.o

led.bin:$(objs)
        $(LD) -Tlink.lds -o led.elf $^
        $(OBJCOPY) -O binary led.elf led.bin
        $(OBJDUMP) -D led.elf > led.dis
        gcc mkv210.c -o mkv210
        ./mkv210 led.bin sd.bin

%.o:%.S
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

%.o:%.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

clean:
        rm *.o *.elf *.bin *.dis mkv210 -f

        mkv210.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUFSIZE                 (16*1024)
#define IMG_SIZE                (16*1024)
#define SPL_HEADER_SIZE         16
//#define SPL_HEADER              "S5PC110 HEADER  "
#define SPL_HEADER              "****************"

int main (int argc, char *argv[])
{
	FILE		    *fp;
	char		    *Buf, *a;
	int		        BufLen;
	int		        nbytes, fileLen;
	unsigned int	checksum, count;
	int		i;
	
	if (argc != 3)
	{
		printf("Usage: %s <source file> <destination file>\n", argv[0]);
		return -1;
	}

	//分配16K的buffer
	BufLen = BUFSIZE;
	Buf = (char *)malloc(BufLen);
	if (!Buf)
	{
		printf("Alloc buffer failed!\n");
		return -1;
	}

	memset(Buf, 0x00, BufLen);

	//读源bin到buffer
	fp = fopen(argv[1], "rb");
	if( fp == NULL)
	{
		printf("source file open error\n");
		free(Buf);
		return -1;
	}
	//获取源bin长度
	fseek(fp, 0L, SEEK_END);								// 定位到文件尾
	fileLen = ftell(fp);									// 得到文件长度
	fseek(fp, 0L, SEEK_SET);								// 再次定位到文件头
	//源bin长度不得超过16K-16byte
	count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))
		? fileLen : (IMG_SIZE - SPL_HEADER_SIZE);
	//buffer[0~15]存放"S5PC110 HEADER  "
	memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE);
	//读源bin到buffer[16]
	nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count, fp);
	if ( nbytes != count )
	{
		printf("source file read error\n");
		free(Buf);
		fclose(fp);
		return -1;
	}
	fclose(fp);

	//计算校验和
	a = Buf + SPL_HEADER_SIZE;
	for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
		checksum += (0x000000FF) & *a++;
	//将校验和保存在buffer[8~15]
	a = Buf + 8;							
	*( (unsigned int *)a ) = checksum;

	//拷贝buffer中的内容到目的bin
	fp = fopen(argv[2], "wb");
	if (fp == NULL)
	{
		printf("destination file open error\n");
		free(Buf);
		return -1;
	}
	//将16k的buffer拷贝到目的bin中
	a = Buf;
	nbytes	= fwrite( a, 1, BufLen, fp);
	if ( nbytes != BufLen )
	{
		printf("destination file write error\n");
		free(Buf);
		fclose(fp);
		return -1;
	}

	free(Buf);
	fclose(fp);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值