自己动手写J-LINK脚本,烧写NAND启动代码
2012-06-09 18:01
435 查看
一、背景
对于J-LINK,一般只能使用J-Flash软件来烧写Norflash,而对于烧写Nandflash不支持,而Hjtag只能够烧写大部分固定平台的Nandflash,问了度娘,也没得到满意的答案,于是索性自己写一个J-LINK脚本来完成烧写工作。
二、平台介绍
CPU:AT91SAM9G10
内部SRAM:16KB
NANDFLASH:128M
三、上电启动过程分析
分为2步,Bootloader0,Bootloader1。
Bootloader0:这一部分主要执行CPU内部ROM中的代码。
1. Stack setup for ARM supervisor mode
2. Main Oscillator Frequency Detection
3. C variable initialization
4. PLL setup: PLLB is initialized to generate a 48 MHz clock necessary to use the USB
Device. A register located in the Power Management Controller (PMC) determines the
frequency of the main oscillator and thus the correct factor for the PLLB.
5. Initialization of the DBGU serial port (115200 bauds, 8, N, 1)
6. Enable the user reset
7. Jump to SerialFlash Boot sequence through NPCS0. If SerialFlash Boot succeeds, perform
a remap and jump to 0x0.
8. Jump to DataFlash Boot sequence through NPCS0. If DataFlash Boot succeeds, perform
a remap and jump to 0x0.
9. Jump to NAND Flash Boot sequence. If NAND Flash Boot succeeds, perform a remap
and jump to 0x0.
10. Jump to SD Card Boot sequence. If SD Card Boot succeeds, perform a remap and
jump to 0x0.
11. Jump to EEPROM Boot sequence. If EEPROM Boot succeeds, perform a remap and
jump to 0x0.
12. Activation of the Instruction Cache
13. Jump to SAM-BA Boot sequence
14. Disable the WatchDog
15. Initialization of the USB Device Port
从上面可以看出,内部ROM做的工作主要为:
1、使能主时钟源。
2、从外设中,一次寻找“有效序列”,找到有效序列,则加载到内部SRAM,然后REMAP,跳转到内部SRAM执行。
有效序列:
以B或LDR的相对寻址异常向量表,其中地址0x14存放的是需要搬运到SRAM的代码长度。
Bootloader1:Nandflash中启动代码,这部分代码主要完成主时钟配置,SDRAM初始化,代码搬运,堆栈初始化等工作。
四、烧写脚本
思路1:在JLinkARM.dll基础上做2次开发。正所谓内事问百度,外事问谷歌,2个都问了,都没有找到接口文档说明,所以此路暂时不通。
思路2:编写一个脚本文件,利用J-LINK的命令窗口J-Link Commander来执行。
方案A:用Window程序来将脚本进行封装,创建2个PIPE,然后CreateProcess一个子进程,将InputR绑定到子进程的标准输入端,OutputW绑定到子进程的标准输出端,这样可以对输出结果进行条件判断。
编写3个BIN文件:
第一个BIN1:加载到SRAM,用来初始化主时钟,和SDRAM。
第二个BIN2:加载到内存地址0x21000000,用于下载第三个BIN到Nandflash。
第三个BIN3:加载到内存0x22000000,Nandflash启动代码。
首先,loadbin BIN1,0x0; setpc 0x0; g;
然后,h; loadbin BIN2,0x21000000; loadbin BIN3,0x22000000; setpc 0x21000000; g;
最后还是存在一个问题,通过WriteFile函数向句柄InputW写数据时,从OutputR端未读到数据。
方案B:纯脚本,使用Windows的system函数来执行脚本文件了。
对于J-LINK,一般只能使用J-Flash软件来烧写Norflash,而对于烧写Nandflash不支持,而Hjtag只能够烧写大部分固定平台的Nandflash,问了度娘,也没得到满意的答案,于是索性自己写一个J-LINK脚本来完成烧写工作。
二、平台介绍
CPU:AT91SAM9G10
内部SRAM:16KB
NANDFLASH:128M
三、上电启动过程分析
分为2步,Bootloader0,Bootloader1。
Bootloader0:这一部分主要执行CPU内部ROM中的代码。
1. Stack setup for ARM supervisor mode
2. Main Oscillator Frequency Detection
3. C variable initialization
4. PLL setup: PLLB is initialized to generate a 48 MHz clock necessary to use the USB
Device. A register located in the Power Management Controller (PMC) determines the
frequency of the main oscillator and thus the correct factor for the PLLB.
5. Initialization of the DBGU serial port (115200 bauds, 8, N, 1)
6. Enable the user reset
7. Jump to SerialFlash Boot sequence through NPCS0. If SerialFlash Boot succeeds, perform
a remap and jump to 0x0.
8. Jump to DataFlash Boot sequence through NPCS0. If DataFlash Boot succeeds, perform
a remap and jump to 0x0.
9. Jump to NAND Flash Boot sequence. If NAND Flash Boot succeeds, perform a remap
and jump to 0x0.
10. Jump to SD Card Boot sequence. If SD Card Boot succeeds, perform a remap and
jump to 0x0.
11. Jump to EEPROM Boot sequence. If EEPROM Boot succeeds, perform a remap and
jump to 0x0.
12. Activation of the Instruction Cache
13. Jump to SAM-BA Boot sequence
14. Disable the WatchDog
15. Initialization of the USB Device Port
从上面可以看出,内部ROM做的工作主要为:
1、使能主时钟源。
2、从外设中,一次寻找“有效序列”,找到有效序列,则加载到内部SRAM,然后REMAP,跳转到内部SRAM执行。
有效序列:
以B或LDR的相对寻址异常向量表,其中地址0x14存放的是需要搬运到SRAM的代码长度。
Bootloader1:Nandflash中启动代码,这部分代码主要完成主时钟配置,SDRAM初始化,代码搬运,堆栈初始化等工作。
四、烧写脚本
思路1:在JLinkARM.dll基础上做2次开发。正所谓内事问百度,外事问谷歌,2个都问了,都没有找到接口文档说明,所以此路暂时不通。
思路2:编写一个脚本文件,利用J-LINK的命令窗口J-Link Commander来执行。
方案A:用Window程序来将脚本进行封装,创建2个PIPE,然后CreateProcess一个子进程,将InputR绑定到子进程的标准输入端,OutputW绑定到子进程的标准输出端,这样可以对输出结果进行条件判断。
编写3个BIN文件:
第一个BIN1:加载到SRAM,用来初始化主时钟,和SDRAM。
第二个BIN2:加载到内存地址0x21000000,用于下载第三个BIN到Nandflash。
第三个BIN3:加载到内存0x22000000,Nandflash启动代码。
首先,loadbin BIN1,0x0; setpc 0x0; g;
然后,h; loadbin BIN2,0x21000000; loadbin BIN3,0x22000000; setpc 0x21000000; g;
最后还是存在一个问题,通过WriteFile函数向句柄InputW写数据时,从OutputR端未读到数据。
方案B:纯脚本,使用Windows的system函数来执行脚本文件了。
#include <stdio.h> #include <process.h> #define BOOT_LOAD "d:\\boot_download\\boot_down.bin" #define BOOT_NAND "d:\\boot_nandflash\\boot_nand.bin" #define JLINK_BAT "d:\\jlink_bat" #define JLINK_DIR "\"C:\\Program Files\\SEGGER\\JLinkARM_V436c\\JLink.exe\"" FILE *stream; void main(void) { stream = fopen(JLINK_BAT,"w"); fprintf(stream, "speed 8000 \n"); fprintf(stream, "le \n"); //禁止内部看门狗 fprintf(stream, "w4 0xFFFFFD44,0x00008000 \n"); //配置时钟 fprintf(stream, "w4 0xFFFFFC14,0xFFFFFFFF \n"); fprintf(stream, "w4 0xFFFFFC04,0xFFFFFFFE \n"); fprintf(stream, "w4 0xFFFFFC20,0x00004001 \n"); fprintf(stream, "w4 0xFFFFFC28,0x2064BF07 \n"); fprintf(stream, "w4 0xFFFFFC30,0x00000102 \n"); fprintf(stream, "Sleep 500 \n"); //配置SDRAM fprintf(stream, "w4 0xFFFFEE30,0x0001003A \n"); fprintf(stream, "w4 0xFFFFF870,0xFFFF0000 \n"); fprintf(stream, "w4 0xFFFFF874,0x00000000 \n"); fprintf(stream, "w4 0xFFFFF804,0xFFFF0000 \n"); fprintf(stream, "w4 0xFFFFEA08,0xA6339279 \n"); fprintf(stream, "w4 0xFFFFEA24,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA00,0x00000001 \n"); fprintf(stream, "w4 0x20000000,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA00,0x00000002 \n"); fprintf(stream, "w4 0x20000000,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA00,0x00000004 \n"); fprintf(stream, "w4 0x20000000,0x00000000 \n"); fprintf(stream, "w4 0x20000004,0x00000000 \n"); fprintf(stream, "w4 0x20000008,0x00000000 \n"); fprintf(stream, "w4 0x2000000C,0x00000000 \n"); fprintf(stream, "w4 0x20000010,0x00000000 \n"); fprintf(stream, "w4 0x20000014,0x00000000 \n"); fprintf(stream, "w4 0x20000018,0x00000000 \n"); fprintf(stream, "w4 0x2000001C,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA00,0x00000003 \n"); fprintf(stream, "w4 0x20000000,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA00,0x00000000 \n"); fprintf(stream, "w4 0x20000000,0x00000000 \n"); fprintf(stream, "w4 0xFFFFEA04,0x000003A3 \n"); fprintf(stream, "loadbin "); fprintf(stream, BOOT_LOAD); fprintf(stream, ",0x21000000 \n"); fprintf(stream, "loadbin "); fprintf(stream, BOOT_NAND); fprintf(stream, ",0x22000000 \n"); fprintf(stream, "h \n"); fprintf(stream, "setpc 0x21000000 \n"); fprintf(stream, "g \n"); fclose(stream); system("\"C:\\Program Files\\SEGGER\\JLinkARM_V436c\\JLink.exe\" d:\\jlink_bat"); }
相关文章推荐
- 【干货】自己动手打造专属代码生成工具(完结篇)
- 自己动手:bash脚本工具统计git历史, 发掘谷歌在Android项目奥秘
- 自己动手的第一个 Hibernate后台代码
- linux 添加自己的启动脚本程序
- 自己动手写操作系统 将引导程序成功写入优盘启动电脑
- 自己动手开发编译器(十二)生成托管代码
- 自己动手写代码,整合Spring和Hibernate(二)之配置数据源
- Centos7开机启动自己的脚本
- 闲的没事,自己动手修改上兴3.2源代码
- 闲的没事,自己动手修改上兴3.2源代码(2)
- 自己动手设计代码编辑器——(六)自己写XML管理类
- Linux Bash 脚本:自己定义延迟代码块(裸数据保存方案)
- 自己动手,结合javascript和dhtml做一个ubb编辑器(附例子代码)
- 自己动手编写VBScript脚本刷QQ群信息
- 分析自己的linux启动代码
- rhel7开机启动自己shell脚本
- 自己动手实现jQuery Callbacks完整功能代码详解
- 在开机启动脚本/etc/init.d/rcS中添加自己的应用程序
- 自己编写脚本启动hadoop各个守护进程需要的特别配置
- 几个启动和检测脚本 防止自己忘记