原创 arm端口设置等

2007-5-24 21:21 6119 3 7 分类: MCU/ 嵌入式
作者:strguo    文章来源:本站原创    点击数:

    更新时间:2004-12-5


前言:本人因工作需要,首次接触到了ARM单片机,但因无人指导,走了不少弯路。下面这些笔记是我在一个多月的学习过程中总结的一点心得(可能比较乱,工作忙,没时间整理,各位朋友莫怪!),现在发到网上,与各位网友共享,希望对大家有点小小的帮助。本人购买的是上海勤研电子提供的ARM实验板,使用三星的S3C44B0X芯片,我在学习过程写的一些程序也参考了他们随板提供的一些源代码,特此致谢!<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


关于ARM和嵌入式我仍是个新手,下面的东东有些可能是错的。因此仅供参考!!并希望网友给予指正。也欢迎各位网友来信共同交流。


本人信箱:strguo@sina.com


 


 


 


系统初始化流程如下:


禁止看门狗——》在中断控制器中屏蔽所有中断——》系统时钟设置——》初始化端口——》DMA设置——》cashe和总线设置——》存储器设置,初始化SDRAM——》初始化堆栈——》设置IRQFIQ的入口——》地址重映射


   


    通常系统初始化有两个阶段组成,分别为汇编和C写成。汇编应尽量简单一些,把更多的任务交给C来做,这样可增加整个程序的可读性和灵活性。必须由汇编来完成的任务有:异常中断向量表的设置、IRQ向量表(向量模式)或ISR初始化(非向量模式)、二级ISR地址表的定义、FlashSDRAM的设置(否则系统无法加载代码)、堆栈设置和模式切换、拷贝RWZI代码、设置系统时钟等。而端口初始化、cashe和总线的设置、DMA配置以及其它控制器如LCDUARTSIOIP等可以在C中第二阶段初始化程序完成,另外也可以继续更改时钟或存储器配置等。下面是几个关键步骤配置的注意事项。


 


看门狗设置


    watch dog即可以作为普通的timer以产生周期性的中断,也可以周期性的产生reset信号(如果每隔一定时间不被清除的话),以防治程序跑飞。


 


系统时钟的初始化:


至少设置三个寄存器:LOCKTIME,PLLCON,LOCKCON


LOCKTIME,地址0x01D8000C。用于指定PLL的初始化时间,在PLL初始化时,系统时钟为晶振输入或外部时钟直接提供,即MCLK=Fin;初始化完成后,切换,MCLK=Fout。初始值为0xfff4095个输入时钟周期。一般将其设为初始值。


PLLCON,,地址0x01D80000。设置MDIV,PDIV,SDIV三个值,用于确定FoutFin的频率分配比值:Fout = (m * Fin) / (p * 2s),其中


m = (MDIV + 8), p = (PDIV + 2), s = SDIV


典型的几个值如下:



No.


Fin


Fout


MDIV


PDIV


SDIV


1


10Mhz


40Mhz


0x48


0x3


0x2


2


10


50


0x2a


0x3


0x1


3


10


60


0x34


0x3


0x1


4


4


60


0x34


0x0


0x1


5


3


60


0x48


0x0


0x1


6


10


75


0x3a


0x3


0x1


 


CLKCON,地址0x01D80004。用于设置是否向外设提供时钟,一般设为默认值0x7ff8,即所有外设提供时钟。


 


存储器初始化(尤其是SDRAM):


ARM7TDMI的地址映射如下:


(在ARM体制中,所有的各种内、外存储器,外设,寄存器,cashewrite buffer,通用IO口等全都采用统一编址)


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


注:0x100000000x100047f0为内部cashe/sram 及其TagLRU的地址。


 


BANK0~BANK5为ROM/SRAM/FLASH,


BANK6~BANK7为SDRAM/ROM/SRAM/FLASH


要设置的寄存器如下:


BWSCON:BANK0~BANK7的UB/LB使能、Wait信号使能、数据线宽度;


BANKCON0~BANKCON5:各bank(flash或Sram)的访问时序控制。flash或Sram主要参数如下所示:


Tacs [14:13] Address set-up before nGCSn


Tcos [12:11] Chip selection set-up nOE


Tacc [10:8] Access cycle


Toch [7:6] Chip selection hold on nOE


Tcah [5:4] Address holding time after nGCSn


Tpac [3:2] Page mode access cycle @ Page mode


PMC [1:0] Page mode configuration


不同厂家、性能、速度的器件设置有所不同。


BANKCON6~BANKCON7:主要用于SDRAM,当然也可以是Flash或SRAM。SDRAM的时序控制稍微复杂,还有:


Trcd [3:2] RAS to CAS delay


    SCAN [1:0] Column address number


当然也可用于DRAM。


 


REFRESH 地址: 0x01C80024,DRAM/SDRAM的更新控制寄存器;


MRSRB6 ~MRSRB7:DRAM/SDRAM的模式控制寄存器,这个寄存器在系统初始时,即SDRAM使用前必须被有效地的设置。


    这几个寄存器的设置比较复杂,应仔细阅读Samsang(page168)的数据手册和相关存储器的资料。


一个典型的配置如下:


ldr r0, =SMRDATA


ldmia r0, {r1-r13}


ldr r0, =0x01c80000 ; BWSCON Address


stmia r0, {r1-r13}


SMRDATA DATA


DCD 0x11222220 ; BWSCON Bank0=OM[1:0],8bits宽 Bank1~Bank5=32bit,Bank6~Bank=16bit,不使用UB/LB信号,WAIT disable; 使用little Endian存储格式


DCD 0x000056A8; GCS0 :Tacs=2clk;Tcos=2clk;Tacc=10clk;


Toch=2clk;Tcah=2clk;Tpac=4clk;PMC=normal(1data)


DCD 0x00000700 ; GCS1 除了Access cycle为14个clk外,其它均为0clk


DCD 0x00000700 ; GCS2


DCD 0x00000700 ; GCS3


DCD 0x00000700 ; GCS4


DCD 0x00000700 ; GCS5


DCD 0x00018005 ; GCS6, SDRAM;RAS to CAS delay 2 clk;Column address number:9bits


DCD 0x0001002a ; GCS7, EDO DRAM(Trcd=3, Tcas="2", Tcp="1", CAN="10bit")


DCD 0x00870441 ; Refresh enable;Auto Refresh; Trp="3", Trc="5", Tchr="3";


刷新计数:1019


DCD 0x17 ; SCLK power down mode enable;Bank6&7 Size, 16MB/16MB


DCD 0x20 ; MRSR 6:CAS Latency="2clk";burst type为线性(不支持交织访问);


burst number:1bit(不支持促发读写)


DCD 0x20 ; MRSR 7(CL=2)


 


注:三星的实验板中在nGCS0外接Flash,型号为SST39VF160,其datasheet中有其读写时序的详细说明和各种时间值的最大或最小值,但均以ns为单位,且各时间值的名称也与寄存器的要求不完全相同。要使Flash达到最优设置,必须读懂其时序并按其推荐值设置寄存器。显然这并不是件容易的事情。在本次实验板的boot程序中,其各时序值均是最大值给出。参见memcfg.h文件。


三星的实验板中在nGCS6外接SDRAM,型号为IC42S16800-7T,(4096ROW*512COLUM*4Bank*16bits=128Mbits=16MB)


由上面的例子可以看出需要设置的参数为:1.Banksize,UB/LB,WAITenable/disable,large/little Endian;


2.RAS to CAS delay, Column address number;


3.Refresh enable/disable,Auto/self refresh, SDRAM RAS pre-charge Time, SDRAM RC minimum Time, Refresh Counter;


4.power down mode,banksize;


4.CAS Latency,burst type,burst number。


 


Refresh counter的设置Refresh period = (211-refresh_count+1)/MCLK


Ex) If refresh period is 16 us and MCLK is 60 MHz,


the refresh count is as follows;


refresh_count = 211 + 1 - 60x16 = 1089


 


上面的例子只是对FlashSDRAM的一个经验设置值,可能不是最优的。最优设置还必须参考器件的数据手册。尤其是对于SDRAMRAS to CAS delay、SDRAM RAS pre-charge Time、SDRAM RC minimum Time三个时序值。


 


特别注意:在线调试阶段,在AXD软件中必须引入对SDRAM初始化的seesion文件或ini文件,或者在command interface中敲入所需的配置命令(在load image之前完成),并且最后注释掉reset汇编程序中的初始化SDRAM的命令。否则程序就可能跑飞。而生成要下载的flash程序代码时,则系统reset时就必须完成此功能。


 


端口初始化


ARM的大部分信号在同一端口是功能复用的。为此初始化时必须指定各PA~PG口的各管脚的功能。在实验板根据外围器件的选择对各端口做如下配置:


PA(10bits):全部用作高端地址线;PCONA=0x3ff


PB(11bits):全部用作存储器控制信号;PCONB=0x7ff


PC(16bits):4~7用于LCD的VD4~VD7;12,13用于UART的TXD1,RXD1(注意:这里的UART没有使用CTS、RTS信号,只用了TX、RX);其它全部用于通用IO口,GPC0~3用于IIS;GPC10和14用于NAND Flash;GPC15用于USB Device;GPC8、9用于LCD;GPC11暂时没用。PCONC=0x5f55ff55.(这里假定IO口全为output,实际应用时再确认一下是In或是out)


