一、问题定位

  

  开发板重启后打印了2个提醒和一个错误,caches的提醒先不看,看看flash和nand下面的提醒,bad CRC,Using default enviroment,我们可以定位Using default enviroment定位到

代码位置,如下:  

  Env_common.c (common)

  

  传入的参数应该是 !badCRC,再次定位函数set_default_env 看是在哪里调用此函数:

  

  

  

  

  

  基本上文件都在common文件夹下,有common中的调用和 dataflash,nand,sf,ubi。暂且不知道是哪个,要看看u-boot.dis中哪里调用了这个函数,再来定位了。

  通过u-boot.dis 可以知道,在几个函数中调用了 set_default_env 这个函数:

    • env_import:Env_common.c (common)
    • env_relocate:Env_common.c (common)
    • do_env_default:Cmd_nvedit.c (common)

二、代码分析

  搜索 Flash: 查看结果:

  

  与此相匹配的为 board_r.c 文件中。

  定位到 board_r.c(common)中的 initr_flash 函数。  

  此函数定义在第二阶段代码 board_init_r 函数中的 init_sequence_r 链表中:

  

2.1 initr_flash

  initr_flash 函数的代码解读如下:

  

  1. #if !defined(CONFIG_SYS_NO_FLASH) //未定义CONFIG_SYS_NO_FLASH这个宏就执行此函数
  2. static int initr_flash(void)
  3. {
  4. ulong flash_size = ; //定义存储 flash 空间大小的变量
  5. bd_t *bd = gd->bd; //定义板信息结构体
  6. puts("Flash: "); //输出字符串 Flash:
  7. if (board_flash_wp_on()) //此为空函数,返回0值,直接执行 else后面的语句
  8. printf("Uninitialized - Write Protect On\n");
  9. else
  10. flash_size = flash_init(); //flash初始化
  11. print_size(flash_size, ""); //打印flash_size的大小
  12. #ifdef CONFIG_SYS_FLASH_CHECKSUM //此宏在 include/configs/jz2440.h 未定义 里面的一段代码不执行
  13. /*
  14. * Compute and print flash CRC if flashchecksum is set to 'y'
  15. *
  16. * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
  17. */
  18. if (getenv_yesno("flashchecksum") == ) {
  19. printf(" CRC: %08X", crc32(,
  20. (const unsigned char *) CONFIG_SYS_FLASH_BASE,
  21. flash_size));
  22. }
  23. #endif /* CONFIG_SYS_FLASH_CHECKSUM */
  24. putc('\n'); //换行
  25. /* update start of FLASH memory */
  26. /* CONFIG_SYS_FLASH_BASE 在 include/configs/jz2440.h中有定义
  27. * #define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
  28. * #define PHYS_FLASH_1 0x00000000 // Flash Bank #0
  29. * 这里定义的宏的大小为0 则我们的CONFIG_SYS_FLASH_BASE 页的基地址为0
  30. */
  31. #ifdef CONFIG_SYS_FLASH_BASE
  32. bd->bi_flashstart = CONFIG_SYS_FLASH_BASE; //bd->bi_flashstart = 0 从0地址开始执行
  33. #endif
  34. /* size of FLASH memory (final value) */
  35. bd->bi_flashsize = flash_size; //flash 的大小
  36. #if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
  37. /* Make a update of the Memctrl. */
  38. update_flash_size(flash_size); //更新flash 的大小
  39. #endif
  40. #if defined(CONFIG_OXC) || defined(CONFIG_RMU) //未定义,不执行
  41. /* flash mapped at end of memory map */
  42. bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
  43. /* #define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_FLASH_BASE
  44. * 从这里可以看出CONFIG_SYS_MONITOR_BASE与CONFIG_SYS_FLASH_BASE相等,
  45. * 则执行宏内语句
  46. */
  47. #elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
  48. bd->bi_flashoffset = monitor_flash_len; /* reserved area for monitor */
  49. #endif
  50. return ;
  51. }
  52. #endif

  标记红色的语句就是我们在执行的语句。可以看出在flash 初始化后就打印出了 flash空间大小。

  定位到 flash_init 中

