3019|1

1382

帖子

2

TA的资源

五彩晶圆(初级)

楼主
 

STM32MP157A-DK1测评 (3) Cortex-A7点个灯 [复制链接]

 
本帖最后由 cruelfox 于 2020-4-19 08:46 编辑

  虽然我已可以使用板载的ST-Link通过SWD口对 STM32MP157 进行调试,但却在实验中遇到意外情况,总之OpenOCD中调试操作并不像对STM32系列MCU那样顺利。我对 OpenOCD 背后的调试原理不熟悉,又是头一次对付 Cortex-A7 核,所以在这里遇到些障碍。

  比如,用 halt 命令停止 CPU 的执行时,可能明显出现等待,然后OpenOCD报个错
> halt
stm32mp15x.cpu0 rev 5, partnum c07, arch f, variant 0, implementor 41
stm32mp15x.cpu0 cluster 0 core 0 multi core
Timeout waiting for halt

  比如遇到 step 命令不能单步执行(PC寄存器无变化)的状态。

  更要命的是,在以前对 Cortex-M 进行复位初始化我用的 reset init 命令不能正常用了。
> reset init
ap 0 selected, csw 0x10006000
mem2array: Read @ 0x50001000, w=4, cnt=1, failed
mem2array: Read @ 0x50000208, w=4, cnt=1, failed
SRST line asserted
SRST line released
stlink_connect(connect)
SWD DPIDR 0x6ba02477
timed out while waiting for target halted
stm32mp15x.cpu0 rev 5, partnum c07, arch f, variant 0, implementor 41
target halted in Thumb state due to debug-request, current mode: Supervisor
cpsr: 0x800001f3 pc: 0x00010b6a
MMU: enabled, D-Cache: disabled, I-Cache: enabled
ap 0 selected, csw 0x10006000
pc (/32): 0x00010B6A
stm32mp15x.cpu1: ran after reset and before halt ...
Timeout waiting for halt
embedded:startup.tcl:24: Error:
in procedure 'ocd_process_reset'
in procedure 'ocd_process_reset_inner' called at file "embedded:startup.tcl", line 261
in procedure 'arp_reset_default_handler'
in procedure 'arp_reset_plan_srst_dbg_gated' called at file "embedded:startup.tcl", line 387
in procedure 'stm32mp15x.cpu1' called at file "embedded:startup.tcl", line 339
in procedure 'ocd_bouncer'
at file "embedded:startup.tcl", line 24

Deferring arp_examine of stm32mp15x.cpu2
Use arp_examine command to examine it manually!
Deferring arp_examine of stm32mp15x.ap2
Use arp_examine command to examine it manually!
timed out while waiting for target halted
TARGET: stm32mp15x.cpu1 - Not halted

 

  假如 reset init 命令能让CPU复位成执行第一条指令之前的状态,那就能定位到程序入口开始跟踪执行过程。对付 Cortex-m 系列我经常这么干的。现在这一招失效,于是一连上调试器并不知道执行的是什么程序。如果是 Linux 运行状态下可能是某个程序或者内核中,如果是 u-boot 期间那多半是 u-boot 的代码。如果TF卡不插入上电的话,那应该就是 ROM bootloader 中的程序,这些是可以推断的。

  但是 halt 超时等现象就不知道是什么梗了。

 

  根据手册中的内存映射表,可以知道4G空间的最低地址 0x0 是 ROM bootloader 所在的地方,然后 0x10000000 开始有几块 SRAM, 而对 A7 核最重要的 SYSRAM 在 0x2FFC0000 处。0x40000000 开始有硬件设备的寄存器,和 STM32 MCU 相似。

  然而,在ROM程序阶段介入调试,用 OpenOCD 内存查看命令竟然出错:

> mdb 0 16
data abort at 0x00000000, dfsr = 0x00000008

> mdb 0x10000000 16
data abort at 0x10000000, dfsr = 0x00000005

> mdb 0x2ffc0000 16
data abort at 0x2ffc0000, dfsr = 0x00000008

> mdb 0x30000000 16
0x30000000: 08 00 00 30 68 02 00 30 00 00 00 00 00 00 00 00

> mdw 0x40000000 16
data abort at 0x40000000, dfsr = 0x00000007

  试了几处地址,除了 RAM alias 区域开头可以读访问之外,其它几个地方竟然不能读?这就费解了,程序在 ROM 中运行,又如何不能读ROM? 查看 PC 寄存器,执行的地址是 ROM 区没错:

> reg pc
pc (/32): 0x0000A396

那么就看这个地址,是可以读取的
> mdb 0xA396 16
0x0000a396: f8 49 c0 1b 88 42 07 d9 07 f0 c9 fb 26 ea 05 05
> arm disassemble 0xA396 4 thumb
0x0000a396  0x49f8      LDR     r1, [pc, #0x3e0]        ; 0x0000a778
0x0000a398  0x1bc0      SUBS    r0, r0, r7
0x0000a39a  0x4288      CMP     r0, r1
0x0000a39c  0xd907      BLS     0x0000a3ae
  看来 ROM 的部分地址被屏蔽了,这可能是启用了保护机制,可能是 MMU (内存管理单元) 控制了的原因。由于不能用 reset init 停在复位之后的状态调试,现在经过 ROM 程序的初始化之后,现场是什么样我不知晓。

  从 SP 寄存器看来,的确 SYSRAM 还能部分访问的。

> reg sp
sp (/32): 0x2FFC1BE0
> mdw 0x2ffc1000 4
0x2ffc1000: 260148df 0640bac1 077ff997 4e5e4a05

  再找个设备的寄存器呢,看看 GPIOA (从手册可以查到地址范围 0x50002000 ~ 0x500023FF)
> mdw 0x50002000 4
0x50002000: f7ffffbf 00002000 0c0000c0 00000000

  说明 GPIOA 可以访问。那么我可以动动手脚,先写段 LED 点灯的程序跑下试试。

 

  在官方的 STM32Cube_FW_MP1_V1.2.0 这个软件包里,我像往常对待 STM32 MCU 那样找出了 stm32mp157axx_ca7.h 这个寄存器定义文件,一看内容和 STM32 MCU 很像嘛!
  这样就可以通过寄存器操作开始玩它了。先点灯,只需要操作 GPIO. (因为 ROM 程序已经把一些初始化工作做了)

  根据电路图,有两个用户 LED 就在 PA13, PA14 上,同时还连着按钮。

  那么点灯程序这样写:

#include "stm32mp157axx_ca7.h"

void _start(void)
{
	int i;
	GPIOA->MODER = 1<<13*2|1<<14*2|~(3<<13*2|3<<14*2);
	for(;;)
	{
		if(GPIOA->ODR & 1<<14)
			GPIOA->BRR = 1<<14;
		else
			GPIOA->BSRR = 1<<14;
		for(i=0;i<10000;i++)
		{
			int n;
			if(GPIOA->ODR & 1<<13)
				GPIOA->BRR = 1<<13;
			else
				GPIOA->BSRR = 1<<13;
			for(n=0;n<100;n++)
			{
				__NOP();
               /////  总共100条 NOP 指令,这里为了页面空间省略了
				__NOP();
			}
		}
	}
}

  因为这里我只是写了一个程序片段,没有初始化代码(不需要,没有全局变量),不用到标准库,都不用写 main()

  然后先试试编译,用以前开发 STM32 那个 GCC 行不行呢?

E:\stm32mp157\a7>arm-none-eabi-gcc -mcpu=cortex-a7 -Os test.c -c -std=gnu99

  这样可以编译的(加 -std=gnu99 是因为使用的头文件需要)。那就看下编译后的代码:

E:\stm32mp157\a7>arm-none-eabi-objdump -d test.o

test.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:   e59f31e0        ldr     r3, [pc, #480]  ; 1e8 <_start+0x1e8>
   4:   e3e0230a        mvn     r2, #671088640  ; 0x28000000
   8:   e5832000        str     r2, [r3]
   c:   e59f31d4        ldr     r3, [pc, #468]  ; 1e8 <_start+0x1e8>
  10:   e5932014        ldr     r2, [r3, #20]
  14:   e3120901        tst     r2, #16384      ; 0x4000
  18:   e3a02901        mov     r2, #16384      ; 0x4000
  1c:   15832028        strne   r2, [r3, #40]   ; 0x28
  20:   05832018        streq   r2, [r3, #24]
  24:   e3023710        movw    r3, #10000      ; 0x2710
  28:   e59f21b8        ldr     r2, [pc, #440]  ; 1e8 <_start+0x1e8>
  2c:   e5921014        ldr     r1, [r2, #20]
  30:   e3110a02        tst     r1, #8192       ; 0x2000
  34:   e3a01a02        mov     r1, #8192       ; 0x2000
  38:   15821028        strne   r1, [r2, #40]   ; 0x28
  3c:   05821018        streq   r1, [r2, #24]
  40:   e3a02064        mov     r2, #100        ; 0x64

 

  看起来正常,那么把它弄到 STM32MP157 的 SRAM 里面运行一下。因为这段代码没有使用除了GPIOA之外的绝对内存地址,放到任何地址运行都是可以的。将编译结果二进制文件提取出来:

E:\stm32mp157\a7>arm-none-eabi-objcopy -Obinary test.o test.bin

  然后,用 OpenOCD 的命令将其写到内存地址 0x2FFC4000 (先确认过这块可访问)
> load_image e:/stm32mp157/a7/test.bin 0x2FFC4000
492 bytes written at address 0x2ffc4000
downloaded 492 bytes in 0.062500s (1.500 KiB/s)

  程序写到 SRAM 里面了,然后就运行它:让 CPU 恢复执行,从 0x2FFC4000 处开始。
> resume 0x2FFC4000
stm32mp15x.cpu0 rev 5, partnum c07, arch f, variant 0, implementor 41
Timeout waiting for halt
Polling target stm32mp15x.cpu0 failed, trying to reexamine
stm32mp15x.cpu0: hardware has 6 breakpoints, 4 watchpoints

  出了问题,而且 PC 寄存器就停留在 0x2FFC4000

> reg pc
pc (/32): 0x2FFC4000

 

  我查看了下 CPSR, 发现 T 位是置1的,那么就给取消一下试试。因为我编译的代码是 ARM 模式的。

> reg cpsr
cpsr (/32): 0x800001F3

> reg cpsr 0x1d3
cpsr (/32): 0x000001D3

> resume

 

  然后,LED开始闪烁,运行了!

  看LED LD6(红色)上面的波形

  因为我在代码中每次修改这个引脚 (PA13) 状态,间隔了10000条NOP指令,可以估算下每条 NOP 指令执行时间:25.1us/10000 = 2.51ns,  若以每条 NOP 指令一个时钟周期的速度执行的话,大约是 400MHz 的时钟。这只是揣测,不一定对。

此内容由EEWORLD论坛网友cruelfox原创,如需转载或用于商业用途需征得作者同意并注明出处

点赞 关注
 
 

回复
举报

1382

帖子

2

TA的资源

五彩晶圆(初级)

沙发
 

  32位的ARM处理器有 ARM 和 Thumb 两种指令编码模式,上面实验我是生成的 ARM 模式代码,从反汇编可以看到每条指令以 32-bit 字长为基本单位编码。而 Cortex-m 系列的 MCU 只支持 Thumb 模式,每条指令字长是 16-bit 为基本单位的。这也意味着 ARM 模式下 PC 寄存器地址是4字节对齐的,而 Thumb 模式下是2字节对齐。

  Cortex-A7 当然也可以用 Thumb 模式运行程序。如上面的程序,如果编译时 GCC 加上 -mthumb 选项,那么就生成 Thumb 代码。

E:\stm32mp157\a7>arm-none-eabi-gcc -mcpu=cortex-a7 -Os test.c -c -std=gnu99 -mthumb

E:\stm32mp157\a7>arm-none-eabi-objdump -d test.o

test.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:   4b40            ldr     r3, [pc, #256]  ; (104 <_start+0x104>)
   2:   f06f 5220       mvn.w   r2, #671088640  ; 0x28000000
   6:   601a            str     r2, [r3, #0]
   8:   4b3e            ldr     r3, [pc, #248]  ; (104 <_start+0x104>)
   a:   695a            ldr     r2, [r3, #20]
   c:   f412 4f80       tst.w   r2, #16384      ; 0x4000
  10:   f44f 4280       mov.w   r2, #16384      ; 0x4000
  14:   bf14            ite     ne
  16:   629a            strne   r2, [r3, #40]   ; 0x28
  18:   619a            streq   r2, [r3, #24]
  1a:   f242 7310       movw    r3, #10000      ; 0x2710
  1e:   4a39            ldr     r2, [pc, #228]  ; (104 <_start+0x104>)
  20:   6951            ldr     r1, [r2, #20]
  22:   f411 5f00       tst.w   r1, #8192       ; 0x2000
  26:   f44f 5100       mov.w   r1, #8192       ; 0x2000
  2a:   bf14            ite     ne
  2c:   6291            strne   r1, [r2, #40]   ; 0x28
  2e:   6191            streq   r1, [r2, #24]
  30:   2264            movs    r2, #100        ; 0x64
  32:   bf00            nop
  34:   bf00            nop
  尺寸上 Thumb 指令占用的空间要省不少。用同样的方式可以把程序载入到 STM32MP157 的 SRAM 中运行。CPU 如果在 ARM 模式则要设置成 Thumb 模式再运行。

  用了 Thumb 模式,Cortex-A7 和 Cortex-m 系列的差别又缩小一步。那么它是否可以执行 Cortex-m0/m3 的指令呢?我想多半是没有问题的,Cortex-A7 覆盖的指令集更大。上面这段程序的话,用 -mcpu=cortex-a7 和 -mcpu=cortex-m3 生成的 Thumb 代码完全一样。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表