IS62WV51216 HAL库FMSC初始化参数验证和调整

通过实验发现CubeMX默认IS62WV51216时序过大导致执行缓慢。通过对比数据手册调整时序参数,将地址设置时间、保持时间和数据准备时间分别缩短,测试函数执行时间降至2秒。最终找到接近最优的55ns时序配置,提升嵌入式设备读写速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在验证板子上的2块IS62WV51216,用CubeMX生成的默认初始化代码,操作IS62WV51216时序的时钟数填的太大,同样的测试函数,执行速度好慢(10秒)。对照数据手册和试验调整小了一些,同样的测试函数执行时间小多了(2秒)。

IS62WV51216可以按照字节(byte)操作(1M 字节),也可以按照半字(WORD)操作(512K WORD).

硬件连接

在1片STM32F407IG上的FSMC上接了2片IS62WV51216,一片用NE3控制,另一片用NE4控制。
在这里插入图片描述
在这里插入图片描述

CubeMX设置

CubeMX版本是6.1.1
在这里插入图片描述
2片IS62WV51216设置如下:
在这里插入图片描述
在这里插入图片描述
这样设置后,2片IS62WV51216地址分别为 0x68000000和0x6C000000开始的1MB字节。

CubeMX生成的FMSC初始化代码

我选择生成IAR V8.32 版本的工程。
在这里插入图片描述