2.2 flash_init  

  文件路径:Cfi_flash.c (drivers\mtd)

  先去掉不必要的宏,代码精简一下。

  1. unsigned long flash_init (void)
  2. {
  3. unsigned long size = ;
  4. int i;
  5. /* Init: no FLASHes known */
  6. /* #define CONFIG_SYS_MAX_FLASH_BANKS 1 */
  7. /* include/configs/jz2440.h中有定义,为 1 */
  8. for (i = ; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
  9. flash_info[i].flash_id = FLASH_UNKNOWN;
  10. /* Optionally write flash configuration register */
  11. cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
  12. cfi_flash_config_reg(i));
  13. /* 检测 flash
  14. * flash_detect_legacy 是旧的检测策略
  15. */
  16. if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
  17. flash_get_size(cfi_flash_bank_addr(i), i);
  18. size += flash_info[i].size;
  19. if (flash_info[i].flash_id == FLASH_UNKNOWN) {
  20. }
  21. }
  22. flash_protect_default(); //flash的默认保护
  23. return (size);
  24. }

  在第18行,看到 flash 检测,这里检测的是 flash 的信息和大小。可以进去看看源码

2.2.1 flash_detect_legacy

  源码位置:Cfi_flash.c (drivers\mtd)

  1. #ifdef CONFIG_FLASH_CFI_LEGACY // include/configs/jz2440.h 中有定义
  2. /* 读取flash 的产品信息 */
  3. static void flash_read_jedec_ids (flash_info_t * info)
  4. {
  5. info->manufacturer_id = ;
  6. info->device_id = ;
  7. info->device_id2 = ;
  8. switch (info->vendor) {
  9. case CFI_CMDSET_INTEL_PROG_REGIONS:
  10. case CFI_CMDSET_INTEL_STANDARD:
  11. case CFI_CMDSET_INTEL_EXTENDED:
  12. cmdset_intel_read_jedec_ids(info);
  13. break;
  14. case CFI_CMDSET_AMD_STANDARD:
  15. case CFI_CMDSET_AMD_EXTENDED:
  16. cmdset_amd_read_jedec_ids(info);
  17. break;
  18. default:
  19. break;
  20. }
  21. }
  22. /*-----------------------------------------------------------------------
  23. * Call board code to request info about non-CFI flash.
  24. * board_flash_get_legacy needs to fill in at least:
  25. * info->portwidth, info->chipwidth and info->interface for Jedec probing.
  26. */
  27. static int flash_detect_legacy(phys_addr_t base, int banknum)
  28. {
  29. flash_info_t *info = &flash_info[banknum];
  30. /* 获得旧的 flash 信息,返回值为 0
  31. * info->portwidth = FLASH_CFI_16BIT; 0x02
  32. * info->chipwidth = FLASH_CFI_BY16; 0x02
  33. * info->interface = FLASH_CFI_X16; 0x01
  34. */
  35. if (board_flash_get_legacy(base, banknum, info)) {
  36. /* board code may have filled info completely. If not, we
  37. use JEDEC ID probing. */
  38. if (!info->vendor) {
  39. int modes[] = {
  40. CFI_CMDSET_AMD_STANDARD,
  41. CFI_CMDSET_INTEL_STANDARD
  42. };
  43. int i;
  44. for (i = ; i < ARRAY_SIZE(modes); i++) {
  45. info->vendor = modes[i];
  46. /* 映射物理地址 */
  47. info->start[] =
  48. (ulong)map_physmem(base,
  49. info->portwidth,
  50. MAP_NOCACHE);
  51. /* if中的语句不执行,前面已经设置 info->portwidth = FLASH_CFI_16BIT;*/
  52. if (info->portwidth == FLASH_CFI_8BIT
  53. && info->interface == FLASH_CFI_X8X16) {
  54. info->addr_unlock1 = 0x2AAA;
  55. info->addr_unlock2 = 0x5555;
  56. } else {/* 执行else 中的语句,发送 0x5555 0x2aaa命令 */
  57. info->addr_unlock1 = 0x5555;
  58. info->addr_unlock2 = 0x2AAA;
  59. }
  60. flash_read_jedec_ids(info);
  61. debug("JEDEC PROBE: ID %x %x %x\n",
  62. info->manufacturer_id,
  63. info->device_id,
  64. info->device_id2);
  65. /* 适配flash */
  66. if (jedec_flash_match(info, info->start[]))
  67. break;
  68. else
  69. unmap_physmem((void *)info->start[],
  70. info->portwidth);
  71. }
  72. }
  73. switch(info->vendor) {
  74. case CFI_CMDSET_INTEL_PROG_REGIONS:
  75. case CFI_CMDSET_INTEL_STANDARD:
  76. case CFI_CMDSET_INTEL_EXTENDED:
  77. info->cmd_reset = FLASH_CMD_RESET;
  78. break;
  79. case CFI_CMDSET_AMD_STANDARD:
  80. case CFI_CMDSET_AMD_EXTENDED:
  81. case CFI_CMDSET_AMD_LEGACY:
  82. info->cmd_reset = AMD_CMD_RESET;
  83. break;
  84. }
  85. info->flash_id = FLASH_MAN_CFI;
  86. return ;
  87. }
  88. return ; /* use CFI */
  89. }
  90. #else
  91. static inline int flash_detect_legacy(phys_addr_t base, int banknum)
  92. {
  93. return ; /* use CFI */
  94. }
  95. #endif

  这里不知道是否执行,可以尝试debug 一下,要debug 首先要打开 debug 宏。在include/common.h的顶端加入debug 宏。 #define DEBUG 然后重新编译开机 打印的flash信息如下:

  

  这里打印了两个 JEDEC PROBE,一个是在 flash_detect_legacy 中打印,还有是什么暂且不知道。

  查看一下 norflash的ID,norflash的型号是MX29LV160DBTI 。

  芯片手册的COMMAND OPERATIONS有如下几行:

  

  

  上面这张图说明了如何去读ID,黄色部分为地址。即在555地址发出aa,在2AA地址发出55命令,在555地址发出90命令,则可以在00地址读出厂家ID c2。

  2249 正好对应我们的设备ID号,看来是已经识别出来了 nor flash.

  JEDEC PROBE在 flash_detect_legacy(Cfi_flash.c (drivers\mtd) )的debug 打印函数中,之后执行jedec_flash_match(info, info->start[0])去匹配。

  在jedec_flash_match 会去匹配jedec_table数组,如果有,则返回1,没有则返回0。

2.2.2 jedec_flash_match

  

  1. int jedec_flash_match(flash_info_t *info, ulong base)
  2. {
  3. int ret = ;
  4. int i;
  5. ulong mask = 0xFFFF;
  6. if (info->chipwidth == )
  7. mask = 0xFF;
  8.  
  9. for (i = ; i < ARRAY_SIZE(jedec_table); i++) {
  10. if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
  11. (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
  12. fill_info(info, &jedec_table[i], base);
  13. ret = ;
  14. break;
  15. }
  16. }
  17. return ret;
  18. }

  查看 jedec_table (Jedec_flash.c (drivers\mtd) ),是否有 c2 2249 0  这些项。搜索后没有,则需要添加进设备信息。

  厂家ID添加(Flash.h (include) ),已在头文件中存在。   

  

  搜索:

  

  分别在两个地方引用了MX_MANUFACT的ID。

  最上面的一个需要定义宏 CONFIG_SYS_FLASH_LEGACY_512Kx8 才可以引用

  下面一个需要定义宏 CONFIG_SYS_FLASH_LEGACY_512Kx16 才能使用。CONFIG_SYS_FLASH_LEGACY_512Kx16 在jz2440中有定义。

  两个可以匹配,但是dev_id 无匹配,仍需要添加。这两个宏也和我们的芯片不匹配,板子上所使用的芯片为 1M X 16的。

2.2.3 修改代码

  jedec_table (Jedec_flash.c (drivers\mtd) )添加设备ID:

  

  在jedec_table 添加设备信息:

  

  1. #ifdef CONFIG_SYS_FLASH_LEGACY_1Mx16
  2. /* JZ2440使用 */
  3. {
  4. .mfr_id = (u16)MX_MANUFACT, /* 厂家ID */
  5. .dev_id = MX29LV160DB, /* 设备ID */
  6. .name = "MXIC MX29LV160DB", /* 芯片名称 */
  7. .uaddr = { /* norflash看到的解锁地址,norflash可以像内存一样读,但写必须先解锁 */
  8. [] = MTD_UADDR_0x0555_0x02AA /* x16 */
  9. },
  10. .DevSize = SIZE_2MiB, /* 总空间大小 */
  11. .CmdSet = P_ID_AMD_STD,/* 命令集 */
  12. .NumEraseRegions= , /* norflash的擦除块 */
  13. .regions = {
  14. 14 ERASEINFO(0x04000, 1),
  15. 15 ERASEINFO(0x02000, 2),
  16. 16 ERASEINFO(0x08000, 1),
  17. 17 ERASEINFO(0x10000, 31),
  18. }
  19. },
  20. #endif

  注意红色扇区部分按datesheet中的地址分布填写,不然显示的地址分布会不一样的。

  在jz2440(include/configs)中修改CONFIG_SYS_FLASH_LEGACY_512Kx16宏为 CONFIG_SYS_FLASH_LEGACY_1Mx16

  

  编译烧写测试,结果如下:

  

  上面报了一个错:ERROR: too many flash sectors

  搜索关键字定位到Jedec_flash.c (drivers\mtd)的fill_info函数,有如下打印调试信息:

  

  定位CONFIG_SYS_MAX_FLASH_SECT(flash的最大扇区),Jz2440.h (include\configs):

  

  这里扇区定义的是19个,但是我们的norflash的扇区有 1+ 2 + 1 + 31 = 35个,改成128:

  

  重新编译,打印输出信息:

  

  norflash打印正常,已经正确添加进来了。

2.3 调试

  执行命令:flinfo

  

  没问题了,就开始烧写字节进去测试数据是否完整(烧写之前,最好把DEBUG给关掉,然后重新编译烧写,否则会有大量的打印信息出来):

  取消写保护:

  

  擦除80000--90000之间的区域:

  

  拷贝DRAM中的数据进norflash:

  

  DRAM 30000000处的数据:

  

  norflash 80000处的数据:

  

  比较两者之间的数据:

  

  里面有个问题, byte at 0x30000654 (0x20) != byte at 0x00080654 (0x0)

  这里主要是在u-boot启动初始化后,栈未设置的原因,源代码位置为 crt0.S中。我们设置的栈指向0x30000f40,但是进行初始化后,未在设置栈,那么栈依然还是指向0x30000f40这快位置。

  

  需要把栈改到指向gd->start_addr_sp,这个变量最后的值在reserve_stacks函数中,board_init_f 中。

  

  reserve_stacks调用arch_reserve_stacks(Stack.c (arch\arm\lib) )函数进行栈设置,代码如下:

  1. int arch_reserve_stacks(void)
  2. {
  3. /* setup stack pointer for exceptions */
  4. gd->irq_sp = gd->start_addr_sp;
  5.  
  6. # if !defined(CONFIG_ARM64)
  7. /* leave 3 words for abort-stack, plus 1 for alignment */
  8. gd->start_addr_sp -= ;
  9. # endif
  10. return ;
  11. }

  我们要获得栈的值,就需要在crt0.S中修改代码,需要在第二阶段重新设置栈。

  gd->start_addr_sp的值为gd->relocaddr

  

  在crt0.S中定义全局变量:

  

  

  此问题尚未解决,有解决方法了再修改此文件。

  

  

  

u-boot移植(十)---代码修改---支持nor flash的更多相关文章

  1. u-boot移植(十二)---代码修改---支持DM9000网卡

    一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory ...

  2. -boot移植(十一)---代码修改---支持nandflash

    一.移植前的修改 1.1 include/configs/jz2440修改 原来的定义: 可以看出,要先定义CONFIG_CMD_NAND才能使能NANDFlash. 这个在我们文件中的82行有定义, ...

  3. U-Boot在FL2440上移植(三)----支持NAND Flash

    <一>支持NAND Flash 1. 首先在配置文件 include/config/fl2440.h 的宏 CONFIG_COMMANDS 中增加 CFG_CMD_NAND, #defin ...

  4. U-Boot在FL2440上移植(二)----支持NOR Flash

    <一>选择NOR flash型号 我的开发板上的nor flash芯片是Intel的JS28F320(4MB)(1device=32blocks,1block=128MB fl2440默认 ...

  5. u-boot移植(十三)---代码修改---支持文件系统及补丁制作

    一.烧写文件系统 1.1 jffs2烧写 1.下载文件系统:tftp 30000000 fs_mini_mdev.jffs2 2.擦除文件的块:nand erase.part rootfs 3.烧入文 ...

  6. spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法

    spring boot / cloud (十四) 微服务间远程服务调用的认证和鉴权的思考和设计,以及restFul风格的url匹配拦截方法 前言 本篇接着<spring boot / cloud ...

  7. Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控

    Spring Boot(二十):使用spring-boot-admin对spring-boot服务进行监控 Spring Boot Actuator提供了对单个Spring Boot的监控,信息包含: ...

  8. 标题:u-boot 移植步骤详解

    1 U-Boot简介U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目.从FADSROM.8xxROM.PPCBOOT逐步发展演化而来.其源码目录.编译形式与 ...

  9. spring boot / cloud (十六) 分布式ID生成服务

    spring boot / cloud (十六) 分布式ID生成服务 在几乎所有的分布式系统或者采用了分库/分表设计的系统中,几乎都会需要生成数据的唯一标识ID的需求, 常规做法,是使用数据库中的自动 ...

随机推荐

  1. SourceTree 如何下载git 管理的代码-如何创建分支,删除分支,提交代码,回退代码

    把用户给的链接拿过来,然后输入浏览器,然后在左侧会有Actions 中有个Clone;点击Clone之后,有个 Clone in Source Tree 点击,打开你的本地Source Tree,然后 ...

  2. js 实现List

    js 实现List 列表是一组有序的数据.每个列表中的数据项称为元素.在 JavaScript 中,列表中的元素可以是任意数据类型. 我们可以根据数组的特性来实现List. List 抽象数据类型定义 ...

  3. python 模块之-re

    就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹 ...

  4. BZOJ3963 WF2011MachineWorks(动态规划+斜率优化+cdq分治)

    按卖出时间排序后,设f[i]为买下第i台机器后的当前最大收益,则显然有f[i]=max{f[j]+gj*(di-dj-1)+rj-pi},且若此值<0,应设为-inf以表示无法购买第i台机器. ...

  5. Leetcode 26.删除排序数组中的重复项 By Python

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...

  6. emwin之点击窗口的无效部分来实现一些功能

    @2018-07-27 触摸屏幕窗口的无效部分实现 Dropdown 部件的折叠操作 > 具体代码 case WM_TOUCH: if (pMsg->Data.p) // Somethin ...

  7. 修复Mysql主从不同步shell

    使用第三方工具MySQL Enterprise Monitor,MySQL企业版监控工具.MONyog – MySQL Monior and Advisor,MONyog大家都不陌生,windows下 ...

  8. JS数组冒泡排序&去重

    冒泡排序: var a = [2,1,4,3,6,5]; for(var d = 0 ; d< a.length; d++){ for(var b = d+1; b < a.length; ...

  9. 【UVA10140】Prime Distance

    题目大意:求出一个给定区间 [l, r] 内相邻素数之间的最大距离和最小距离. 题解:由于 l, r 的范围太大,没法直接用筛法得出区间的素数.考虑筛出区间的素数等价于筛掉区间内的所有和数, 根据算术 ...

  10. (转)sublime text3简体中文版汉化教程

    preferens——package controller——输入 install package——等待安装完成后输入 localizationChinese 请使用主菜单的 帮助/Language ...