ARM 的分散加载
...
和栈的头部: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再存数据。
ARM分散加 相关文章:
- ARM的分散加载文件(scatter)介绍(11-09)
- ARM分散加载文件(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)