ngswfx

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx  发布于  2016-04-17 05:34:59
采纳率 0%
55个问答
7459

外部看门狗,U-boot终于搞定了,发帖庆祝一下

 
本帖最后由 ngswfx 于 2016-4-23 18:44 编辑

我用的方法自己感觉就是苦力活,这那是在编程,简直是“搬代码砖头”。

之所以要在U-boot搞这个看门狗,那也是被逼无奈,系统下外部看门狗,前几天已经搞定了。这几天又搞定了U盘文件系统升级,其实以前就弄好了,只不过,自己U盘不行,一直以为代码没弄好。前几天找了个新U盘发现可以升级时,升级到一半,大约50秒左右,系统自动重启。

哎,又爱又恨的外部狗动作了。只能硬着头皮,几乎把U-boot目录翻了个底朝天。看结构,研究那些东西和3520D流程有关......,U-boot目录东西,一大堆,也不知道那些被编译了,那些没有被真正使用。只能自己添加printf,打印信息,然后不停的刷呀刷。

其实最主要的是找到写寄存器的代码,找到升级的详细流程代码所在的文件位置,没有文档介绍,只能一个个目录看,一个个C文件看(当然都是一扫而过,然后把可能用到的文件记录下来),推敲有没有用到的可能。

首先研究U-boot代码,找到能写寄存器的代码,其实3520D里面就是那个
Hi3520D_SDK/osdrv/uboot/u-boot-2010.06/board/hi3520d/board.c
文件中发现了
reg = readl(CRG_REG_BASE + PERI_CRG57);
        reg &= ~UART_CKSEL_APB;
        writel(reg, CRG_REG_BASE + PERI_CRG57);
这就是读写寄存器的代码了。

////////////////////////////////

然后就是找一个watchdog.c模板,哪个都可以,自己写也行,就是添加如下这2个函数而已:


static int bDogOutState=0;
static int bDogInited=0;
void watchdog_reset(void)
{       
      if(!bDogInited)
         return;
        if(bDogOutState>1){
          writel(0x00, 0x201D0200); //外部狗接的GPIO8_7
          bDogOutState=0;
        }else{
          writel(0xFF, 0x201D0200);
          bDogOutState++;
        }       
}

int watchdog_init(void)
{
        /////
        writel(0x01, 0x200F0008);////外部狗接的GPIO8_7
        udelay(100);
        writel(0xFF, 0x201D0400);
        udelay(100);
        bDogInited=1;
        return 0;
}



然后就是开启全局,允许看门狗。
文件
Hi3520D_SDK/osdrv/uboot/u-boot-2010.06/include/configs/hi3520d.h
里面添加了
#define CONFIG_WATCHDOG
全局就打开了。


然后就是沿着U-boot启动流程,开始长征一样的的添加头文件,添加喂狗代码。现在想想全局添加应该起作用的,但多一次无妨,应为编译一次也挺费尽,编译才发现缺少头文件就郁闷了。
#include

watchdog_reset();
watchdog_reset();
watchdog_reset();

到处都在添加.

现在想想,主要是几个地方,都是沿着自动升级的流程来的。

SPI flash读取 mtd目录下的spi目录下的hisfc350目录内的几个文件
Fat目录下的fat.c
disk目录下的part.c

都搞定了一步步测试,终于能升级撑过1分钟了(兴奋异常,这已经表明喂狗起作用了,仅仅是有些地方没喂及时,导致的重启),到升级文件CRC这里不行了,因为rootfs升级,文件较大,估计超过1秒的时间占用了。

又去找crc32代码,
Hi3520D_SDK/osdrv/uboot/u-boot-2010.06/lib/crc32.c
文件中,修改了半天,编译过不了,提示找不到watchdog_reset,后来想想也对,系统编译crc32.c比较靠前,此时,watchdog.c还没编译呢,哪里来的watchdog_reset。(按理说肯定有更好的解决方法,因为crc32.c里面默认就有watchdog相关代码)

想想,我这个半路出家的程序猿(不是学习计算机出身的,工作后自己研究学习的,计算机基础理论很差,只要一深入,没戏),实在有心无力搞定这复杂的编译环境。

最后干脆吧crc32代码拷贝一份,放到Hi3520D_SDK/osdrv/uboot/u-boot-2010.06/product/hiupdate/auto_update.c文件中,把函数改变一下名字。(当时已经做好准备实在高不定,去除CRC代码了,呵呵)

就这样,升级OK了,狗没有重启系统。

感觉就是这种外部狗,没法临时关闭,真费劲。代码真乱。感觉加了1千多个喂狗动作(当然990个都是白搭,没必要)。慢慢长征路。哎,不管了,先这么用着吧,懒得再去折腾这10几个文件了,关键目录一层一层,找半天。

