需求

使用 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 <==========");
}

参考