微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM 的分散加载

ARM 的分散加载

时间:11-09 来源:互联网 点击:

...

和栈的头部:StackIrq DCD IrqStackSpace + Length*4。因为栈是向下生长的。

与目标板有关的初始化程序可以放在一个名为"Target.c"的文件里。

1、定义中断处理入口:void IRQ_Exception(void), void FIQ_Exception(void), void Timer0_Exception(void)。

2、向量中断控制器初始化。

3、remap,系统时钟,实时时钟,存储器加速。

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

C语言中的延时:

__asm{

nop;

nop;}

即可。

关注C编译器:"=="的优先级确实比"&"的高,所以,凡牵扯到逻辑的东西,用"()"确认优先级,以避免出现低级错误。

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

对定时器的操作:

void Timer0Init(uint8 VICSlot, uint32 fdiv)

{

T0PR = 0; //Prescaling = 0

T0PC = 0; //Prescalar Counter

T0TC = 0; //T0 Counter

T0MR0 = Fpclk / fdiv; //计数周期

T0MCR = 0x03; //计数达到T0MR0则置位中断,计数器复位并继续运行。

T0CCR = 0x00; //不用捕获模式

T0TR = 0xffffffff; //清中断

T0TCR = 0x01; //运行

if(VICSlot <= 15){

*((uint32*)(&VICVectAddr0 + VICSlot)) = (uint32)Timer0_Exception;

*((uint32*)(&VICVectCntl0 + VICSlot)) = 0x20 | 0x04;

VICIntEnable = 1 < 0x04;

}

}

注意:

1、"*((uint32*)(&VICVectAddr0 + VICSlot)) = ..."中,&VICVectAddr0作为基址,VICSlot作为偏移量。由于前面已经有(uint32*)声明这是一个指向uint32的指针,故偏移量每变化一个数字代表地址变化了4个字节,在基址与偏移量相加的时候,系统自动将VICSlot乘以4。如果程序中写成"... + 4 * VICSlot"就错了。

2、一定要用"Fpclk / fdiv"设置,以延时1/fdiv秒。该参数不可以以uS为单位。若"Fpclk * us / 1000000"在计算中会乘法溢出,不易避免,又无警告,故不可用。

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

对I2C占空比的设置:

I2SCLH = (Fpclk / fi2c + 1) / 2;

I2SCLL = (Fpclk / fi2c) / 2;

妙哉!无论"Fpclk / fi2c"是奇是偶,单方面的"Fpclk / fi2c + 1"使得I2C总周期"Fpclk / fi2c = I2SCLH + I2SCLL"在方法上没有误差。

I2C必须工作在中断模式。因为:"When the "SI" flag is reset, no serial interrupt is requested, and there is no stretching of the serial clock on the SCL line."

I2C的资料在http://www.semiconductors.philips.com/acrobat/various/8xC552_562OVERVIEW_2.pdf.

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

宏的应用:

在片内外设如I2C,UART,T0,T1,SPI的设置过程中,都需要根据Fpclk计算出一些设定值。我讨厌用ARM做除法,所以就用宏来实现,除法在编译时就可以完成。

首先,所有片内外设的初始化程序都名为:"void _xxxInit();"。之所以在正式函数名之前加一个"_",是为了与宏区别开,不至于误写函数。因为宏的名字与函数名相同,只是全部大写,并且前面没有"_"。如:

#define TIMER0INIT(VICSlot,ms) _Timer0Init(VICSlot,Fpclk/100*ms/10);

void _Timer0Init(uint8 VICSlot,uint32 ClockCycle);

在函数中,直接"T0MR0 = ClockCycle"即可。

注意宏里面的表达式,不可写成"Fpclk*ms/1000",因为如果这样写,当mS太大时,比如mS=1000, Fpclk*mS=(11059200/4)*1000=0xA4CB8000,算到这一步,编译器认为是溢出(它把计算结果看作是有符号数),只要有溢出的警告出现,设置就不正确。

也不可以先做除法,以防止吃掉精度,使计算结果为"0"而令定时器死掉。

总之,既要保证计算精度,又不可以出现溢出警告。

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

关于C编译器使用的堆栈设置:

1、在Startup.s中有一句:

MSR CPSR_C,#0x5f//系统模式

LDR SP, =UsrStack //用户栈

2、在Scatter文件中,有

STACKS 0x40004000 UNINT

{

UsrStack.o(+ZI)

}

3、在UsrStack.s中有

AREA Stacks, DATA, NOINT

EXPORT UsrStack

UsrStack SPACE 1

END

定义一个UsrStack,大小都无所谓,把它放在可用物理内存的最顶端。C编译器在编译子程序调用时,会将要保护的寄存器压栈,如:

stmfd r13!,{r3-r7,r14}

其中,r13的别名是SP。

这是一个满递减堆栈。即SP指向的单元内的数据是有效的,入栈时先减SP再存数据。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top