您尚未登录。

楼主 # 2022-08-26 17:10:38

dg
会员
注册时间: 2018-11-22
已发帖子: 38
积分: 91

stm32f446外接PSRAM的问题

板子
       单片机:STM32F446
       PSRAM: APS6404L    (PageSize=1024Bytes)

硬件接线
    PB2:       QSPI_CLK    6
    PC11:      QSPI_NCS    1
    PE7:       QSPI_IO0    5
    PE8:      QSPI_IO1    2
    PE9:     QSPI_IO2    3
    PE10:    QSPI_IO3    7

软件环境
        HAL库

问题:

1: 能通信上,但QPI模式只能工作在2线数据, 4线数据则数据不正确
2: 写入后立即读出同一地址的数据没问题;但往前读则读到的数据是最后写入的数据
    猜测是Page的机制问题,如何跨页读取?


初始化代码:

int QSPI_PSRAM_Init(void)  
{
  QSPIHandle.Instance = QUADSPI;	
        
  QSPIHandle.Init.ClockPrescaler     = 2;   
  QSPIHandle.Init.FifoThreshold      = 4;
  QSPIHandle.Init.SampleShifting     = QSPI_SAMPLE_SHIFTING_NONE;
  QSPIHandle.Init.FlashSize          = 22;//64Mbits=8Mbtye=2^23.size取22。
  QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;     
  QSPIHandle.Init.ClockMode          = QSPI_CLOCK_MODE_0;          
  QSPIHandle.Init.FlashID            = QSPI_FLASH_ID_2;            
  QSPIHandle.Init.DualFlash          = QSPI_DUALFLASH_DISABLE;       //禁止双闪存模式
		
  if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
  {
    return PSRAM_ERR_INIT;
  }
	
  QSPI_PSRAM_Resetenable(&QSPIHandle);
  QSPI_PSRAM_Reset(&QSPIHandle);
  HAL_Delay(1);
  
  return PSRAM_OK;
}


void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
   //static DMA_HandleTypeDef hdma;
	
  if(hqspi->Instance==QUADSPI)
  {
    /* USER CODE END QUADSPI_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_QSPI_CLK_ENABLE();
    /* Reset the QuadSPI memory interface */
    __HAL_RCC_QSPI_FORCE_RESET();
    __HAL_RCC_QSPI_RELEASE_RESET();		
		
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
		
    /* Enable DMA clock */
    QSPI_DMA_CLK_ENABLE(); 		
		
    /**QUADSPI GPIO Configuration
    PB2     ------> QUADSPI_CLK
    PE7     ------> QUADSPI_BK2_IO0
    PE8     ------> QUADSPI_BK2_IO1
    PE9     ------> QUADSPI_BK2_IO2
    PE10     ------> QUADSPI_BK2_IO3
    PC11     ------> QUADSPI_BK2_NCS
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QSPI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL; //GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_QSPI;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QSPI;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* USER CODE BEGIN QUADSPI_MspInit 1 */

    /* USER CODE END QUADSPI_MspInit 1 */
		
    HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0);
    HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
		
    //中断使能
    //__HAL_QSPI_ENABLE_IT(hqspi, QSPI_IT_TC);
  }

}


读写代码

int QSPI_PSRAM_ReadPage(QSPI_HandleTypeDef *hQspi,uint8_t *pData,uint32_t FirstAddr, uint32_t BufSize)
{
	QSPI_Send_CMD(hQspi,PSRAM_CMD_READ_QUAD,FirstAddr,PSRAM_QPI_READ_DUMCYCLES,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_1_LINE,QSPI_ADDRESS_24_BITS,QSPI_DATA_2_LINES,BufSize);
	return _Read(hQspi,pData);
}

int QSPI_PSRAM_WritePage(QSPI_HandleTypeDef *hQspi,uint8_t *pData,uint32_t FirstAddr, uint32_t BufSize)
{
	QSPI_Send_CMD(hQspi,PSRAM_CMD_WRITE_QUAD,FirstAddr,PSRAM_QPI_WRITE_DUMCYCLES,QSPI_INSTRUCTION_4_LINES,QSPI_ADDRESS_1_LINE,QSPI_ADDRESS_24_BITS,QSPI_DATA_2_LINES,BufSize);
	hQspi->Instance->DLR = BufSize-1;
	return _Write(hQspi,pData); 
}


测试代码:

这样读写是成功的:

	for (i=0; i<8; i++)
	{
		memset(temp,i%0xff,1024);
		r1 = QSPI_PSRAM_WritePage(&QSPIHandle,(uint8_t*)temp,i*1024,1024);
		
		memset(temp, 0, 1024);
		r1 = QSPI_PSRAM_ReadPage(&QSPIHandle,(uint8_t*)temp, i*1024, 1024);
		
		//测试发现:写1块立即读该块,都是成功的!
		if (temp[123]!=(i%0xff))
		{
			e++;
			printf("err:%d times, i=%d -->",e, i);    //只要不打这个就是好的	
		}
	}

这样写,再读,读到的数据就总是最后写入的数据:

        //写入:
	for (i=0; i<8; i++)
	{
		memset(temp,i%0xff,1024);
		QSPI_PSRAM_WritePage(&QSPIHandle,(uint8_t*)temp,i*1024,1024);
	}

        //读出:
	for (i=0; i<8; i++)
	{
		memset(temp, 0, 1024);
		QSPI_PSRAM_ReadPage(&QSPIHandle,(uint8_t*)temp, i*1024, 1024);
		if (temp[30]!=(i%0xff))
                {
                   printf("%4d: ",i*1024);
		   ShowBuffer(temp,32);
                 }
	}

离线

#1 2022-08-26 18:32:02

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 519
积分: 640
个人网站

Re: stm32f446外接PSRAM的问题

如果一个数据所占用的空间跨了两页,那么就要分两次写,第一次写到第一个页的结尾,第二次从下一个页开始写。

离线

楼主 #2 2022-08-27 09:45:10

dg
会员
注册时间: 2018-11-22
已发帖子: 38
积分: 91

Re: stm32f446外接PSRAM的问题

写入暂时没问题。主要是读出。
比如连续写了 1.2.3.4.5 共5页。
然后再回读第1页, 发现第1页是第5页的内容。

但如果 写1读1,写2读2,写5读5. 这样操作则数据都是正确的

离线

楼主 #3 2022-08-27 10:01:01

dg
会员
注册时间: 2018-11-22
已发帖子: 38
积分: 91

Re: stm32f446外接PSRAM的问题

从这个文件看来,PSRAM只需要不在同一次CS中,即可任意换页。
而我的设置,采用的是MCU自己产生的CS信号,量了下波形也是每次发命令就发的CS。
所以应该是可以换页的。不知何故。。。

27.png

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn