历史上的今天
返回首页

历史上的今天

今天是:2025年04月18日(星期五)

正在发生

2020年04月18日 | S3C2440A之ARM学习的所有的问题

2020-04-18 来源:eefocus

问题1:关于Nor/Nand启动判断的问题:


视频讲解是用写0到[0x0],取出还是0则Nand启动,视频例程:

mov r1, 0

ldr r0, [r1]

str r1, [r1]

ldr r2, [r1]

cmp r1, r2

//如果r1 != r2, nor启动

ldr sp, =0x40000000 + 4096

//如果r1 == r2, nand启动

moveq sp, #4096

streq r0, [r1]

如果:拨码开关为Nor启动,Norflash[0x0]地址中数据原本

即为0,Nor启动不能写入,但cmp r1, r2时,r1==r2依然

成立,系统是否会判断为Nand启动?有没有影响?怎么判断?


答:1>【传说】hceng(1307410945):不会为0的,因为你的代码烧在nor/nand 0地址上,既然有代码,就不会为0;    


hexdump xx.bin 你会看到 首个数据 不会是0的;  


 正因为 0地址的数据是有用的,所以才会先保存到r0,最后再从r0恢复: ldr r0, [r1]   ->   streq r0, [r1]


nand启动才会修改,nor不会。 也就是说 nor启动,下次还能启动,,先nand启动就废了


你试试 去掉streq r0, [r1]  理论上 下次就启动不了,,我没试,我是从理论上分析的。。。帮忙试下 告诉结果。。。==

 

2>会 可以改下代码先判断nor中第一个是否和写入的相同

3>这个跟判断 大小段端  一个原理  差异处 区分 


问题2:裸板实验操作流程:Windows环境下编写start.S、*.c、Makefile文件,文件上传到Ubuntu环境(即主机)并编译连接生成*.bin文件,把.bin文件通过DOS系统的命令行工具烧写到开发板Norflash/Nandflash,把开发板启动开关调至相应的启动开关,关闭电源拔掉eop烧写器,重新上电,观察开发板现象。

程序烧写到什么位置啦(即程序的存储位置)?Norflash/Nandflash?

芯片有多种启动方式,而这些启动方式都可以由配置引脚来选择。芯片在启动时读取这些配置引脚的电平,就可以判断从那种方式启动。通常在研发阶段的实验板或者很多学习板(如:JZ2440)通常采用开关或跳线帽等方式来将配置引脚的电平置为高电平或置为低电平。在出厂时, 配置引脚一般通过上下拉电阻来设置电平。

从NOR FLASH启动:


    从NOR FLASH启动时,由前面的图1,由nGCS0控制的bank0直接连接了nor flash,而bank0能访问的地址范围为:256M(0X00000000----0X08000000),JZ2440开发板使用的nor flash大小为2M(0X00000000----0X00200000),从而S3C2440芯片的物理地址(0X00000000----0X00200000)就由nor flash来占据。


    选择从NOR FLASH启动,上电,S3C2440芯片就会去运行nor flash上地址为0x0处的指令。从后面的实验中,可以清楚的知道,读nor flash可以像读内存那样读,但是要用额外的命令向nor flash写入数据。如果nor flash像内存那样读和那样写,那nor flash完全可以被内存所替代。


(摘录自:博客园-韦东山  https://www.cnblogs.com/weidongshan/p/6689728.html)

由此可知,(1)DOS环境下命令行工具烧写设置决定了.bin文件的烧写到开发板的存储位置(即Norflash、Nandflash),因此,不管是Nor/Nand启动,地址[0x0]一定不为空(即地址[0x0]内的数据一定不为0);

(2)S3C2440的启动方式则由OM0和OM1引脚(开发板具体通过拨码开关控制)来选择。因此,当程序烧写到Norflash而选择Nandflash启动开发板不会有现象,Nandflash同理。

(3)执行程序时,通过在程序中对已知启动方式的判断,来设置栈区地址(个人理解程序开头对启动方式进行判断的作用就是干这个的)。程序执行是从0x0地址开始:(假设Nand启动)Nandflash中已经存有代码,地址[0]数据不为0,因此,通过【写0到[0x0],然后取出与0比较:如果r1 != r2, nor启动;如果r1 == r2, nand启动;假设r1 == r2】则表示程序存储在Nandflash(以地址0x0开始)且前4k映射到SRAM,栈区在SRAM顶部,地址为4096;    (假设Nor启动)Norflash中已经存有代码,地址[0]的存储空间不可进行写操作且数据不为0。Nor启动,则程序直接在Norflash启动,栈区地址也在SRAM顶部,地址为(0x40000000+4096)。因此,杜绝了Nand/Nor启动时地址[0x0]的空间未被赋值0时原本数据为0的可能性。

(此即问题1的答案)


问题3:Nor启动,SRAM除了存储寄存器sp之类,还有别的作用吗?


问题4:ARM中Makefile的规则、语法、函数及实例


1.Makefile的说明:


1)功能【gcc -Werror -Iinclude  -c  -o  c.o  c.c  -MD  -MF   .c.o.d】来自gcc,和Makefile本身无关


2)当工程中文件(包括 .c/ .h/ .s ...)路径发生变化后,需要【make distclean】一次,再重新make(为什么?)


3)当工程文件(包括 .c/ .h/ .s ...)只执行了内容修改,直接make即可重新编译生成  .o文件,原来的依赖可直接用(?)


2. arm-led工程:include/s3c2440_soc.h、led.c、Makefile、start.S四个文件


实现功能:单灯流水、双灯流水、三灯流水,循环


实验结果:完全实现预定功能,可参考成功arm-Makefile例程如下:




问题5:变量/函数的声明、定义、初始化的作用和区别?


(1)变量:声明是告诉编译器有这么个变量,但并不实现。定义就是实现这个变量,真正在内存(堆或栈中)为此变量分配空间


声明简单的说就是 定义变量类型但不为其分配空间。



定义就是指定变量类型,然后分配空间并为其初始化。

(2)函数:声明嘛表示有这么个函数了,定义就是具体实现了,举个例子:

函数声明:

int fun(int a, int b);    //a,b为形参


函数定义:

int fun(int a,int b)

{ int c;

c=a+b;


return c; }


函数调用(即函数初始化):


fun(3, 5);        //3, 5为实参




声明就象是定义的头部,比较简略,函数是用来调用的,如果函数定义部写到调用的位置后面,执行到调用位置,后面根本没执行就找不到了,当然报错了,就要在前面加声明,表示有这个函数,反之先写函数体,后调用声明就用不了,不在同一源文件,道理也是如此



//声明在函数外,声明后面的函数(无论main还是其他函数)都可以调用                //声明在函数内部,只能在本函数内,声明后面的区域可以调用    

问题6:UART特殊功能模块的寄存器操作机理和使用疑难的问题

    6.1 配置UART的几个寄存器:

UBRDIVn寄存器:设置波特率,S3C2440 UART的时钟源有两种选择:PCLK、UEXTCLK、FCLK/n,其中n的值通过UCON0-UCON2联合设置


ULCONn寄存器:设置传输格式


UCONn寄存器:它用于选择UART时钟源、设置UART中断方式


UFCONn寄存器、UFSTATn寄存器,UFCONn寄存器:用于设置是否使用FIFO,设置各FIFO的触发阙值,即发送FIFO中有多少个数据时产生中断、接收


      FIFO中有多少个数据时产生中断。并可以通过设置UFCONn寄存器来复位各个FIFO。读取UFSTATn寄存器可以知道各个FIFO是否已经满,其中有多少个数据。


UMCONn寄存器、UMSTATn寄存器:这两类寄存器用于流量控制,具体看数据手册UTRSTATn寄存器:它用来表明数据是否已经发送完毕、是否已经接收到数据


UERSTATn寄存器:用来表示各种错误是否发生


UTXHn寄存器:CPU将数据写入这个寄存器,UART即会将它保存到缓冲区中,并自动发送出去


URXHn寄存器:当UART接收到数据时,CPU读取这个寄存器,即可获得数据。


    6.2

问一个关于串口的问题:

int puts(const char *s)

{

while(*s)

{

putchar(*s);

s++;

}

}

当字符串结束,*s=0,跳出while()循环

问:为什么字符串结束后, *s一定等于0?

答:对于字符串,程序是当做字符数组处理的,在数组的结尾,程序会自动加一位元素''作为结束标志,因此,*s = ‘’,即为空,为假,跳出循环

    6.3 UART0作调试打印功能时,输入之后再PC机串口工具回显输出乱码的问题


答:可能的原因有  种,


    01:波特率设置不对,导致此的可能原因有:


          a)UBRDIV0设置或计算错误;


            b)UCON0  位[11 : 10]时钟选择错误:


            UCON0  位[11 : 10],选择 PCLK,UEXTCLK 或 FCLK/n 给 UART 波特率。


            UBRDIVn = (int)(被选时钟 / (波特率 × 16) ) – 1;              00 = PCLK  10 = PCLK  01 = UEXTCLK  11 = FCLK/n  


            (如果希望选择 FCLK/n,应该在选择或取消选择 FCLK/n 后加上“NOTE”的代码。)


void uart0_init(void)

{

//设置UART0输出输入引脚

GPHCON &= ~((3<<4)|(3<<6));

GPHCON |= ((2<<4)|(2<<6));

//GPHUP &= ~((1<<2)|(1<<3));    //该句屏蔽不影响串口的操作,为什么要写?操作GPF4,5,6时问什么不需要设置?

//设置波特率

UCON0 = 0x00000005;    //若UCON0 = 0x00000003,则PC机串口工具无输出显示

UBRDIV0 = 26;

//设置数据格式

ULCON0 = 0x00000003; //8n1

}


        c)时钟分频寄存器CLKDIVN = 0b101 = 5,设置错误


/*设置时钟分频寄存器CLKDIVN = 0b101 = 5*/

ldr r0, = 0x4c000014

mov r1, #5        //若#5改为 #3 ,则PC机串口工具输出乱码

str r1, [r0]

/*如果 HDIVN 不为 0,CPU 总线模式应该使用以下指令使其从快总线模式改变为异步总线模式(S3C2440

*不支持同步总线模式)

*/

MRC  p15, 0,  r0,  c1,  c0,  0

ORR  r0,  r0,  #0xc0000000

MCR  p15, 0,  r0,  c1,  c0,  0

/*设置多层锁相环控制寄存器MPLL,使得MPLL = 400MHz*/

ldr r0, = 0x4c000004

ldr r1, = ((92<<12) | (1<<4) | (1<<0))

str r1, [r0]

    02:数据格式不对?

问题7:操作寄存器的规范

改变寄存器的话。读 改 写 三步。别影响其他位。

对某个寄存器进行操作时,先对该寄存器清零,再赋值。

详细:见【归纳】C语言代码编写规范——ARM


问题8:ARM架构芯片(如ARM9-s3c2440a),寄存器都是32位,为什么?


答:寄存器的本质是内存,且ARM架构下固定的32 bits 操作码(opcode)长度,降低编码数量所产生的耗费,减轻解码和流水线化的负担。大多均为一个CPU周期执行。组成操作码字段的位数一般取决于计算机指令系统的规模。


问题9:S3C2440芯片手册中,EINT[]; 什么意思?

_EINT();是打开全局中断,跟51中EA=1;效果相似

_DINT();是关闭全局中断,跟51中EA=0;效果相似

_EINT();是打开全局中断,跟51中EA=1;效果相似

_DINT();是关闭全局中断,跟51中EA=0;效果相似

问题10:编译时,反汇编 *.dis 文件显示,0X0地址非<_start>,编译生成的 *.bin 文件在开发板显示失败的原因查找


Makefile:

arm-linux-ld -Ttext 0 start.o led.o uart.o init.o main.o -o uart.elf

该步完成链接功能,把汇编好的OBJ(机器码)文件、库文件链接起来,最终形成可以在特定平台运行的可执行文件,用到的工具为arm-linux-gcc。

链接顺序从  arm-linux-ld -Ttext 0  之后,从0X0地址开始,依次存放start.o led.o uart.o init.o main.o文件,顺序一定要注意,start文件在第一位,main文件在最后位

