當(dāng)前位置:首頁 > 嵌入式 > 嵌入式硬件
[導(dǎo)讀]1. u-boot 介紹u-boot 是一個(gè)open source 的bootloader,目前版本是1.1.2。u-boot 是在ppcboot 以及armboot 的基礎(chǔ)上發(fā)展而來,相當(dāng)?shù)某墒旌头€(wěn)定,已經(jīng)在許多嵌入式系統(tǒng)開

1. u-boot 介紹

u-boot 是一個(gè)open source 的bootloader,目前版本是1.1.2。u-boot 是在ppcboot 以及armboot 的基礎(chǔ)上發(fā)展而來,相當(dāng)?shù)某墒旌头€(wěn)定,已經(jīng)在許多嵌入式系統(tǒng)開發(fā)過程中被采用。由于其開發(fā)源代碼,其支持的開發(fā)板眾多。

為什么我們需要u-boot?顯然可以將uClinux 直接燒入flash,從而不需要額外的引導(dǎo)裝載程序(bootloader)。但是從軟件升級(jí)的角度以及程序修補(bǔ)的來說,軟件的自動(dòng)更新非常重要。事實(shí)上,引導(dǎo)裝載程序(bootloader)的用途不僅如此,但僅從軟件的自動(dòng)更新的需要就說明我們的開發(fā)是必要的。同時(shí),u-boot 移植的過程也是一個(gè)對嵌入式系統(tǒng)包括軟硬件以及操作系統(tǒng)加深理解的一個(gè)過程。

2. u-boot 移植的框架

移植u-boot 到新的開發(fā)板上僅需要修改和硬件相關(guān)的部分。在代碼結(jié)構(gòu)上:

1) 在board 目錄下創(chuàng)建gold44b 目錄,創(chuàng)建gold44b.c 以及flash.c,memsetup.S,u-boot.lds等。不需要從零開始,可選擇一個(gè)相似的目錄,直接復(fù)制過來,修改文件名以及內(nèi)容。我在移植u-boot 過程中,選擇的是Dave/B2目錄。由于u-boot 已經(jīng)包含基于s3c24b0 的開發(fā)板目錄,作為參考,也可以復(fù)制相應(yīng)的目錄。

2) 在cpu 目錄下創(chuàng)建s3c44b0x 目錄,主要包含start.S,interrupts.c 以及cpu.c,serial.c幾個(gè)文件。同樣不需要從零開始建立文件,直接從arm720t 復(fù)制,然后修改相應(yīng)內(nèi)容。

3) 在include/configs 目錄下添加gold44b.h,在這里放上全局的宏定義等。

4) 找到u-boot 根目錄下Makefile 修改加入

gold44b_config : unconfig

@./mkconfig $(@:_config=) arm s3c44b0 gold44b

5) 運(yùn)行make ev44bii_config,如果沒有錯(cuò)誤就可以開始硬件相關(guān)代碼移植的工作

3. u-boot 的體系結(jié)構(gòu)

1) 總體結(jié)構(gòu)

u-boot 是一個(gè)層次式結(jié)構(gòu)。做移植工作的軟件人員應(yīng)當(dāng)提供串口驅(qū)動(dòng)(UART Driver),以太網(wǎng)驅(qū)動(dòng)(Ethernet Driver),Flash 驅(qū)動(dòng)(Flash 驅(qū)動(dòng)),USB 驅(qū)動(dòng)(USB Driver)。目前,通過USB 口下載程序顯得不是十分必要,而且開發(fā)板上也沒有USB接口,所以暫時(shí)沒有移植USB 驅(qū)動(dòng)。驅(qū)動(dòng)層之上是u-boot 的應(yīng)用,command 通過串口提供人機(jī)界面。我們可以使用一些命令做一些常用的工作,比如內(nèi)存查看命令md。

Kermit 應(yīng)用主要用來支持使用串口通過超級(jí)終端下載應(yīng)用程序。TFTP 則是通過網(wǎng)絡(luò)方式來下載應(yīng)用程序,例如uClinux 操作系統(tǒng)。

2) 內(nèi)存分布

gold44b 的flash 大小2M(8bits),現(xiàn)在將0-40000 共256k 作為u-boot 的存儲(chǔ)空間。由于u-boot 中有一些環(huán)境變量,例如ip 地址,引導(dǎo)文件名等,可在命令行通過setenv 配置好,通過saveenv 保存在40000-50000(共64k)這段空間里。如果存在保存好的環(huán)境變量,u-boot 引導(dǎo)將直接使用這些環(huán)境變量。正如從代碼分析中可以看到,我們會(huì)把flash 引導(dǎo)代碼搬移到DRAM 中運(yùn)行。u-boot 的代碼在DRAM中的位置在u-boot-1.1.2/board/gold44b/config.mk配置如下:TEXT_BASE = 0x0C700000。這樣,引導(dǎo)代碼u-boot將從0x0000 0000 處搬移到0x0C700000 處。特別注意的由于gold44b uClinux 中斷向量程序地址在0x0c000 0000 處,所以不能將程序下載到0x0c000 0000 出,通常下載到0x0c008 0000 處。

4. start.S 代碼結(jié)構(gòu)

1) 定義入口

一個(gè)可執(zhí)行的Image 必須有一個(gè)入口點(diǎn)并且只能有一個(gè)唯一的全局入口,通常這個(gè)入口放在Rom(flash)的0x0 地址。例如start.S 中的

.globl _start

_start:

值得注意的是你必須告訴編譯器知道這個(gè)入口,這個(gè)工作主要是修改連接器腳本文件(lds)。

開發(fā)板上的u-boot.lds如下:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

. = 0x00000000;

. = ALIGN(4);

.text :

{

cpu/s3c44b0/start.o (.text)

*(.text)

}

. = ALIGN(4);

.rodata : { *(.rodata) }

. = ALIGN(4);

.data : { *(.data) }

. = ALIGN(4);

.got : { *(.got) }

__u_boot_cmd_start = .;

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .;

armboot_end_data = .;

. = ALIGN(4);

__bss_start = .;

.bss : { *(.bss) }

_end = .;

}

2) 設(shè)置異常向量(Exception Vector)

異常中斷矢量表(Exception Vector Table)是u-boot與uClinux內(nèi)核發(fā)生聯(lián)系關(guān)鍵的地方之一。即使uClinux內(nèi)核已經(jīng)得到處理器的控制權(quán)運(yùn)行,一旦發(fā)生中斷,處理器還是會(huì)自動(dòng)跳轉(zhuǎn)到從0x0地址開始的第一級(jí)異常中斷矢量表中的某個(gè)表項(xiàng)(依據(jù)于中斷類型)處讀取指令運(yùn)行。

異常中斷矢量表必須是從0 地址開始,連續(xù)的存放。如下面的就包括了復(fù)位(reset),未定義處理(undef),軟件中斷(SWI),預(yù)去指令錯(cuò)誤(Pabort),數(shù)據(jù)錯(cuò)誤 (Dabort),保留,以及IRQ,FIQ 等。注意這里的值必須與uClinux 的vector_base 一致。這就是說如果uClinux 中vector_base(include/armnommu/proc-armv/system.h)定義為0x0c00 0000,則HandleUndef 應(yīng)該在

0x0c00 0004。

.globl _start

_start: b reset

/*Modfied by zl 2005-2-21 */

/* add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

*/

ldr pc, =0x0c000004

ldr pc, =0x0c000008

ldr pc, =0x0c00000c

ldr pc, =0x0c000010

ldr pc, =0x0c000014

ldr pc, =0x0c000018

ldr pc, =0x0c00001c

.balignl 16,0xdeadbeef

這里,地址0x0處的一級(jí)異常中斷矢量表只簡單地包含向二級(jí)異常中斷矢量表的跳轉(zhuǎn)指令就可以。這樣,就能夠正確地將發(fā)生的事件交給uClinux的中斷處理程序來處理。這樣設(shè)計(jì)是因?yàn)樵诒緐-boot移植里不使用中斷,8019和Timer都是輪詢中斷的,如果u-boot要使用中斷(如要用到USB設(shè)備),就需要建立二級(jí)異常中斷矢量表了。代碼如下(沒有調(diào)試通過):[!--empirenews.page--]

.globl _start

_start: b reset

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

add pc, pc, #0x0c000000

.balignl 16,0xdeadbeef

....

在Reset是復(fù)制中斷矢量表

/*

now copy to sram the interrupt vector

*/

adr r0, real_vectors

add r2, r0, #1024

ldr r1, =0x0c000000

add r1, r1, #0x08

vector_copy_loop:

ldmia r0!, {r3-r10}

stmia r1!, {r3-r10}

cmp r0, r2

ble vector_copy_loop

....

建立三級(jí)中斷跳轉(zhuǎn)

/*************************************************/

/* interrupt vectors */

/*************************************************/

/*

real_vectors:

b reset

b undefined_instruction

b software_interrupt

b prefetch_abort

b data_abort

b not_used

b irq

b fiq

*/

/*************************************************/

undefined_instruction:

mov r6, #3

b reset

software_interrupt:

mov r6, #4

b reset

prefetch_abort:

mov r6, #5

b reset

data_abort:

mov r6, #6

b reset

not_used:

/* we *should* never reach this */

mov r6, #7

b reset

irq:

mov r6, #8

b reset

fiq:

mov r6, #9

b reset

3) 初始化CPU 相關(guān)的pll,clock,中斷控制寄存器

依次為關(guān)閉watch dog timer,關(guān)閉中斷,設(shè)置LockTime,PLL(phase lock loop),以及時(shí)鐘。

這些值(除了LOCKTIME)都可從Samsung 44b0 的手冊中查到。

/*

*************************************************************************

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

*************************************************************************

*/

#define INTCON (0x01c00000+0x200000)

#define INTMSK (0x01c00000+0x20000c)

#define LOCKTIME (0x01c00000+0x18000c)

#define PLLCON (0x01c00000+0x180000)

#define CLKCON (0x01c00000+0x180004)

#define WTCON (0x01c00000+0x130000)

cpu_init_crit:

/* disable watch dog */

ldr r0, =WTCON

ldr r1, =0x0

str r1, [r0]

/*

* mask all IRQs by clearing all bits in the INTMRs

*/

ldr r1,=INTMSK

ldr r0, =0x03fffeff

str r0, [r1]

ldr r1, =INTCON

ldr r0, =0x05

str r0, [r1]

/* Set Clock Control Register */

ldr r1, =LOCKTIME

ldrb r0, =800

strb r0, [r1]

ldr r1, =PLLCON

#if CONFIG_S3C44B0_CLOCK_SPEED==64

ldr r0, =0x38021 /* smdk4110: Xtal=8MHz Fclk=64MHz */

#elif CONFIG_S3C44B0_CLOCK_SPEED==66

ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif

str r0, [r1]

ldr r1,=CLKCON

ldr r0, =0x7ff8

str r0, [r1]

mov pc, lr

4) 初始化SDRAM控制器

內(nèi)存控制器(主要是SDRAM控制器),主要通過設(shè)置13 個(gè)從1c80000 開始的寄存器來設(shè)置,包括總線寬度,8 個(gè)內(nèi)存bank,bank 大小,sclk,以及兩個(gè)bank mode。

#ifdef CONFIG_INIT_CRITICAL

bl cpu_init_crit

/*

* before relocating, we have to setup RAM timing

* because memory timing is board-dependend, you will

* find a memsetup.S in your board directory.

*/

bl memsetup

#endif

初始化內(nèi)存控制器的代碼存放在u-boot-1.1.2/board/gold44b/memsetup.S中

與ADS或者SDT下的boot代碼(memcfg.s和44binit.s)一致,只是匯編格式有點(diǎn)不一樣。

5) 將rom 中的程序復(fù)制到RAM 中

首先利用PC 取得bootloader 在flash 的起始地址,再通過標(biāo)號(hào)之差計(jì)算出這個(gè)程序代

碼的大小。這些標(biāo)號(hào),編譯器會(huì)在連接(link)的時(shí)候生成正確的分布的值。取得正

確信息后,通過寄存器(r3 到r10)做為復(fù)制的中間媒介,將代碼復(fù)制到RAM 中。

relocate: /* relocate U-Boot to RAM */

adr r0, _start /* r0 <- current position of code */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp r0, r1 /* don't reloc during debug */

beq stack_setup

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot */

add r2, r0, r2 /* r2 <- source end address */

copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0] */

stmia r1!, {r3-r10} /* copy to target address [r1] */

cmp r0, r2 /* until source end addreee [r2] */

ble copy_loop

6) 初始化堆棧

進(jìn)入各種模式設(shè)置相應(yīng)模式的堆棧.

/* Set up the stack */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */[!--empirenews.page--]

sub r0, r0, #CFG_MALLOC_LEN /* malloc area */

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack */

7) 轉(zhuǎn)到RAM 中執(zhí)行

使用指令ldr,pc,RAM 中C 函數(shù)地址就可以轉(zhuǎn)到RAM 中去執(zhí)行。

ldr pc, _start_armboot

5. 系統(tǒng)初始化部分

1) 串口部分(u-boot-1.1.2/cpu/s3c44b0/serial.c)

串口的設(shè)置主要包括初始化串口部分,值得注意的串口的Baudrate 與時(shí)鐘MCLK 有很大關(guān)系,是通過:rUBRDIV0=( (int)(MCLK/16./(gd ->baudrate) + 0.5) -1 )計(jì)算得出。這可以在手冊中查到。由于u-boot支持可變的波特率,所以采用宏定義設(shè)置默認(rèn)波特率(64Mhz,115200bps)和其他波特率。代碼如下:

void serial_setbrg (void)

{

DECLARE_GLOBAL_DATA_PTR;

u32 divisor = 0;

/* get correct divisor */

switch(gd->baudrate) {

case 1200:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 3124;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

divisor = 3905;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64 /默認(rèn)

divisor = 3332;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif

break;

case 9600:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 390;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

divisor = 487;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64 /默認(rèn)

divisor = 416;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif

break;

case 19200:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 194;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

divisor = 243;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64 /默認(rèn)

divisor = 207;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif

break;

case 38400:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 97;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

divisor = 121;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64 /默認(rèn)

divisor = 103;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif break;

case 57600:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 64;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75

divisor = 80;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64 /默認(rèn)

divisor = 68;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif break;

case 115200:

#if CONFIG_S3C44B0_CLOCK_SPEED==66

divisor = 32;

#elif CONFIG_S3C44B0_CLOCK_SPEED==64

divisor = 34;

#elif CONFIG_S3C44B0_CLOCK_SPEED==75 /默認(rèn)

divisor = 40;

#else

# error CONFIG_S3C44B0_CLOCK_SPEED undefined

#endif break;

}

serial_flush_output();

serial_flush_input();

UFCON0 = 0x0;

ULCON0 = 0x03;

UCON0 = 0x05;

UBRDIV0 = divisor;

UFCON1 = 0x0;

ULCON1 = 0x03;

UCON1 = 0x05;

UBRDIV1 = divisor;

for(divisor=0; divisor<100; divisor++) {

/* NOP */

}

}

其他的函數(shù)包括發(fā)送,接收。這個(gè)時(shí)候沒有中斷,是通過循環(huán)等待來判斷是否動(dòng)作完成。

例如,接收函數(shù):

static int serial_flush_input(void)

{

volatile u32 tmp;

/* keep on reading as long as the receiver is not empty */

while(UTRSTAT0&0x01) {

tmp = REGB(URXH0);

}

return 0;

}

2) 時(shí)鐘部分(u-boot-1.1.2/cpu/s3c44b0/interrupt.c)

實(shí)現(xiàn)了延時(shí)函數(shù)udelay。

這里的get_timer 由于沒有使用中斷,是使用全局變量來累加的。

void udelay (unsigned long usec)

{

ulong tmo;

tmo = usec / 1000;

tmo *= CFG_HZ;

tmo /= 8;

tmo += get_timer (0);

while (get_timer_masked () < tmo)

/*NOP*/;

}

3) flash 部分(u-boot-1.1.2/board/gold44b.c)

flash 作為內(nèi)存的一部分,讀肯定沒有問題,關(guān)鍵是flash 的寫部分。

Flash 的寫必須先擦除,然后再寫。

flash_init 完成初始化部分,這里的主要目的是檢驗(yàn)flash 的型號(hào)是否正確。

unsigned long flash_init (void)

{

#ifdef __DEBUG_START_FROM_SRAM__

return CFG_DUMMY_FLASH_SIZE;

#else

unsigned long size_b0;

int i;

/* Init: no FLASHes known */

for (i=0; i flash_info[i].flash_id = FLASH_UNKNOWN;

}

/* Static FLASH Bank configuration here - FIXME XXX */

size_b0 = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]);

if (flash_info[0].flash_id == FLASH_UNKNOWN) {

printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",

size_b0, size_b0<<20);

}

/* Setup offsets */

flash_get_offsets (0, &flash_info[0]);

/* Monitor protection ON by default */

(void)flash_protect(FLAG_PROTECT_SET,

[!--empirenews.page--]

-CFG_MONITOR_LEN,

0xffffffff,

&flash_info[0]);

flash_info[0].size = size_b0;

return (size_b0);

#endif

}

flash_erase 擦除flash,BlankCheck 則檢查該部分內(nèi)容是否擦除成功。

int flash_erase (flash_info_t *info, int s_first, int s_last)

{

volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *)(info->start[0]);

volatile CFG_FLASH_WORD_SIZE *addr2;

int flag, prot, sect, l_sect;

ulong start, now, last;

int i;

if ((s_first < 0) || (s_first > s_last)) {

if (info->flash_id == FLASH_UNKNOWN) {

printf ("- missing\n");

} else {

printf ("- no sectors to erase\n");

}

return 1;

}

if (info->flash_id == FLASH_UNKNOWN) {

printf ("Can't erase unknown flash type - aborted\n");

return 1;

}

prot = 0;

for (sect=s_first; sect<=s_last; ++sect) {

if (info->protect[sect]) {

prot++;

}

}

if (prot) {

printf ("- Warning: %d protected sectors will not be erased!\n",

prot);

} else {

printf ("\n");

}

l_sect = -1;

/* Disable interrupts which might cause a timeout here */

flag = disable_interrupts();

/* Start erase on unprotected sectors */

for (sect = s_first; sect<=s_last; sect++) {

if (info->protect[sect] == 0) { /* not protected */

addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[sect]);

if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

addr2[0] = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */

for (i=0; i<50; i++)

udelay(1000); /* wait 1 ms */

} else {

if (sect == s_first) {

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00800080;

addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

}

addr2[0] = (CFG_FLASH_WORD_SIZE)0x00300030; /* sector erase */

}

l_sect = sect;

}

}

/* re-enable interrupts if necessary */

if (flag)

enable_interrupts();

/* wait at least 80us - let's wait 1 ms */

udelay (1000);

/*

* We wait for the last triggered sector

*/

if (l_sect < 0)

goto DONE;

start = get_timer (0);

last = start;

addr = (CFG_FLASH_WORD_SIZE *)(info->start[l_sect]);

while ((addr[0] & (CFG_FLASH_WORD_SIZE)0x00800080) != (CFG_FLASH_WORD_SIZE)0x00800080) {

if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {

printf ("Timeout\n");

return 1;

}

/* show that we're waiting */

if ((now - last) > 50000000) { /* every second */

putc ('.');

last = now;

}

}

DONE:

/* reset to read mode */

addr = (CFG_FLASH_WORD_SIZE *)info->start[0];

addr[0] = (CFG_FLASH_WORD_SIZE)0x00F000F0; /* reset bank */

printf (" done\n");

return 0;

}

wirte_word 則想flash 里面寫入unsigned long 類型的data,因?yàn)閒lash 一次只能寫入16bits,所以這里分兩次寫入。

/*-----------------------------------------------------------------------

* Write a word to Flash, returns:

* 0 - OK

* 1 - write timeout

* 2 - Flash not erased

*/

static int write_word (flash_info_t *info, ulong dest, ulong data)

{

volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *)(info->start[0]);

volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *)dest;

volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *)&data;

ulong start;

int flag;

int i;

/* Check if Flash is (sufficiently) erased */

if ((*((volatile ulong *)dest) & data) != data) {

return (2);

}

/* Disable interrupts which might cause a timeout here */

flag = disable_interrupts();

for (i=0; i<4/sizeof(CFG_FLASH_WORD_SIZE); i++)

{

addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00AA00AA;

addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE)0x00550055;

addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE)0x00A000A0;

dest2[i] = data2[i];

/* re-enable interrupts if necessary */[!--empirenews.page--]

if (flag)

enable_interrupts();

/* data polling for D7 */

start = get_timer (0);

while ((dest2[i] & (CFG_FLASH_WORD_SIZE)0x00800080) !=

(data2[i] & (CFG_FLASH_WORD_SIZE)0x00800080)) {

if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {

return (1);

}

}

}

return (0);

}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