ADSP-BF538F: драйвер встроенной FLASH-памяти S29AL008D |
![]() |
Добавил(а) microsin | ||||||||||||||||
В процессоре ADSP-BF538F применяется встроенная FLASH-память на основе микросхемы S29AL008D (8 мегабит/1 мегабайт, организация 512K x 16 бита с возможностью чтения как 1M x 8 бит). Обычно эту память применяют для загрузки процессора (для хранения образа LDR-файла [3] кода программы). Чтобы использовать эту память для самопрограммирования (например, для хранения энергонезависимых констант или реализации загрузчика) необходимо реализовать алгоритм программирования этой памяти, описанный в даташите на микросхему [1]. К счастью, в составе библиотек VisualDSP есть код драйвера для этой микросхемы adi_S29AL004D_8D.c. Этот драйвер предназначен для программирования микросхем FLASH-памяти S29AL004D и S29AL008D. Код драйвера adi_S29AL004D_8D.c можно найти в каталоге %ProgramFiles% \ Analog Devices \ VisualDSP 5.0 \ Blackfin \ lib \ src \ drivers \ flash \ S29AL004D_8D, заголовочный файл adi_S29AL004D_8D.h находится в каталоге %ProgramFiles% \ Analog Devices \ VisualDSP 5.0 \ Blackfin \ include \ drivers \ flash. Пример использования можно найти в проекте %ProgramFiles \ Analog Devices \ VisualDSP 5.0 \ Blackfin \ Examples \ ADSP-BF538F EZ-KIT Lite \ Flash Programmer \ InternalFlash (файл main.c). Однако в самом драйвере adi_S29AL004D_8D нашел ошибку. Оригинальный код компилируется, но не работает. Неправильно срабатывает определение количества секторов Flash (gNumSectors) в функции GetCodes, потому что для этого вычисления используется функция GetFlashStartAddress, которая в свою очередь использует GetSectorStartEnd с параметром gNumSectors. Получается попытка поймать себя за хвост - из-за того, что изначально gNumSectors равно 0, то GetSectorStartEnd вычисляет адреса неправильно, следовательно GetFlashStartAddress возвращает неверный адрес, и в результате тип микросхемы определяется неправильно и gNumSectors получает ошибочное значение 11 вместо 19. Исправление ошибки: unsigned long GetFlashStartAddress( unsigned long ulAddr) { /* 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); */ return 0x20000000; // Сюда подставляется адрес FLASH, который он занимает // в адресном пространстве ADSP-BF538F. } [Принцип работы драйвера adi_S29AL004D_8D] Драйвер реализует чтение и запись микросхем S29AL004D и S29AL008D на низком уровне, порциями по 2 байта (через одномерный буфер ADI_DEV_1D_BUFFER). Запись сделана блокирующей с ожиданием готовности микросхемы, т. е. для записи каждых 2 байт прерывания запрещаются, выполняется запись, и процессор в функции PollToggleBit выполняет пустые циклы опроса с ожиданием, пока операция записи не завершится. Запись осуществляется нулевыми битами, т. е. если бит ячейки памяти установлен в лог. 0, то записать в единицу его уже нельзя. Таким образом, данные успешно запишутся произвольными данными только в том случае, если исходное состояние всех байт ячеек данных в 0xFF. Поэтому, если нужно поменять хотя бы один байт таким образом, чтобы у него некоторые биты перешли из состояния лог. 0 в лог. 1, то это будет возможно только если предварительно стереть весть сектор FLASH-памяти целиком. Драйвер adi_S29AL004D_8D в терминологии ADI это стандартный драйвер, и управляется он обычным образом [2], как это принято в модели библиотек Системных Служб (System Services Libraries, SSL) компании Analog Devices. adi_dev_Open открывает драйвер и выполняет его необходимую инициализацию. adi_dev_Control конфигурирует драйвер - устанавливает способ обмена данными, обеспечивает управление драйвером и получение от него служебной информации (информация о микросхеме, количество секторов памяти FLASH, начальный и конечный адрес нужного сектора, стирание всей микросхемы или конкретного сектора, получение номера сектора по абсолютному адресу). adi_dev_Read выполняет чтение данных из микросхемы FLASH. adi_dev_Write выполняет запись данных в микросхему FLASH. adi_dev_Close закрывает драйвер и освобождает выделенные под него ресурсы. [Пример Flash Programmer \ InternalFlash] Пример проекта Flash Programmer \ InternalFlash для процессора ADSP-BF538 показывает, как использовать драйвер adi_S29AL004D_8D для программирования микросхем FLASH-памяти S29AL004D и S29AL008D. Показана инициализация драйвера и реализация функций для манипулирования содержимым памяти микросхем (см. таблицу ниже).
Пример получился перегружен ненужным кодом и имеет ошибки. Что не так: 1. Реализован ненужный код, который проверяет записанные в память данные. Ветки с проверкой и без проверки данных дублируются, что приводит к разрастанию кода. 2. В функции WriteData есть ошибка - в цикле записи данных вызывается adi_dev_Control вместо adi_dev_Write, в результате чего ветка, которая должна работать без проверки памяти при записи на самом деле ничего в память не пишет. 3. Код функций FillData и WriteData неоправданно запутан. 4. Используется динамическое выделение памяти под составление карты памяти секторов микросхемы, что ИМХО не нужно, потому что память все равно обычно записывается в пределах одного сектора, и достаточно вызвать один раз функцию определения начального и конечного адреса каждого сектора в процессе чтения и записи. 5. Функция чтения данных ReadData фактически бесполезна, поскольку микросхема все равно включена в адресное пространство, и её данные можно читать напрямую. 6. Для чтения / записи данных выделяется динамический буфер размером в 0x600 байт, что ИМХО также бесполезно, поскольку не дает никакого прироста производительности при записи, а чтение можно осуществлять напрямую обращением к адресному пространству. [Ссылки] 1. S29AL008D 8 Mbit (1M x 8-Bit / 512 K x 16-Bit), 3 V Boot Sector Flash site:cypress.com. |