现在想想,GPIO8_7是一个CLCK引脚,要是能开机,让时钟出来,由时钟去喂狗,能被控制住,应该不用这么费劲了(当然,这还要看,这个时钟是不是符合狗WDI要求了)。
//////////////////////////////经查,这个脚好像是输入脚,不能这么用













我来回答
回答11个
时间排序
认可量排序

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-17 16:46:42
认可0
本帖最后由 ngswfx 于 2016-4-23 18:45 编辑

其实写寄存器地址直接赋值也行,我是看了别人的U-boot命令行加密以及LED控制才知道,原来就是几行,自己想多了,还费劲找了好久writel。呵呵。:lol

原贴地址找不到了,不知当时怎么搜到的,再搜就搜不到了,文中描述了命令行密码保护,LED控制,版本验证等好些代码,都是我需要的。在此还是表示由衷感谢。

不会写的代码,从来都是先找葫芦,找到了葫芦,瓢就能弄出来了。

#define GPIO8_5_CON (*((volatile unsigned int *)0x200F0000))//GPIO控制寄存器
#define GPIO8_5_DIR (*((volatile unsigned int *)0x201D0400))//GPIO方向寄存器
#define GPIO8_5_DAT (*((volatile unsigned int *)0x201D0080))//GPIO数据寄存器

void led_on(void)//on led
{
        watchdog_reset();
        GPIO8_5_CON = 0x00;
        GPIO8_5_DIR = 0xFF;
        GPIO8_5_DAT = 0x00;
}

void led_off(void)//off led
{
        watchdog_reset();
        GPIO8_5_CON = 0x00;
        GPIO8_5_DIR = 0xFF;
        GPIO8_5_DAT = 0xFF;
}
void udelayMs(unsigned long n)
{
  while(n>0){
        watchdog_reset(); //必须有,否则外不狗,长时间延迟,会控制重启
        udelay(1000);
        n--;          
  }  
}
//失败后,慢速交替闪烁,需要用户手动断电
void led_flash_Failed()//write flash  failed run
{
        GPIO8_5_CON = 0x00;
        GPIO8_5_DIR = 0xFF;
        while(1)
        {
                GPIO8_5_DAT = 0x0;
                udelayMs(1500);
                GPIO8_5_DAT = 0XFF;
                udelayMs(1500);
        }
}
/////////////开始写 之前,快速闪烁几次
void led_flash_Start()
{
        led_off();
        udelayMs(200);
        led_on();
        udelayMs(200);
        led_off();
        udelayMs(200);
        led_on();
        udelayMs(200);
        led_off();
        udelayMs(200);
        led_on();
        udelayMs(200);
        led_off();
        udelayMs(200);
        led_on();
        udelayMs(200);
}
//版本验证 部分代码
/*
#define IH_MAGIC 0x27051956 //Image Magic Number
#define IH_NMLEN 32 // Image Name Length
typedef struct image_header {
uint32_t ih_magic; // Image Header Magic Number
uint32_t ih_hcrc; // Image Header CRC Checksum
uint32_t ih_time; /// Image Creation Timestamp  //可以用来作为版本号判断,每次产生的包时间肯定不同,主要是避免U盘插入,如果不拔下,会多次升级,而且用户不知道什么时候拔下,很容易系统崩溃,有了版本判断,升级成功后,下次启动就直接进系统了
uint32_t ih_size; // Image Data Size
uint32_t ih_load; ///Data Load Address
uint32_t ih_ep; /// Entry Point Address
uint32_t ih_dcrc;// Image Data CRC Checksum
uint8_t ih_os;// Operating System
uint8_t ih_arch;/// CPU architecture
uint8_t ih_type;// Image Type
uint8_t ih_comp;// Compression Type
uint8_t ih_name[IH_NMLEN];/// Image Name  //可以配合mkimage生成升级包时,加-n,导入特殊名称例如rootfs_128M,或者rootfs_512,然后在代这里判断,用来判断这个升级包是给哪种内存规格的U-boot,避免升级包不合适,当然也可以自己弄个复杂的编号,里面不但带版本号,还带其他信息,我嫌弃这种方法,SH编写mkimage麻烦,就直接用时间代替版本号了。
} image_header_t;
*/
/////////////////////////////////////////////////////
//文件版本
char *env_img_ver[AU_MAXFILES] = {
                "firmware_ver",
                "kernel_ver",
                "rootfs_ver",
        };
char ImageVersionEx[32];
char *image_get_ver(image_header_t *hdr)
{
     memset(ImageVersionEx,0,32);
     sprintf(ImageVersionEx, "%lx", (unsigned long)ntohl(hdr->ih_time));
     return ImageVersionEx;
}
//需要升级,返回1,不需要升级,返回0
static int check_version(int i)
{
       watchdog_reset();
        const image_header_t *hdr;
        hdr = (image_header_t *)LOAD_ADDR;

        char *old_ver = getenv(env_img_ver);//get image version env
        if (NULL == old_ver)
        {
                printf("get old env failed ,can update!\n");
                return 1;
        }
        char *new_ver = image_get_ver(hdr);//get image name
        if ((strcmp((const char*)new_ver,(const char*)old_ver))!=0) //compare version name
        {
                printf("The version %s had been the new version! old:%s can update!\n",new_ver,old_ver);
                return 1;
        }
        printf("-------need not------updating---------------- %s\n",hdr->ih_name);
        //setenv(env_img_ver,image_get_ver(hdr));//save new version env
        //sprintf(env, "%lx", (unsigned long)ntohl(hdr->ih_time));
        //setenv(env_img_ver, image_get_ver(hdr));

        printf("The version %s same with the old version:%s need not update!\n",new_ver,old_ver);
        return 0;
}

在au_check_header_valid中,添加

//检查版本是否重复
       if(check_version(idx)==0){
               printf("Image %s check ver failed\n", aufile[idx]);
               return -1;
       }


在文件升级写入成功后,就是在static int au_do_update(int idx, long sz)中, unmap_physmem(buf, len); 后面,需要添加:

//已经升级成功,保存版本号
        setenv(env_img_ver[idx], image_get_ver(hdr));
        env_crc_update();
        saveenv();
//////////////////////////////////////////////////////////////////////////////////

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-17 17:10:57
认可0
另:
[url]http://blog.csdn.net/l_nan/article/details/21877003[/url]

//////////////////////////////////////////////////////////////////////////////////////////////////////
在common/main.c文件中,修改int readline (const char *const prompt);函数。

--> 在readline函数的开头位置添加内容如下

    #ifdef CONFIG_UBOOT_PWD  
        char pwd[64];  
        char c;  
        int index;  
        static int bPwd = 1;  
        while (bPwd){  
            puts ("### Please input uboot password: ###\n");  
            index = 0;  
            while ((c = getc()) != '\r'){  
                if (c == 8) /* Backspace */  
                {  
                    if (index > 0){  
                        printf ("\b \b");  
                        index--;  
                    }  
                    continue;  
                }  
    //          else if (c == 3){ /* Ctrl + c */  
    //              do_reset();  
    //          }  
                putc('*');  
                pwd[index] = c;  
                index++;  
            }  
            pwd[index] = '\0';  
            putc ('\n');  
            char *s;  
            s = getenv ("ubootpwd");  
            if (!s){  
                s = "geenovo";  
            }  
            if (!strcmp (pwd, s)){  
                bPwd = 0;  
            }  
        }  
    #endif  

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-17 17:14:24
认可0
有了这些基础,在读取某个按键状态或者跳线状态(GPIO状态),实现U-boot阶段清空密码,或者某些部分系统恢复默认,也就自己想怎么写就怎么写了

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-19 03:25:27
认可0
本帖最后由 ngswfx 于 2016-4-19 03:27 编辑

今天又调整了一下,减少升级时,环境变量失败,停留在U-boot命立行的几率。

通过在HI3520D中修改设定:

#define CONFIG_BOOTARGS "mem=64M lpj=5996544 console=ttyAMA0,115200 root=/dev/mtdblock4 rootfstype=jffs2 mtdparts=hi_sfc:128K(boot),64K(UB_ENV),64K(Config),1920K(kernel),13760K(rootfs),320K(Setting),128K(UB_LOGO)"

#define CONFIG_BOOTCOMMAND "sf probe 0;sf read 0x81000000 0x40000 0x1E0000;sf read 0x81fe0000 0xFe0000 0x20000;decjpg;setvobg 0 0x0;startvo 0 36 14;startgx 0 0x84fe0000 2048 0 0 1024 768;bootm 0x81000000"

SDK默认已经有CONFIG_BOOTARGS

把CONFIG_BOOTCOMMAND也加上,和自己的配置一样即可。

这样即便出了异常,尤其是环境变量CRC校验失败,会执行set_default_env(); 这样就还是正确的配置。避免停留在命令行,从用户感觉像是升级失败了,如果set_default_env,则能够正常启动。


说白了就是写死了环境变量的关键部分。

ethancwchen

0个粉丝

1

问答

0

专栏

0

资料

ethancwchen 2016-04-23 12:13:07
认可0
uboot code 可以分享嗎 ?

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-04-26 04:35:17
认可0
本帖最后由 ngswfx 于 2016-4-26 04:38 编辑

最新修改,在U-boot中增加内存大小 #define  BOARD_DDR_SIZE 128 或者 #define BOARD_DDR_SIZE 256  #define BOARD_DDR_SIZE 512

然后,根据这个变量,能够支持好几个功能,首先,不同内存大小,应用程序可能有些差别,尤其是默认的内存分配。甚至牵扯到程序的具体能力。内存低,需要进行功能限制。

这就造成升级包不同,我的解决方法如下:

首先升级包位于u盘 update根目录,然后是二级目录,根据内存大小 分别是128 256或者512

三级目录才是对应的u-boot rootfs 以及其他。

修改u-boot代码,使能够直接从相应目录查找升级文件。这样做最大的好处是,给用户升级包时,不用考虑具体是那种内存规格了,直接吧update打包给用户即可,用户解压update包,后,程序自己会判断相应的目录。

我自己的项目中,为了能支持不同内存,做到系统自适应,需要支持不同大小内存。不同的设备能力不同。
主要是,经过实际验证 file_fat_read可以支持目录结构。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
相关代码如下:在static int update_to_flash(void)内修改

char strUpdateFileName[64];
        memset(strUpdateFileName,0,sizeof strUpdateFileName);
        int nCurMem=BOARD_DDR_SIZE;

sprintf(strUpdateFileName,"%s",aufile);
                if(nCurMem==128)
                   sprintf(strUpdateFileName,"/update/128/%s",aufile);
                else if(nCurMem==256)
                   sprintf(strUpdateFileName,"/update/256/%s",aufile);
                else if(nCurMem==512)
                   sprintf(strUpdateFileName,"/update/512/%s",aufile);
                printf("cur mem:%d readFile:%s\n",nCurMem,strUpdateFileName);
                //优先检查符合条件的目录是否有相关文件
                sz = file_fat_read(strUpdateFileName, LOAD_ADDR,sizeof(image_header_t));
                printf("read head %s sz %ld hdr %d\n",strUpdateFileName, sz, sizeof(image_header_t));
                //再次检查根目录
                if(sz<=0||sz                         sprintf(strUpdateFileName,"%s",aufile);
                        //再次尝试读取
                        sz = file_fat_read(strUpdateFileName, LOAD_ADDR,sizeof(image_header_t));
                        printf("read head %s sz %ld hdr %d\n",strUpdateFileName, sz, sizeof(image_header_t));
                }

ghbgmc

0个粉丝

1

问答

0

专栏

0

资料

ghbgmc 2016-05-31 01:29:56
认可0
请问外部看门狗是那部分电路 怎么调整喂狗时间

ngswfx

1个粉丝

55

问答

1

专栏

40

资料

ngswfx 2016-05-31 06:51:23
认可0
本帖最后由 ngswfx 于 2016-5-31 06:57 编辑

[quote][url=forum.php?mod=redirect&goto=findpost&pid=30890&ptid=11004]ghbgmc 发表于 2016-5-31 01:29[/url]
请问外部看门狗是那部分电路 怎么调整喂狗时间[/quote]

是一个独立的5条腿的芯片,如果其中一个喂狗腿,一定时间内(这个时间其实很短,通常1-2s,这里我也很疑惑,如果开始彻底不喂狗,能坚持60秒左右,但如果一开始喂,就启动了一样,只能1-2秒了,虽然逻辑上我们需要这种,绕开系统启动环节,但不太符合大多数喂狗芯片的文档描述,反正我是没看到这样的描述,当然文档我是随便找了一个,因为我想,这种芯片原理都差不多),电平没有高低变化的话。

复位腿会向3520D发出复位动作。

//////////////////////////////////////硬件不是我弄的,是HB NVR 2106C,最开始我是把复位腿断开,调试程序,正常了,才焊接上。目前这种复位动作感觉很完美,由于是外部的,不依赖3520D芯片,复位保护功能更强一些。芯片内部的那条狗,还有时钟死的问题。

巡山的小妖

0个粉丝

6

问答

0

专栏

0

资料

巡山的小妖 2016-04-17 14:26:41
认可0
想学。。。。

myearth

0个粉丝

3

问答

0

专栏

3

资料

myearth 2016-04-18 11:27:39
认可0
辛苦了:lol

hik

0个粉丝

3

问答

0

专栏

0

资料

hik 2016-04-21 13:45:07
认可0
楼主牛X!!!!
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区