OMAP138新建工程怎么让ARM进入特权模式啊......不然好多资源操作不了啊,比如管脚复用寄存器
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
好的,谢谢,已经可以了。
By default the TI Code Generation tools for the ARM put the ARM in user mode. This means that certain SYSCFG registers, such as those that control the pinmuxing, cannot be modified by the code. To keep the ARM in supervisor mode, a modified boot.asm file should be included in your ARM project. This file can be found in the following LED blink example project: [3]. In CCS3.3, the "Resolve Symbols to First Library (-priority)" box should be checked in the project linker options to avoid linking errors.
因为缺少了“boot.asm”这个文件,把这个文件添加进来就可以了。
其实可以不用调用CPUSwitchToPrivilegedMode()函数进入了,一调用这个函数就飞了。感谢技术支持......
#1. 首先了解一下ARM进入supervisor mode的方法是通过SWI指令.
#2. 参考一下starterware里的代码:
函数:
cpu.c:
void CPUSwitchToPrivilegedMode(void)
{
asm(" SWI #458752"); }
上面函数的调用会进入SWIHandler, 这里只是做了一个参数的简单比较,当然用户也可以修改这个参数用来实现不同值的传递,达到判断不同条件,从而做不同处理的目的, mode切换就是在下面两条语句实现的。
exceptionhandler.asm:
SWIHandler:
STMFD r13!, {r0-r1, r14} ; Save context in SVC stack
LDR r0, [r14, #-4] ; R0 points to SWI instruction
BIC r0, r0, #MASK_SWI_NUM ; Get the SWI number
CMP r0, #458752
MRSEQ r1, spsr ; Copy SPSR
ORREQ r1, r1, #0x1F ; Change the mode to System
MSREQ spsr_cf, r1 ; Restore SPSR
LDMFD r13!, {r0-r1, pc}^ ; Restore registers from IRQ stack
异常向量表的排放在在startup.c里实现的。
static unsigned int const vecTbl[14]=
{
0xE59FF018,
0xE59FF018,
0xE59FF018,
0xE59FF018,
0xE59FF014,
0xE24FF008,
0xE59FF010,
0xE59FF010,
(unsigned int)Entry,
(unsigned int)UndefInstHandler,
(unsigned int)SWIHandler,
(unsigned int)AbortHandler,
(unsigned int)IRQHandler,
(unsigned int)FIQHandler
};
unsigned int start_boot(void)
{
/* Enable write-protection for registers of SYSCFG module. */
SysCfgRegistersLock();
/* Disable write-protection for registers of SYSCFG module. */
SysCfgRegistersUnlock();
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_UART2, 0, PSC_MDCTL_NEXT_ENABLE);
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_AINTC, 0, PSC_MDCTL_NEXT_ENABLE);
/* Initialize the vector table with opcodes */
CopyVectorTable();
/* Calling the main */
main();
while(1);
}
static void CopyVectorTable(void)
{
unsigned int *dest = (unsigned int *)0xFFFF0000;
unsigned int *src = (unsigned int *)vecTbl;
unsigned int count;
for(count = 0; count < sizeof(vecTbl)/sizeof(vecTbl[0]); count++)
{
dest[count] = src[count];
}
}
对于ARM,这个异常向量表的地址有两种模式,要么放地址0,要么放地址0xFFFF0000. 在L138的ARM上,为0xFFFF0000.
程序中的中断等,将都进入这个向量表再跳转.
感谢你的回答,说的很详细。
http://processors.wiki.ti.com/index.php/StarterWare_01.10.01.01_User_Guide,里面也说
to privileged mode usingCPUSwitchToPrivilegedMode() at any time
所以一开始我是在main函数的地方调用“CPUSwitchToPrivilegedMode”。可是调用这个切换到特权模式的时候就会跑飞,直到Shine Zhang告诉我需要Boot.asm就可以了。然后就发现不用调用这个函数就可以默认进入特权模式了。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我估计是不是我的工程哪里配置有问题啊,我把cpu.c、startup.c都添加进了工程,代码如下:
void main(void)
{
//ptest = (unsigned int *)0xC0000010;
//*ptest = 0xAA55;
CPUSwitchToPrivilegedMode();
PSCModuleControl(SOC_PSC_1_REGS,HW_PSC_GPIO,PSC_POWERDOMAIN_ALWAYS_ON,PSC_MDCTL_NEXT_ENABLE);
......
程序就跑飞了????这种方式出现的这个问题现在也不知道为啥。您有啥高见?
CCS给出的提示为:
No source available for "0xfffd45e0"
右侧对应的汇编
fffd45e0: EAFFFFFD B 0xFFFD45DC
fffd45e4: E92D4010 STMFD R13!, {R4, R14}
fffd45e8: E59F4B74 LDR R4, 0xFFFD5164
fffd45ec: E3A020A0 MOV R2, #0xA0
fffd45f0: E3A01000 MOV R1, #0x0
fffd45f4: E1A00004 MOV R0, R4
fffd45f8: EB00117B BL 0xFFFD8BEC
fffd45fc: E59FCB64 LDR R12, 0xFFFD5168
fffd4600: E584C07C STR R12, [R4, #0x7C]
fffd4604: EB00001A BL 0xFFFD4674
fffd4608: E1D4C0B2 LDRH R12, [R4, #0x2]
weihua li 说:所以一开始我是在main函数的地方调用“CPUSwitchToPrivilegedMode”。可是调用这个切换到特权模式的时候就会跑飞,直到Shine Zhang告诉我需要Boot.asm就可以了。然后就发现不用调用这个函数就可以默认进入特权模式了。
原因是因为原始的boot.asm里初始化时,配置成了user模式,而你新参考的配置的是supervisor模式(其实不配置,默认就是supervisor mode), 代码对比如下:
原始的,即CCS安装目录下C:\ti\ccsv6\tools\compiler\arm_5.0.11\lib\src\boot.asm
_c_int00: .asmfunc
;***************************************************************
;* FUNCTION DEF: _c_int00
;***************************************************************
_c_int00: .asmfunc
.if __TI_NEON_SUPPORT__ | __TI_VFP_SUPPORT__
;*------------------------------------------------------
;* SETUP PRIVILEGED AND USER MODE ACCESS TO COPROCESSORS
;* 10 AND 11, REQUIRED TO ENABLE NEON/VFP
;* COPROCESSOR ACCESS CONTROL REG
;* BITS [23:22] - CP11, [21:20] - CP10
;* SET TO 0b11 TO ENABLE USER AND PRIV MODE ACCESS
;*------------------------------------------------------
MRC p15,#0x0,r0,c1,c0,#2
MOV r3,#0xf00000
ORR r0,r0,r3
MCR p15,#0x0,r0,c1,c0,#2
;*------------------------------------------------------
; SET THE EN BIT, FPEXC[30] TO ENABLE NEON AND VFP
;*------------------------------------------------------
MOV r0,#0x40000000
FMXR FPEXC,r0
.endif
;*------------------------------------------------------
;* SET TO USER MODE
;*------------------------------------------------------
MRS r0, cpsr
BIC r0, r0, #0x1F ; CLEAR MODES
ORR r0, r0, #0x10 ; SET USER MODE
MSR cpsr_cf, r0
你新参考的boot.asm也是基于上面这个文件改的,只将0x10改成了0x13(不过注释没改):
;* SET TO USER MODE
;*------------------------------------------------------
MRS r0, cpsr
BIC r0, r0, #0x1F ; CLEAR MODES
ORR r0, r0, #0x13 ; SET USER MODE
MSR cpsr_cf, r0
因为你的新工程序默认的入口entry_point是_c_int00(这个函数本身是在rts库里的,只是编译器在工程里找符号时是先从源文件里找,再到库里找,所以你把boot.asm加进来后,调用的_c_int00是上面修改后的了),所以程序下载后就从上面执行下来,初始为对应的mode了。其实上面把这段代码去掉,效果是一样的,因为默认为supervisor mode,还有一个常识是如果当前是user mode,是不能通过这种直接修改cpsr从user mode改到supervisor模式的。这也是为什么有swi存在的原因。从user mode,必需先进入swi才能修改cpsr。
第二问题是为什么跑飞了,原因是你的工程序里没有初始化异常向量表,就比如工程中没有初始化中断向量表,又把中断使能了,而且来了个中断,自然就跑飞了。
有兴趣可以继续看一下boot.asm和auto_init.asm,RTS库从这里就跳入用户的main了,没有进一步的初始化。这对于简单的C工程可以正常运行,因为需要的C环境初始化都做了,但是对于系统来说,还没有做exception vector的初始化,所以系统不能有中断。
weihua li 说:怎么让程序运行到 startup.c 里面的 start_boot(),需要在cmd文件里面怎么设置呢?
对比一个startware里的工程,比如拿timerCounter.cmd:
-stack 0x8000 /* SOFTWARE STACK SIZE */
-heap 0x2000 /* HEAP AREA SIZE */
-e Entry
/* SPECIFY THE SYSTEM MEMORY MAP */
上面指定了入口是Entry,这个是init.asm里的, 这里初始化各个模式下的堆栈,最后是system mode的,所以你看到的是为什么starterware工程起来后就可以改任意寄存器。
; Set up the Stack for USer/System mode
;
MSR cpsr_c, #MODE_SYS|I_F_BIT ; change to system mode
MOV sp,r0 ; write the stack pointer
; Set up the Stack for USer/System mode
;
MSR cpsr_c, #MODE_SYS|I_F_BIT ; change to system mode
MOV sp,r0 ; write the stack pointer
;
; Clear the BSS section here
;
Clear_Bss_Section:
LDR r0, _bss_start ; Start address of BSS
LDR r1, _bss_end ; End address of BSS
SUB r1,r1,#4
MOV r2, #0
Loop:
STR r2, [r0], #4 ; Clear one word in BSS
CMP r0, r1
BLE Loop ; Clear till BSS end
BL __TI_auto_init ; Call TI auto init
;
; Enter the start_boot function. The execution still happens in system mode
;
LDR r10, _start_boot ; Get the address of start_boot
MOV lr,pc ; Dummy return
BX r10 ; Branch to start_boot
SUB pc, pc, #0x08 ; looping
所以上面你把这几个文件加到了你的工程序,但是没有把入口地址改成entry,所以没有执行上面步骤,上面代码最后跳到start_boot,做了向量初始化后才真正进入用户的main.
unsigned int start_boot(void)
{
/* Enable write-protection for registers of SYSCFG module. */
SysCfgRegistersLock();
/* Disable write-protection for registers of SYSCFG module. */
SysCfgRegistersUnlock();
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_UART2, 0, PSC_MDCTL_NEXT_ENABLE);
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_AINTC, 0, PSC_MDCTL_NEXT_ENABLE);
/* Initialize the vector table with opcodes */
CopyVectorTable();
/* Calling the main */
main();
while(1);
}
(其实不配置,默认就是supervisor mode), 代码对比如下:
原始的,即CCS安装目录下C:\ti\ccsv6\tools\compiler\arm_5.0.11\lib\src\boot.asm
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我使用的是ccsv5.5,在你说的路径下面没有看到有boot.asm呀,
路径如下 C:\ti\ccsv5\tools\compiler\arm_5.1.1\lib,没发现这个文件。
我一开始用过ccs6.0,只是用的早发现仿真不行,后来跟咱们技术支持沟通退回到5.5了。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我参考过你说的那个timerCounter.cmd,试着将 -e Entry加上,但总是报错
>> Compilation failure
warning #10063-D: entry-point symbol other than "_c_int00" specified: "Entry"
error #10010: errors encountered during linking; "omapl138_arm.out" not built
gmake: *** [omapl138_arm.out] Error 1
gmake: Target `all' not remade because of errors.
**** Build Finished ****
另外,我不知道要加rts库,我加上这个库再试试吧
C:\ti\ccsv6\tools\compiler\arm_5.0.11\lib\src\boot.asm VS. C:\ti\ccsv5\tools\compiler\arm_5.1.1\lib
rts库默认就加上了。
>> Compilation failure
warning #10063-D: entry-point symbol other than "_c_int00" specified: "Entry" ----这只是提醒。
error #10010: errors encountered during linking; "omapl138_arm.out" not built ----- 要查这个错误怎么来的。
#1. 你上面提供的编译出错信息,完整的应该是下面所示,而你把关键的部分没提供出来,这些信息告知这些函数找不到,这里在starterware库里的,这里鉴于简单验证而已经,那么就在startup.c里先注释掉其调用。你也可以把库加进来.
<Linking>
undefined first referenced
symbol in file
--------- ----------------
PSCModuleControl ./startup.obj
SysCfgRegistersLock ./startup.obj
SysCfgRegistersUnlock ./startup.obj
error #10234-D: unresolved symbols remain
warning #10063-D: entry-point symbol other than "_c_int00" specified: "Entry"
error #10010: errors encountered during linking; "arm9_previlege_Mode.out" not built
>> Compilation failure
gmake: *** [arm9_previlege_Mode.out] Error 1
gmake: Target `all' not remade because of errors.
**** Build Finished ****
#2. 还应该有头文件找不到的出错,把相应的头文件路径加进来。
#3. cmd里也可做简单修改,如果你把system_config.lib加到了工程里,就不用改了。
.init : {
/* system_config.lib<init.obj> (.text) */
} load > 0xC1080000
然后编译结果如下,成功生成.out:
"./startup.obj" "../timerCounter.cmd" -l"libc.a"
<Linking>
warning #10063-D: entry-point symbol other than "_c_int00" specified: "Entry"
'Finished building target: arm9_previlege_Mode.out'
' '
**** Build Finished ****
运行结果如下: