前言
在验证板子上的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试试,我这里可以