7.3 KiB
Драйвер внешней Flash-памяти DS_W25X40CL
Низкоуровневая библиотека на Си для работы с энергонезависимой NOR Flash-памятью Winbond W25X40CL (объем 4 Мбит / 512 Килобайт) по интерфейсу SPI. Память разбита на 8 блоков, 128 секторов по 4 КБ и 2048 страниц по 256 байт.
📌 Особенности реализации
- Блочная очистка и запись: Реализована поддержка постраничной записи (Page Program, до 256 байт) и посекторного стирания (Sector Erase, 4 КБ), что является обязательным требованием для NOR Flash архитектуры.
- Контроль занятости (Busy Checking): Функции записи и стирания автоматически опрашивают первый регистр статуса памяти (Status Register 1, бит
BUSY), блокируя выполнение до тех пор, пока чип физически не завершит операцию во внутренней памяти. - Идентификация чипа: Наличие функции чтения JEDEC ID позволяет программно проверить подлинность микросхемы и успешность подключения по шине SPI при старте системы.
🚀 Способ добавления в проект (Git Submodule)
Драйвер подключается к вашему текущему проекту как подмодуль Git, изолируя код управления памятью от прикладной логики.
1. Подключение подмодуля
Выполните команду в корневом каталоге вашего проекта:
git submodule add https://domstudent.ru Library/DS_W25X40CL
2. Автоматическое обновление CMake
Запустите PowerShell-скрипт для автоматического добавления путей Inc и файлов Src подмодуля памяти в структуру сборки проекта:
cd tools/
./UpdateCMakeList.ps1
🔌 Схема подключения (SPI)
Интерфейс SPI настраивается в CubeMX в режиме Full-Duplex Master (или Transmit Only, если чтение не требуется, но для памяти чтение обязательно), Data Size: 8 Bits, First Bit: MSB First. Режим SPI: CPOL = Low (0), CPHA = 1 Edge (0) (SPI Mode 0) или CPOL = High, CPHA = 2 Edge (SPI Mode 3).
| Вывод микросхемы W25X40CL | Вывод STM32 | Назначение |
|---|---|---|
| /CS (Pin 1) | Любой GPIO_Output | Выбор чипа (Chip Select, активен в 0) |
| DO (IO1) (Pin 2) | SPIx_MISO | Выход данных (Master Input Slave Output) |
| /WP (Pin 3) | 3.3V или GPIO | Защита от записи (Write Protect, притянуть к 3.3В) |
| GND (Pin 4) | GND | Общая земля |
| DI (IO0) (Pin 5) | SPIx_MOSI | Вход данных (Master Output Slave Input) |
| CLK (Pin 6) | SPIx_SCK | Тактовая линия шины SPI |
| /HOLD (Pin 7) | 3.3V или GPIO | Удержание шины (Hold, притянуть к 3.3В) |
| VCC (Pin 8) | 3.3V | Питание микросхемы (2.3V — 3.6V) |
💻 Пример использования в main.c
Помните специфику NOR Flash: перед записью данных в любую область памяти, этот сектор обязательно нужно стереть, иначе новые данные логически смешаются со старыми.
#include "DS_W25X40CL.h"
extern SPI_HandleTypeDef hspi1;
DS_W25X40CL external_flash;
uint8_t write_buffer[256];
uint8_t read_buffer[256];
int main(void) {
// ... Автоматическая инициализация HAL, GPIO, SPI ...
/* 1. Инициализация дескриптора памяти */
DS_W25X40CL_Init(&external_flash, &hspi1, GPIOA, GPIO_PIN_4);
/* 2. Проверка связи с чипом (Чтение Manufacturer и Device ID) */
uint32_t jedec_id = DS_W25X40CL_ReadID(&external_flash);
if (jedec_id == 0xEF3013) { // 0xEF - Winbond, 0x3013 - W25X40CL
// Память успешно опознана контроллером!
}
/* 3. Запись и чтение данных (Пример работы с Сектором 0, Адрес 0x000000) */
// Подготовка тестовых данных
for(uint16_t i=0; i<256; i++) write_buffer[i] = i;
// ШАГ A: Стираем сектор (4 КБ) перед записью
DS_W25X40CL_EraseSector(&external_flash, 0x000000);
// ШАГ Б: Записываем страницу памяти (макс 256 байт)
DS_W25X40CL_WritePage(&external_flash, 0x000000, write_buffer, 256);
// ШАГ В: Считываем данные обратно для проверки
DS_W25X40CL_ReadData(&external_flash, 0x000000, read_buffer, 256);
while (1) {
// Основной цикл
}
}
📋 Справочник API функций
void DS_W25X40CL_Init(DS_W25X40CL *flash, SPI_HandleTypeDef *hspi, GPIO_TypeDef *CS_Port, uint16_t CS_Pin)
Выполняет логическую инициализацию структуры драйвера, привязывает к ней шину SPI и программный пин управления защелкой /CS.
uint32_t DS_W25X40CL_ReadID(DS_W25X40CL *flash)
Отправляет команду 0x9F (Read JEDEC ID) и вычитывает 3 байта ответа. Возвращает упакованное 24-битное число, содержащее ID производителя и емкость чипа.
void DS_W25X40CL_EraseSector(DS_W25X40CL *flash, uint32_t SectorAddress)
Отправляет команду разрешения записи 0x06 (Write Enable), затем команду стирания сектора 0x20 и его 24-битный адрес. Ожидает окончания процесса стирания через опрос регистра статуса.
void DS_W25X40CL_WritePage(DS_W25X40CL *flash, uint32_t PageAddress, uint8_t *pData, uint16_t Size)
Записывает массив данных размером до 256 байт в пределах одной физической страницы памяти (команда 0x02). Автоматически контролирует бит готовности чипа.
void DS_W25X40CL_ReadData(DS_W25X40CL *flash, uint32_t Address, uint8_t *pData, uint16_t Size)
Выполняет непрерывное чтение данных любого объема, начиная с указанного 24-битного адреса памяти (команда 0x03). Автоматически инкрементирует адрес на стороне чипа во время удержания линии /CS.