PD(8bits):全部用于LCD的控制信号。PCOND=0xaaaa。


PE(9bits):8用于Endian,确定存储器格式;1,2分别为TXD0,RXD0;0,3~7用于通用IO口(暂定output),PE3用于蜂鸣器;PE4~7用于LED显示。PCONE=0x05569。


PF(9bits):0、1用于IIC总线的SCK、SDA信号;其它均为通用IO口(暂定output),其中GPF2~4用于IDE,GPF5~8用于触摸屏。PCONF=0x09255a。


PG(8bits):全部用于外部中断EXINT0~7。PCONG=0xffff。


注意:上述端口分配是S3C44b0x测试板(勤研电子)的分配情况。


 


另外还有下面几个寄存器需要设置:


上拉电阻寄存器,包括一些端口和数据线;


EXTIN:设置8个外中断的触发方式,low,high,rising or falling edge等。


EXTINTPND:中断待处理寄存器,用于解决EXTINT4~7共享一个中断源的问题。


 


 


Cache&Bus设置


通过内部寄存器可以设置cashe mode(cashe和sram),write buffer,non-cashable area,以及bus的优先级等。


通常,在一般的用户程序中不使用cashe(即全部用作Sram),禁用write buffer,bus优先级选择默认就可以了,即1. DRAM refresh controller2. LCD_DMA3. ZDMA0,14. BDMA0,15. External bus master6. Write buffer7. Cache & CPU


只配置一下SYSCFG:0x0。


 


 


DMA配置


ZDMA在系统总线上,完成系统总线上器件的数据传送,如存储器。BDMA也有2个,桥接系统总线和外设总线,即可以完成分别位于两条总线上的器件的数据传送,也可完成外设总线上器件如SIO、UART、TIMER等之间数据传送。


DMA的四种数据传送方式。


DMA的触发选择:XDREQ/XDACK、S/W、H/W等。


一般地,DMA的初始化只需完成BDMA的目标地址寄存器的初始化:BDIDES0,1=0x40000000,即传送方向为内部存储器到外设,初始目的地址:0x0。


 


 


 


中断寄存器的配置和中断向量表的设计


中断有两种IRQ和FIQ,后者优先级高于前者。另外,ARM系统还做了些特殊安排以使FIQ有更快的响应速度,如FIQ的ISR可以直接放在0x1c(紧跟FIQ)开始的地址单元中,免去了跳转;属于FIQ的中断向量表可常驻cashe;FIQ较IRQ有更多的物理寄存器等。通常在简单的用户程序中,可以不使用FIQ,所有中断都设为IRQ(默认情况)。


ARM7有30个中断源,实际使用25个。其优先级如下所示:



 


一些重要的中断设置寄存器如下:


INTCON  0x01E00000 :中断控制。指定IRQ是否采用向量模式(一般采用非向量模式,这也是默认值)。指定CPU是否响应IRQFIQ


INTPND:只读。指定中断源是否有中断请求,可以同时有多个中断请求。当对应的ISR结束时,通过向I_ISPCF-ISPC1来清除INTPND中对应的比特位,否则该中断将连续执行。


INTMSK:各中断源是否屏蔽。初始值时屏蔽。


INTMOD:指定各中断源是IRQFIQ,默认值全为IRQ


I_PSLV  0x01E00010   R/W    IRQ priority of slave register  0x1b1b1b1b


I_PMST  0x01E00014   R/W    IRQ priority of master register  0x00001f1b


I_CSLV  0x01E00018   R       Current IRQ priority of slave register  0x1b1b1b1b


I_CMST  0x01E0001C  R       Current IRQ priority of master register  0x0000xx1b


I_ISPR   0x01E00020   R      IRQ interrupt service pending register


I_ISPC   0x01E00024   W      IRQ interrupt service clear register


F_ISPC   0x01E00024   W      FIQ interrupt service clear register


优先级取默认值就可以了。


ISPR只读,指示当前被响应的中断源,没有或只有一个被响应,尽管此时INTPND中可能有几个中断请求。ISR结束时,通过向ISPC对应位写1来清除ISPR中的对应位。


ARM7TDMI中,中断向量表的设置有两种模式:向量模式和非向量模式。前者只适于全IRQ的设置。采用非向量模式时,通过分析ISPR(发生中断时,其中只有一个位为1,其它全为0)找到要执行的ISR的入口地址。在向量模式中,当发生IRQ时,CPU自动产生跳转地址,如同异常中断的使用。各IRQ的一级ISR的跳转地址如下:



中断有异常中断(如:DabortPabortUndef等)和IRQFIQ两种。下面以向量模式下的IRQ为例介绍一下中断设置。


过程如下:IRQ中断向量表设置——>写一级ISR——>分配二级ISR的入口地址表——>写二级ISR——>把二级ISR的入口地址放到二级ISR的入口地址表中。这样在开中断的情况下,一个ISR就可以正常执行了。一个ISR的执行过程如下。


首先要在系统初始化时开中断:INTMSK各中断位清零且INTCONIRQ位清零(使能)且CPSRI比特清零(使能),缺一不可。中断发生时,首先由模式SYSUser切换至IRQ,同时完成现场保护(工作指针入栈、保存CPSRPC>LR),然后PC直接跳到IRQ中断向量表的相应地址(一级ISR的入口),紧接着跳到一级ISR并执行;一级ISR通常由汇编写成,仅完成一个跳转任务(有时也看一下寄存器ISPR,判断该中断是否被错误触发,如果错误将直接返回),即从二级ISR的入口地址表中找到相应中断的入口地址,其间工作现场没有变化。二级ISR通常由c语言写成,中断的真正的响应程序就在此处。ISR结束时,要对INTMSK中的pending比特清零(通过置位ISPR中相应比特),否则将连续响应该中断。然后CPU自动切换至中断前的工作模式,并恢复现场。


 


C语言中关键字__irq的作用:当ISR定义时有此关键字,则ISR结束后CPU自动从栈中恢复中断前模式的LR,并把它赋值给PC,完成ISR的正常返回。如果无此关键字,则CPU只能返回到二级ISR前的中断状态,此时仍为IRQ工作模式。当然也能够继续执行用户程序,只是工作模式不对,此模式下再不能响应其它IRQ中断。


事实上,CPU响应中断并执行ISR相当于一个程序调用过程。用户程序不必干预CPU的模式切换、现场保护、程序返回。


 


中断向量表的设置。一级中断向量表紧跟异常中断向量表,位于0x20~0xc0。只读。由于S3C44b0x没有MMU和地址映射功能,该中断向量表必须和异常中断向量表一起固化到系统地址空间的0x0处,即Flash的起始处。在线调试阶段也必须保证该表存在于Flash中。二级ISR的地址表一般位于RAM空间的最后256个字节处,紧跟在堆栈后,在汇编语言中由MAP语句创建(8个异常中断和25个IRQ,共33×4=132Byte),可读写。同时在c中定义一组指向相同地址空间的无符号型指针,当然指针名称必须和汇编中的定义相同。这样在C中的ISR初始化程序中,可直接把二级ISR的入口放到地址表中。如:pISR_EINT0=(unsigned)Isr_Eint0; pISR_EINT0为地址表中的指针,而Isr_Eint0为ISR的名称,也是其入口地址。二级ISR地址表和一级表不同的是,其各中断的顺序可任定,但必须保证汇编和C中的定义一致。


对于非向量模式,不使用IRQ中断向量表,但二级ISR地址表的设置是相同的。在本测试程序中boot.s同时包含了两种格式的设置,只要设置好INTCON中的mode比特,两种模式都可以用。注意非向量模式,在汇编中要设置IRQ和FIQ的入口地址。因为在非向量模式要靠IsrIRQ和IsrFIQ来定位响应的中断源位置。


    另外,为了保证开中断后,程序不至于跑飞,最好编写所有的IRQ 的ISR,该ISR可以是个空函数,确保能正常返回就行了。


 


堆栈初始化和工作模式的切换


ARM7TDMI有7种工作模式,要用到6个stack,其中SYS和User共用一个Stack。堆栈设置采用流行的FD模式(full decresment)。通常放在RAM空间的次最高段(最高的256B为ISR的地址表),在16M的SDRAM中,各stack设置如下:


0x0cff_f000~0x0cff_fa00: Uers and SYS stack,2560B,够大了。


0x0cff_fa01~0x0cff_fb00: SVC stack, 256B;


0x0cff_fb01~0x0cff_fc00: Undef stack, 256B;


0x0cff_fc01~0x0cff_fd00: Abort stack, 256B;


0x0cff_fd01~0x0cff_fe00: IRQ stack, 256B;


0x0cff_fe01~0x0cff_ff00: FIQ stack, 256B;


0x0cff_ff01~0x0cff_ffff: ISR地址表, 256B;


 


CPU的模式切换通常由异常中断产生,或者在SVC或SYS模式下完成。User模式中用户程序不能改变工作模式(除了应用异常中断,如SWI),当然也不能改变CPSR的值(也就不能开关中断了!)。通常如果不用嵌入式OS,单任务的用户程序工作在SYS或SVC模式下更好一些,这样可以更方便的使用硬件资源。如果使用SVC模式,甚至可以不设置SYS and User stack。


系统加电重起时,首先进入SVC模式,完成初始化,在调用C的main函数之前再切换到SYS或User模式。因此可以把堆栈初始化放到最后执行,并最后设置SYS stack,这样进入main之后可以直接工作在SYS模式下。本测试程序就是如此设置的。


 


 


 


分布式加载


ADS1.2中的ARM linker支持分布式加载,即加载域(load)和执行域(image)的各个输出段(RO、RW、ZI)可以有不同的地址。可以很方便的生成供在线调试和下载的elf格式的文件。通常总线调试只需设置RO base=0x0c000000;而生成下载代码则要设置RO base=0x0,RW base=0x0c000000,并且一定要把boot.o设成first section,否则程序入口不在0x0则无法完成异常中断和普通中断,包括reset。至于ropi、rwpi、split的应用参见linker的有关资料。


链接器同时产生一组符号,给出各个域或者各个输出段的区间的长度,装载地址和执行地址。由于链接器和C库都没有将代码从它的装载区间拷贝到执行区间,或创建一个零初始化区域的功能,所以要由应用程序员利用这组符号产生的信息完成这项工作,这是在呼叫C程序之前必须完成的,举例如下:


LDR r0, = |Load$$DRAM$$Base|
LDR r1, = |Image$$DRAM$$Base|
CMP r0, r1  
检查装载地址和执行地址是否相同
BEQ do_zi_init  
相同,则不拷贝该区间,初始化零数据区
MOV r2, r1 
 不相同,将装载区拷贝到执行区 
LDR r4, = |Image$$DRAM$$length|
ADD r2, r2, r4
BL copy
do_zi_init
LDR r1, = |Image$$DRAM$$ZI$$Base|
MOV r2, r1
LDR r4, = |Image$$DRAM$$ZI$$length|
ADD r2, r2, r4
MOV r3, #0
BL zi_init  
调用零初始化子程序


 


上例中使用了ARM Linker产生的与域有关的几个符号,域名可以在scatter文件中指定。在本测试程序中,因为只有一个load域和一个image域,因此可以使用ARM Linker产生的与输出段有关的符号,如|Image$$RO$$Base|、|Image$$RO$$Limit|、|Image$$RW$$Base|、|Image$$ZI$$Base|、|Image$$ZI$$Limit|等。必须注CPU或系统本身都不能自动完成分布式加载的任务,所以系统在第一阶段初始化时(即汇编语言写的初始化代码),就必须编写用户程序根据上述几个符号把代码考到RAM区中。通常要把除了汇编写的第一阶段的初始化代码以外的RO代码、RW和ZI代码都要拷到RAM中,这样可以代码的执行速度。RW和ZI是必须要拷到RAM中,否则程序无法运行。注意ZI是RW区中的位于最后的一段零初始化的RAM区,RW limit和ZI limit两个值相等。在本程序中只拷贝了RW和ZI段。


 


 


 


 


LCD设置


本系统所带LCD没有内置控制器、显存、字符查找表等,需要靠ARM所带LCD控制器进行显示,在系统的SRAM中开辟一块显存区,本测试程序中显存framebuffer开在ZI区之后,且能保证不进入RAM高端的堆栈区,实际上黑白字符的显存为14400Byte(前者分辨率为480×240),彩色图片的显存115200B(分辨率为320×240)。支持MONO、灰4,灰16、256色四种模式。面板模式有4bit single、8bit single、4bit dual scan三种。黑白字符显示采用4bit dual scan,彩色图片采用8bit single。


往显存中写入数据,系统会自动把数据代表的内容显示在LCD的相应位置上,ASCII采用8×16点阵。图片中每象素需8比特信息(红3绿3兰2),BMP图片的显示原理还没搞清楚。


虚拟屏幕显示。显存的大小定义为SCR_XSIZE*SCR_YSIZE,即可以放进这么大的BMP图片,而能显示的范围是LCD_XSIZE*LCD_YSIZE,只能显示图片的某个区域,设置好PAGEWITDH和OFFSIZE参数,改变光标的位置,就可移动显示图片的其它部分(Lcd_moveviewport函数),本测试程序中令SCR_SIZE=LCD_SIZE,即没有使用虚拟屏幕显示。


去抖动算法和AFC。灰4和灰16图片的显示根据的是AFC原理。去抖动算法是保证相邻帧之间任一象素on/off的概率相当。这些是ARM中的LCD控制器自动完成。


彩色查找表。设定不同深度的颜色。红和绿:16取8,兰:16取4。


 


 


PS/2键盘接口设计


键盘接口通常有扫描和中断两种方式。扫描方式的键盘制作简单,但是要占用过多的微处理器的端口资源,并且由于采用查询方式接收键盘数据,导致CPU资源的浪费。中断方式的键盘较为复杂,但接口简单,如采用5芯或6芯的PS/2接口,而且由于采用中断方式接收键盘扫描码,相应地也减少了CPU资源的占用。目前标准PC机键盘技术已经很成熟,且成本也已经很低。本监控板将采用标准PC机键盘作为人机命令的输入接口。


PS/2接口信号线主要有两根:CLK、DATA。键盘和主机间的通信是同步和异步方式的结合。按键时在DATA线上发送11位的扫描码,起始位0、8个数据位(LSB在前)、1个校验位和一个结束位0。放键时先发送放键标志F0,接着再发送一遍扫描码。CLK的上升沿触发主机的中断,主机执行ISR(ExINT4567)接收1bit数据。接收完完整的8bits数据后,ISR将判断是否为F0,若是,则把紧接着接收的下一个8bits数据译码,变为ASCII或OEM码或者Windows虚拟码,放入64Byte的键盘缓冲区中,并通知主机上位程序进行相应的处理,如打印字符或处理特殊符号(ESC、Enter、F1之类)。


 


后来发现上述编程思路又问题:只实现了位同步,不能实现11bits的字节或帧同步,当发生干扰而产生INT0中断时,一个错误比特被读入,导致后续比特全错。改进如下:每接收11bit对起始位、结束位、校验位进行判断,若发生错误,则失步,下一比特被舍弃,重新同步。结果有所改进,但仍不理想。


 


下表是部分按键的扫描码、系统码、ASCII、Windows虚拟码的对应关系。



 


 


SWI的使用


Swi.h 头文件的定义;使用__swi伪操作对swi函数进行说明;在main中可直接调用该函数。SWI的两级ISR设置基本同普通的IRQ,但要设置功能号。


现在的问题是无法返回sys mode, 调用功能号不对。


 


 


 


UART设置


S3C44B0X有两个独立的UART,均采用RS232接口。每个UART有1个16B的Rx buffer 和一个Rx buffer(实际上可以不用,若通信双方的时钟精度足够号的话)。本测试程序中使用non FIFO mode.


AFC 和 non AFC mode:所谓AFC就是利用握手信号RTS和CTS来自动控制双方的通信,对端也必须是UART,若对端是modem,则只能用non AFC mode,即用软件读写RTS和CTS。


中断模式和DMA模式。本测试程序使用中断模式,但ISR未作任何处理,实际上是查询方式收发数据。发数据:通过UTRSTAT0中的状态指示位看发送数据寄存器UTXH0是否空,不空则等待,空则把数据写到该数据寄存器。然后Uart控制器会自动把数据串至RS232的Tx脚上。接收类同。这种方式适合发数据。接收数据时,CPU就不能干其它事了,好在人机交互时,CPU也只是等待命令,不干其它。若用于从主机快速接收大量数据,则必须取数据的函数放到UART的ISR中。


 


 


以太网接口芯片的设置


RTL8019AS的三种工作模式:


跳线模式:这种模式与早期的网络控制器兼容。RTL8019AS的端口基地址、中断口等都


由开关或跳线器(或者由CPU的通用IO口模拟跳线器)决定。跳线模式简单,但配置资源麻烦。


PnP模式:与微软的PnP协议兼容(play and plug),适于PC机模式。在这种模式下,RTL8019AS的端口基地址、中断口等都由EEPROM93C46设定,但需要进行PnP芯片的识别,不便与DSP接口。


RT模式:为了避免PnP模式下的PnP芯片识别和配置过程,readlted公司提供RT模式。


Boot程序存于BROMFlash种。在RT模式下,RTL8019AS的端口基地址、中断口等也是由EEPROM93C46决定的。SMEMR和SMEMW引脚接高电平,屏蔽了远程自举加载功能。


事实上,在嵌入式系统设计中,RTL8019AS固定于嵌入板上,而且单片机可以很方便的对其初始化和各种控制,因此可以使用跳线模式,但不用跳线器,也不用通用IO来模拟,直接把控制字写入各配置寄存器就可以了,如PAR,CONFIG等。当然config可以不设置,按默认就可以了:


IO起始地址:0x300(即范围:0x300~0x31f)


中断:int0


接口选择:10baseT


 


寄存器表(通过CR中的ps0,1来确定页:这种安排太对调试太恶劣了!!)



初始化时必须设置号RCR TCR DCR三个有关接收、传输、数据格式的寄存器。ISR和IMR实现中断功能。


注意:ISR寄存器不只和中断有关,当接收缓冲溢出时,如果不清ISR(写入FFH),芯片将一直停止接收。在流量较大时溢出经常发生,此时不清ISR,就会导致网卡芯片死机。另外,有时一些无法识别的包或没有对该包作出应答包时,ISRRST位也会置1,导致8019死机。原因不祥。所以最好在每次中断服务程序的结束处对ISRRST位清零。


18H1FH8个地址,为复位端口。对该端口地址的读或者写入任何数,都会引起网卡的复位。


 


让人遗憾的是,勤研电子的板子,8019与ARM的地址连线错:8019A0—ARMA1,导致8019中的这些8位寄存器无法正常寻址,解决办法是用16位地址模拟,CR的地址:0x300,CLDA0:0x302,…,CNTR2:0x31e。这样写入是正确的,但在AXD中从0x06000300中读出的数页必须按16位理解,即奇数地址忽略掉。


  


 


以太网帧格式:



    PR 同步位 用于收发双方的时钟同步 同时也指明了传输的速率 10M和100M 的时钟频率不一样 所以100M 网卡可以兼容10M 网卡 是56 位的二进制数101010101010.....


SD: 分隔位,表示下面跟着的是真正的数据,而不是同步时钟,为8位的10101011,跟同步位不同的是最后2位是11而不是10.


DA:目的地址,以太网的地址为48位(6个字节)二进制地址,表明该帧传输给哪个网卡.如果为FFFFFFFFFFFF,则是广播地址,广播地址的数据可以被任何网卡接收到.


SA:源地址,48 位,表明该帧的数据是哪个网卡发的,即发送端的网卡地址,同样是6个字节.


TYPE 类型字段 表明该帧的数据是什么类型的数据 不同的协议的类型字段不同 如 0800H 表示数据为IP 包 0806H 表示数据为ARP包 814CH 是SNMP包,8137H 为IPX/SPX 包 小于0600H 的值是用于IEEE802 的 表示数据包的长度


DATA 数据段 该段数据不能超过1500 字节 因为以太网规定整个传输包的最大长度不能超过1514字节 14 字节为DA SA TYPE


RTL8019AS是ISA总线式网卡,速率为10M。


 


    NIC帧格式(位于16KSRAM种的接受和待发送的帧结构)


值得注意的是,收到的数据包格式并不是802.3帧的真子集,而是如下图所示。明显地,8019自动添加了“接收状态、下一页指针、以太网帧长度(以字节为单位)”三个数据成员(4字节)。这些数据成员的引入方便了驱动程序的设计,体现了软硬件互相配合协同工作的设计思路。当然,发送数据包的格式是802.3帧的真子集,如图3所示。



RTL8019AS接收帧结构,不为Enthernet的真子集


接收状态


下一页指针


以太网帧长度


目的IP地址DA


IP地址SA


类型TYPE


数据域DATA


填充PAD


校验CRC


8bits


8bits


16bits


48bits


48bits


16bits


<=1500B


可选


32bits


 



RTL8019AS发送帧结构,为Enthernet的真子集


以太网帧长度


目的IP地址DA


IP地址SA


类型TYPE


数据域DATA


填充PAD


校验CRC


 


 


16bits


48bits


48bits


16bits


<=1500B


可选


32bits


 


 


 


   16kSRAM地址:0x40000x7fff,对应页地址:0x400x7f(每页256B),其地址与IO(寄存器)、EEPROMBROM的地址是分开的,具体的我也不清楚。


  


8019有两个DMALocal DMARemote DMA,分别位于双端口SRAM的两边,64SRAM分为两步分:58页的Rx buffer6页的Tx buffer6页为1536Byte,恰可容那一个TxRxNIC以太帧,其最大长度为1500B)。Local DMA完成NICSRAM的数据传输,它是8019自动完成的,无需Host干预;Remot DMA完成SRAMHost RAM的数据传送,需要host干预,即通过相关的有关传输数据起始、长度的寄存器的设定,并通过Readwrite等命令(位于CR寄存器)来完成传输。16KSRAM不能直接寻址,只有通过0x100x1f的寄存器来实现数据传输。主机设置好远端DMA开始地址(RSAR0,1)和远端DMA数据字节数 (RBCR0,1),并在CR中设置读/写,就可以从远端DMA口寄存器里读出芯片RAM里的数据/把数据写入芯片RAM


 


    接收缓冲区构成一个循环FIFO队列,PSTARTPSTOP两个寄存器限定了循环队列的开始和结束页,CURR为写入指针,受芯片控制,BNRY为读出指针,由主机程序控制。根据CURR==BNRY+1?可以判断是否收到新的数据包,新收到的数据包按Rx NIC格式存于以CURR指出的地址为首址的RAM中。当CURR==BNRY时芯片停止接收数据包。


 


 


注意:很多时候一个网间通信连接(一对通信进程)往往使用不同的端口号,如TFTP的目标端口号:69,但源端口号可以不是(本程序是1124)。


 


