2014年11月

LD文档——1.概览

原文:

https://sourceware.org/binutils/docs/ld/Overview.html#Overview

ld是组合很多的obj文件和库文件,并且对它们的数据及相关符号引用进行重定位。通常情况下,ld被放在编译过程的最后一步。

ld接受使用AT&T的链接编辑命令语言语法的超集编写的Linker命令语言文件,为链接过程提供显示的整体控制。

ld的版本使用通常的BFD库对obj文件进行操作。同时允许ld可以在不同种的格式下读取,组合和改写obj文件,例如COFF或者a.out。不同的格式也可以被链接在一起,产生出其它有可以的obj文件。获得更多信息,请查阅BFD。

抛开灵活性,在提供诊断信息方面,gnu链接器也比其它的更有帮助。很多的链接器当遇到错误,会放弃继续执行;无论什么情况下,ld都会继续执行,允许你标识其它的错误(或者,有些情况下,会不顾错误地得到一个输出文件)。

OpenOCD使用OSBDM接口调试K60

折腾这么长时间,OpenOCD与OpenJTAG还是有无法连接的时候,特别是在对flash擦写后,OpenOCD会是示无法获知K60芯片的状态。幸好开发板上自带了OSBDM接口,使用通用的USB线与开发板连接即可。OpenOCD使用以下的配置文件:

telnet_port 4444
gdb_port 3333
gdb_memory_map disable
interface osbdm
reset_config srst_only

source [find target/k60.cfg]

$_TARGETNAME configure -event reset-init {
puts "-event reset-init occured"
}

#
# Bank definition for the 'program flash' (instructions and/or data)
#
flash bank pflash.0 kinetis 0x00000000 0x40000 0 4 $_TARGETNAME
flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME

MAC OS下搭建K60开发环境

公司项目中要使用K60的芯片,所以需要先行把相关的开发环境搭建起来.之前有中电器材的K60开板,直接在上面做部分开发。嵌入式上的开发环境基本上是两类,一类是IDE,一类是VIM+MAKE+CSCOPE。现在的很多芯片厂商都开始注重生态圈的建设,所以各家都有自己的IDE,而且多数是从Eclipse扩展出来的。另一类属于DIY型,芯片公司已经把Linux移植在芯片上,中间的构建过程都是由shell脚本和makefile文件组成,便于开发者使用。

自从MAC PRO到手后,就一直想在MAC OS下完成大多数的开发任务,不能浪费这么好的系统么。嵌入式开发过程需要软件和硬件的配合才得以完成,当然有些是硬件是在开发板上有提供。我使用的开发板是中电器材的K60(也没个正式的名字,就这样吧),芯片使用Freescale家的MK60N512ZVLQ10,板子分为CPU板和BASE板,CPU板以DDR接口形式插在BASE板上。因为芯片是ARM的,所以调试接口JTAG是支持的,Freescale又搞了OSJTAG使用MINI USB接口与PC相连。我这里使用的Debuger是韦东山的OpenJTAG,是由FTDI提供的USB转JTAG的芯片完成调试功能。

  1. 硬件连接

之前有写过文章openjtag debuger for freescale k60 chip,具体接线参考此文即可。需要购买mini jtag的头和排线。

  1. 软件配置

软件使用OpenOCD与OpenJTAG通讯,在MAC OS下直接使用brew安装即可

brew install openocd

brew中提供的openocd是0.8.0版本的。接下来是写openocd的配置文件,以便识别到OpenJTAG和开发板芯片。

telnet_port 4444
gdb_port 3333
gdb_memory_map disable

# interface for openjtag
interface ft2232
adapter_khz 1000
#jtag_speed 0
ft2232_vid_pid 0x1457 0x5118
ft2232_layout "jtagkey"
ft2232_device_desc "USB<=>JTAG&RS232"

# about target
source [find target/swj-dp.tcl]
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME k60
}

if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}

if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x4ba00477
}

set _TARGETNAME $_CHIPNAME.cpu
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu

cortex_m reset_config sysresetreq

#
# Bank definition for the 'program flash' (instructions and/or data)
#
flash bank pflash.0 kinetis 0x00000000 0x40000 0 4 $_TARGETNAME
flash bank pflash.1 kinetis 0x00040000 0x40000 0 4 $_TARGETNAME

然后执行openocd即可

sudo openocd -f k60.cfg

输出结果如下:

Open On-Chip Debugger 0.8.0 (2014-08-04-08:53)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter speed: 1000 kHz
cortex_m reset_config sysresetreq
Info : add flash_bank kinetis pflash.0
Info : add flash_bank kinetis pflash.1
Warn : Using DEPRECATED interface driver 'ft2232'
Info : Consider using the 'ftdi' interface driver, with configuration files in interface/ftdi/...
Info : clock speed 1000 kHz
Info : JTAG tap: k60.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Info : k60.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : accepting 'telnet' connection from 4444
Info : accepting 'gdb' connection from 3333
undefined debug reason 7 - target needs reset
Info : JTAG tap: k60.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
  1. 调试程序

开发过程中,调试是必需的步骤,由其是嵌入式开发,很多问题基本是靠debug出来的,然后再解决掉。这里使用GDB调试,通过openocd连接,进行远端调试。

首先,在编译源码时,要编写linker文件,指定程序入口点为内存地址处,这样使用GDB时才可以把ELF文件加载在相应内存处,然后执行。当然,有时候你的RAM是外置的,需要先把RAM初始化后才可以使用。我使用了一个LED的小程序来测试调试的过程。

[k60_led_demo](https://github.com/Blackrose/k60_led_demo)

这里面有两个linker文件,调试时使用k60n128_ram.ld即可。在已经运行OpenOCD基础上,通过GDB连接OpenOCD的调试端口;

arm-none-eabi-gdb out/k60_gpio_demo.elf
target remote localhost:3333
monitor reset init
load

这时,会有加载成功的提示,接下来就与PC上的GDB调试相同了,break,continue之类的。

  1. 烧写程序

调试完成后,通常会把程序烧写进芯片,做外部功能性测试。烧写直接使用OpenOCD就可以了,编译时使用k60n512_flash.ld文件,这样程序是从FLASH的0x0处执行。以下是烧写过程:

telnet localhost 4444
reset init
flash write_image erase out/k60_gpio_demo.elf

等待完成后,断开OpenOCD和JTAG调试器,程序就可以独立运行在芯片上了。

The sound of silence

Tags: music

1976年12月,电影《毕业生》上映,其中的主题曲就是这首歌。演唱者是Paul Simon和Garfunkel,完成于1966年。

记一次见证高温的奇迹

6月份时,公司的产品要求增加TCPIP协议栈,以便完成以太网的通讯功能,接入上层管理系统。作为一名业余“救火”程序员,用三天时间完成了TCPIP的协议栈移植,然后又与现有的RS485通讯程序整合。兴冲冲的去现场为用户更新软件,带着悠闲地心情回到公司。三个月后,现场打电话说,“装置通讯时,出现反覆的重启现象,但是过段时间又好了”。对于工业产品来说,通讯可以没有,但不能无故重启,否则会有事故发生的可能。为了确认问题的出现原为,让现场人员分多次观测装置,发现中午12点至16点之间,装置重启的可能性最大。面对这种情况,我的第一反映是温度导致以太网芯片过热,由于MCU与以太网芯片是使用SPI方式连接,怀疑是SPI通讯没有复位,导致MCU卡在在某个whille中,WatchDog将MCU硬复位了。

这个地方有一些疑点:

  1. 不加以太网程序时,装置并没有重复重启情况发生

  2. 增加以太网程序时,在常温下没有出现类似问题

  3. 以太网的程序是由MicroChip公司提供的MicrochipLibraryApplication套件,这个里面有实现TCPIP协议栈处理和SPI通讯

TCPIP的库是由官网提供的不应该有问题,但装置本身也是没有重启现象。早些时候觉得可能是TCPIP处理中有while卡死,所有就在主循环一定时间后把以太网芯片复位,可问题依旧。这个时候,决定再做一些测试,期间没有把局域网的网线接在交换机,只有交换机与装置以太网接口相连,发现高温持续很长时间后长会有重启现象。

这里突然想到,会不会是上层处理数据包时卡死。代码跟踪一圈后,在TCP处理时,有对数据包的校验,发现里面竟然直接有Reset()这种函数的调用,最终发现了下面的东东:

#define Reset() asm("reset")

我嘞个去啊,大哥,不带这么玩我呢。你校验个TCP头,觉得有问题,可以扔掉或者复位以太网芯片呢。为什么要把MCU都Reset掉,这绝对是个坑呢。我以为一切都结束呢,结果高温测试时,以太网一直在重启中。

这时想到了个问题,高温对SPI线上的数据还是有影响的,导致数据包有问题,所以以太网芯片就一直在重启,因为每个包都有问题么。郁闷之迹,看到校验判断前有注释,可能还比较多(我为了查看方便把Folding功能是打开的,只能看见一行),打开后有很长一段,其中说明了为什么会有校验判断这片代码,还提到了可能会出现这种情况的原因,其中说如果MCU的SPI总线与以太网芯片通讯速率太快,数据包可能会不完整。

难道是配置的通讯速率太快了么??

最大16MHz,我使用12MHz,那就换5MHz吧。接下来就是见证奇迹的时候,果然高温测试时,不再有重启现象。问题是解决了,但个中原因还是不详啊。硬件工程师给出了一个满意的答案:

12MHz来通讯是很快,但是MCU与以太网芯片比较远,SPI总线就很长了,速度快肯定是要衰减的,
同时速度快就会很容易受外界的影响,高温就导致你的MAC数据帧有错乱,上面又是Reset,所以就会出现这种问题了。

很多时候,我在通讯时都尽量避免使用最大速率通讯,但是还有一些外界的情况没有考虑到。所以,没有最快速率,只有最合适的。

Linux下编译MQX的RTCS例程

Tags: linux,mqx

在RTCS中有四个例程,本次编译"httpsrv"例程。

首先进入例程的编译目录:

cd rtcs/examples/httpsrv/build/make/httpsrv_twrk60n512
./build_gcc_arm.sh

编译成功后,会显示“Build done"。同时,在build_arm目录下有相应的elf二进制文件,烧写到芯片即可。

我这里编译时出现libgcc.a库无法找到,仔细查看编译过程发现,里面的库路径是"gcc-arm-none-eabi-48-2014q3/lib/gcc/arm-none-eabi/4.8.3/armv7e-m/libgcc.a",而我下载的GCC中的路径已已经是4.8.4了。所以需要修改tools目录下的gccarm.mk文件:

vi tools/gcc_arm.mk

搜索ligcc.a的地方,把路径修改正确后,重新编译就可以得到elf文件了。

Linux下命令行编译MQX

Tags: linux,mqx

最近,公司开始搞新项目,需求使用一个RTOS,基本上就指定是Freescale家的MQX了。为了理解方便,先在linux下用手工的方式编译下。

编译前要先下载好GCC的工具链

gcc-arm-none-eabi-4_8-2014q3-20140805-linux.tar.bz2

然后编写一个sh文件来加载相关的环境变量。

解压MQX的源码文件,然后进入源码根目录下。首先要修改一个文件,以便可以使用工具链来编译整个系统:

build/common/make/global.mak

里面有TOOLCHAIN_ROOTDIR的变量,修改为工具链的路径即可。

因为MQX支持多个目标板,我这里以twrk60n512为例:

cd build/twrk60n512/make
./build_gcc_arm.sh

这样就可以编译MQX的所有Componments,编译完成后,会在lib/twrk60n512.gcc_arm/release下的各个componment目录下有相关的头文件和*.a的静态库文件。我在编译过程中,遇到两个小问题,解决如下:

1.缗译时出现creating command not found.

解决:这是由global.mk文件的最后那个PRINT引起的,把echo前的@删除即可。

2.编译时出现“stdbool.h”无法找到的问题

解决:stdbool.h文件在工具链的两个地方有出现,既然GCC无法找到,就手动将目录加到环境变量中:

C_INCLUE_PATH=/home/blackrose/freescale-mqx/gcc-arm-none-eabi-4_8-2014q3/lib/gcc/arm-none-eabi/4.8.4/include:${C_INCLUDE_PATH}

3.编译RTCS时,出现无法找到limits.h文件

解决:添加limits.h文件所在的目录到CINCLUDEPATH

export C_INCLUDE_PATH=gcc-arm-none-eabi-4_8-2014q3/lib/gcc/arm-none-eabi/4.8.4/include-fixed:$C_INCLUDE_PATH

最新文章

最近回复

  • Blackrose: 感谢拍砖!嗯,那句话...
  • aa: “Raspberry...
  • Blackrose: 外部只是帮你把芯片启...
  • : 内部时钟比外部的频率...
  • Blackrose: 你这评论比正文更有内容么
  • 7hao: CR+LF ...
  • Blackrose: 可以是你更新软件源后...
  • sxk: 博主,我的系统是ub...
  • Blackrose: 你深得精髓么
  • qihao: 这篇文章的简单总结就...

分类

归档

其它