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

2023-10-02 18:38

本文主要是介绍S5PV210裸机(二):看门狗,栈,icache,SoC时钟,重加载,led,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看门狗
        电子设备会跑飞或者死机,需要设备自动复位,看门狗是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 led_blink
                链接地址和运行地址相同,短跳转和长跳转无差异
                链接地址和运行地址不同,短跳转在运行地址,长跳转在链接地址处

        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

        时钟设置寄存器
                xPLL_LOCK:控制PLL锁定周期


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


                 三类寄存器CON、SRC、DIV,CON决定PLL倍频,SRC决定来源,DIV决定分频 

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


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

         

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


                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://关看门狗ldr r0, =WTCONldr r1, =0x0str r1, [r0]//初始化时钟bl clock_init//设置SVC栈ldr sp, =SVC_STACK//开/关icachemrc p15,0,r0,c1,c0,0;			// 读出cp15的c1到r0中//bic r0, r0, #(1<<12)			// bit12 置0  关icacheorr r0, r0, #(1<<12)			// bit12 置1  开icachemcr p15,0,r0,c1,c0,0;//重定位adr r0, _start  			//ldr指令用于加载_start的链接地址:0xd0024000ldr r1, =_start // bss段的起始地址ldr r2, =bss_start	cmp r0, r1			beq clean_bss		//拷贝
copy_loop:ldr r3, [r0], #4    // 源str r3, [r1], #4	// 目的   cmp r1, r2			bne copy_loop// 清bss段
clean_bss:ldr r0, =bss_start					ldr r1, =bss_endcmp r0, r1				// 如果r0等于r1则bss段为空beq run_on_dram			// 清除bss完之后的地址mov r2, #0
clear_loop:str r2, [r0], #4		cmp r0, r1				bne clear_looprun_on_dram:	//长跳转led_blinkldr pc, =led_blink				//调用C程序,bl指令实现短跳转//bl led_blink					b .

        led.c

#define GPJ0CON   0xE0200240
#define GPJ0DAT   0xE0200244#define rGPJ0CON  *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT  *((volatile unsigned int *)GPJ0DAT)void delay_time()
{volatile unsigned int i = 900000;   while (i--);              
}void led_blink()
{// led初始化,设置GPJ0CON为输出模式rGPJ0CON = 0x11111111;while (1){// led亮rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));//延时delay_time();// led灭rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));}
}

clock_init.c

//时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE    0xE0100000  
//相关寄存器偏移
#define APLL_LOCK_OFFSET    0x00    
#define MPLL_LOCK_OFFSET    0x08
#define APLL_CON0_OFFSET    0x100
#define MPLL_CON_OFFSET     0x108
#define CLK_SRC0_OFFSET     0x200
#define CLK_SRC_MASK0_OFFSET  0x280
#define CLK_DIV0_OFFSET     0x300
#define CLK_DIV0_MASK     0x7fffffff#define APLL_MDIV           0x7d    // 125
#define APLL_PDIV           0x3
#define APLL_SDIV           0x1
#define MPLL_MDIV           0x29b   // 667
#define MPLL_PDIV           0xc
#define MPLL_SDIV           0x1#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL      set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL      set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)#define REG_CLK_SRC0  (ELFIN_CLOCK_POWER_BASE + CLK_SRC0_OFFSET)
#define REG_APLL_LOCK (ELFIN_CLOCK_POWER_BASE + APLL_LOCK_OFFSET)
#define REG_MPLL_LOCK (ELFIN_CLOCK_POWER_BASE + MPLL_LOCK_OFFSET)
#define REG_CLK_DIV0  (ELFIN_CLOCK_POWER_BASE + CLK_DIV0_OFFSET)
#define REG_APLL_CON0 (ELFIN_CLOCK_POWER_BASE + APLL_CON0_OFFSET)
#define REG_MPLL_CON  (ELFIN_CLOCK_POWER_BASE + MPLL_CON_OFFSET)#define rREG_CLK_SRC0 (*(volatile unsigned int *)REG_CLK_SRC0)
#define rREG_APLL_LOCK  (*(volatile unsigned int *)REG_APLL_LOCK)
#define rREG_MPLL_LOCK  (*(volatile unsigned int *)REG_MPLL_LOCK)
#define rREG_CLK_DIV0 (*(volatile unsigned int *)REG_CLK_DIV0)
#define rREG_APLL_CON0  (*(volatile unsigned int *)REG_APLL_CON0)
#define rREG_MPLL_CON (*(volatile unsigned int *)REG_MPLL_CON)void clock_init()
{//禁止PLLrREG_CLK_SRC0 = 0x0;//设置锁定时间rREG_APLL_LOCK = 0x0000ffff;rREG_MPLL_LOCK = 0x0000ffff;//设置分频rREG_CLK_DIV0 = 0x14131440;//设置PLL// FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHzrREG_APLL_CON0 = APLL_VAL;// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHzrREG_MPLL_CON = MPLL_VAL;//使用PLLrREG_CLK_SRC0 = 0x10001111;
}

        link.lds

SECTIONS
{. = 0xd0024000;.text : {start.o* (.text)}.data : {* (.data)}bss_start = .; .bss : {* (.bss)}bss_end  = .;	
}

        Makefile

led.bin: start.o led.o clock.oarm-linux-ld -Tlink.lds -o led.elf $^arm-linux-objcopy -O binary led.elf led.binarm-linux-objdump -D led.elf > led_elf.disgcc mkv210_image.c -o mkx210./mkx210 led.bin 210.bin%.o : %.Sarm-linux-gcc -o $@ $< -c -nostdlib%.o : %.carm-linux-gcc -o $@ $< -c -nostdlibclean:rm *.o *.elf *.bin *.dis mkx210 -f	

        mkv210_image.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的bufferBufLen = BUFSIZE;Buf = (char *)malloc(BufLen);if (!Buf){printf("Alloc buffer failed!\n");return -1;}memset(Buf, 0x00, BufLen);//读源bin到bufferfp = 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-16bytecount = (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中的内容到目的binfp = 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;
}

这篇关于S5PV210裸机(二):看门狗,栈,icache,SoC时钟,重加载,led的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/43

相关文章

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

Android WebView无法加载H5页面的常见问题和解决方法

《AndroidWebView无法加载H5页面的常见问题和解决方法》AndroidWebView是一种视图组件,使得Android应用能够显示网页内容,它基于Chromium,具备现代浏览器的许多功... 目录1. WebView 简介2. 常见问题3. 网络权限设置4. 启用 JavaScript5. D

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

SpringBoot项目删除Bean或者不加载Bean的问题解决

《SpringBoot项目删除Bean或者不加载Bean的问题解决》文章介绍了在SpringBoot项目中如何使用@ComponentScan注解和自定义过滤器实现不加载某些Bean的方法,本文通过实... 使用@ComponentScan注解中的@ComponentScan.Filter标记不加载。@C

springboot 加载本地jar到maven的实现方法

《springboot加载本地jar到maven的实现方法》如何在SpringBoot项目中加载本地jar到Maven本地仓库,使用Maven的install-file目标来实现,本文结合实例代码给... 在Spring Boothttp://www.chinasem.cn项目中,如果你想要加载一个本地的ja