📄 flash_amd29lv800.c
字号:
/*
file: flash_AMD29LV800.c
contents: implementation of flash routines
for the AMD part.
author: Aaron Ferrucci
*/
#include "nios.h"
// ---------------------------------------------
// Private Routines
// Wait for the given address to contain 0xFFFF.
// Return value: 1 on success, 0 on timeout failure.
static int await_erase_complete(int entire_chip, volatile unsigned short *addr)
{
int iTimeout = 20;
// The "typical" time for an erase command is 0.7 seconds.
// Empirically (as expected), it takes longer to erase the entire
// chip than a single sector. Give a generous timeout for a single
// sector, and even more for the entire chip.
if (entire_chip)
iTimeout = 120;
while (iTimeout)
{
nr_delay(100); // Wait 100 ms.
if (0xFFFF == *addr)
return 0;
iTimeout--;
}
// Timeout error.
return -1;
}
// This routine actually takes about 3 us on a 33.333MHz Nios32.
static wait_at_least_1_us(void)
{
volatile unsigned long iTimeout = nasys_clock_freq_1000 / 8250;
while (iTimeout--)
{
;
}
}
// Unlock bypass mode, enabling fast writes.
static void unlock_bypass_mode(volatile unsigned short *flash_base)
{
flash_base[0x555] = 0xAA;
flash_base[0x2AA] = 0x55;
flash_base[0x555] = 0x20;
}
// Turn bypass mode off, disabling fast writes and enabling normal function.
static void reset_bypass_mode(volatile unsigned short *flash_base)
{
*flash_base = 0x90;
*flash_base = 0x0;
}
// Read the given address until two successive reads yield the
// same value.
// Return value: 0 on success, -1 on timeout failure.
static int await_write_complete(volatile unsigned short *addr,unsigned short correct_value)
{
unsigned long iTimeout = 40;
unsigned short us1;
// The "typical" time for a word write is 11 us.
// Set a timeout of about 4 times "typical".
while (iTimeout)
{
wait_at_least_1_us();
// While the flash is occupied with a task, it toggles data
// bit 6 on each read. When the flash is idle, data bit 6
// stops toggling. So, read twice and compare - there's no
// need for bit masking.
us1 = *addr;
if (us1 == correct_value)
return 0;
iTimeout--;
}
return -1;
}
static int erase_flash_single_command(volatile unsigned short *flash_base)
{
int result;
// Erase the entire flash in one command.
flash_base[0x555] = 0xAA;
flash_base[0x2AA] = 0x55;
flash_base[0x555] = 0x80;
flash_base[0x555] = 0xAA;
flash_base[0x2AA] = 0x55;
flash_base[0x555] = 0x10;
result = await_erase_complete(1, flash_base);
}
// Write val to the given flash address, in bypass mode (assumes
// that bypass mode has been enabled already).
// Return value: 0 on success, -1 on failure.
static int nr_flash_write_bypass(volatile unsigned short *flash_base,
unsigned short *addr, unsigned short val)
{
unsigned short us1, us2;
int iTimeout;
int result = 0;
*flash_base = 0xA0;
*addr = val;
result = await_write_complete(addr,val);
if(result)
return result;
us1 = *addr;
if (us1 != val)
result = -1;
return result;
}
// ---------------------------------------------
// Public Routines
// Erase the flash sector at sector_address.
// Return value: 0 on success, -1 on failure.
int nr_flash_erase_sector
(
unsigned short *flash_base,
unsigned short *sector_address
)
{
volatile unsigned short *fb = flash_base;
int result;
#ifdef nasys_main_flash
if (-1 == (int)fb)
fb = nasys_main_flash;
#endif // nasys_main_flash
fb[0x555] = 0xAA;
fb[0x2AA] = 0x55;
fb[0x555] = 0x80;
fb[0x555] = 0xAA;
fb[0x2AA] = 0x55;
*sector_address = 0x30;
// Loop until the data reads as 0xFFFF.
result = await_erase_complete(0, sector_address);
return result;
}
// Erase the entire flash.
// Return value: 0 on success, -1 on failure.
int nr_flash_erase(unsigned short *flash_base)
{
volatile unsigned short *fb = flash_base;
int result = 0;
#if __nios32__
#define ALLSECTORERASE 1
#if ALLSECTORERASE
#ifdef nasys_main_flash
if (-1 == (int)fb)
{
fb = nasys_main_flash;
}
#endif // nasys_main_flash
result = erase_flash_single_command(fb);
return result;
#else // !ALLSECTORERASE
int i;
// For nios32, the 29LV800B is divided into sectors as follows:
// [0, 0x4000)
// [0x4000, 0x6000)
// [0x6000, 0x8000)
// [0x8000, 0x10000)
// [0x10000, 0x20000)
// [0x20000, 0x30000)
// ...
int sectorOffset[] = {
0, 0x4000, 0x6000, 0x8000, 0x10000, 0x20000, 0x30000, 0x40000,
0x50000, 0x60000, 0x70000, 0x80000, 0x90000, 0xA0000, 0xB0000,
0xC0000, 0xD0000, 0xE0000, 0xF0000,
};
if (-1 == (int)fb)
fb = nasys_main_flash;
// Erase each sector in turn.
for (i = 0; i < sizeof(sectorOffset) / sizeof(*sectorOffset); ++i)
{
int sector = (int)fb + sectorOffset[i];
result = nr_flash_erase_sector(fb, (unsigned short*)sector);
if(result)
break;
}
return result;
#endif // ALLSECTORERASE
#else // !__nios32__
#ifdef nasys_main_flash
if (-1 == (int)fb)
fb = nasys_main_flash;
#endif // nasys_main_flash
result = erase_flash_single_command(fb);
return result;
#endif // __nios32__
}
// Write val to the given flash address.
// Return value: 1 on success, 0 on failure.
int nr_flash_write
(
unsigned short *flash_base,
unsigned short *addr,
unsigned short val
)
{
volatile unsigned short *fb = flash_base;
volatile unsigned short *a = addr;
unsigned short us1, us2;
int result = 0;
#ifdef nasys_main_flash
if (-1 == (int)fb)
fb = nasys_main_flash;
#endif // nasys_main_flash
fb[0x555] = 0xAA;
fb[0x2AA] = 0x55;
fb[0x555] = 0xA0;
*a = val;
result = await_write_complete(a,val);
if(result)
return result;
us1 = *a;
if (us1 != val)
result = -1;
return result;
}
// Write a buffer of data to the flash, using bypass mode.
// Return value: 1 on success, 0 on failure.
int nr_flash_write_buffer
(
unsigned short *flash_base,
unsigned short *start_address,
unsigned short *buffer,
int size
)
{
volatile unsigned short *fb = flash_base;
int i;
int result = 0;
#ifdef nasys_main_flash
if (-1 == (int)fb)
fb = nasys_main_flash;
#endif // nasys_main_flash
unlock_bypass_mode(fb);
for (i = 0; i < size; ++i)
{
result = nr_flash_write_bypass(fb, start_address + i, buffer[i]);
if(result)
break;
}
reset_bypass_mode(fb);
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -