硬汉嵌入式论坛

 找回密码
 立即注册
查看: 486|回复: 5
收起左侧

[SPI/QSPI] H743 使用QSPI 双bank读写外部RAM 受限

[复制链接]

10

主题

43

回帖

73

积分

初级会员

积分
73
发表于 2023-8-3 11:58:56 | 显示全部楼层 |阅读模式
RAM选用 ISSI的IS66系列,参照V7 QSPI读写W25Q更改配置,可读可写,但发现单次读写数据长度只能小于2048字节,超过长度就从原点开始重复读写。IS66的burstlength默认1024。求解为什么不能配置起始地址后连续读取。


[C] 纯文本查看 复制代码
void bsp_InitQSPI(void)
{
	/* 复位QSPI */
	QSPIHandle.Instance = QUADSPI;
	if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
	QSPIHandle.Init.ClockPrescaler	= 2;//0:200MHz	1:100MHz 2:66MHz 
	
	/* 设置FIFO阀值,范围1 - 32 */
	QSPIHandle.Init.FifoThreshold	= 32; 
	
	/* 
		QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
		在外部信号延迟时,这有利于推迟数据采样。
	*/
	QSPIHandle.Init.SampleShifting	= QSPI_SAMPLE_SHIFTING_HALFCYCLE; 
	
	/*Flash大小是2^(FlashSize + 1) = 2^23 = 8MB */
	QSPIHandle.Init.FlashSize		= QSPI_FLASH_SIZE - 1; 
	
	/* 命令之间的CS片选至少保持1个时钟周期的高电平 */
	QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
	
	/*
	   MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
	   MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平
	*/
	QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
	
	/* QSPI有两个BANK,这里使用的BANK1 */
	QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;
	
	/* V7开发板仅使用了BANK1,这里是禁止双BANK */
	QSPIHandle.Init.DualFlash =QSPI_DUALFLASH_ENABLE; //QSPI_DUALFLASH_DISABLE;//

	/* 初始化配置QSPI */
	if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}	

}	

[C] 纯文本查看 复制代码
void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	/* 使能QPSI时钟  */
	QSPI_CLK_ENABLE();

	/* 复位时钟接口 */
	QSPI_FORCE_RESET();
	QSPI_RELEASE_RESET();

	/* 使能GPIO时钟 */
	QSPI_CS_GPIO_CLK_ENABLE();
	//	QSPI_CS2_GPIO_CLK_ENABLE();
	QSPI_CLK_GPIO_CLK_ENABLE();
	QSPI_BK1_D0_GPIO_CLK_ENABLE();
	QSPI_BK1_D1_GPIO_CLK_ENABLE();
	QSPI_BK1_D2_GPIO_CLK_ENABLE();
	QSPI_BK1_D3_GPIO_CLK_ENABLE();
	QSPI_BK2_D0_GPIO_CLK_ENABLE();//  __HAL_RCC_GPIOE_CLK_ENABLE()
	QSPI_BK2_D1_GPIO_CLK_ENABLE();//  __HAL_RCC_GPIOE_CLK_ENABLE()
	QSPI_BK2_D2_GPIO_CLK_ENABLE();//  __HAL_RCC_GPIOE_CLK_ENABLE()
	QSPI_BK2_D3_GPIO_CLK_ENABLE();//  __HAL_RCC_GPIOE_CLK_ENABLE()	

	/* QSPI CS GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_CS_PIN;
	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = QSPI_CS_AF;
	HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &GPIO_InitStruct);

	//		/* QSPI CS GPIO 引脚配置 */
	//	GPIO_InitStruct.Pin       = QSPI_CS2_PIN;
	//	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	//	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	//	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
	//	GPIO_InitStruct.Alternate = QSPI_CS2_AF;
	//	HAL_GPIO_Init(QSPI_CS2_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI CLK GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_CLK_PIN;
	GPIO_InitStruct.Pull      = GPIO_NOPULL;
	GPIO_InitStruct.Alternate = QSPI_CLK_AF;
	HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D0 GPIO pin 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D0_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D0_AF;
	HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D1 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D1_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D1_AF;
	HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D2 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D2_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D2_AF;
	HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D3 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D3_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D3_AF;
	HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &GPIO_InitStruct);

		/* QSPI D0 GPIO pin 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK2_D0_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK2_D0_AF;
	HAL_GPIO_Init(QSPI_BK2_D0_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D1 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK2_D1_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK2_D1_AF;
	HAL_GPIO_Init(QSPI_BK2_D1_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D2 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK2_D2_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK2_D2_AF;
	HAL_GPIO_Init(QSPI_BK2_D2_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D3 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK2_D3_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK2_D3_AF;
	HAL_GPIO_Init(QSPI_BK2_D3_GPIO_PORT, &GPIO_InitStruct);

	/* 使能QSPI中断 */
	HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x02, 0);
	HAL_NVIC_EnableIRQ(QUADSPI_IRQn);

	/* 配置MDMA时钟 */
	QSPI_MDMA_CLK_ENABLE();

	hmdma.Instance = MDMA_Channel1;                         /* 使用MDMA的通道1 */
	hmdma.Init.Request = MDMA_REQUEST_QUADSPI_FIFO_TH;      /* QSPI的FIFO阀值触发中断 */
	hmdma.Init.TransferTriggerMode = MDMA_BUFFER_TRANSFER;  /* 使用MDMA的buffer传输 */
	hmdma.Init.Priority = MDMA_PRIORITY_HIGH;               /* 优先级高 */
	hmdma.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;/* 小端格式 */
	hmdma.Init.SourceInc = MDMA_SRC_INC_BYTE;               /* 源地址字节递增 */
	hmdma.Init.DestinationInc = MDMA_DEST_INC_DISABLE;      /* 目的地址无效自增 */
	hmdma.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE;     /* 源地址数据宽度字节 */
	hmdma.Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE;      /* 目的地址数据宽度字节 */
	hmdma.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE;   /* 小端,右对齐 */
	hmdma.Init.BufferTransferLength = 128;                  /* 每次传输128个字节 */
	hmdma.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE;      /* 源数据单次传输 */
	hmdma.Init.DestBurst = MDMA_DEST_BURST_SINGLE;          /* 目的数据单次传输 */

	hmdma.Init.SourceBlockAddressOffset = 0;                /* 用于block传输,buffer传输用不到 */
	hmdma.Init.DestBlockAddressOffset = 0;                  /* 用于block传输,buffer传输用不到 */

	/* 关联MDMA句柄到QSPI句柄里面  */
	__HAL_LINKDMA(hqspi, hmdma, hmdma);

	/* 先复位,然后配置MDMA */
	HAL_MDMA_DeInit(&hmdma);  
	HAL_MDMA_Init(&hmdma);

	/* 使能MDMA中断,并配置优先级 */
	HAL_NVIC_SetPriority(MDMA_IRQn, 0x02, 0);
	HAL_NVIC_EnableIRQ(MDMA_IRQn);
}

[C] 纯文本查看 复制代码
void SS67_enter_qpi_mode(void)
{
	QSPI_CommandTypeDef     sCommand = {0};
	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 每次传输都发指令 */
	
	/* 写使能 */
	sCommand.Instruction       = SS67_ENTER_QPI_MODE;  /* 写使能指令 */
	sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */
	sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
	sCommand.DummyCycles       = 0;                 /* 空周期  */

	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
}

[C] 纯文本查看 复制代码
uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
{
	QSPI_CommandTypeDef sCommand={0};
	//LED3_0();
	/* 用于等待发送完成标志 */
	TxCplt = 0;

	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_4_LINES;    /* 4线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 仅发送一次命令 */	
	
	/* 写序列配置 */
	sCommand.Instruction = SS67_QPI_WRITE; /* 32bit地址的4线快速写入命令 */
	sCommand.DummyCycles = 0;                    /* 不需要空周期 */
	sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址方式 */
	sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
	sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
	sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
	
	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 启动MDMA传输 */
	if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 等待数据发送完毕 */
//	while(TxCplt == 0);
//	TxCplt = 0;
	
//	/* 等待Flash页编程完毕 */
//	StatusMatch = 0;
//	QSPI_AutoPollingMemReady(&QSPIHandle);	
//	while(StatusMatch == 0);
//	StatusMatch = 0;	
	return 1;
}

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*	函 数 名: QSPI_ReadBuffer
*	功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
*	形    参: _pBuf : 数据源缓冲区。
*			  _uiReadAddr :起始地址。
*			  _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
*	返 回 值: 无
*********************************************************************************************************
*/
void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
{
	
	QSPI_CommandTypeDef sCommand = {0};
	
	/* 用于等待接收完成标志 */
	RxCplt = 0;
	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_4_LINES;    	/* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;      	/* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  	/* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      	/* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  	/* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;		/* 每次传输要发指令 */	
 
	/* 读取数据 */
	sCommand.Instruction = SS67_QPI_READ; /* 32bit地址的4线快速读取命令 */
	sCommand.DummyCycles = 6;                    /* 空周期 */
	sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
	sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ 
	sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ 
	sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 
	
	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
//if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 
//	{
//		ERROR_HANDLER();
//	}

	/* MDMA方式读取 */
	if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}	
	
//	/* 等接受完毕 */
//	while(RxCplt == 0);
//	RxCplt = 0;
}

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107645
QQ
发表于 2023-8-3 13:21:47 | 显示全部楼层
可以考虑测试下内存映射方式试试。看看读取是否有问题。
回复

使用道具 举报

10

主题

43

回帖

73

积分

初级会员

积分
73
 楼主| 发表于 2023-8-3 14:46:20 | 显示全部楼层
eric2013 发表于 2023-8-3 13:21
可以考虑测试下内存映射方式试试。看看读取是否有问题。

读写都有这个问题,是不是哪里配置不太匹配。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107645
QQ
发表于 2023-8-4 09:31:48 | 显示全部楼层
lishang4650 发表于 2023-8-3 14:46
读写都有这个问题,是不是哪里配置不太匹配。

这个不太清楚了,不能连续读,太诡异了。

不使用DMA,不使用内存映射,调用那个查询方式读也是这种情况吗
回复

使用道具 举报

10

主题

43

回帖

73

积分

初级会员

积分
73
 楼主| 发表于 2023-8-7 09:07:12 | 显示全部楼层
eric2013 发表于 2023-8-4 09:31
这个不太清楚了,不能连续读,太诡异了。

不使用DMA,不使用内存映射,调用那个查询方式读也是这种情 ...

试了下 查询也是到2048就重复读
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107645
QQ
发表于 2023-8-7 15:15:32 | 显示全部楼层
lishang4650 发表于 2023-8-7 09:07
试了下 查询也是到2048就重复读

那得研究下这个芯片,是不是超过2048了要重新指定地址才可以。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-6-10 19:07 , Processed in 0.255900 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表