Библиотеки функций для доступа к памяти FLASH можно найти в среде разработки VisualDSP++ 5.0 (здесь в качестве примера показан файл adi_S29AL004D_8D.c с переведенными комментариями).
/******************************************************************************************/
/* (C) Copyright 2004 - Analog Devices, Inc. All rights reserved. */
/* */
/* FILE: VisualDSP5.0\Blackfin\lib\src\drivers\flash\S29AL004D_8D\adi_S29AL004D_8D.c */
/* */
/* CHANGES: 1.00.0 - initial release */
/* */
/* НАЗНАЧЕНИЕ: Выполняет действия по перепрограммированию устройства памяти */
/* flash S29AL004D_8D (процессор ADSP-BF538F и т. п.) с использованием */
/* модели драйверов устройств adi. */
/******************************************************************************************/
//---- подключаемые файлы ----//
#include < ccblkfn.h >
#include < drivers\flash\util.h >
#include < drivers\flash\adi_m29w320.h >
#include < drivers\flash\Errors.h >
//---- определения переменных -----//
static char *pFlashDesc;
static char *pDeviceCompany = "Spansion";
static int gNumSectors;
//---- Прототипы функций ----//
static ERROR_CODE EraseFlash(unsigned long ulStartAddr);
static ERROR_CODE EraseBlock( int nBlock, unsigned long ulStartAddr );
static ERROR_CODE GetCodes(int *pnManCode, int *pnDevCode, unsigned long ulStartAddr);
static ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector );
static ERROR_CODE GetSectorStartEnd( unsigned long *ulStartOff,
unsigned long *ulEndOff, int nSector );
static ERROR_CODE PollToggleBit(unsigned long ulOffset);
static ERROR_CODE ReadFlash(unsigned long ulOffset, unsigned short *pusValue );
static ERROR_CODE ResetFlash(unsigned long ulStartAddr);
static ERROR_CODE WriteFlash(unsigned long ulOffset, unsigned short usValue );
static unsigned long GetFlashStartAddress( unsigned long ulAddr);
// Функция открывает устройство памяти
static u32 adi_pdd_Open(
ADI_DEV_MANAGER_HANDLE ManagerHandle, // device manager handle
u32 DeviceNumber, // device number
ADI_DEV_DEVICE_HANDLE DeviceHandle, // device handle
ADI_DEV_PDD_HANDLE *pPDDHandle, // указатель на место размещения PDD handle
ADI_DEV_DIRECTION Direction, // направление передачи данных
void *pEnterCriticalArg, // параметр входа в критическую область
ADI_DMA_MANAGER_HANDLE DMAHandle, // handle для DMA manager
ADI_DCB_HANDLE DCBHandle, // callback handle
ADI_DCB_CALLBACK_FN DMCallback // функция callback для device manager
);
// Функция закрывает устройство памяти
static u32 adi_pdd_Close(
ADI_DEV_PDD_HANDLE PDDHandle
);
// Чтение из устройства памяти
static u32 adi_pdd_Read(ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer);
// Запись в устройство памяти
static u32 adi_pdd_Write(ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer);
// Управление устройством памяти
static u32 adi_pdd_Control(ADI_DEV_PDD_HANDLE PDDHandle,
u32 Command,
void *pArg);
ADI_DEV_PDD_ENTRY_POINT ADIS29AL004D_8DEntryPoint =
{
adi_pdd_Open,
adi_pdd_Close,
adi_pdd_Read,
adi_pdd_Write,
adi_pdd_Control
};
// ---- Функции API для доступа к физическому устройству ----//
//----------- adi_pdd_Open ----------//
// НАЗНАЧЕНИЕ
// Эта функция открывает устройство памяти flash типа S29AL004D_8D
// с целью его использования.
//
// Входные параметры:
// ManagerHandle - device manager handle
// DeviceNumber - номер устройства
// DeviceHandle - device handle
// PDDHandle - этот handle используется для идентификации устройства
// Direction - направление перемещения данных
// *pEnterCriticalArg - параметр входа в критическую область
// DMAHandle - handle для DMA manager
// DCBHandle - callback handle
// DMCallback - функция callback для device manager
//
// Возвращаемое значение: код результата операции
u32 adi_pdd_Open(
ADI_DEV_MANAGER_HANDLE ManagerHandle,
u32 DeviceNumber,
ADI_DEV_DEVICE_HANDLE DeviceHandle,
ADI_DEV_PDD_HANDLE *pPDDHandle,
ADI_DEV_DIRECTION Direction,
void *pEnterCriticalArg,
ADI_DMA_MANAGER_HANDLE DMAHandle,
ADI_DCB_HANDLE DCBHandle,
ADI_DCB_CALLBACK_FN DMCallback)
{
// проверка на ошибки, если это требуется
#ifdef ADI_S29AL004B_8B_ERROR_CHECKING_ENABLED
if (DeviceNumber > 0) // проверка номера устройства
return (ADI_DEV_RESULT_BAD_DEVICE_NUMBER);
if (Direction != ADI_DEV_DIRECTION_BIDIRECTIONAL) // проверка направления данных
return (ADI_DEV_RESULT_DIRECTION_NOT_SUPPORTED);
#endif
return (NO_ERR);
}
//----------- adi_pdd_Close ----------//
// НАЗНАЧЕНИЕ
// Эта функция закрывает устройство S29AL004D_8D (память flash).
//
// Входные параметры:
// PDDHandle - хэндл, используемый для идентификации устройства.
//
// Возвращаемое значение: код результата операции
u32 adi_pdd_Close(ADI_DEV_PDD_HANDLE PDDHandle)
{
return (NO_ERR);
}
//----------- adi_pdd_Read ----------//
// НАЗНАЧЕНИЕ
// Предоставляет буферы для S29AL004D_8D flash device, чтобы
// принять поступающие данные.
//
// Входные параметры:
// PDDHandle - хэндл, используемый для идентификации устройства.
// BufferType - аргумент, идентифицирующий тип буфера: одноразмерный,
// двухразмерный, или кольцевой.
// *pBuffer - адрес буфера или первого буфера в цепочке буферов.
//
// Возвращаемое значение: код результата операции
u32 adi_pdd_Read(ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer)
{
ADI_DEV_1D_BUFFER *pBuff1D; // указатель на буфер
unsigned short *pusValue; // значение, прочитанное из flash
unsigned long *pulAbsoluteAddr; // абсолютный адрес для чтения
u32 Result; // возвращаемый код ошибки
// приведение нашего буфера к одноразмерному буферу
pBuff1D = (ADI_DEV_1D_BUFFER*)pBuffer;
// получение адреса для данных в буфере
pusValue = (unsigned short *)pBuff1D->Data;
// получение смещения на данные
pulAbsoluteAddr = (unsigned long *)pBuff1D->pAdditionalInfo;
Result = ReadFlash( *pulAbsoluteAddr, pusValue );
return(Result);
}
//----------- adi_pdd_Write ----------//
// НАЗНАЧЕНИЕ
// Предоставляет буферы для S29AL004D_8D flash device, используемые
// при передаче исходящих данных.
//
// Входные параметры:
// PDDHandle - хэндл, используемый для идентификации устройства.
// BufferType - аргумент, идентифицирующий тип буфера: одноразмерный,
// двухразмерный, или кольцевой.
// *pBuffer - адрес буфера или первого буфера в цепочке буферов.
//
// Возвращаемое значение: код результата операции
u32 adi_pdd_Write(ADI_DEV_PDD_HANDLE PDDHandle,
ADI_DEV_BUFFER_TYPE BufferType,
ADI_DEV_BUFFER *pBuffer)
{
ADI_DEV_1D_BUFFER *pBuff1D; // указатель на буфер
short *psValue; // значение, записываемое во flash
unsigned long *pulAbsoluteAddr; // абсолютный адрес для записи
unsigned long ulFlashStartAddr; // адрес начала flash
u32 Result; // возвращаемый код ошибки
// приведение нашего буфера к одноразмерному буферу
pBuff1D = (ADI_DEV_1D_BUFFER*)pBuffer;
// получение адреса для данных в буфере
psValue = (short *)pBuff1D->Data;
// получение смещения на данные
pulAbsoluteAddr = (unsigned long *)pBuff1D->pAdditionalInfo;
// получения адреса начала flash из абсолютного адреса
ulFlashStartAddr = GetFlashStartAddress(*pulAbsoluteAddr);
// разблокировка flash
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0554, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xa0 );
// программирование нашего актуального значения
Result = WriteFlash( *pulAbsoluteAddr, *psValue );
// гарантируем, что запись была успешной
Result = PollToggleBit(*pulAbsoluteAddr);
return(Result);
}
//----------- adi_pdd_Control ----------//
// НАЗНАЧЕНИЕ
// Эта функция устанавливает или считывает параметр конфигурации
// для S29AL004D_8D flash device.
//
// Входные параметры:
// PDDHandle - хэндл, используемый для идентификации устройства.
// Command - идентификатор команды
// *pArg - адрес параметра, зависящего от команды
//
// Возвращаемое значение: код результата операции
u32 adi_pdd_Control(ADI_DEV_PDD_HANDLE PDDHandle,
u32 Command,
void *pArg)
{
ERROR_CODE ErrorCode = NO_ERR;
COMMAND_STRUCT *pCmdStruct = (COMMAND_STRUCT *)pArg;
// switch для обработки команды
switch ( Command )
{
// Все стереть:
case CNTRL_ERASE_ALL:
ErrorCode = EraseFlash(pCmdStruct->SEraseAll.ulFlashStartAddr);
break;
// Стереть сектор:
case CNTRL_ERASE_SECT:
ErrorCode = EraseBlock( pCmdStruct->SEraseSect.nSectorNum,
pCmdStruct->SEraseSect.ulFlashStartAddr );
break;
// Получить код производителя и код устройства памяти:
case CNTRL_GET_CODES:
ErrorCode = GetCodes((int *)pCmdStruct->SGetCodes.pManCode,
(int *)pCmdStruct->SGetCodes.pDevCode,
(unsigned long)pCmdStruct->SGetCodes.ulFlashStartAddr);
break;
case CNTRL_GET_DESC:
//Чтение описания устройства:
pCmdStruct->SGetDesc.pDesc = pFlashDesc;
pCmdStruct->SGetDesc.pFlashCompany = pDeviceCompany;
break;
case CNTRL_GET_SECTNUM:
// Получить номер сектора в зависимости от адреса:
ErrorCode = GetSectorNumber( pCmdStruct->SGetSectNum.ulOffset,
(int *)pCmdStruct->SGetSectNum.pSectorNum );
break;
case CNTRL_GET_SECSTARTEND:
// Получить адресов начала и конца сектора по его номеру:
ErrorCode = GetSectorStartEnd( pCmdStruct->SSectStartEnd.pStartOffset,
pCmdStruct->SSectStartEnd.pEndOffset,
pCmdStruct->SSectStartEnd.nSectorNum );
break;
case CNTRL_GETNUM_SECTORS:
// Получить количество секторов:
pCmdStruct->SGetNumSectors.pnNumSectors[0] = gNumSectors;
break;
case CNTRL_RESET:
// Сброс:
ErrorCode = ResetFlash(pCmdStruct->SReset.ulFlashStartAddr);
break;
case ADI_DEV_CMD_SET_DATAFLOW:
// Запустить поток данных (команда, требуемая для всех драйверов
// устройств):
ErrorCode = NO_ERR;
break;
case ADI_DEV_CMD_SET_DATAFLOW_METHOD:
// Нет никаких действий, простой возврат:
break;
case ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT:
// Получить информацию о поддержке DMA (команда, требуемая для всех драйверов
// устройств):
(*(u32 *)pArg) = FALSE; // это устройство не поддерживается аппаратурой DMA
break;
default:
// Отсутствие команды, или не известная команда:
ErrorCode = UNKNOWN_COMMAND;
break;
}
return(ErrorCode);
}
//----- Вспомогательные функции ----//
//----------- ResetFlash ----------//
// НАЗНАЧЕНИЕ
// Посылает команду сброса для flash.
//
// Входные параметры:
// unsigned long ulStartAddr - адрес начала flash
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE ResetFlash(unsigned long ulAddr)
{
unsigned long ulFlashStartAddr; //адрес начала flash
// Получение начального адреса flash из абсолютного адреса
// Значение ulAddr должно идеально указывать на начало
// flash, однако здесь делается повторная проверка.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// Отправка команды сброса во flash:
WriteFlash( ulFlashStartAddr + 0x0554, 0xf0 );
// Сброс должен всегда завершиться успешно
return NO_ERR;
}
//----------- EraseFlash ----------//
// НАЗНАЧЕНИЕ
// Посылает flash команду "стереть все".
//
// Входные параметры:
// unsigned long ulStartAddr - адрес начала flash
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE EraseFlash(unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR;
int nBlock = 0; // индекс для каждого очищаемого блока
unsigned long ulFlashStartAddr; // адрес начала flash
// Получение адреса начала flash по абсолютному адресу.
// Значение ulAddr должно идеально указывать на начальный
// адрес flash, однако здесь делается повторная проверка.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// Очистка содержимого flash:
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0554, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0x80 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0554, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0AAA, 0x10 );
// Опрос с ожиданием завершения команды.
ErrorCode = PollToggleBit(ulFlashStartAddr + 0x0000);
return ErrorCode;
}
//----------- EraseBlock ----------//
// НАЗНАЧЕНИЕ
// Посылает flash команду "очистить блок".
//
// Входные параметры:
// int nBlock - номер блока (сектора) для стирания в нем данных
// unsigned long ulStartAddr - адрес начала flash
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE EraseBlock( int nBlock, unsigned long ulAddr )
{
ERROR_CODE ErrorCode = NO_ERR;
unsigned long ulSectStart = 0x0; //хранит начальное смещение для сектора
unsigned long ulSectEnd = 0x0; //хранит конечное смещение для сектора
// (хотя здесь это не используется)
unsigned long ulFlashStartAddr; //адрес начала flash
// Получение адреса начала flash по абсолютному адресу.
// Значение ulAddr должно идеально указывать на начальный
// адрес flash, однако здесь делается повторная проверка.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// Получение начального смещения сектора. Здесь мы автоматически
// также получим и конечное смещение сектора, хотя оно не нужно
// для актуальной очистки сектора.
GetSectorStartEnd( &ulSectStart, &ulSectEnd, nBlock );
// Отправка команды erase block:
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0xaa );
WriteFlash( (ulFlashStartAddr + 0x0554), 0x55 );
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0x80 );
WriteFlash( (ulFlashStartAddr + 0x0AAA), 0xaa );
WriteFlash( (ulFlashStartAddr + 0x0554), 0x55 );
// Последняя запись должна быть в пределах адресов блока.
WriteFlash( (ulFlashStartAddr + ulSectStart), 0x30 );
// Опрос с ожиданием завершения команды.
ErrorCode = PollToggleBit(ulFlashStartAddr + ulSectStart);
return ErrorCode;
}
//----------- PollToggleBit ----------//
// НАЗНАЧЕНИЕ
// Опрашивает флаг завершения (toggle bit) памяти flash, чтобы определить
// момент завершения текущей операции.
//
// Входные параметры:
// unsigned long ulAddr - адрес в flash
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE PollToggleBit(unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR;
unsigned short sVal1;
unsigned short sVal2;
// Чтение flash 1 раз
ReadFlash( ulAddr, &sVal1 );
while( ErrorCode == NO_ERR )
{
// Чтение 2 раза
ReadFlash( ulAddr, &sVal1 );
ReadFlash( ulAddr, &sVal2 );
// Операция XOR, чтобы определить побитную разницу.
sVal1 ^= sVal2;
// Определить, была ли смена состояния:
if( !(sVal1 & 0x40) )
break;
// Проверка бита ошибки:
if( !(sVal2 & 0x20) )
continue;
else
{
// Прочитать значение 2 раза
ReadFlash( ulAddr, &sVal1 );
ReadFlash( ulAddr, &sVal2 );
// Операция XOR, чтобы определить побитную разницу.
sVal1 ^= sVal2;
// Определить, была ли смена состояния:
if( !(sVal1 & 0x40) )
break;
else
{
ErrorCode = POLL_TIMEOUT;
ResetFlash(ulAddr);
}
}
}
return ErrorCode;
}
//----------- GetCodes ----------//
// НАЗНАЧЕНИЕ
// Посылает команду "auto select" устройству flash, которая
// позволяет получить коды производителя и устройства.
//
// Входные параметры:
// int *pnManCode - указатель для кода производителя
// int *pnDevCode - указатель для кода устройства
// unsigned long ulStartAddr - начальный адрес flash
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE GetCodes(int *pnManCode, int *pnDevCode, unsigned long ulAddr)
{
unsigned long ulFlashStartAddr; //начальный адрес flash
// Получение адреса начала flash по абсолютному адресу.
// Значение ulAddr должно идеально указывать на начальный
// адрес flash, однако здесь делается повторная проверка.
ulFlashStartAddr = GetFlashStartAddress(ulAddr);
// Отправка команды auto select:
WriteFlash( ulFlashStartAddr + 0x0aaa, 0xaa );
WriteFlash( ulFlashStartAddr + 0x0554, 0x55 );
WriteFlash( ulFlashStartAddr + 0x0aaa, 0x90 );
// Теперь можно прочитать коды:
ReadFlash( ulFlashStartAddr + 0x0000,(unsigned short *)pnManCode );
*pnManCode &= 0x00FF;
ReadFlash( ulFlashStartAddr + 0x0002, (unsigned short *)pnDevCode );
*pnDevCode &= 0x00FF;
if( *pnDevCode == 0x5B )
{
//Память flash размером 1 мегабайт (как у ADSP-BF538F)
gNumSectors = 19;
pFlashDesc = "S29AL008D(512 x 16)";
}
else
{
//Память flash размером 512 килобайт
gNumSectors = 11;
pFlashDesc = "S29AL004D(256 x 16)";
}
// Нужно послать какую-нибудь другую команду, и чтобы вывести устройство
// из режима auto select, мы просто посылает команду сброс. Это возвратит
// устройство обратно в режим чтения.
ResetFlash(ulAddr);
return NO_ERR;
}
//----------- GetSectorNumber ----------//
// НАЗНАЧЕНИЕ
// Получение номера сектора по смещению.
//
// Входные параметры:
// unsigned long ulAddr - абсолютный адрес
// int *pnSector - указатель на номер сектора
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE GetSectorNumber( unsigned long ulAddr, int *pnSector )
{
int nSector = 0;
int i;
int error_code = 1;
unsigned long ulMask; // маска смещения
unsigned long ulOffset; // смещение
unsigned long ulStartOff;
unsigned long ulEndOff;
ulMask = 0x3fffff;
ulOffset = ulAddr & ulMask;
for(i = 0; i < gNumSectors; i++)
{
GetSectorStartEnd(&ulStartOff, &ulEndOff, i);
if ( (ulOffset >= ulStartOff)
&& (ulOffset < = ulEndOff) )
{
error_code = 0;
nSector = i;
break;
}
}
// Если это допустимый сектор, установим его:
if (error_code == 0)
*pnSector = nSector;
// Иначе это недопустимый сектор, возврат кода ошибки:
else
return INVALID_SECTOR;
return NO_ERR;
}
//----------- GetSectorStartEnd ----------//
// НАЗНАЧЕНИЕ
// Получение адресов начала и конца сектора по его номеру.
//
// Входные параметры:
// unsigned long *ulStartOff - указатель на начальное смещение
// unsigned long *ulEndOff - указатель на конечное смещение
// int nSector - номер сектора
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE GetSectorStartEnd( unsigned long *ulStartOff,
unsigned long *ulEndOff,
int nSector )
{
long lSectorSize = 0;
long lChipNo;
int nSectorOffsetInChip;
long lChipSize;
lChipNo = nSector/gNumSectors;
nSectorOffsetInChip = nSector%gNumSectors;
lChipSize = 1024 * 1024;
if( nSectorOffsetInChip == 0 )
{
*ulStartOff = 0x0;
*ulEndOff = (*ulStartOff + 0x4000) - 1;
}
else if( nSectorOffsetInChip == 1 )
{
*ulStartOff = 0x4000;
*ulEndOff = (*ulStartOff + 0x2000) - 1;
}
else if( nSectorOffsetInChip == 2 )
{
*ulStartOff = 0x6000;
*ulEndOff = (*ulStartOff + 0x2000) - 1;
}
else if( nSectorOffsetInChip == 3 )
{
*ulStartOff = 0x8000;
*ulEndOff = (*ulStartOff + 0x8000) - 1;
}
else if( (nSectorOffsetInChip >= 4) && (nSectorOffsetInChip < = 18) )
{
*ulStartOff = (nSectorOffsetInChip - 3) * 0x10000;
*ulEndOff = (*ulStartOff + 0x10000) - 1;
}
else
return INVALID_SECTOR;
return NO_ERR;
}
//----------- GetFlashStartAddress ----------//
// НАЗНАЧЕНИЕ
// Получение начального адреса flash по абсолютному адресу.
//
// Входные параметры:
// unsigned long ulAddr - абсолютный адрес
//
// Возвращаемое значение: адрес
unsigned long GetFlashStartAddress( unsigned long ulAddr)
{
ERROR_CODE ErrorCode = NO_ERR;
unsigned long ulFlashStartAddr; //начальный адрес flash
unsigned long ulSectStartAddr; //адрес начала сектора
unsigned long ulSectEndAddr; //адрес конца сектора
unsigned long ulMask; //маска смещения
// Получение начального адреса flash из абсолютного адреса
GetSectorStartEnd( &ulSectStartAddr, &ulSectEndAddr, (gNumSectors-1));
ulMask = ~(ulSectEndAddr);
ulFlashStartAddr = ulAddr & ulMask;
return(ulFlashStartAddr);
}
//----------- ReadFlash ----------//
// НАЗНАЧЕНИЕ
// Читает данные из flash по указанному адресу.
//
// Входные параметры:
// unsigned long ulAddr - адрес, откуда нужно читать
// u16* pnValue - указатель, куда нужно сохранить данные
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE ReadFlash( unsigned long ulAddr, unsigned short *pusValue )
{
// Запрет прерываний перед выполнением операции load или store
// [см. предупреждение на странице 6-71 руководства ADSP-BF533]
unsigned int uiSaveInts = cli();
// Установка нашего адреса flash, откуда хотим читать:
unsigned short *pFlashAddr = (unsigned short *)(ulAddr);
// Чтение значения:
*pusValue = (unsigned short)*pFlashAddr;
// Разрешение прерываний
sti(uiSaveInts);
return NO_ERR;
}
//----------- WriteFlash ----------//
// НАЗНАЧЕНИЕ
// Запись значения по указанному адресу flash.
//
// Входные параметры:
// unsigned long ulAddr - адрес, куда нужно записывать
// unsigned short nValue - значение для записи
//
// Возвращаемое значение:
// ERROR_CODE - значение кода ошибки, если она была
// NO_ERR - или если ошибки не было
ERROR_CODE WriteFlash( unsigned long ulAddr, unsigned short usValue )
{
// Запрет прерываний перед выполнением операции load или store
// [см. предупреждение на странице 6-71 руководства ADSP-BF533]
unsigned int uiSaveInts = cli();
// Установка адреса
unsigned short *pFlashAddr = (unsigned short *)(ulAddr);
*pFlashAddr = usValue;
// Разрешение прерываний
sti(uiSaveInts);
return NO_ERR;
}