具体原理不是很清楚,不过大概是链接器从左到右依次解析输入文件,判断是否是目标文件与存档文件


问题11:关于头文件包含的问题


11.1 对头文件的包含的问题:

1)使用文件和头文件在同一个目录,用法:#include "s3c2440_soc.h"

2)使用文件和头文件不在同一个目录,用法:#include


需要注意的是,方法2有时候对不再同一个目录的头文件包含时会出错,原因未知


    例如:下面main()中使用头文件:


    1.#include     #include


    Makefile1可以顺利编译,Makefile2不可


现有工程文件E:Linux-ARM编程一期ARM裸板程序内存控制器NorFlash

start.S, Makefile, main.c, led.c  文件夹:include 

头文件夹include:s3c2440_soc.h, uart.h

 

Makefile:

objs = main.o  led.o  start.o

dep_files := $(patsubst %, .%.d, $(objs))

dep_files := $(wildcard $(dep_files))

CFLAGS = -Werror  -Iinclude

all: $(objs)

arm-linux-ld -Ttext 0 start.o  led.o  main.o -o led.elf

arm-linux-objcopy -O binary -S led.elf led.bin

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

ifneq ($(dep_files), )

include $(dep_files)

endif

%.o: %.c

arm-linux-gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d

%.o: %.S

arm-linux-gcc $(CFLAGS) -c -o $@ $< 

clean:

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

distclean:

rm $(dep_files)

.PHONY:

clean

 

Makefile2:

all:

arm-linux-gcc -c -o led.o led.c

arm-linux-gcc -c -o uart.o uart.c

arm-linux-gcc -c -o init.o init.c

arm-linux-gcc -c -o main.o main.c

arm-linux-gcc -c -o start.o start.S

arm-linux-ld -Ttext 0 start.o led.o uart.o init.o main.o -o uart.elf

arm-linux-objcopy -O binary -S uart.elf uart.bin

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

clean:

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



11.2 头文件的制作




例程:


#ifndef _MY_PRINTF_H

#define _MY_PRINTF_H

 

int printf(const char * fmt, ...);

int my_printf_test(void);

 

#endif


参考链接


http://topic.csdn.net/u/20101125/22/15af528d-d417-4f6b-8fa9-565e3d980eb2.html

http://blog.csdn.net/zlwzlwzlw/archive/2009/12/07/4955560.aspx

http://hi.baidu.com/paladin1893/blog/item/8dab19510325586b843524e1.html


https://blog.csdn.net/duan19920101/article/details/50991794


问题12:关于特殊功能寄存器使能内部上拉的问题




控制LED灯的寄存器GPF4,5,6使能内部上拉没有专门写到程序,而控制UART0的输出输入引脚的GPH2,3程序专门写了使能内部上拉


已知:芯片重启时,GP_UP端初始状态[0x00],0:默认使能附加上拉功能到相应端口引脚


问1:UART0的输出输入引脚的GPH2,3为什么还写内部上拉?为了程序严谨吗?


问2:控制LED灯的寄存器GPF4,5,6使能内部上拉为什么不写?不担心内部电平过低(当GPF4,5,6的使能端被改动时)?


问题13:关于波特率分频寄存器UBRDIVn,设置公式为什么这样写的问题


UBRDIVn: UART baud rate divisor registers  → UARTUART  波特率分频寄存器


baud英 [bɔːd] 美 [bɔd]    n. 波特(信息传输速率的单位)       n. (Baud)人名;(英)鲍德;(法)博

rate英 [reɪt] 美 [ret]    n. 比率,率;速度;价格;等级      vt. 认为;估价;责骂    vi. 责骂;被评价

divisor英 [dɪ'vaɪzə]美 [dɪ'vaɪzɚ]n. 除数;因子

波特率发生


每个UART 的波特率发生器为发送器和接受器提供串行时钟。波特率发生器的源时钟可以选择 S3C2440A 的内部系统时钟或 UEXTCLK。换句话说,分频由设置 UCONn 的时钟选项选择。波特率时钟是通过 16 和由 UART波特率分频寄存器(UBRDIVn)指定的 16 位分频系数来分频源时钟(PCLK,FCLK/n 或 UEXTCLK)产生的。

    UBRDIVn 由下列表达式决定:

    UBRDIVn = (int)( UART 时钟 / ( 波特率 × 16) ) - 1

    (UART 时钟:PCLK,FCLK/n 或 UEXTCLK)

当然,UBRDIVn 应该是从 1 至(2 16 -1),只有在使用小于 PCLK 的 UEXTCLK 时设置为 0(旁路模式)。

例如,如果波特率为 115200 bps 并且 UART 时钟为 40 MHz,则 UBRDIVn 为:

    UBRDIVn = (int)(40000000 / (115200 x 16) ) - 1

    = (int)(21.7) - 1 [ 取最接近的整数]

    = 22 - 1 = 21


问题14:UART0回显程序完成并运行成功之后,查看赋值操作和位操作时的寄存器的类别情况


答:1)对寄存器的赋值运算只是简单的赋值单项运算; 对寄存器的位操作大多是把数值进行位操作之后与寄存器进行逻辑运算,然后把结果再赋值给寄存器,算是复合运算

2)进行位操作复合运算的全部是I/O Ports寄存器,而进行单项赋值运算的则全是特殊功能寄存器


问题15:怎样提高程序查错调试的效率?


1)有么有可以查看一段内存中所有数据的办法?并且可以查看这段内存的代码和地址?


原因:当程序出错时,编译器播出错误的地方,但实际错误可能只在最前面,这样检查错误耗费大量时间,于是想直接查看程序在开发板上的地址和对应的代码,这个方法现实吗?有没有呢?貌似反汇编可以完成这个任务?但汇编太不人性化,很难


解决方法:



2)按照编译器提示的错误原因和错误代码位置,细心逐行排除


例:JZ2440一个按键控制LED的程序,编译链接时出现:




问题发现:指令后面的 ';'未加,很简单,费了好久时间才找到原因,逐行排除法最快






问题16:关于全局变量g_char、g_char3进行自加运算时,一直输出同样的大小写字母的解决

==============================================================

SDRAM设置之后,测试结果:

--------------------------------------------------------------

当g_char、g_char3是main()函数的局部变量时:

Nand运行时:AaBbCcDd ...  LED循环

推荐阅读

史海拾趣

Globaltech Semiconductor Co Ltd公司的发展小趣事

为了保持技术领先地位,Globaltech持续加大研发投入,建立了先进的研发中心和测试实验室。公司不断引进国内外顶尖的研发人才,并与多所知名高校和研究机构建立产学研合作关系。这些努力使得Globaltech在电源管理IC领域取得了多项技术突破,并成功拓展了产品线,涵盖了ESD保护器件、MOSFET等多个领域。这些新产品不仅丰富了公司的产品线,也为客户提供了更加全面的解决方案。

Desco Tools公司的发展小趣事

Desco Tools公司一直注重客户服务和品质保障。公司建立了完善的客户服务体系,为客户提供全方位的技术支持和解决方案。同时,公司还建立了严格的质量管理体系,确保每一件产品都符合高标准的质量要求。这些举措赢得了客户的信任和好评,也为公司的长期发展提供了有力保障。

磁联达(CND-tek)公司的发展小趣事

磁联达(CND-tek)公司成立于2002年,正值中国电子行业的蓬勃发展期。创始人王雪霞凭借对市场敏锐的洞察力和对技术的深厚理解,决定专注于网络通讯类变压器和滤波器的研发与生产。初创时期,公司面临着资金短缺、技术积累不足和市场竞争激烈等多重挑战。然而,王雪霞带领团队坚持不懈地研发新产品,不断优化生产工艺,逐渐在市场上赢得了客户的认可。

港源(GANGYUAN)公司的发展小趣事

磁联达(CND-tek)公司成立于2002年,正值中国电子行业的蓬勃发展期。创始人王雪霞凭借对市场敏锐的洞察力和对技术的深厚理解,决定专注于网络通讯类变压器和滤波器的研发与生产。初创时期,公司面临着资金短缺、技术积累不足和市场竞争激烈等多重挑战。然而,王雪霞带领团队坚持不懈地研发新产品,不断优化生产工艺,逐渐在市场上赢得了客户的认可。

ELEMENT14公司的发展小趣事

ELEMENT14的在线社区是其成功的关键因素之一。公司投入大量资源建设和发展在线社区,吸引了大批电子设计工程师和采购专员的参与。在这个平台上,工程师们可以分享经验、交流技术、解决问题。ELEMENT14还通过社区收集客户反馈和需求,不断优化产品和服务。这个活跃的在线社区不仅增强了客户黏性,也为公司提供了宝贵的市场信息。

FOCI Fiber Optic Communications Inc公司的发展小趣事

为了满足全球客户的需求,ELEMENT14致力于构建和优化全球供应链。公司与多家国际知名电子元器件制造商建立了长期稳定的合作关系,确保了货源的稳定性和多样性。同时,ELEMENT14还建立了全球物流体系,实现了快速、准确的物流配送服务。这些措施不仅提升了客户满意度,也增强了公司在全球市场的竞争力。

问答坊 | AI 解惑

求购“VHDL入门·解惑·经典实例·经验总结”

可以是二手,只要是一本VHDL入门·解惑·经典实例·经验总结即可!谢谢,我的QQ号:544013869  可以出原价22元,有意者请与我联系…

查看全部问答>

求助:CP5512卡与什么接口匹配?

求助:CP5512卡与什么接口匹配?现在市场上带PCMCIA接口的笔记本电脑没有了,是新的EXPRESS CARD接口,机械尺寸没有办法保证,CP5512卡怎么用啊?!另外CP5512卡属于 TYPE ⅠⅡⅢ 中哪种?有一款DELL有CP5512口的TYPE Ⅰ和Ⅱ,买回 ...…

查看全部问答>

寻Wince开发工程师

寻Wince BSP开发和应用开发工程师。望有识之士联系! peizhi78@126.com…

查看全部问答>

如何做嵌入式下的无线软件升级系统?

是用socket做还是用web services做?如果要用web services是不是evc不能用,只能用vs.net呢?望各位指教!…

查看全部问答>

在WINCE5.0 可以改变默认字体的大小吗?

当使用液晶分辨率高是,WINCE的字体和菜单就显示得很小了,可不可以修改内核增大字体和菜单呢?…

查看全部问答>

步进控制系统

请各位老师指教一下 我有一个800型热切热封制袋机 想改一套步进控制系统 请问我要买什么型号的电机 和驱动器 还有控制机器 电脑之类的 要求价格合理 精度高 速度快 不想改伺服 太贵  以前我这个机器是机械式的 没有电脑 谢谢各位老 ...…

查看全部问答>

usb虚拟串口例程,USB_DISCONNECT_PIN是干什么用的?

                                 看程序好像是联接/断开USB用的,这个脚连到了USB端口?还是只是个连接的状态指示灯?…

查看全部问答>

电子技术探讨

电子技术探讨 XC2C64A. 朋友们,你们好!   在下有个问题要请教下各位,希望大家热烈踊跃探讨! 在XILINX 产品系列中,应该有相似的可以相互代替的 XC2C64A也算是廉价的产品之一。 问题探讨: 想在XILINX产品中找与XC2C64A特性功 ...…

查看全部问答>

12864并行驱动程序

已知BUG:显示”液晶12864驱动程序“乱码,就是中文和西文必须分开显示 代码:主函数main.c #include <msp430g2553.h> #include \"lcd12864.h\" void main() { WDTCTL = WDTPW + WDTHOLD;BCSCTL1 = CALBC1_8MHZ; // 多谐2楼指导 D ...…

查看全部问答>

TI首届低功耗设计大赛参赛网友设计进展汇总(12月17日更新)

活动详情>>TI首届低功耗设计大赛之玩转MSP430 FRAM MCU! 离大赛结束的时间(1月5日)越来越近了,请大家抓紧时间提交设计。 关于参赛文档的提交,请看:https://bbs.eeworld.com.cn/thread-452861-1-1.html 以下是参赛者的设计过程分享: tzia ...…

查看全部问答>