/* FSMC initialization function */
void MX_FSMC_Init(void)
{
  /* USER CODE BEGIN FSMC_Init 0 */

  /* USER CODE END FSMC_Init 0 */

  FSMC_NORSRAM_TimingTypeDef Timing = {0};

  /* USER CODE BEGIN FSMC_Init 1 */

  /* USER CODE END FSMC_Init 1 */

  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FSMC_NORSRAM_DEVICE;
  hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram1.Init */
  hsram1.Init.NSBank = FSMC_NORSRAM_BANK3;
  hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
  hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
  hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
  hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FSMC_ACCESS_MODE_A;
  /* ExtTiming */

  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }

  /** Perform the SRAM2 memory initialization sequence
  */
  hsram2.Instance = FSMC_NORSRAM_DEVICE;
  hsram2.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram2.Init */
  hsram2.Init.NSBank = FSMC_NORSRAM_BANK4;
  hsram2.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
  hsram2.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
  hsram2.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram2.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
  hsram2.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram2.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
  hsram2.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
  hsram2.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
  hsram2.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
  hsram2.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
  hsram2.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram2.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
  hsram2.Init.PageSize = FSMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FSMC_ACCESS_MODE_A;
  /* ExtTiming */

  if (HAL_SRAM_Init(&hsram2, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FSMC_Init 2 */

  /* USER CODE END FSMC_Init 2 */
}

在上面代码处,关于访问IS62WV51216的时间设置如下:

  Timing.AddressSetupTime = 15;
  Timing.AddressHoldTime = 15;
  Timing.DataSetupTime = 255;

这3个时间值要和IS62WV51216数据表符合,才能调整出最合适(时间最短,且读写操作可靠)的时序参数。

先用CubeMX默认生成的代码,加上测试函数试试读写IS62WV51216全片。如果读写不相同,就退出。在退出那下断点,就知道参数值是否能让IS62WV51216读写稳定。

测试代码

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void test_mem_ex1(void)
{
  uint32_t u32_i = 0;
  uint32_t u32_mem_addr_begin = 0x68000000;
  uint32_t u32_mem_addr_end = u32_mem_addr_begin + 1024 * 1024 - 1;
  uint8_t u8_tmp = 0;
  
  uint16_t u16_tmp1 = 0;
  uint16_t u16_tmp2 = 0;
  
//  uint8_t u8_tmp1 = 0;
//  uint8_t u8_tmp2 = 0;
  
  for (u32_i = u32_mem_addr_begin, u8_tmp = 0; u32_i < u32_mem_addr_end; u32_i++, u8_tmp++) {
    u16_tmp1 = u8_tmp * 0x100 + (u8_tmp + 1);
    *(uint16_t*)u32_i = u16_tmp1;
    u16_tmp2 = *(uint16_t*)u32_i;
    if (u16_tmp1 != u16_tmp2) {
      break;
    }
    
//    u8_tmp1 = *(uint8_t*)u32_i;
//    u8_tmp2 = *(uint8_t*)(u32_i + 1);

    *(uint8_t*)u32_i = u8_tmp;
    *(uint8_t*)(u32_i + 1) = ~u8_tmp;
  }
}

void test_mem_ex2(void)
{
    uint32_t u32_i = 0;
  uint32_t u32_mem_addr_begin = 0x6c000000;
  uint32_t u32_mem_addr_end = u32_mem_addr_begin + 1024 * 1024 - 1;
  uint8_t u8_tmp = 0;
  
  uint16_t u16_tmp1 = 0;
  uint16_t u16_tmp2 = 0;
  
//  uint8_t u8_tmp1 = 0;
//  uint8_t u8_tmp2 = 0;
  
  for (u32_i = u32_mem_addr_begin, u8_tmp = 0; u32_i < u32_mem_addr_end; u32_i++, u8_tmp++) {
    u16_tmp1 = u8_tmp * 0x100 + (u8_tmp + 1);
    *(uint16_t*)u32_i = u16_tmp1;
    u16_tmp2 = *(uint16_t*)u32_i;
    if (u16_tmp1 != u16_tmp2) {
      break;
    }
    
//    u8_tmp1 = *(uint8_t*)u32_i;
//    u8_tmp2 = *(uint8_t*)(u32_i + 1);

    *(uint8_t*)u32_i = u8_tmp;
    *(uint8_t*)(u32_i + 1) = ~u8_tmp;
  }
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

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

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CO2();E BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FSMC_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  test_mem_ex1();
  test_mem_ex2();
  /* USER CODE END 2 */

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

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

进了test_mem_ex1(), 好久没出来,感觉有10几秒。

IS62WV51216 datasheet中的时序要求

在力创上买的IS62WV51216访问速度是55ns的。
在这里插入图片描述
IS62WV51216 datasheet关于55ns型号用红框圈住了。
在这里插入图片描述
对照 CubeMX生成的初始化代码,看看那3个时间参数对应数据表中的哪个值。

  Timing.AddressSetupTime = 15; // datasheet tAA, - to 55
  Timing.AddressHoldTime = 15; // datasheet tOHA, 10 to -
  Timing.DataSetupTime = 255; // datasheet tRC, 55 ~ -

datasheet和CubeMX中的变量名称不一样,不太确定哪个是哪个。
从datasheet中看到最大的时间是55ns. 最小的操作时间是10ns.
那将前2个值换成10ns对应的时钟周期,将第3个值换成55ns对应的时钟周期试试。

STM32F407外接8MHZ HSE, 通过PLL,变成168MHZ.
1/168MHZ = 0.00595238us = 5.9ns.
10ns对应2个时钟周期,55ns对应10个时钟周期。
尝试改成如下初始化代码。

  /* Timing */
  Timing.AddressSetupTime = 2 /*15*/;
  Timing.AddressHoldTime = 2 /*15*/;
  Timing.DataSetupTime = 10 /*255*/;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FSMC_ACCESS_MODE_A;
  /* ExtTiming */

再跑一下测试程序,同样遍历操作一个IS62WV51216,只需要2秒不到。
再尝试将这3个值改小点如下:

  /* Timing */
  Timing.AddressSetupTime = 1 /*15*/;
  Timing.AddressHoldTime = 1 /*15*/;
  Timing.DataSetupTime = 5 /*255*/;
  Timing.BusTurnAroundDuration = 15;
  Timing.CLKDivision = 16;
  Timing.DataLatency = 17;
  Timing.AccessMode = FSMC_ACCESS_MODE_A;
  /* ExtTiming */

再跑测试程序,发现已经出现读写数据不相同的情况了。
现在2,2,10已经接近最优的IS62WV51216时序要求了,先这样。

补充 - 2023_0211_2249

csdn上有个同学试了一个新参数可用, 以后用到的时候, 我也试试.

w1934406350
时序3 0 3试试,我这里可以

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值