移植uboot之修改代码支持NorFlash记录

学习交流加

  • 个人qq:
    1126137994
  • 个人微信:
    liu1126137994
  • 学习交流资源分享qq群:
    962535112

今天我们的任务是修改uboot源码支持NorFlash。
上两篇关于uboot移植的文章,我们修改了uboot源代码,支持了串口的输出,以及nand启动(点击连接可以查看上两面文章的相关内容移植uboot支持串口输出,移植uboot支持NAND启动)
同时分享一个很好的书:Linux设备驱动开发详解-宋宝华

(注:写到后面发现没有告诉大家用的flash芯片的型号,我们用的flash芯片的型号是:MX29LV160DB,芯片手册大家可以自行到网上下载,从中可以查看芯片的厂家ID和设备ID等信息)
我们移植uboot,都是一步一步调试而来,所以会比较繁琐,但是我觉得记录这些,是一件很有意义的事,虽然很麻烦,但是对将来,会有莫大的影响!!!
上次移植支持NAND后,串口启动界面如下:
这里写图片描述
我们在source insight中搜索“Flash:”这个字符串出现在哪里,在Board.c中的board_init_r函数中,有这样几行代码:

#if !defined(CONFIG_SYS_NO_FLASH)puts("Flash: ");flash_size = flash_init();if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUMchar *s = getenv("flashchecksum");print_size(flash_size, "");/** Compute and print flash CRC if flashchecksum is set to 'y'** NOTE: Maybe we should add some WATCHDOG_RESET()? XXX*/if (s && (*s == 'y')) {printf("  CRC: %08X", crc32(0,(const unsigned char *) CONFIG_SYS_FLASH_BASE,flash_size));}putc('\n');
# else	/* !CONFIG_SYS_FLASH_CHECKSUM */print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */} else {puts("0 KB\n\r");puts(failed);hang();}
#endif

课件代码是执行到了这两行:

		puts(failed);hang();

查看hang()这个函数为:
void hang(void)
{
puts("### ERROR ### Please RESET the board ###\n");
for (;?;
}
很明显,代码进入了一个死循环,所以无法启动uboot了。
回过头看上面的board_init_r函数里的flash_size = flash_init();,应该是flash的一个初始化,初始化后成功后才执行下面的if语句,很明显我们这里没有初始化成功。进入flash_init。查看代码如下(在drivers/mtd/Cfi_flash.c中):

unsigned long flash_init (void)
{unsigned long size = 0;int i;#ifdef CONFIG_SYS_FLASH_PROTECTION/* read environment from EEPROM */char s[64];getenv_f("unlock", s, sizeof(s));
#endif/* Init: no FLASHes known */for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {flash_info[i].flash_id = FLASH_UNKNOWN;/* Optionally write flash configuration register */cfi_flash_set_config_reg(cfi_flash_bank_addr(i),cfi_flash_config_reg(i));if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))flash_get_size(cfi_flash_bank_addr(i), i);size += flash_info[i].size;if (flash_info[i].flash_id == FLASH_UNKNOWN) {
#ifndef CONFIG_SYS_FLASH_QUIET_TESTprintf ("## Unknown flash on Bank %d ""- Size = 0x%08lx = %ld MB\n",i+1, flash_info[i].size,flash_info[i].size >> 20);
#endif /* CONFIG_SYS_FLASH_QUIET_TEST */}
#ifdef CONFIG_SYS_FLASH_PROTECTIONelse if ((s != NULL) && (strcmp(s, "yes") == 0)) {/** Only the U-Boot image and it's environment* is protected, all other sectors are* unprotected (unlocked) if flash hardware* protection is used (CONFIG_SYS_FLASH_PROTECTION)* and the environment variable "unlock" is* set to "yes".*/if (flash_info[i].legacy_unlock) {int k;/** Disable legacy_unlock temporarily,* since flash_real_protect would* relock all other sectors again* otherwise.*/flash_info[i].legacy_unlock = 0;/** Legacy unlocking (e.g. Intel J3) ->* unlock only one sector. This will* unlock all sectors.*/flash_real_protect (&flash_info[i], 0, 0);flash_info[i].legacy_unlock = 1;/** Manually mark other sectors as* unlocked (unprotected)*/for (k = 1; k < flash_info[i].sector_count; k++)flash_info[i].protect[k] = 0;} else {/** No legancy unlocking -> unlock all sectors*/flash_protect (FLAG_PROTECT_CLEAR,flash_info[i].start[0],flash_info[i].start[0]+ flash_info[i].size - 1,&flash_info[i]);}}
#endif /* CONFIG_SYS_FLASH_PROTECTION */}flash_protect_default();
#ifdef CONFIG_FLASH_CFI_MTDcfi_mtd_init();
#endifreturn (size);
}

里面有一个if判断语句:

			if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))flash_get_size(cfi_flash_bank_addr(i), i);

从字面意思看出flash_detect_legacy为旧的检测flash,flash_get_size就应该为新的检测flash机制,先看一下旧的,没看出什么,再看flash_get_size,发现有很多debug调试信息,有这么多调试信息,那就应该用起来:
在flash_get_size中的debug信息

		debug ("manufacturer is %d\n", info->vendor);debug ("manufacturer id is 0x%x\n", info->manufacturer_id);debug ("device id is 0x%x\n", info->device_id);debug ("device id2 is 0x%x\n", info->device_id2);debug ("cfi version is 0x%04x\n", info->cfi_version);

搜索debug 查到:
在include/common.h中有下面的代码

#define debug(fmt, args...)			\debug_cond(_DEBUG, fmt, ##args)

很明显应该是用的_DEBUG,搜索_DEBUG,有:

#ifdef DEBUG
#define _DEBUG	1
#else
#define _DEBUG	0
#endif

好,那么我们就把#define _DEBUG 1给加上,在Cfi_flash.c中定义如下两行:

#define DEBUG	1   (不确定是哪个就都定义,反正也不会出错)
#define _DEBUG	1

重新编译uboot烧写启动看一下:
这里写图片描述
打印的这句话:JEDEC PROBE: ID c2 2249 0
告诉我们读到的厂家ID,设备ID,我们查看datasheet,发现这个读到的ID是没有错的,厂家ID是c2,设备ID是2249,

根据打印信息,在源码中搜索字符串“JEDEC PROBE:”在Cfi_flash.c中的flash_detect_legacy函数中有如下代码片段:

						debug("JEDEC PROBE: ID %x %x %x\n",info->manufacturer_id,info->device_id,info->device_id2);if (jedec_flash_match(info, info->start[0]))break;elseunmap_physmem((void *)info->start[0],MAP_NOCACHE);

看出设备ID时如何打印的,下面的jedec_flash_match还需要进行一下匹配,我们去jedec_flash_match函数里看看是实现的什么内容(在drivers/mtd/jeder_flash.c中):

/*-----------------------------------------------------------------------* match jedec ids against table. If a match is found, fill flash_info entry*/
int jedec_flash_match(flash_info_t *info, ulong base)
{int ret = 0;int i;ulong mask = 0xFFFF;if (info->chipwidth == 1)mask = 0xFF;for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&(jedec_table[i].dev_id & mask) == (info->device_id & mask)) {fill_info(info, &jedec_table[i], base);ret = 1;break;}}return ret;
}

发现一个数组jedec_table,匹配设备的ID用的应该就是这个数组里的内容了,查看数组如下:

static const struct amd_flash_info jedec_table[] = {
#ifdef CONFIG_SYS_FLASH_LEGACY_256Kx8{.mfr_id		= (u16)SST_MANUFACT,.dev_id		= SST39LF020,.name		= "SST 39LF020",.uaddr		= {[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */},.DevSize	= SIZE_256KiB,.CmdSet		= P_ID_AMD_STD,.NumEraseRegions= 1,.regions	= {ERASEINFO(0x01000,64),}},。。。。。。。。。。(还有很多跟上面相同的类型的内容,我这里给省略了)

这个结构体里的内容,定义了许多类型的flash,每一个定义就是一个flash芯片。我们在里面自己定义我们的芯片结构项。

		/* jz2440使用的是MX29LV160DB芯片 */{.mfr_id		= (u16)MX_MANUFACT, /*厂家ID*/.dev_id		= 0x2249,			/*设备ID*/.name		= "MXIC MX29LV160DB",.uaddr		= {				/*NOR FLASH看到的解锁地址*/[0] = MTD_UADDR_0x0555_0x02AA /* x16 */},.DevSize	= SIZE_2MiB,	/* 总大小 */.CmdSet		= P_ID_AMD_STD,.NumEraseRegions= 4,   /* 擦除区域的数目 */.regions	= {   /* 这些内容涉及芯片手册的阅读,之后的文章会单独写关于硬件的操作 */ERASEINFO(16*1024, 1), ERASEINFO(8*1024, 2),ERASEINFO(32*1024, 1),ERASEINFO(64*1024, 31),}},

里面涉及到 的硬件操作,我会在之后的讲解NOR FLASH 驱动时,讲解如何操作这个芯片里面涉及到,在这里,我们移植uboot,只需要这样做就可以,暂时不需要追根究底(无底洞啊!!!)。

然后就是最开始忘记了一件事,就是把board.中的board_init_r中的两行代码(自己回头看上面的代码)屏蔽掉:

		//puts(failed);//hang();

然后重新编译uboot,烧写启动运行:
这里写图片描述
哈哈哈!!!!先庆祝一下,终于启动进去了,虽然还没有完善,但是得一步一步来嘛!
显示有错误:ERROR: too many flash sectors,在源码中搜索这个错误找到(Cfi_flash.c中):

if (sect_cnt >= CONFIG_SYS_MAX_FLASH_SECT) {printf("ERROR: too many flash sectors\n");break;}

跳转到CONFIG_SYS_MAX_FLASH_SECT这个定义(在smdk2440.h中),有:

#define CONFIG_SYS_MAX_FLASH_SECT	(19)

将19改为128吧:

#define CONFIG_SYS_MAX_FLASH_SECT	(128)

然后再把我们之前加的Debug调试信息去掉,因为我们已经不需要那些打印信息了,去掉的话会看起来简洁一些,去掉下面的两个宏定义:

//#define DEBUG	1
//#define _DEBUG	1

重新编译烧写,看启动界面:
这里写图片描述
这次启动界面比较简洁,而且上面出现的错误也没有了!!!
那我们现在来测试一下NORFLASH能否擦除与读写。
串口中输入:protect off all,先解除写保护
输入:flinfo,打印输出正常:
这里写图片描述
输入:erase 80000 8ffff
这里写图片描述
输入:cp.b 30000000 80000 10000 (把内存中30000000位置的内容拷贝到flash80000地址)
这里写图片描述
到了这里,出现了一些问题,无法将内存的代码拷贝过来,无法写flash。。。。。。。。。啊,天哪,感觉又得花时间去看了!!!

放到下一篇博客吧,这篇已经写了很多了!!!

想获得各种学习资源以及交流学习的加我:
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保持一颗好学之心

保持一颗好学之心 初见这个题目&#xff0c;许多人可能会对自己相当满意&#xff1a;“我还是很好学的”。真的是这样吗&#xff1f;个人之见&#xff0c;有不少人其实并不像他们想象的那么好学&#xff0c;尤其是那些有了一定经验&#xff0c;在某些方面有些过人之处的“聪明”…

Vue.js 学习

后端和数据库角色&#xff0c;确参加了前端培训&#xff0c;哪就总结一下&#xff1a;后续继续更新 1.首先是vue.js 与jquery 的比较 vue.js 是采用数据和dom元素分类&#xff0c;采用的VMMV 模式 V view 视图 M Model 存放数据&#xff0c;VM 在M和V 主要是处理一些业务逻辑…

移植uboot之修改代码支持NorFlash记录续集

接着上一篇文章写的内容&#xff08;上一篇文章链接&#xff1a;移植uboot之修改代码支持NORFLASH&#xff09;&#xff0c;上一篇结尾测试flash的擦除读写功能&#xff0c;结果无法写flash&#xff0c;卡在了这里&#xff1a; 前面已经擦除成功&#xff0c;这里写内容写不进…

C#开发终端式短信的原理和方法

本文示例源代码或素材下载 简介 没发过短信的年轻人肯定是属于那种受保护的稀有动物&#xff0c;通讯发达的今天短信已经成为人们交流的重要手段&#xff0c;其中也蕴含着巨大的市场和经济利益&#xff0c;掌握短信技术的人才也受到各大公司的追捧是目前职场上耀眼的明星。本文…

移植uboot之修改代码支持NorFlash记录续集二

先说一个事&#xff1a;我会在最后把移植好的uboot&#xff0c;内核&#xff0c;分别做一个补丁文件&#xff0c;以后如果用到相同的uboot以及内核都可以直接下载我这个补丁进行打补丁操作就可以直接用~ 上一个移植uboot续集&#xff0c;我们解决了无法写flash的问题&#xff…

Mysql function(函数)

1.mysql 拼接函数 1. 1CONCAT(string1,string2,…) 说明 : string1,string2代表字符串,concat函数在连接字符串的时候&#xff0c;只要其中一个是NULL,那么将返回NULL 1.2 CONCAT_WS(separator,str1,str2,...)说明 : string1,string2代表字符串,concat_ws 代表 conca…

【C++深度剖析教程6】C++之友元

这几天在复习数学考试&#xff0c;都没有学C&#xff0c;今天抽空来学一点。 什么是友元&#xff1f; 友元是C中的一种关系友元发生在函数与类之间或者类与类之间友元关系是单向的&#xff0c;不能传递 在具体讲解友元的性质之前&#xff0c;我们先来看看一个程序&#xff…

SpringAOP xml 方式和注解简单实现日志处理

1.首先是用注解方式捕捉Controller 层异常&#xff1a; 首先是引入aop 依赖的jar <!-- Spring AOP 日志管理需要导入的包 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.13</…

call stack and stack buffer overflow

http://en.wikipedia.org/wiki/Call_stack http://en.wikipedia.org/wiki/Stack_buffer_overflow Stack_buffer_overflow里提到的frame pointer 的位置不一样&#xff0c;不同的系统实现应该是不一样的。 运行时的栈是从高地址向低地址分配的&#xff0c;堆是从低地址向高地址…

谈一下我对如何设计微服务接口的理解和思考

微服务是一个独立运行、自带数据存储管理&#xff0c;对外提供接口的自治系统。微服务设计很关键的一点是微服务接口的设计。不同微服务经常是分配给不同的团队开发的&#xff0c;接口是各团队编程的契约。 下面只讨论微服务间接口的设计&#xff0c;至于微服务内部子模块间接…

【C++深度剖析教程7】C++之类中的函数重载

函数重载的回顾&#xff08;接上一篇文章&#xff09;&#xff1a; 函数重载的本质为相互独立的不同的函数C中通过函数名和函数参数确定函数调用无法直接通过函数名得到重载函数的入口地址函数重载必然发生在同一个作用域中 类中的成员函数可以进行重载 构造函数的重载普通成…

Linux 服务器远程控制三剑客Telnet、SSH 和 VNC 之 VNC

使用VNC服务实现远程控制Telnet和SSH服务只能实现基于字符界面的远程控制&#xff0c;如果要基于图形界面进行远程控制&#xff0c;可以借助免费的VNC来完成。VNC是VirtualNetworkComput-ing英文的缩写&#xff0c;它是一款优秀远程控制软件&#xff0c;类似Windows的终端服务。…

嵌入式Linux操作系统移植IMX6开发板之实现USB 自动挂载

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 本篇文章讲述如何实现USB自动挂载&#xff0c;U盘即插即用&#xff0c;不用手动挂载的方法&#xff0c;以及给出U盘自动挂载的原理。 目前做的IMX6开发…

C# 繁体,简体 互转

usingMicrosoft.VisualBasic; publicstaticstringTraditional2Simplified(stringstr) { //繁体转简体 return(Microsoft.VisualBasic.Strings.StrConv(str, Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0)); } publicstaticstringSimplified…

【C++深度剖析教程8】C++的操作符重载的概念

之前学习了类的函数重载的概念&#xff0c;今天学习操作符重载的概念。在这之前我们先看一个例子&#xff1a; 上面是一个复数的加法&#xff0c;a为复数的实部&#xff0c;b为复数的虚部&#xff0c;在main函数里我想实现复数c1与c2的加法。很显然&#xff0c;正常的号操作符…

大数据开发者应该知道的分布式系统 CAP 理论

无论你是一个系统架构师&#xff0c;还是一个普通开发&#xff0c;当你开发或者设计一个分布式系统的时候&#xff0c;CAP理论是无论如何也绕不过去的。本文就来介绍一下到底什么是CAP理论&#xff0c;如何证明CAP理论&#xff0c;以及CAP的权衡问题。 CAP理论概述 CAP理论&a…

【C++深度剖析教程11】C++学习之编写代码实现复数类

今天&#xff0c;我来学习将复数的加减乘除以及比较运算&#xff0c;编写一个复数类&#xff0c;方便计算复数之间的运算。具体用的方法就是之前写过的操作符重载的概念来实现&#xff08;操作符重载的概念学习&#xff09;。 那么为了显得清晰&#xff0c;今天写的程序运用模块…

IT餐馆—第二十五回 结对

周五开会时&#xff0c;有人提出在团队中采用结对开发的Agile实践。 当然团队里有人说&#xff0c;如果让新手与水平高的人结对&#xff0c;基本上就是知识的单向传递了&#xff0c;对于新手来说的确是个不错的学习机会&#xff0c;但对于水平高的开发者&#xff0c;就未必不乐…

Spring Cloud各组件总结归纳

前面介绍了很多Spring Cloud的组件&#xff0c;本篇按照自己的角度来做一次归纳。 Spring Cloud技术应用从场景上可以分为两大类&#xff1a;润物无声类和独挑大梁类。 润物无声&#xff0c;融合在每个微服务中、依赖其它组件并为其提供服务。 Ribbon&#xff0c;客户端负载均…

移植Linux系统到iMX6开发板之LVDS显示屏驱动程序的框架分析与移植

学习交流加 个人qq&#xff1a; 1126137994个人微信&#xff1a; liu1126137994学习交流资源分享qq群&#xff1a; 962535112 今天记录一下项目中的关于LVDS显示屏的驱动程序的分析与移植。因为驱动源码厂家已经提供好&#xff0c;我们需要做的就是读懂驱动程序的代码&#xff…