📄 flash_test.c
字号:
/*******************************************************************************
*
* Copyright (C) 2003, MOTOROLA INC. All Rights Reserved
*
* FILE NAME : flash_test.c
* DATE CREATED : 06-18-03
*
* DESCRIPTION: Function and Test code for AMD Am29BDS128H Flash
* This code will query the burst flash on the eval board for its manufacturer ID
* AND device ID. If device ID is incorrect, the code will report this failure.
* If manufacturer ID not correct, the code will also report this.
*
* Next, this code will erase the contents of the burst flash device and program
* it with instructions (add "..." to R2). Then the code will enable the EIM
* to burst read these instructions. Use an logic analyzer to verify burst
* operation.
*
*
* NOTE: Jumper bank J6 must have pins 3-4 bridged. This sets the Am29BDS128H
* flash to chip select 0. The other chip selects do not have sufficient
* address space. There should be only one jumper per row, and no two
* rows should have the same pins bridged.
*
* ****************************
* IMPORTANT NOTE ON FUNCTIONS:
* ****************************
*
* When passing an address to a function, the function assumes that the address
* passed to it is the Flash address as a standard integer, not the System address.
* E.g., regardless of where in the system memory the Flash resides, the functions
* should be passed address values between 0x000000 and 0x7FFFFF. The functions will
* automatically adjust to write or read to the correct system address based off of
* the value of CS_BASE. Address values between 0x000000 and 0x7FFFFF represent the
* entire FLASH (x16) address range. This test code assumes a system with a x32
* FLASH configuration. Thus the functions will convert the x16 FLASH address to the
* appropriate and desired SYSTEM (x32) address.
*
* If a function needs to be passed a sector value, it will accept either the
* NEGATIVE number of the sector or any Flash address within the sector.
*
* Ex: Sector 2 starts at Flash address 0x002000 and ends at 0x002FFF
* Passing -2, 0x002000, 0x002FFF or 0x0023F9 would all work correctly
* Passing 2 would be interpreted as an address in sector 0
*
* The sector value functions will actually also operate correctly when passed
* a system address that points to the sector.
*
* In general though, the intent is that as long as CS_BASE is defined, the function
* user does not need to bother with where the Flash resides in system memory.
*
* Revision history:
* rev 0.0 - original release
* rev 0.1 - updated for i.mx21
*
********************************************************************************
* I N C L U D E F I L E S
*******************************************************************************/
#include "common.h"
#include "tht_memory_map_defines.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Modify SysInit() for different system initialization settings */
extern int SysInit(void);
extern int MemInit(void);
/******************************************************************************
* DEFINES
******************************************************************************/
/* i.MX21 specific defines */
/***** Critical *****/
// CS_BASE informs the program of the base system address of the Flash
#define CS_BASE (volatile unsigned int *)CS0_BASE_ADDR // Chip select 0, i.mx21
/***************************************************
********* AMD Burst Flash Constant Defines *********
***************************************************/
// Read adjusting for CS_BASE
#define read(x) *(CS_BASE+x)
//reset & unlock writes
#define reset() *CS_BASE=0x00F000F0
#define unlock() *(CS_BASE + 0x555)=0x00AA00AA; *(CS_BASE + 0x2AA)=0x00550055
//manufacturer and device ID values
#define MANU_ID 0x00010001
#define MANU_ID_AD (CS_BASE)
#define DEV_ID_1 0x227E227E
#define DEV_ID_AD_1 (CS_BASE + 0x1)
#define DEV_ID_2 0x22182218
#define DEV_ID_AD_2 (CS_BASE + 0xE)
#define DEV_ID_3 0x22002200
#define DEV_ID_AD_3 (CS_BASE + 0xF)
// base addresses of FLASH banks
#define BANK_D (CS_BASE)
#define BANK_C (CS_BASE + 0x100000)
#define BANK_B (CS_BASE + 0x400000)
#define BANK_A (CS_BASE + 0x700000)
// used for convenience during polling
#define DQ7 ((1<<23)|(1<<7))
#define DQ6 ((1<<22)|(1<<6))
#define DQ5 ((1<<21)|(1<<5))
#define DQ4 ((1<<20)|(1<<4))
#define DQ3 ((1<<19)|(1<<3))
#define DQ2 ((1<<18)|(1<<2))
#define DQ1 ((1<<17)|(1<<1))
#define DQ0 ((1<<16)|(1<<0))
/******************************
****** Globals Variables ******
******************************/
unsigned char UBM = 0; //Unlock Bypass Mode flag
volatile unsigned int gFailCount;
/*****************************
****** Function Defines ******
*****************************/
/* Sector Base Address Convertor */
// Takes in flexible input to return base address of desired sector
// Parameter: int sector = negative of Sector # [0:-269]
// or Flash address in desired sector [0:0x7FFFFF]
// or System address in desired sector (CS_BASE+[0:0x7FFFFF])
// Returns: Base address of the sector calculated, or 'null' if the input is invalid
// as a "volatile unsigned int *"
// Examples: assuming CS_BASE = 0x16000000
// Correct:
// sector_calc(-15) would return the base address of sector 15 (0x16040000)
// sector_calc(0x04A820) would return the base address of sector 15 also
// sector_calc(0x1604A820) would return the base address of sector 15 as well
// sector_calc(0) returns CS_BASE
// Incorrect:
// sector_calc(-273) would return null, as there is not a sector 273
// sector_calc(0x9FFFFF) would return null, as the address is outside of the flash
volatile unsigned int * sector_bcalc(int sector){
if(sector<1){
sector*=-1;
if (sector<8){
return (CS_BASE + sector * 0x1000);
} else if (sector<262){
return (CS_BASE + (sector - 7) * 0x8000);
} else if (sector<270){
return (CS_BASE + (sector - 262) * 0x1000 + 0x7F8000);
} else {
return 0;
}
} else if(sector<0x800000){
sector+=(int)CS_BASE;
} else if((sector > (int)CS_BASE) && (sector < (int)CS_BASE+0x800000)){
if((sector > (int)CS_BASE+0x7FFF) && (sector < (int)CS_BASE+0x7F8000)){
return (volatile unsigned int *)(sector&0xFFFF8000);
} else {
return (volatile unsigned int *)(sector&0xFFFFF000);
}
}
return 0;
}
/***************************************************
********* AMD Burst Flash Function Defines *********
***************************************************/
/*****/
/* Asynchronous Read */
// This is actually just a define that adjusts for CS_BASE
// Syntax:
// int store_data=read(x); where x is the desired Flash address to be read
/*****/
/* Asynchronous Read Multiple */
// Read out a chunk of data to dynamically allocated memory
// Parameters: volatile unsigned int* address = pointer to "lowest" address to be read
// int words = number of words to be read
// Returns: pointer to an array containing the read data.
// This pointer has been acquired using malloc, therefore:
// **** NOTE: ****
// returned pointer should be released before program ends using
// free(<pointer>);
// Do not lose, overwrite, alter, etc...this pointer!
// after free() you will no longer have address to the data in it
int* read_m(int address, int words){
int *data = malloc(words * sizeof(int));
address = ((int)CS_BASE + 4*address);
reset();
memcpy(data,(int*)address,words*4);
return data;
}
/*****/
/*** Autoselect Commands ***/
/* Manufacturer ID */
// Returns: 1 if manufacturer id matches expected value (MANU_ID)
int auto_manu_id(void){
int temp;
*CS_BASE=0x00F000F0;
unlock();
*(CS_BASE + 0x555)=0x00900090;
temp=*MANU_ID_AD;
reset();
return (temp==MANU_ID);
}
/*****/
/* Device ID */
// Returns: 1 if device id matches expected values (DEV_ID_x, x=(1..3))
int auto_dev_id(void){
int temp[3];
*CS_BASE=0x00F000F0;
unlock();
*(CS_BASE + 0x555)=0x00900090;
temp[0]=*DEV_ID_AD_1;
temp[1]=*DEV_ID_AD_2;
temp[2]=*DEV_ID_AD_3;
reset();
return (temp[0]==DEV_ID_1&&temp[1]==DEV_ID_2&&temp[2]==DEV_ID_3); // relational operator, compares and returns true (1) or false (0)
}
/*****/
/* Sector Lock Verify */
// Parameter: int sector = negative sector # or a flash/system address within the sector to be erased
// Returns: 1 if sector is locked
// WARNING: function is fairly flexible for input, but does not error check,
int auto_sect_lock_ver(int sector){
volatile unsigned int * sector_p=sector_bcalc(sector);
sector_p+=0x555;
reset();
unlock();
*sector_p=0x00900090;
sector = *sector_p;
reset();
return (sector==0x00010001); // relational operator, compares and returns true (1) or false (0)
}
/*****/
/* Indicator Bits */
// Returns: indicator bits - DQ15-DQ8 = 0, DQ7: factory lock bit,
// DQ6: customer lock bit, DQ5: Handshake bit (1 = reduced wait, 0 = standard),
// DQ4-DQ0 = 0
int auto_indicator(void){
int temp;
reset();
unlock();
*(CS_BASE + 0x555)=0x00900090;
temp = *(CS_BASE + 0x3);
reset();
return temp;
}
/*** End of Autoselect Commands ***/
/*****/
/*** Unlock Bypass Mode ***/
// while in UBM mode data cannot be read
// Commands that benefit from UBM mode:
// Program, Sector Erase, Erase
// Highly recommended for write multiple
/* Unlock Bypass Entry */
// Enables Unlock Bypass Mode, sets the UBM flag to 1
void ub_entry(void){
reset();
unlock();
*(CS_BASE + 0x555)=0x00200020;
UBM = 1;
}
/*****/
/* Unlock Bypass Reset */
// Exits Unlock Bypass Mode, sets the UBM flag to 0
void ub_reset(void){
reset();
*CS_BASE = 0x00900090;
*CS_BASE = 0x00000000;
UBM = 0;
}
/*** End of UBM commands ***/
/*****/
/* Program */
// Parameters: int address = flash address to be written to
// int data = data to be written
// Returns: 1 on succesful write, null on failure
int write(int address,int data){
if(!UBM){
unlock();
}
*(CS_BASE + 0x555)=0x00A000A0;
*(CS_BASE + address)=data;
// Polling for completion
while(((*(CS_BASE + address)^data)&DQ7) != 0){
if((*(CS_BASE + address)&DQ5)==DQ5){
if(((*(CS_BASE + address)^data)&DQ7)==0){
return 1;
} else {
return 0;
}
}
}
return 1;
}
/*****/
/* Program multiple */
// Writes a chunk of data sequentially starting at a pointer
// Parameters: int address = starting flash address to be written to
// int words = number of words of data to be written
// int * data = pointer to start of data
// Returns: 1 on success, 0 if an attempt to write a word of data fails
// twice in a row.
int write_m(int address,int words, int * data){
int z=0,error=0;
reset();
ub_entry();
while(z<words){
if(write(address + z,data[z])){
z+=1;
error=0;
} else {
error+=1;
if(error>1){
ub_reset();
return 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -