AT91SAM7S系列微控制器的分散加载程序设计
一、AT91SAM7S系列芯片简介
AT91SAM7S系列控制器芯片是ATMEL公司推出的基于ARM内核的Flash闪存控制器芯片。其集成了ARM7TDMI ARM Thumb处理器,片内高速Flash存储器,片内高速SRAM,丰富的外设资源,包括一个USB2.0设备,使外部器件数目减至最低的完整系统功能集。这个芯片是那些正在寻求额外处理能力和更大存储器的8位处理器用户的理想选择。
AT91SAM7S系列芯片主要有AT91SAM7S64/AT91SAM7S128/AT91SAM7S256/AT91SAM7S512几种型号。它们之间主要的区别在于Flash和SRAM空间大小的不同,以适应不同产品应用的需要。
二、目标平台介绍和要实现的功能
平台主要实现一个移动电视USB Dongle的功能。外观类似于一个U盘,直接接到电脑或其它支持USB传输的移动设备上,配合视音频解码播放器即可实现移动电视的接收、播放功能。USB Dongle由Tuner、Demodulator和AT91SAM7S64三个主芯片组成。Tuner实现空中高频信号到中频信号的转换,Demodulator实现信号的基带解调功能,AT91SAM7S64主要完成程序的控制以及将解调出的视音频数据向PC端传输。AT91SAM7S64包含一个64K的片内Flash和一个16K的片内SRAM。
目前平台使用了一块EEPROM用于存储CA(Conditional Access)的一些信息。主程序在Flash上运行,除去主程序占用的空间外,Flash上还留有较大的空间。目标是用实现用剩下的Flash空间替换原来的EEPROM,以节省产品的成本。
三、分散加载程序的实现
AT91SAM7S64的内部Flash只有一个Plane(目前该系列芯片只有AT91SAM7S512是Dual Plane的),在对其编程时不能在其上运行程序,所以对Flash进行编程时,程序必须调入RAM中运行。ATMEL网站上描述如下:
The AT91SAM7S device has only one flash memory plane, thus making impossible read-while-write operations.
All write/erase flash routines must be run from the internal SRAM. Depending on the memory layout of the application, it will be preferable to disable all interrupts during write and erase operations.
If the exception vectors (and also ISR's) are kept in flash memory, and if IRQs are not disabled, the ARM core will make an access to the vector table located in the flash memory when an IRQ appears. If a write or an erase sequence is on-going at that time, it may lead to an unsuccessfull write or erase operation.
要实现这样的功能在IAR编译器上比较容易实现,只需要在函数定义之前用关键字__ramfunc声明即可。但在ADS上相对要麻烦很多,实现的方法有多种,这里只介绍其中两种。
第一、在启动代码中用汇编实现将存储在Flash上的程序全部Copy到SRAM中,然后再跳转到SRAM上运行。以下代码实现程序拷贝和地址重映射功能:
;------------------------------------------------
;copy bootloader in RAM
LDR r0, =ramstart
LDR r1, =bootsize
LDR r2, =0
copy
LDR r3, [r2]
STR r3, [r2, r0]
ADD r2, r2, #4
SUBS r1, r1, #1
BNE copy
;perform a RAM remap
LDR r0, =AT91C_BASE_MC
LDR r1, =AT91C_MC_RCB
STR r1, [r0, #MC_RCR]
;------------------------------------------------
第二、利用ADS分散加载程序的方法实现不同程序加载到不同的地址空间上运行。
由于AT91SAM7S64的片内SRAM只有16K的存储空间,而程序超过了16K,不能满足平台要求,所以用了第二种方法。要实现分散加载必须对AT91SAM7S64地址空间的分配比较清楚。下图列出了AT91SAM7S64的片内存储器映射关系,地址0x00000000在AT91SAM7S64的Remap之前是Flash的访问地址,Remap之后是SRAM的访问地址。
了解AT91SAM7S64的片内存储器空间分配之后需要对自己的程序存放位置进行规划,以下是自定义的Scf文件(关于Scf文件格式参考另一篇文章“ADS下的分散加载文件应用实例”)。
ROM_LOAD 0x00100000
{
ROM_EXEC 0x00100000
{
Cstartup.o (reset, +First)
* (+RO)
}
RAM1 0x00200800
{
* (+RW,+ZI)
}
RAM2 0x00202800
{
flash.o (ramfunc) ; 对Flash编程的函数定义在该文件中
}
}
利用分散加载方法需要自定义一个函数__user_initial_stackheap,否则编译器编译时会报错。__user_initial_stackheap定义如下:
#include <rt_misc.h>
__value_in_regs struct __initial_stackheap __user_initial_stackheap(
unsigned R0, unsigned SP, unsigned R2, unsigned SL)
{
struct __initial_stackheap config;
//config.heap_base = (unsigned int)&bottom_of_heap; // defined in heap.s
// placed by scatterfile
config.stack_base = SP; // inherit SP from the execution environment
return config;
}
在<rt_misc.h>文件中你可以找到结构体__initial_stackheap的定义
struct __initial_stackheap {
unsigned heap_base; /* low-address end of initial heap */
unsigned stack_base; /* high-address end of initial stack */
unsigned heap_limit; /* high-address end of initial heap */
unsigned stack_limit; /* low-address end of initial stack */
};
设置编译器的链接方式为Scattered,选择自定义的scf文件,make成功。通过打印函数地址显示,Flash.c文件中定义的函数在SRAM里面运行,其它函数在Flash的地址空间中运行,在Flash中运行的函数调用SRAM中编程Flash的函数,读写正常。