
W25QXX — Семейство микросхем SPI флеш-памяти от компании Winbond. Широко применяются на отладочных платах микроконтроллеров и могут использоваться, как EEPROM (более 100 000 циклов перезаписи).
ВНИМАНИЕ: На видео неточность! SPI1 должен работать в режиме Full-Duplex Master. На видео — Transmit Only Master. Хотя, по какой-то причине и так на флешку пишет и с флешки читает (возможно, библиотека W25Qxx сама исправляет при инициализации), но нужно выбирать Full-Duplex Master.

Скачать библиотеку W25qxx для STM32CubeIDE (Zip)
Enable SPI and a Gpio as output(CS pin).Connect WP and HOLD to VCC. Select software CS pin. Config w25qxxConf.h. Call W25qxx_Init(). After init, you can watch w25qxx struct.(Chip ID,page size,sector size and ...) In Read/Write Function, you can put 0 to NumByteToRead/NumByteToWrite parameter to maximum. Dont forget to erase sector/block before write. |

ВНИМАНИЕ: Включение SPI, назначение ножек и добавление библиотеки в STM32CubeIDE смотрите в видео выше.
Функции библиотеки
bool W25qxx_Init(void); void W25qxx_EraseChip(void); void W25qxx_EraseSector(uint32_t SectorAddr); void W25qxx_EraseBlock(uint32_t BlockAddr); uint32_t W25qxx_PageToSector(uint32_t PageAddress); uint32_t W25qxx_PageToBlock(uint32_t PageAddress); uint32_t W25qxx_SectorToBlock(uint32_t SectorAddress); uint32_t W25qxx_SectorToPage(uint32_t SectorAddress); uint32_t W25qxx_BlockToPage(uint32_t BlockAddress); bool W25qxx_IsEmptyPage(uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_PageSize); bool W25qxx_IsEmptySector(uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_SectorSize); bool W25qxx_IsEmptyBlock(uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToCheck_up_to_BlockSize); void W25qxx_WriteByte(uint8_t pBuffer, uint32_t Bytes_Address); void W25qxx_WritePage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_PageSize); void W25qxx_WriteSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_SectorSize); void W25qxx_WriteBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToWrite_up_to_BlockSize); void W25qxx_ReadByte(uint8_t *pBuffer, uint32_t Bytes_Address); void W25qxx_ReadBytes(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead); void W25qxx_ReadPage(uint8_t *pBuffer, uint32_t Page_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_PageSize); void W25qxx_ReadSector(uint8_t *pBuffer, uint32_t Sector_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_SectorSize); void W25qxx_ReadBlock(uint8_t *pBuffer, uint32_t Block_Address, uint32_t OffsetInByte, uint32_t NumByteToRead_up_to_BlockSize); |
Структура флеш памяти W25QXX
Pages (256 bytes) — > Sectors (4096 bytes) -> Blocks (65536 bytes)
Вся память разбита на блоки, количество которых зависит от общего объема памяти.
Размер каждого блока составляет 65536 байт.
Каждый блок состоит из 16 секторов по 4096 байт.
Каждый сектор состоит из 16 страниц по 256 байт каждая.
ВНИМАНИЕ: Перед записью данных нужно стереть весь сектор целиком! Иначе перезапись данных внутри сектора производиться не будет.
void W25qxx_EraseSector(uint32_t SectorAddr);
Читать данные можно всегда любым удобным способом.
Инициализация
Подключаем библиотеку.
... /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ ... #include "w25qxx.h" /* USER CODE END Includes */ ... |
Вызываем процедуру инициализации 1 раз перед бесконечным циклом.
W25qxx_Init(); |
Чтение данных
Побайтно
W25qxx_ReadByte(Buf(uint8_t), Addr(0-...)); uint8_t buf[64] = {0,}; W25qxx_ReadByte(&buf[0], 0); W25qxx_ReadByte(&buf[1], 1); W25qxx_ReadByte(&buf[2], 2); ... |
Сразу несколько байт в буфер pbuf
uint8_t pbuf[256]; W25qxx_ReadBytes(pbuf,0,256); |
Пока не проверил за ненадобностью, можно ли с помощью W25qxx_ReadBytes читать несколько байтов сразу из нескольких страниц/секторов/блоков. Для чтения большого количества данных лучше использовать функции чтения страниц, секторов и блоков.
Запись данных
Перед записью данных необходимо стереть сектор или блок
W25qxx_EraseSector(Addr(0-...)); W25qxx_EraseSector(0); W25qxx_EraseSector(1); ... |
Далее записываем Байты, страницу, сектор или блок.
Буфер записи 256 байт (1 страница).
uint8_t pbuf[256]; ... W25qxx_WritePage(pbuf,0,0,0); |
Как преобразовать однобайтное число в четырехбайтное (и наоборот)
Так как чтение происходит побайтно, максимальное значение однобайтного (8-битного) числа от 0 до 255 (256 значений). Если требуется записать или прочитать 32-битное число (четырехбайтное), необходимо его преобразовать из/в массив из четырех 8-байтных чисел.
Нижепредложенный способ хорошо и быстро работает. Для меня такой способ более привычен. Если вам такой способ по какой-то причине не нравится, используйте другие функции.
Чтобы получить 32 бит целое число из 4 отдельных байтов, можно произвести следующие расчеты
uint32_t TestINT32; uint8_t pbuf[4]; TestINT32 = pbuf[0]*16777216 + pbuf[1]*65536 + pbuf[2]*256 + pbuf[3]; |
Для разбития 32 разрядного числа на 4 байта расчеты выглядят так
pbuf[0] = TestINT32/16777216; pbuf[1] = TestINT32/65536; pbuf[2] = TestINT32/256; pbuf[3] = TestINT32-pbuf[2]*256; |

(2 оценок, среднее: 4,50 из 5)