STM32(H7S7)学习记录-9:XSPI Octal Flash内存映射

        最近在使用STM32H7S78-DK这块板的时候,发现官方只给了PSRAM(hexa spi)的内存映射的例子,但是官方没有给Octal_flash的内存映射例子。在此记录一下。目前STM32H7RS软件包还是V1.0。cubeMX版本是6.11.1 (cubemx生成的STM32H7S系列的代码还是不太完整,需要参考官方例程以及查找官方文档)。

        简单介绍一下XSPI的一些知识(想要知道更多的话可以看一些具有XSPI芯片的参考手册)。XSPI支持两个协议,regular-command / hyperbus protocol,三个模式,间接、间状态轮询(hyperbus protocol 没有这个模式)、内存映射。XSPI可以配置成single_SPI、Dual_SPI、Quad_SPI、Octal_SPI、hexa_SPI、hyperbus。

       regular-command protocol有以下阶段:

• instruction phase

• address phase

• alternate-byte phase

• dummy-cycle phase

• data phase

注意:Only the data phase uses 16 bits. Instruction, address, and alternate phases use only the eight LSB of the bus as for octal configuration.

支持SDR\DTR模式。

对目前cubemx里面的XSPI参数进行解释:

Fifo threshold :设置的是Fifo阈值的大小。

memory mode:此处不太确定(没找到相应的寄存器)。应该是指协议regular-command protocol /HyperBus protocol。看官方例程都是disable。

memory type:这里是 你所使用的内存厂家。

memory size:你所使用的memory大小。

Schip select high time cycle:查阅STM32H7S7手册:当空闲时,ncs引脚是高电平。也就是与外部设备进行各项事务之间保持高电平的时间。

free running clock :手册里面的解释(翻译了一下)→自由时钟 自由时钟(free running clock),即运行时时钟频率、占空比等不随时间发生变化的时钟,通俗来讲线上一直有稳定的时钟信号,比如 I2S 的MCLK、BCLK 非自由时钟 非自由时钟(Non-free running clock),即在运行时,时钟信号不是稳定产生的,只有发送、接受数据时才需要时钟信号,比如 I2C 、SPI 的时钟信号。

clock mode:0: CLK必须保持在低电平,而NCS是高电平(芯片选择释放),称为时钟模式0。  1: CLK必须保持在高电平,而NCS是高电平(芯片选择释放),称为时钟模式3。(没有时钟模式2!)

wrap size:(这个意思其实我没太理解好)表示配置内存的包装大小。针对需要包装指令的内存。这个位字段表示与XSPI_WPIR中保存的命令相关联的包装大小

clock prescaler:预分频数(实际XSPI时钟频率=XSPI的频率/预分频数+1)。

sample shift :默认情况下,数据由外部设备驱动后,XSPI采样CLK周期的1/2。允许稍后对数据进行采样,以便考虑外部信号的延迟(STR)。

delay holde quarter cycle:当外部DQS被用作采样时钟时,对于所有在freq_min以上的频率,它被精确地移动SPI时钟周期的四分之一,以补偿产品嵌入时“高速接口”中的数据传播延迟。

chip select boundary:例如,如果CSBOUND[4:0] = 0x4,则将边界设置为2^4 = 16字节。因此,每次LSB地址等于0xF时,以及每次发出一个新事务以处理下一个数据时,都会释放NCS。

maximum transfer:是否启用通信调节功能。当另一个XSPI请求访问总线时,每一个最大的+1时钟周期都会释放NCS

refresh rate:启用刷新率功能。在写入时,NCS每次时钟周期+1进行刷新,在读取时,每时钟周期+4进行刷新。当在单、双或四spi模式下的字节传输期间发生刷新时,这个值可以用少数时钟周期进行扩展,因为字节( a byte)传输必须完成。

memory select: 选择片选信号,NCS1 或者NCS2对应芯片不同引脚!(对于H7S7来说有两个port,每个port都有NCS1与NCS2,当XSPI_1 与 XSPI_2用同一个port 会有仲裁器判断)。

以下是配置Octal_SPI_FLASH例子(使用的是XSPI_2对应地址0x7000 0000;如果你是用的是XSPI_1的话对应地址0x9000 0000):

        

记得配置时钟,我这配置了100MHz。

我这里还开了一个串口,方便调试。

以下是主要代码:

int main(void)
{

  /* USER CODE BEGIN 1 */
  XSPI_RegularCmdTypeDef sCommand = {0};
  XSPI_MemoryMappedTypeDef sMemMappedCfg={0};
  uint32_t v=0;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Update SystemCoreClock variable according to RCC registers values. */
  SystemCoreClockUpdate();

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_UART7_Init();
  MX_XSPI2_Init();
  /* USER CODE BEGIN 2 */

XSPI_NOR_OctalDTRModeCfg(&hxspi2);
//XSPI_WriteEnable(&hxspi2);

  sCommand.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionWidth   = HAL_XSPI_INSTRUCTION_16_BITS;
  sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
  sCommand.AddressMode        = HAL_XSPI_ADDRESS_8_LINES;
  sCommand.AddressWidth       = HAL_XSPI_ADDRESS_32_BITS;
  sCommand.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_ENABLE;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode           = HAL_XSPI_DATA_8_LINES;
  sCommand.DataDTRMode        = HAL_XSPI_DATA_DTR_ENABLE;
  sCommand.DQSMode            = HAL_XSPI_DQS_ENABLE;
  
  
    sCommand.OperationType      = HAL_XSPI_OPTYPE_READ_CFG;
  sCommand.Instruction        = OCTAL_IO_DTR_READ_CMD;
  sCommand.DummyCycles        = DUMMY_CLOCK_CYCLES_READ_OCTAL;
  
  if (HAL_XSPI_Command(&hxspi2, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
sCommand.OperationType = HAL_XSPI_OPTYPE_WRITE_CFG;
	sCommand.Instruction = OCTAL_PAGE_PROG_CMD;
	sCommand.DummyCycles = 0;
  
  if (HAL_XSPI_Command(&hxspi2, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
 
  sMemMappedCfg.TimeOutActivation = HAL_XSPI_TIMEOUT_COUNTER_ENABLE;
  sMemMappedCfg.TimeoutPeriodClock      = 0x34;
  
  
  if (HAL_XSPI_MemoryMapped(&hxspi2, &sMemMappedCfg) != HAL_OK)
  {
    Error_Handler();
  }
  
  volatile uint32_t *pAddress = (volatile uint32_t *)0x70000000;
  v= * pAddress;
  HAL_UART_Transmit(&huart7,(uint8_t*)&v,4,0xff);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */

static void XSPI_WriteEnable(XSPI_HandleTypeDef *hxspi)
{
  XSPI_RegularCmdTypeDef  sCommand ={0};
  uint8_t reg[2];
  
  /* Enable write operations ------------------------------------------ */
  sCommand.OperationType      = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.Instruction        = OCTAL_WRITE_ENABLE_CMD;
  sCommand.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionWidth    = HAL_XSPI_INSTRUCTION_16_BITS;
  sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
  sCommand.AddressMode        = HAL_XSPI_ADDRESS_NONE;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode           = HAL_XSPI_DATA_NONE;
  sCommand.DummyCycles        = 0;
  sCommand.DQSMode            = HAL_XSPI_DQS_DISABLE;
  
  if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* Configure automatic polling mode to wait for write enabling ---- */
  sCommand.Instruction    = OCTAL_READ_STATUS_REG_CMD;
  sCommand.Address        = 0x0;
  sCommand.AddressMode    = HAL_XSPI_ADDRESS_8_LINES;
  sCommand.AddressWidth    = HAL_XSPI_ADDRESS_32_BITS;
  sCommand.AddressDTRMode = HAL_XSPI_ADDRESS_DTR_ENABLE;
  sCommand.DataMode       = HAL_XSPI_DATA_8_LINES;
  sCommand.DataDTRMode    = HAL_XSPI_DATA_DTR_ENABLE;
  sCommand.DataLength     = 2;
  sCommand.DummyCycles    = DUMMY_CLOCK_CYCLES_READ_OCTAL;
  sCommand.DQSMode        = HAL_XSPI_DQS_ENABLE;
  
  do
  {
    if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
      Error_Handler();
    }
    
    if (HAL_XSPI_Receive(hxspi, reg, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
      Error_Handler();
    }
  } while((reg[0] & WRITE_ENABLE_MASK_VALUE) != WRITE_ENABLE_MATCH_VALUE);
}

/**
* @brief  This function read the SR of the memory and wait the EOP.
* @param  hxspi: XSPI handle
* @retval None
*/
static void XSPI_AutoPollingMemReady(XSPI_HandleTypeDef *hxspi)
{
  XSPI_RegularCmdTypeDef  sCommand={0};
  uint8_t reg[2];
  
  /* Configure automatic polling mode to wait for memory ready ------ */
  sCommand.OperationType      = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.Instruction        = OCTAL_READ_STATUS_REG_CMD;
  sCommand.InstructionMode    = HAL_XSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionWidth    = HAL_XSPI_INSTRUCTION_16_BITS;
  sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_ENABLE;
  sCommand.Address            = 0x0;
  sCommand.AddressMode        = HAL_XSPI_ADDRESS_8_LINES;
  sCommand.AddressWidth        = HAL_XSPI_ADDRESS_32_BITS;
  sCommand.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_ENABLE;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataMode           = HAL_XSPI_DATA_8_LINES;
  sCommand.DataDTRMode        = HAL_XSPI_DATA_DTR_ENABLE;
  sCommand.DataLength             = 2;
  sCommand.DummyCycles        = DUMMY_CLOCK_CYCLES_READ_OCTAL;
  sCommand.DQSMode            = HAL_XSPI_DQS_ENABLE;
  
  do
  {
    if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
      Error_Handler();
    }
    
    if (HAL_XSPI_Receive(hxspi, reg, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
      Error_Handler();
    }
  } while((reg[0] & MEMORY_READY_MASK_VALUE) != MEMORY_READY_MATCH_VALUE);
}

/**
* @brief  This function configure the memory in Octal DTR mode.
* @param  hxspi: XSPI handle
* @retval None
*/
static void XSPI_NOR_OctalDTRModeCfg(XSPI_HandleTypeDef *hxspi)
{
  uint8_t reg = 0;
  XSPI_RegularCmdTypeDef  sCommand = {0};
  XSPI_AutoPollingTypeDef sConfig  = {0};
  
  sCommand.OperationType      = HAL_XSPI_OPTYPE_COMMON_CFG;
  sCommand.InstructionMode    = HAL_XSPI_INSTRUCTION_1_LINE;
  sCommand.InstructionWidth    = HAL_XSPI_INSTRUCTION_8_BITS;
  sCommand.InstructionDTRMode = HAL_XSPI_INSTRUCTION_DTR_DISABLE;
  sCommand.AddressDTRMode     = HAL_XSPI_ADDRESS_DTR_DISABLE;
  sCommand.AlternateBytesMode = HAL_XSPI_ALT_BYTES_NONE;
  sCommand.DataDTRMode        = HAL_XSPI_DATA_DTR_DISABLE;
  sCommand.DummyCycles        = 0;
  sCommand.DQSMode            = HAL_XSPI_DQS_DISABLE;
  sConfig.MatchMode           = HAL_XSPI_MATCH_MODE_AND;
  sConfig.AutomaticStop       = HAL_XSPI_AUTOMATIC_STOP_ENABLE;
  sConfig.IntervalTime        = 0x10;
  
  
  /* Enable write operations */
  sCommand.Instruction = WRITE_ENABLE_CMD;
  sCommand.DataMode    = HAL_XSPI_DATA_NONE;
  sCommand.AddressMode = HAL_XSPI_ADDRESS_NONE;

  if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }

  /* Reconfigure XSPI to automatic polling mode to wait for write enabling */
  sConfig.MatchMask           = 0x02;
  sConfig.MatchValue          = 0x02;
  
  sCommand.Instruction    = READ_STATUS_REG_CMD;
  sCommand.DataMode       = HAL_XSPI_DATA_1_LINE;
  sCommand.DataLength         = 1;
  
  if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_XSPI_AutoPolling(hxspi, &sConfig, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* Write Configuration register 2 (with Octal I/O SPI protocol) */
  sCommand.Instruction = WRITE_CFG_REG_2_CMD;
  sCommand.AddressMode = HAL_XSPI_ADDRESS_1_LINE;
  sCommand.AddressWidth = HAL_XSPI_ADDRESS_32_BITS;
  
  sCommand.Address = 0;
  reg = 0x2;
  
  
  if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
  if (HAL_XSPI_Transmit(hxspi, &reg, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
  sCommand.Instruction    = READ_STATUS_REG_CMD;
  sCommand.DataMode       = HAL_XSPI_DATA_1_LINE;
  sCommand.DataLength     = 1;
  
  if (HAL_XSPI_Command(hxspi, &sCommand, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
  if (HAL_XSPI_AutoPolling(hxspi, &sConfig, HAL_XSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
  
}

一些定义:

/* Flash commands */
#define OCTAL_IO_READ_CMD           0xEC13
#define OCTAL_IO_DTR_READ_CMD       0xEE11
#define OCTAL_PAGE_PROG_CMD         0x12ED
#define OCTAL_READ_STATUS_REG_CMD   0x05FA
#define OCTAL_SECTOR_ERASE_CMD      0x21DE
#define OCTAL_WRITE_ENABLE_CMD      0x06F9
#define READ_STATUS_REG_CMD         0x05
#define WRITE_CFG_REG_2_CMD         0x72
#define WRITE_ENABLE_CMD            0x06

/* Dummy clocks cycles */
#define DUMMY_CLOCK_CYCLES_READ            6
#define DUMMY_CLOCK_CYCLES_READ_REG        4
#define DUMMY_CLOCK_CYCLES_READ_OCTAL      6

/* Auto-polling values */
#define WRITE_ENABLE_MATCH_VALUE    0x02
#define WRITE_ENABLE_MASK_VALUE     0x02

#define MEMORY_READY_MATCH_VALUE    0x00
#define MEMORY_READY_MASK_VALUE     0x01

#define AUTO_POLLING_INTERVAL       0x10

/* Memory registers address */
#define CONFIG_REG2_ADDR1           0x0000000
#define CR2_DTR_OPI_ENABLE          0x02

#define CONFIG_REG2_ADDR3           0x00000300
#define CR2_DUMMY_CYCLES_66MHZ      0x07

/* Memory delay */
#define MEMORY_REG_WRITE_DELAY      40
#define MEMORY_PAGE_PROG_DELAY      2

/* End address of the OSPI memory */
#define OSPI_END_ADDR               (1 << OSPI_FLASH_SIZE)

/* Size of buffers */
#define BUFFERSIZE                  256

运行效果:

串口打印的内容:

debug模式下,查看内存:

作者:做只小小jet

物联沃分享整理
物联沃-IOTWORD物联网 » STM32(H7S7)学习记录-9:XSPI Octal Flash内存映射

发表回复