需求
使用 STM32U575 主控芯片,使用 OSPI 驱动 W25Q128。
解决
代码如下:
/*
* flash.cpp
*
* Created on: Oct 31, 2023
* Author: Administrator
*/
#include "flash.h"
#include "main.h"
#include "stm32u5xx_hal_ospi.h"
#include "octospi.h"
#include "config.h"
#define PIN_POWER_LOW HAL_GPIO_WritePin(Flash_Power_En_GPIO_Port, Flash_Power_En_Pin, GPIO_PIN_RESET)
#define PIN_POWER_HIGH HAL_GPIO_WritePin(Flash_Power_En_GPIO_Port, Flash_Power_En_Pin, GPIO_PIN_SET)
Flash flash{};
static void PowerPinControl(bool b)
{
if (b) {
PIN_POWER_LOW;
} else {
PIN_POWER_HIGH;
}
}
static void OspiCmdParam(const W25qxxHal::Command& cmd, OSPI_RegularCmdTypeDef& s_command)
{
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
switch (cmd.instruction_mode) {
case W25qxxHal::kInstructionModeLine1:
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
break;
case W25qxxHal::kInstructionModeLine4:
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;
break;
default:
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_NONE;
break;
}
s_command.Instruction = cmd.instruction;
switch (cmd.address_mode) {
case W25qxxHal::kAddressModeLine1:
s_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
break;
case W25qxxHal::kAddressModeLine4:
s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES;
break;
default:
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
break;
}
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
switch (cmd.data_mode) {
case W25qxxHal::kDataModeLine1:
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
break;
case W25qxxHal::kDataModeLine4:
s_command.DataMode = HAL_OSPI_DATA_4_LINES;
break;
default:
s_command.DataMode = HAL_OSPI_DATA_NONE;
break;
}
s_command.DummyCycles = cmd.dummy_cycles;
s_command.NbData = cmd.num_of_data;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
switch (cmd.sioo_mode) {
case W25qxxHal::kSIOOModeInstEveryCmd:
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
break;
case W25qxxHal::kSIOOModeInstOnlyFirstCmd:
s_command.SIOOMode = HAL_OSPI_SIOO_INST_ONLY_FIRST_CMD;
break;
default:
s_command.SIOOMode = 0;
break;
}
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
switch (cmd.address_size) {
case W25qxxHal::kAddressSize8:
s_command.AddressSize = HAL_OSPI_ADDRESS_8_BITS;
break;
case W25qxxHal::kAddressSize16:
s_command.AddressSize = HAL_OSPI_ADDRESS_16_BITS;
break;
case W25qxxHal::kAddressSize24:
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
break;
case W25qxxHal::kAddressSize32:
s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
break;
default:
s_command.AddressSize = 0;
break;
}
s_command.Address = cmd.address;
}
static bool OspiCommand(const W25qxxHal::Command& cmd)
{
OSPI_RegularCmdTypeDef s_command {};
OspiCmdParam(cmd, s_command);
return (!HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE));
}
static bool OspiPoll(const W25qxxHal::Poll& poll)
{
OSPI_AutoPollingTypeDef s_config;
s_config.Match = poll.match;
s_config.Mask = poll.mask;
s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;
s_config.Interval = poll.interval;
s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
uint32_t timeout;
if (poll.timeout == W25qxxHal::kPollTimeHalDefault) {
timeout = HAL_OSPI_TIMEOUT_DEFAULT_VALUE;
} else {
timeout = poll.timeout;
}
return (!HAL_OSPI_AutoPolling(&hospi1, &s_config, timeout));
}
static bool OspiWrite(const uint8_t * p)
{
return (!HAL_OSPI_Transmit(&hospi1, const_cast<uint8_t *>(p), HAL_OSPI_TIMEOUT_DEFAULT_VALUE));
}
static bool OspiRead(uint8_t * p)
{
return (!HAL_OSPI_Receive(&hospi1, p, HAL_OSPI_TIMEOUT_DEFAULT_VALUE));
}
Flash::Flash() : w25qxx_hal_({OspiCommand, OspiPoll, OspiWrite, OspiRead, W25qxxHal::kIdW25Q128})
{
}
void Flash::On()
{
if (on_) {
return;
}
PowerPinControl(true);
w25qxx_hal_.Init();
on_ = true;
}
void Flash::Off()
{
if (!on_) {
return;
}
PowerPinControl(false);
on_ = false;
}
bool Flash::Read(uint8_t * buf, uint32_t address, uint32_t size)
{
return w25qxx_hal_.Read(buf, address, size);
}
uint8_t Flash::ReadStatusRegister(StatusRegister reg)
{
switch (reg) {
case kStatusRegister1:
return w25qxx_hal_.ReadStatusRegister(W25qxxHal::kInstructionReadStatus1);
break;
case kStatusRegister2:
return w25qxx_hal_.ReadStatusRegister(W25qxxHal::kInstructionReadStatus2);
break;
case kStatusRegister3:
return w25qxx_hal_.ReadStatusRegister(W25qxxHal::kInstructionReadStatus3);
break;
default:
return 0;
break;
}
}
bool Flash::Write(uint32_t address, const uint8_t * buf, uint32_t size)
{
return w25qxx_hal_.Write(address, buf, size);
}
bool Flash::ChipErase()
{
return w25qxx_hal_.EraseChip();
}
bool Flash::EraseSector(uint32_t address, uint32_t length)
{
uint32_t address_end = address + length - 1;
uint32_t sector_start = address / W25qxxHal::kSectorSize;
uint32_t sector_end = address_end / W25qxxHal::kSectorSize;
for (uint32_t i = 0; i < (sector_end - sector_start + 1); i++) {
uint32_t sector_address = (sector_start + i) * W25qxxHal::kSectorSize;
w25qxx_hal_.EraseSector(sector_address);
}
return true;
}
#include <cstring>
#include "log.h"
void FlashTest()
{
LOGD("FlashTest: begin ==========>");
flash.On();
uint8_t value;
bool ret;
// Test: chip erase
LOGD("FlashTest: ==> chip erase <==");
ret = flash.ChipErase();
ASSERT_FAIL((ret == true), "chip erase error");
// Test: read status1
LOGD("FlashTest: ==> read status1 <==");
value = flash.ReadStatusRegister(Flash::kStatusRegister1);
LOGD("FlashTest: status 1 = %x", value);
ASSERT_FAIL((value == 0), "read status1 error");
// Test: read status2
LOGD("FlashTest: ==> read status2 <==");
value = flash.ReadStatusRegister(Flash::kStatusRegister2);
LOGD("FlashTest: status 2 = %x", value);
ASSERT_FAIL((value == 2), "read status2 error");
// Test: read status3
LOGD("FlashTest: ==> read status3 <==");
value = flash.ReadStatusRegister(Flash::kStatusRegister3);
LOGD("FlashTest: status 3 = %x", value);
ASSERT_FAIL((value == 0x60), "read status3 error");
// Test: write over page
LOGD("FlashTest: ==> write over page <==");
uint8_t w[20];
uint32_t address = 250;
for (size_t i = 0; i < sizeof(w); i++) {
w[i] = i + 1;
}
ret = flash.Write(address, w, sizeof(w));
ASSERT_FAIL((ret == true), "write over page error");
LOGD("FlashTest: write page = %x, %x, %x, %x, %x, %x, %x, %x; "
"%x, %x, %x, %x, %x, %x, %x, %x, "
"%x, %x, %x, %x, ",
w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7],
w[8], w[9], w[10], w[11], w[12], w[13], w[14], w[15],
w[16], w[17], w[18], w[19]);
// Test: read over page
LOGD("FlashTest: ==> read over page <==");
uint8_t r[30];
memset(r, 0, sizeof(r));
ret = flash.Read(r, address, sizeof(r));
ASSERT_FAIL((ret == true), "read over page error");
LOGD("FlashTest: read page = %x, %x, %x, %x, %x, %x, %x, %x; "
"%x, %x, %x, %x, %x, %x, %x, %x, "
"%x, %x, %x, %x, %x, %x, %x, %x, ",
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7],
r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]);
// Test: write over sector
LOGD("FlashTest: ==> write over sector <==");
address = 4080;
for (size_t i = 0; i < sizeof(w); i++) {
w[i] = 2 * i + 1;
}
ret = flash.Write(address, w, sizeof(w));
ASSERT_FAIL((ret == true), "write over sector error");
LOGD("FlashTest: write sector = %x, %x, %x, %x, %x, %x, %x, %x; "
"%x, %x, %x, %x, %x, %x, %x, %x, "
"%x, %x, %x, %x, ",
w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7],
w[8], w[9], w[10], w[11], w[12], w[13], w[14], w[15],
w[16], w[17], w[18], w[19]);
// Test: read over sector
LOGD("FlashTest: ==> read over sector <==");
memset(r, 0, sizeof(r));
ret = flash.Read(r, address, sizeof(r));
ASSERT_FAIL((ret == true), "read over sector error");
LOGD("FlashTest: read sector = %x, %x, %x, %x, %x, %x, %x, %x; "
"%x, %x, %x, %x, %x, %x, %x, %x, "
"%x, %x, %x, %x, %x, %x, %x, %x, ",
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7],
r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15],
r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]);
// check erase sector by breakpoint
// [10, 30], [235, 255], [400, 420]
ret = flash.Write(10, w, sizeof(w));
ret = flash.Write(235, w, sizeof(w));
ret = flash.Write(400, w, sizeof(w));
uint8_t buf [4];
for (size_t i = 0; i < sizeof(buf); i++) {
buf[i] = i + 1;
}
// ret = flash.Write(4605, buf, sizeof(buf));
// ASSERT_FAIL((ret == true), "write data error");
int32_t data_address_start = 0;//4352;
for (int i = 0; i < 4194240; i++) {
ret = flash.Write(data_address_start + i * sizeof(buf), buf, sizeof(buf));
LOGD("FlashTest: write with 32-bit, i = %d", i);
ASSERT_FAIL((ret == true), "write data error");
}
flash.Off();
LOGD("FlashTest: end <==========");
}