Difference between revisions of "STM32 W25Qxx"
(→init) |
|||
Line 50: | Line 50: | ||
=== init === | === init === | ||
− | + | The init function does a couple of things. It stores the SPI, and CS in the handler and attempt to retrieve a chip ID from the w25qxx device. Based on this chip ID, the memory layout of the device is stored. | |
+ | |||
+ | <pre> | ||
+ | W25QXX_result_t w25qxx_init(W25QXX_HandleTypeDef *w25qxx, | ||
+ | SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) { | ||
+ | |||
+ | W25QXX_result_t result = W25QXX_Ok; | ||
+ | |||
+ | DBG("w25qxx_init"); | ||
+ | |||
+ | w25qxx->spiHandle = hspi; | ||
+ | w25qxx->cs_port = cs_port; | ||
+ | w25qxx->cs_pin = cs_pin; | ||
+ | |||
+ | uint32_t id = w25qxx_read_id(w25qxx); | ||
+ | if (id) { | ||
+ | w25qxx->manufacturer_id = (uint8_t) (id >> 16); | ||
+ | w25qxx->device_id = (uint16_t) (id & 0xFFFF); | ||
+ | |||
+ | switch (w25qxx->manufacturer_id) { | ||
+ | case W25QXX_MANUFACTURER_WINBOND: | ||
+ | |||
+ | w25qxx->block_size = 0x10000; | ||
+ | w25qxx->sector_size = 0x1000; | ||
+ | w25qxx->sectors_in_block = 0x0f; | ||
+ | w25qxx->page_size = 0x100; | ||
+ | w25qxx->pages_in_sector = 0x10; | ||
+ | |||
+ | switch (w25qxx->device_id) { | ||
+ | case 0x4018: | ||
+ | w25qxx->block_count = 0x100; | ||
+ | break; | ||
+ | default: | ||
+ | DBG("Unknown Winbond device") | ||
+ | ; | ||
+ | result = W25QXX_Err; | ||
+ | } | ||
+ | |||
+ | break; | ||
+ | default: | ||
+ | DBG("Unknown manufacturer") | ||
+ | ; | ||
+ | result = W25QXX_Err; | ||
+ | } | ||
+ | } else { | ||
+ | result = W25QXX_Err; | ||
+ | } | ||
+ | |||
+ | if (result == W25QXX_Err) { | ||
+ | // Zero the handle so it is clear initialization failed! | ||
+ | memset(w25qxx, 0, sizeof(W25QXX_HandleTypeDef)); | ||
+ | } | ||
+ | |||
+ | return result; | ||
+ | |||
+ | } | ||
+ | </pre> | ||
=== read === | === read === |
Revision as of 03:10, 1 March 2022
This page describes how to use W25Qxx Serial Flash/EEPROM chips with the STM32. The examples and code on this page has been developed on and for the Black Pill development board.
The resulting library can be found here: https://github.com/lbthomsen/stm32-w25qxx
An example using this library can be found here: https://github.com/lbthomsen/blackpill/tree/master/eeprom
Black Pill EEPROM
The Black Pill boards, whether original or copy, all includes an unpopulated footprint on the back side, with space for a "generic eeprom". This footprint can be populated with a wide range of compatible EEPROM chips.
The examples on this page are all using a Black Pill with a Winbond W25Q128.
The original Black Pill board have been going through a few changes which can be a bit confusing. In all cases, the footprint is wired up to SPI1, but it is important to notice that on some boards the DO (MISO) pin of the W25Qxx is wired to PA6, and on some it is wired to PB4. Be certain to check which one is actually used.
In our case, the Black Pill board is clearly not an original, and PA6 is being used throughout:
W25Qxx Library
To make the W25Qxx easy to use, we need to develop a library with a set of simple functions:
W25QXX_result_t w25qxx_init(W25QXX_HandleTypeDef *w25qxx, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin); W25QXX_result_t w25qxx_read(W25QXX_HandleTypeDef *w25qxx, uint32_t address, uint8_t *buf, uint32_t len); W25QXX_result_t w25qxx_write(W25QXX_HandleTypeDef *w25qxx, uint32_t address, uint8_t *buf, uint32_t len); W25QXX_result_t w25qxx_erase(W25QXX_HandleTypeDef *w25qxx, uint32_t address, uint32_t len);
We will use a handle to keep information such as GPIO pins.
typedef struct { SPI_HandleTypeDef *spiHandle; GPIO_TypeDef *cs_port; uint16_t cs_pin; uint8_t manufacturer_id; uint16_t device_id; uint32_t block_size; uint32_t block_count; uint32_t sector_size; uint32_t sectors_in_block; uint32_t page_size; uint32_t pages_in_sector; } W25QXX_HandleTypeDef;
init
The init function does a couple of things. It stores the SPI, and CS in the handler and attempt to retrieve a chip ID from the w25qxx device. Based on this chip ID, the memory layout of the device is stored.
W25QXX_result_t w25qxx_init(W25QXX_HandleTypeDef *w25qxx, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) { W25QXX_result_t result = W25QXX_Ok; DBG("w25qxx_init"); w25qxx->spiHandle = hspi; w25qxx->cs_port = cs_port; w25qxx->cs_pin = cs_pin; uint32_t id = w25qxx_read_id(w25qxx); if (id) { w25qxx->manufacturer_id = (uint8_t) (id >> 16); w25qxx->device_id = (uint16_t) (id & 0xFFFF); switch (w25qxx->manufacturer_id) { case W25QXX_MANUFACTURER_WINBOND: w25qxx->block_size = 0x10000; w25qxx->sector_size = 0x1000; w25qxx->sectors_in_block = 0x0f; w25qxx->page_size = 0x100; w25qxx->pages_in_sector = 0x10; switch (w25qxx->device_id) { case 0x4018: w25qxx->block_count = 0x100; break; default: DBG("Unknown Winbond device") ; result = W25QXX_Err; } break; default: DBG("Unknown manufacturer") ; result = W25QXX_Err; } } else { result = W25QXX_Err; } if (result == W25QXX_Err) { // Zero the handle so it is clear initialization failed! memset(w25qxx, 0, sizeof(W25QXX_HandleTypeDef)); } return result; }
read
To be added
write
To be added
erase
To be added
Using the library
To be added