# Драйвер внешней 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. Подключение подмодуля Выполните команду в корневом каталоге вашего проекта: ```bash git submodule add https://domstudent.ru Library/DS_W25X40CL ``` ### 2. Автоматическое обновление CMake Запустите PowerShell-скрипт для автоматического добавления путей `Inc` и файлов `Src` подмодуля памяти в структуру сборки проекта: ```powershell 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: перед записью данных в любую область памяти, этот сектор **обязательно нужно стереть**, иначе новые данные логически смешаются со старыми. ```c #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`.