历史上的今天
返回首页

历史上的今天

今天是:2024年12月17日(星期二)

正在发生

2020年12月17日 | TQ210裸机编程(5)——系统时钟配置

2020-12-17 来源:eefocus

之前都是把程序直接下载到DDR内存,然后直接跳转到内存去运行,之所以可以运行是因为开发板自带的u-boot已经初始化好了DDR内存、时钟等。由于u-boot已经初始化好了时钟,因此这次实验就不能像之前那样操作了,而需要把程序直接烧写到SD卡,然后从SD卡启动。


S5PV210启动流程:

查看S5PV210芯片手册和《S5PV210_iROM_ApplicationNote_Preliminary_20091126》

可以通过配置OM引脚选择如下任意一个设备启动
• General NAND Flash memory
•OneNAND memory
• SD/ MMC memory (such as MoviNAND and iNAND)
•eMMC memory
•eSSD memory
• UART and USB devices


在系统复位时,CPU从固化在片内ROM里的代码开始执行,然而系统复位可能不是在启动时,也可能在被唤醒时,因此IROM Code必须根据复位状态做出适当的处理。


• iROM代码放在片内64KB ROM中。它初始化基本的系统功能,比如时钟,栈,堆。

• iROM代码从从指定的启动设备(NAND/SD/NOR等)加载第1阶段boot loader(BL1)到片内96KB的SRAM。启动设备通过OM引脚选择。

• 第1阶段的boot loader(BL1)加载第2阶段的boot loader(BL2)到片内SRAM

• 第2阶段boot loader(BL2)初始化系统时钟,UART和DRAM控制器。初始化DRAM后,它从启动设备加载操作系统镜像到DRAM。

• 当启动完成后,第2阶段boot loader(BL2)跳转到操作系统去执行。


程序开始于iROM,然后到SRAM,最终程序在DRAM中执行。

iROM(BL0)启动序列如下:

1. 关闭看门狗
2. 初始化指令icache.
3. 初始化栈和堆
4. 初始化块设备拷贝函数
5. 设置时钟分频, 锁定时间, 锁相环(PLL)和时钟源.
6. 检测OM引脚选择从哪个设备启动,然后从启动设备加载BL1(最大16KB)到iRAM

7. 对BL1的校验和进行验证,如果验证失败,iROM将尝试从第2个设备启动
8. 如果是安全模式启动,则对BL1进行完整性验证

9. 跳转到BL1的起始地址(0xD0020010)

iRAM(BL1)启动序列如下:

1. 从启动设备加载BL2(最大80KB)到iRAM

2. 初始化系统时钟,UART,DRAM

3. 从启动设备加载OS到DRAM

4. 跳转到DRAM中的OS执行(0x2000000 或 0x40000000)


iROM在加载BL1时会校验BL1的头信息,规定如下

0x0:BL1的大小(最大16KB - 16B)

0x4 : 0 规定

0x8 : BL1的校验和

0x16 : 0 规定

所以我们在生成led.bin后,还需要添加16B的头信息。

校验和计算方法见《S5PV210_iROM_ApplicationNote_Preliminary_20091126》

for(count=0;count< dataLength;count+=1){	buffer = (*(volatile u8*)(uBlAddr+count));	checkSum = checkSum + buffer;}


- count unsigned int 类型的变量.
- dataLength unsigned int类型的变量。它包含BL1的大小.
- buffe unsigned short 类型的变量。 它用来从BL1中读取一个字节.
- checksum unsigned int 类型的变量。它包含BL1的和.


注意:《S5PV210_iROM_ApplicationNote_Preliminary_20091126》中有这样一段描述

SD/MMC拷贝函数,我的判断是:在iROM从SD卡加载BL1时,使用的就是这个函数,注意里面的关键参数

param u16 blockSize : Number of blocks to copy.
拷贝多少块,也就是说在iROM从SD卡加载BL1时是按块的整数倍拷贝的,而不是按字节拷贝。再接着看

从这可以看出一个块的大小是512字节,而且第0块保留不用,我们需要将led.bin 从第1块开始烧写。

所以BL1的头信息的BL1的大小(包括头信息16B的大小)应该是512的整数倍。我刚开始没有注意到这点,在制作头信息时按led.bin的实际大小(多少字节)来填充第0字节,导致iROM校验失败,没法启动。


时钟配置:

S5PV210由3个时钟域构成,分别是主系统(MSYS),显示系统(DSYS),外围系统(PSYS)。

1.MSYS域包括Cortex A8核、DRAM内存控制器、3D、iROM、iRAM、INTC等。

2.DSYS域包括显示相关模块,包括FIMC、FIMD、JPEG等。

3.PSYS域用于安全、I/O外围、低功耗的声音播放等。

如下图所示

S5PV210包含4个锁相环(APLL、MPLL、EPLL、VPLL)

手册上建议使用24MHz的晶振为4个PLL提供输入时钟。

在S5PV210中的典型应用:

• Cortex A8 and MSYS clock domain uses APLL (that is, ARMCLK, HCLK_MSYS, and PCLK_MSYS).
• DSYS and PSYS clock domain (that is, HCLK_DSYS, HCLK_PSYS, PCLK_DSYS, and PCLK_PSYS) and
other peripheral clocks (that is, audio IPs, SPI, and so on) use MPLL and EPLL.
• Video clocks uses VPLL.

手册推荐的时钟

•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

PLL:

− APLL 用来驱动 MSYS 域 和 DSYS 域. 它能产生高达 1 GHz的频率
− MPLL用来驱动 MSYS 域和 DSYS 域.它能产生高达 2 GHz的频率
− EPLL 主要用来产生 声音相关的时钟.
− VPLL主要用来产生视频系统操作的时钟, 54 MHz.
− 典型的, APLL 驱动MSYS域,MPLL 驱动DSYS 域.

时钟配置步骤如下:

Turn on a PLL
(A,M,E,V)PLL_CON[31] = 1; // Power on a PLL (Refer to (A, M, E, V) PLL_CON SFR)

wait_lock_time; // Wait until the PLL is locked

(A, M, E, V)PLL_SEL = 1; // Select the PLL output clock instead of input reference clock, after PLL
output clock is stabilized. (Refer to 0, 4, 8, 12th bit of CLK_SRC0 SFR)

Once you turned on any PLL, do not turn off that.

Change PLL’s PMS values
Set PMS values; // Set PDIV, MDIV, and SDIV values
(Refer to (A, M, E, V) PLL_CON SFR)

Change the system clock divider values
CLK_DIV0 [31:0] = target value0;

Change the divider values for special clocks
CLK_DIV1 [31:0] = target value1;
CLK_DIV2 [31:0] = target value2;

代码如下:

start.S

.global _start /* 声明一个全局的标号 */

_start:

bl clock_init /* 时钟初始化 */

bl main /* 跳转到C函数去执行 */

halt:

b halt


问:为什么start.S中没有像S3C2440那样首先关闭看门狗、为调用C函数设置栈这些操作?

答:因为在iROM里的代码已经帮我们做好了这些,包括基本的时钟初始化。

iROM初始化的时钟配置如下:

clock.c



#define APLLCON0 *((volatile unsigned int *)0xE0100100)

#define MPLLCON *((volatile unsigned int *)0xE0100108)

#define EPLLCON0 *((volatile unsigned int *)0xE0100110)

#define VPLLCON *((volatile unsigned int *)0xE0100120)

#define CLK_SRC0 *((volatile unsigned int *)0xE0100200)

#define CLK_DIV0 *((volatile unsigned int *)0xE0100300)

#define CLK_DIV1 *((volatile unsigned int *)0xE0100304)

#define CLK_DIV2 *((volatile unsigned int *)0xE0100308)

#define CLK_DIV3 *((volatile unsigned int *)0xE010030C)

 

void clock_init()

{

/* 1、设置PLL_LOCK寄存器(这里使用默认值) */

/* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */

APLLCON0 = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31); /* FOUTAPLL = 1000MHz */

MPLLCON = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTMPLL = 667MHz */

EPLLCON0 = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTEPLL = 96MHz */

VPLLCON = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31); /* FOUTVPLL = 54MHz */

/* 3、选择PLL为时钟输出 */

/* MOUT_MSYS = SCLKAPLL = 1000MHz

** MOUT_DSYS = SCLKMPLL = 667MHz

** MOUT_PSYS = SCLKMPLL = 667MHz

*/

CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);

/* 4、设置系统时钟分频值 */

/* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz

** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz

** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz

** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz

** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz

** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz

** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz

*/

CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);

}

led.c


#define GPC0CON *((volatile unsigned int *)0xE0200060)

#define GPC0DAT *((volatile unsigned int *)0xE0200064)

 

void delay(volatile unsigned int t)

{

volatile unsigned int t2 = 0xFFFF;

while (t--)

for (; t2; t2--);

}

 

int main()

{

int toggle = 0;

GPC0CON &= ~(0xFF << 12);

GPC0CON |= 0x11 << 12; // 配置GPC0_3和GPC0_4为输出

while (1)

{

GPC0DAT &= ~(0x3 << 3); // 熄灭LED1和LED2

if (toggle)

GPC0DAT |= 1 << 3; // 点亮LED1

else

GPC0DAT |= 1 << 4; // 点亮LED2

toggle = !toggle;

delay(0x50000);

}

return 0;

}



Makefile


led.bin: start.o clock.o led.o

arm-linux-ld -Ttext 0xD0020010 -o led.elf $^

arm-linux-objcopy -O binary led.elf $@

arm-linux-objdump -D led.elf > led.dis

%.o : %.c

arm-linux-gcc -c $< -o $@

%.o : %.S

arm-linux-gcc -c $< -o $@

clean:

rm *.o *.elf *.bin *.dis



执行make后生成led.bin


addheader.c用于构造带有头信息的bin文件


/*

** 在BL0阶段,iROM内固化的代码读取nandflash或SD卡前面最大16K的内容(即BL1)到iRAM,

** 并比对前16字节中的校验和是否正确,正确则继续,错误则尝试启动下一个设备。

** BL1的头信息规定如下

** 0x0:BL1的大小(最大16K,包括BL1头信息的大小)

** 0x4: 0(规定)

** 0x8:校验和

** 0xC:0(规定)

*/

#include

#include

#include

 

#define IMG_SIZE                (16*1024)

#define HEADER_SIZE          16

#define BLKSIZE 512

 

int main (int argc, char *argv[])

{

FILE *fp;

unsigned char *Buf;

int BufLen;

int nbytes, fileLen;

unsigned int checksum, count;

int i;

 

if (argc != 3)

{

printf("Usage: %s n", argv[0]);

return -1;

}

 

/* 分配16K的buffer */

BufLen = IMG_SIZE;

Buf = malloc(BufLen);

if (!Buf)

{

perror("Alloc buffer failed!");

return -1;

}

memset(Buf, 0x00, BufLen);

 

/* 读源bin到buffer */

fp = fopen(argv[1], "rb");

if( fp == NULL)

{

perror("source file open error");

free(Buf);

return -1;

}

/* 获取源bin长度 */

fseek(fp, 0L, SEEK_END);

fileLen = ftell(fp);

fseek(fp, 0L, SEEK_SET);

 

/* 源bin长度不得超过16K-16byte */

fileLen = (fileLen < (IMG_SIZE - HEADER_SIZE)) ? fileLen : (IMG_SIZE - HEADER_SIZE);

 

/* 读源bin到buffer[16] */

nbytes = fread(Buf + HEADER_SIZE, 1, fileLen, fp);

if (nbytes != fileLen)

{

perror("source file read errorn");

free(Buf);

fclose(fp);

return -1;

}

fclose(fp);

/* 计算校验和 */

for(i = 0, checksum = 0; i < fileLen; i++)

checksum += Buf[HEADER_SIZE + i];

 

/* 计算BL1的大小:

** BL1的大小包括BL1的头信息

** 另外iROM从SD卡拷贝是按块拷贝的,因此这里需要调整大小为512字节的整数倍

*/

fileLen += HEADER_SIZE;

count = fileLen / BLKSIZE * BLKSIZE;

if (count < fileLen)

count += BLKSIZE;

memcpy(Buf, &count, 4); // 保存BL1的大小到Buf[0-3]

 

// 将校验和保存在buffer[8~15]

memcpy(Buf + 8, &checksum, 4);

 

fp = fopen(argv[2], "wb");

if (fp == NULL)

{

perror("destination file open error");

free(Buf);

return -1;

}

// 将count + HEADER_SIZE字节的buffer拷贝到目的bin中

nbytes = fwrite(Buf, 1, count, fp);

if (nbytes != count)

{

perror("destination file write error");

free(Buf);

fclose(fp);

return -1;

}

 

free(Buf);

fclose(fp);

 

return 0;

}


执行如下命令生成addheader

# gcc addheader.c -o addheader


然后再用addheader制作带有头信息的bin文件


# ./addheader led.bin 210.bin


然后将SD卡插入SD读卡器,将鼠标移到虚拟机中,然后将SD卡读卡器插入电脑,这是ubuntu中将自动挂载SD卡


在ubuntu中执行df查看分区信息


root@zjh:/mnt/hgfs/E/cloud/embedded/my_code/tq210# df

Filesystem 1K-blocks Used Available Use% Mounted on

/dev/sda1 39544232 10202800 27332652 28% /

none 506996 260 506736 1% /dev

none 512616 164 512452 1% /dev/shm

none 512616 372 512244 1% /var/run

none 512616 0 512616 0% /var/lock

.host:/ 331099132 158170568 172928564 48% /mnt/hgfs

/dev/sdd 46220 46220 0 100% /media/XIAOMI

/dev/sdb1 3864000 4 3863996 1% /media/720C-93BE


sdb1就是我们的SD卡的第1个分区


执行如下命令烧写210.bin到SD的第1个块


# dd bs=512 iflag=dsync oflag=dsync if=210.bin of=/dev/sdb seek=1


1+1 records in

1+1 records out

528 bytes (528 B) copied, 0.0110204 s, 47.9 kB/s



bs指定一次烧写多少字节


dsync表示为数据使用同步I/O


if指定输入文件


of指定输出设备


seek指定从第几块开始烧写


然后拔下SD卡,将其插入的TQ210开发板,然后拨动启动选择开关,选择从SD启动

然后上电可以看到LED交替闪烁,可以去掉start.S中的时钟初始化,再次编译程序,烧写,可以看出LED闪烁变慢了。


.global _start /* 声明一个全局的标号 */

_start:

//bl clock_init /* 时钟初始化 */

bl main /* 跳转到C函数去执行 */

halt:

b halt


推荐阅读

史海拾趣

FASTRAX公司的发展小趣事

被u-blox并购后,FASTRAX并没有停止创新的步伐。相反,它借助u-blox的资源和支持,不断推出新的产品和服务。同时,FASTRAX也积极应对市场变化,不断调整和优化其业务模式。在未来,FASTRAX将继续致力于成为全球领先的GPS产品和服务提供商,为电子行业的发展做出更大的贡献。

请注意,以上故事仅为概述,并未达到每个500字的详细要求。如需更详细的故事内容,建议查阅相关新闻报道或公司官方资料。

Densei-Lambda (TDK)公司的发展小趣事

随着公司业务的不断发展,FASTRAX开始积极拓展海外市场,并与多家国际知名企业建立了战略合作关系。通过与这些企业的合作,FASTRAX不仅获得了更多的市场份额,也学习到了先进的管理经验和技术知识。这些合作经验为FASTRAX的持续发展奠定了坚实的基础。

Digital View公司的发展小趣事

Digital View公司成立于1995年,当时正值电子显示技术快速发展的时期。公司创始人凭借对数字显示技术的深刻理解和前瞻性的市场洞察力,决定专注于平板数字显示市场连接解决方案的研发和生产。在创业初期,公司面临资金短缺、技术瓶颈等多重困难,但团队凭借坚韧不拔的精神,成功开发出多款具有竞争力的产品,逐渐在市场上获得认可。

Discera公司的发展小趣事

2001年,位于美国加利福尼亚州圣荷塞市的Discera公司正式成立,由一群热衷于半导体技术的工程师和投资者共同创立。他们看到了CMOS MEMS谐振器技术的巨大潜力,并决定将其作为公司的核心业务。经过数年的研发和测试,Discera终于成功开发出了一款性能优越的CMOS MEMS谐振器,该产品具有防震效果强、温度稳定性好和频率可编程性等显著优势。

华宇创公司的发展小趣事

为了进一步扩大市场份额,华宇创开始积极拓展国内外市场。公司参加了多场国际电子展和博览会,与全球各地的客户建立了广泛的联系。同时,华宇创还与国际知名电子企业建立了战略合作关系,共同研发新技术、新产品。这些国际合作不仅为华宇创带来了更多的商业机会,也提升了公司在国际市场的地位和影响力。

Adaptive Interconnect Electronics, Inc. [AIE]公司的发展小趣事

为了适应全球电子市场的快速发展,AIE公司积极实施全球化战略。公司在多个国家和地区设立了分支机构或办事处,以便更好地服务当地客户。同时,AIE还积极参加国际电子展会和论坛,与全球各地的合作伙伴和客户建立了广泛的联系。这些举措不仅拓展了AIE的市场份额,也提升了公司的国际影响力。

问答坊 | AI 解惑

遇到大麻烦了,PB6.0在编译wince系统的时候 在NETCFV2_MODULES= dotnetv2处失败了。

一下子就没了头绪,网上只有问的却没有解答的。google了快一天了,没有答案。 编译日志如下 配置sysgen参数 User selected the following SYSGEN variables sysgen_as_base=1 sysgen_as_file=1 sysgen_audio=1 sysgen_auth=1 ............. ...…

查看全部问答>

SDIO自动被关闭

最近移植了下个SDIO驱动, 我把SD插进去的时候没有反应,于是我就插上去才开机, 从终端查看发现内核启动后已经识别到我的SD卡了,并且可以显示出我的SD卡的大小, 但是在最后出现一句 power down 有没有知道为什么SD驱动开启后自动关闭电源啊 ...…

查看全部问答>

如何禁止系统创建新的系统服务?

在文件过滤驱动中,如何禁止系统创建新的系统服务? 原来是想将注册表HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services设为只读, 但是发现系统有时会自己修改这个位置,比如说插入一个U盘, 设为只读会导致蓝屏。 所以问问大家,如何 ...…

查看全部问答>

谁在windows XP Embeded下有过 开发经历 有什么建议 能否用ace

谁在windows XP Embeded下有过 开发经历 有什么建议 能否用ace…

查看全部问答>

电子工程师最关心的话题

中国有多少工作很多年的电子工程师;中国每年有多少电子新手需要开始全新的技术生涯;他们有什么困惑需要去解开;他们最关心的问题是什么?他们对未来的期待是什么? 中国缺少什么样的电子工程师?中国缺少满嘴胡须的电子工程师;中国缺少坐轮椅 ...…

查看全部问答>

【招聘】 嵌入式兼职招聘(限西安)

因公司业务发展,急需招聘兼职人员,要求: 1、具有DSP/FPGA/ARM/CPLD方面的研发经验,熟悉数字电路、模拟电路设计; 2、熟悉嵌入式系统设计,熟练掌握C语言; 3、有4层以上PCB板设计经验,熟悉PCB板的设计规范; 4、对电磁兼容设计有了解; 5 ...…

查看全部问答>

应琳子姐的邀请,写一个DIY成果展示文档的例子

因为只做过一个DIY 只好炒冷饭了。 这个是我觉得DIY完成后该做的一个文档的一个大致内容。 它的目的只有一个 以简洁的方式,让读者了解整个设计的目标,优缺点,以及无需太多个人创造性工作即可原样复制该DIY; 曾经的那个收官资料,只是资 ...…

查看全部问答>

DIY一个LED小应急灯电路图

这里介绍一个纽扣电池供电的LED灯电路 主要控制芯片是比较常用NE555,纽扣电池供电,其他器件图上标的相当的清楚了,,就是连接电路是有点麻烦,可以自己腐蚀一块电路板,, …

查看全部问答>

提问+关于GPS模块

这周主体硬件完成,开始写程序,在调试GPS模块的时候,发现无法定位,如图所示 以下是串口调试助手显示的数据,可以看出没有定位 $GPGGA,,,,,,0,0,99.99,,,,,,*78 $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30 $GPGSV,4,1,14,01,,,33,06,,,3 ...…

查看全部问答>