网络字节顺序。其独立于两端的主机的字节顺序。ARMWindows均使用little Endian格式;SUN则使用big endian格式。“互联网联网标准”要求采用“网络字节顺序”为Big Endian。对于4Byte的字和2Byte 的半字在通信协议程序实现的两端都必须进行字节顺序的转换,否则协议无法识别。对于以Byte为单位的数据则无所谓。本程序使用函数:Swap_Word()Swap_HalfWord()来实现顺序转换功能。转换是可逆的。


 


校验和的计算


IP头部的校验和计算:16字节对齐,check0,对每个16位二进制数反码求和(也可先求和再取反,只是要注意16位溢出后的处理,见CheckSum()函数),结果放在check字段中;接收时对头部再进行相同的计算,结果应为全1,否则IP头出错。注意在上述算法中,IP头时网络字节顺序。


UDP头部的校验和计算:不仅包含了UDP头,还有一个12Bytes的伪头部,包含一些IP包的信息(见NetConfig.h中的定义)。UDP头中的check字段式两步分校验和之和,算法依然是反码求和。接收时对头部再进行相同的计算,结果应为全1,否则UDP头出错。另外,UDP的校验和是个可选项,也可以不进行校验和计算,此时check0;接收时也应该做相应的判断。


TCP头部的校验和计算:和UDP头的计算完全相同,也需要一个12Bytes的伪头部。有点区别是TCP头部计算是个强制项,不能设伪零。


 


本程序的功能:实现IP层管理(即用ICMP)的ping命令的支持;实现简单文件传输(TFTP)。TCP/IP协议处理流程图如下:



 


TCP/IP协议栈设计


    C中用struct定义各协议的枕头和分组,详细的设计参见NetConfig.h文件;


    Host RAM中开辟一个以太分组的Buffer(能容纳一个以太分组就可以了);


    分组封装:高层—>四层—>三层—>二层(以太)—>NIC,解包反之,使用指针通过共享存储空间来实现参数传递;


 


ARP分组格式



协议类型:ARP0x0806IP0x0800


 


 


IP分组格式



IP头采用标准的20Byte结构;


TOS通常不使用,即置零;


16位的标志用于区分不同的IP包,从1计数至65536,循环往复;


IP包通常不进行分片,16位偏移置零,IP分组长度不大于以太帧最大长度就可以了(1500Byte);


TTL通常设为128


8位协议:ICMP:1 TCP:6 UDP:17

PARTNER CONTENT

文章评论4条评论)

登录后参与讨论

用户1418102 2009-6-4 16:35

学习。。。

用户1403908 2007-12-18 09:09

请问一下,进行ARM端口设置时,有什么规定吗?
比如设置端口F,rPCONF=0x24900a,那对应的rPDATF,rPUPF应该怎么设置呢?
有资料说,对于功能管脚应该设置对应的上拉电阻不使能;对于输出管脚应该上拉电阻不使能,且DATA置高;
对于输入管脚应该上拉电阻使能.

可是我发现我的板子却不是这样设置的,谢谢了.(我的板子也是三星S3C44B0X.)

用户1403908 2007-12-18 08:59

辛苦楼主了,有点恍然大悟的感觉.

用户59437 2007-8-31 20:36

很好,看了很有收获!

相关推荐阅读
用户71670 2010-01-20 16:38
GUN make 语法
译者按: 本文是一篇介绍 GNU Make 的文章,读完后读者应该基本掌握了 make 的用法。而 make 是所有想在 Unix(当然也包括 Linux )系统上编程的用户必须掌握的工具。如果你写的...
用户71670 2009-12-29 10:24
latch与dff区别
6 标签: 无标签 ...
用户71670 2009-12-08 15:09
wxWidgets编译多种库(转载)
这几天研究了一下如何在Debian Lenny下编译wxWidgets,实现多个库共存。有点入门,写出来与感兴趣的朋友一起研究。这里编译的是wxGTK 2.8.7版本,解压后,进入解压的目录,建立4个...
用户71670 2009-10-29 09:10
字符串转化为数字
6.1.2  字符串转化为数字面试例题3:使用库函数将字符串转换为数字。考点:C库函数中字符串转换为数字的使用。出现频率:★★★★解析与上节数字转换为字符串类似,C/C++语言提供了几个标准库函数,可...
用户71670 2009-09-27 16:23
ucf文件约束法
1.约束文件的概念 FPGA设计中的约束文件有3类:用户设计文件(.UCF文件)、网表约束文件(.NCF文件)以及物理约束文件(.PCF文件),可以完成时序约束、管脚约束以及区域约束。3类约束文件的关...
用户71670 2009-09-06 10:12
#pragma使用详解
在所有的预处理指令中,#Pragma>指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全...
EE直播间
更多
我要评论
4
3
关闭 站长推荐上一条 /3 下一条