返回列表 发新帖我要提问本帖赏金: 40.00元(功能说明)

[单片机芯片] 片内扩展 PSRAM 存储器-屏显神器

[复制链接]
416|7
abner_ma 发表于 2026-6-30 23:17 | 显示全部楼层 |阅读模式
本帖最后由 abner_ma 于 2026-6-30 23:23 编辑

   之前的搞的S**32F429+片外RAM扩展驱动4寸RGB显示,无奈芯片和RAM涨价太厉害。沁恒CH32V4系列 是基于青稞 RISC-V 内核设计的工业级互联型微控制器,支持 200MHz 主频零等待运行,支持 V 向量指令集,用于加速计算或并行处理等应用。CH32V4内置 2 组 USB 2.0 高速 PHY 收发器(480Mbps)、以太网 MAC 控制器及 10/100 兆物理层收发器;内置双 ADC 单元、双 DAC 单元、OPA 运放等模拟资源;提供了 2 组共 24 路 DMA 控制器、SDIO、DVP 数字图像接口、RNG、ARGB、LTDC、FSMC、多组定时器、10 组 USART 串口、I2C 接口、I3C 接口、3 组 SPI、2 组 I2S、CAN 接口等丰富外设资源。
      CH32V467 在 CH32V407 的基础上增加了 4M 或 8M 字节的片内扩展 PSRAM 存储器,支持 DMA。没有 PSRAM仅片内 SRAM 只有几百K,大分辨率 RGB 屏(480*800 等)显存放不下,会内存溢出、跑不了高分辨率 GUI;有片内 PSRAM后直接开辟几 MB 显存给 LTDC,配合 DMA 硬件搬运,不占用 CPU;
VV1.png
VV2.png
VV3.png
VV4.png

    做复显示思路:SPI 总线读取外部 SPI Flash 里的图片 / 字库;通过 DMA 把图片数据搬运到片内 PSRAM缓存;LTDC 硬件直接从 PSRAM 读取显存,自动刷新 RGB 屏幕;SPI:负责持久存储资源读取(Flash→PSRAM)PSRAM:负责临时画面缓存(显存容器)LTDC:负责硬件刷屏输出(PSRAM→屏幕)。
   程序设计:



  1. #include "debug.h"
  2. #include "string.h"
  3. #include "PSRAM.h"

  4. #define PSRAM_ADDR      0X80000000
  5. #define BUFFER_SIZE     1024
  6. __attribute__((aligned(1))) uint32_t TxBuffer[BUFFER_SIZE];
  7. __attribute__((aligned(1))) uint32_t RxBuffer[BUFFER_SIZE];

  8. /*********************************************************************
  9. * @fn      PSRAM_INIT
  10. *
  11. * [url=/u/brief]@brief[/url]   Initializes PSRAM
  12. *
  13. * [url=/u/return]@return[/url]  none
  14. */
  15. void PSRAM_INIT(void)
  16. {
  17.     PSRAMInitTypeDef PSRAMInitStruct = {0};
  18.     PSRAMTimingInitTypeDef PSRAMTimingStruct= {0};
  19.     RCC_HBPeriphClockCmd(RCC_HBPeriph_PSRAM, ENABLE);
  20.    
  21.     PSRAMDeInit();

  22.     PSRAMTimingStruct.PSRAM_trc=0x14;
  23.     PSRAMTimingStruct.PSRAM_tcph=0xC;
  24.     PSRAMTimingStruct.PSRAM_txlpd=0x7;
  25.     PSRAMInitStruct.PSRAM_cfifo=PSRAM_CFIFO_BTWWRRD;
  26.     PSRAMInitStruct.PSRAM_cap_cfg=PSRAM_CAPCFG_32M;
  27.     PSRAMInitStruct.PSRAM_exti_lpmd=PSRAM_EXIT_LPMD;
  28.     PSRAMInitStruct.PSRAMTimingStruct=&PSRAMTimingStruct;
  29.     PSRAMInit(&PSRAMInitStruct);
  30.     Delay_Ms(1);
  31.         //Set the Read Latency and Write Latency
  32.     SetWrLatency(MR4_Write_200M,Latency_200M);
  33.     SetRdLatency(MR0_Read_200M,Latency_200M,Read_Variable);   
  34. }

  35. /*********************************************************************
  36. * @fn      PSRAM_200MHz_HSE
  37. *
  38. * @brief   Sets PSRAM clock frequency to 200MHz.
  39. *
  40. * @return  none
  41. */
  42. static void PSRAM_200MHz_HSE(void)
  43. {
  44.     __IO uint32_t StartUpCounter = 0, HSEStatus = 0 , FLASH_Temp = 0;
  45.     RCC->CTLR |= (uint32_t)0x00000001;
  46.     RCC->CFGR0 &= (uint32_t)0x80FF0000;
  47.     while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x00)
  48.     {
  49.     }

  50.     RCC->CTLR &= (uint32_t)0xFEA6FFFF;
  51.     RCC->CTLR &= (uint32_t)0xFFFBFFFF;

  52.     RCC->CFGR0 &= (uint32_t)0xFFC0FFFF;
  53.     RCC->CFGR2 &= (uint32_t)0xFFFFEFFF;
  54.     RCC->CFGR2 &= (uint32_t)0x03F11800;

  55.     RCC->CFGR0 |= (uint32_t)(0x20000000);
  56.     RCC->CFGR3 = 0x00000000;
  57.     RCC->INTR = 0x008F0000;   
  58.     RCC->CTLR |= ((uint32_t)RCC_HSEON);

  59.     /* Wait till HSE is ready and if Time out is reached exit */
  60.     do
  61.     {
  62.       HSEStatus = RCC->CTLR & RCC_HSERDY;
  63.       StartUpCounter++;
  64.     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  65.     if ((RCC->CTLR & RCC_HSERDY) != RESET)
  66.     {
  67.       HSEStatus = (uint32_t)0x01;
  68.     }
  69.     else
  70.     {
  71.       HSEStatus = (uint32_t)0x00;
  72.     }

  73.     if (HSEStatus == (uint32_t)0x01)
  74.     {
  75.       /* HCLK = SYSCLK  */
  76.       RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
  77.       /* PCLK2 = HCLK */
  78.       RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
  79.       /* PCLK1 = HCLK */
  80.       RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;

  81.       /* PLL configuration: HCLK = (HSE * 8) / 1 = 200 MHz */
  82.       RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLMULL8);

  83.       /* Enable PLL */
  84.       RCC->CTLR |= RCC_PLLON;
  85.       /* Wait till PLL is ready */
  86.       while((RCC->CTLR & RCC_PLLRDY) == 0)
  87.       {
  88.       }

  89.       RCC->CFGR2 |= (uint32_t)(RCC_SYSPLLSRC_PLL | RCC_SYSPLLDIV1);
  90.       /* Wait till PLL clock is used as SYSPLLSRC clock source */
  91.       while ((RCC->CFGR2 & (uint32_t)RCC_SYSPLLSRC) != (uint32_t)RCC_SYSPLLSRC_PLL)
  92.       {
  93.       }     

  94.       /* Select FLASH clock frequency*/
  95.       FLASH->KEYR = ((uint32_t)0x45670123);
  96.       FLASH->KEYR = ((uint32_t)0xCDEF89AB);
  97.       FLASH->MODEKEYR = ((uint32_t)0x45670123);
  98.       FLASH->MODEKEYR = ((uint32_t)0xCDEF89AB);

  99.       FLASH_Temp = FLASH->CTLR ;
  100.       FLASH_Temp &= ~((uint32_t)FLASH_CTLR_SCKMOD);
  101.       FLASH_Temp |= FLASH_CTLR_SCKMOD_Div2;
  102.       FLASH->CTLR = FLASH_Temp;
  103.       FLASH->CTLR |= ((uint32_t)0x00008080);

  104.       /* Select PLL as system clock source */
  105.       RCC->CFGR2 |= (uint32_t)RCC_SYSPLL_GATE;
  106.       RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
  107.       /* Wait till PLL is used as system clock source */
  108.       while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
  109.       {
  110.       }
  111.     }
  112.     else
  113.     {
  114.       /*
  115.        * If HSE fails to start-up, the application will have wrong clock
  116.        * configuration. User can add here some code to deal with this error
  117.        */
  118.     }
  119. }
  120. /*********************************************************************
  121. * @fn      main
  122. *
  123. * @brief   Main program.
  124. *
  125. * @return  none
  126. */
  127. int main(void)
  128. {
  129.     u32 i=0;
  130.     u32 times=0;
  131.     SystemCoreClockUpdate();
  132.     PSRAM_200MHz_HSE();
  133.     SystemCoreClockUpdate();
  134.     USART_Printf_Init(115200);       
  135.     Delay_Init();
  136.     printf("SystemClk:%d\r\n", SystemCoreClock);
  137.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
  138.     printf("PSRAM TEST\r\n");
  139.     PSRAM_INIT();
  140.     while(1){
  141.     for(int j=0; j<BUFFER_SIZE; j++)
  142.     {
  143.       TxBuffer[j] = j;
  144.       RxBuffer[j]=0;
  145.           }
  146.     /*     1.  CPU write  CPU read */
  147.     printf("CPU write data\r\n");
  148.     for(i=0; i<BUFFER_SIZE; i++)
  149.     {
  150.       *(u32*)(PSRAM_ADDR + 4*i) = TxBuffer[i];
  151.           }
  152.     printf("CPU Read data\r\n");
  153.     for(i=0; i<BUFFER_SIZE; i++)
  154.     {
  155.       RxBuffer[i]= *(vu32*)(PSRAM_ADDR + 4*i);  
  156.     }
  157.     if(memcmp(TxBuffer, RxBuffer, BUFFER_SIZE))
  158.     {
  159.       printf("  fail\n\r");
  160.       for(int k=0;k<BUFFER_SIZE;k++)
  161.       {
  162.         if(TxBuffer[k]!=RxBuffer[k])
  163.         {
  164.           printf(" TxBuffer[%d]=%x\n\r",k,TxBuffer[k]);
  165.           printf(" RxBuffer[%d]=%x\n\r",k,RxBuffer[k]);
  166.         }
  167.       }
  168.       break;
  169.     }
  170.     else
  171.     {
  172.       times++;
  173.       printf("sucess times:%d\r\n",times);  
  174.     }

  175.     /*     2. DMA write  DMA read */
  176.     for(int j=0; j<BUFFER_SIZE; j++)
  177.     {
  178.       TxBuffer[j] = j+1;
  179.       RxBuffer[j]=0;
  180.           }
  181.     printf("DMA write data\r\n");
  182.     PSRAMDMAWrite(TxBuffer,PSRAM_ADDR,BUFFER_SIZE,PSRAM_MEMORYSIZE_32bit,DMA_BRST_NUM2,DMA_PAUSE_TIM0 );
  183.     printf("DMA Read data\r\n");
  184.     PSRAMDMARead(RxBuffer,PSRAM_ADDR,BUFFER_SIZE,PSRAM_MEMORYSIZE_32bit,DMA_BRST_NUM2,DMA_PAUSE_TIM0 );
  185.     if(memcmp(TxBuffer, RxBuffer, BUFFER_SIZE))
  186.     {
  187.       printf("  fail\n\r");
  188.       for(int k=0;k<BUFFER_SIZE;k++)
  189.       {
  190.         if(TxBuffer[k]!=RxBuffer[k])
  191.         {
  192.           printf(" TxBuffer[%d]=%x\n\r",k,TxBuffer[k]);
  193.           printf(" RxBuffer[%d]=%x\n\r",k,RxBuffer[k]);
  194.         }
  195.       }
  196.       break;
  197.     }
  198.     else
  199.     {
  200.       times++;
  201.       printf("sucess times:%d\r\n",times);  
  202.     }

  203.     /*     3.DMA write CPU read */
  204.     for(int j=0; j<BUFFER_SIZE; j++)
  205.     {
  206.       TxBuffer[j] = j+2;
  207.       RxBuffer[j]=0;
  208.           }
  209.     printf("DMA write data\r\n");
  210.     PSRAM_DMA_CFIFO(ENABLE);// This function must be available in this read/write mode
  211.     PSRAMDMAWrite(TxBuffer,PSRAM_ADDR,BUFFER_SIZE,PSRAM_MEMORYSIZE_32bit,DMA_BRST_NUM2,DMA_PAUSE_TIM0 );
  212.     PSRAM_DMA_CFIFO(DISABLE);// This function must be available in this read/write mode
  213.     PSRAM_DMA_DIR(DMA_DIR_MEM);// This function must be available in this read/write mode
  214.     printf("CPU Read data\r\n");
  215.     for(i=0; i<BUFFER_SIZE; i++)
  216.     {
  217.       RxBuffer[i]= *(vu32*)(PSRAM_ADDR + 4*i);  
  218.     }
  219.     if(memcmp(TxBuffer, RxBuffer, BUFFER_SIZE))
  220.     {
  221.       printf("  fail\n\r");
  222.       for(int k=0;k<BUFFER_SIZE;k++)
  223.       {
  224.         if(TxBuffer[k]!=RxBuffer[k])
  225.         {
  226.           printf(" TxBuffer[%d]=%x\n\r",k,TxBuffer[k]);
  227.           printf(" RxBuffer[%d]=%x\n\r",k,RxBuffer[k]);
  228.         }
  229.       }
  230.       break;
  231.     }
  232.     else
  233.     {
  234.       times++;
  235.       printf("sucess times:%d\r\n",times);  
  236.     }

  237.     /*     4.CPU write DMA read */
  238.     for(int j=0; j<BUFFER_SIZE; j++)
  239.     {
  240.       TxBuffer[j] = j+3;
  241.       RxBuffer[j]=0;
  242.           }
  243.     printf("CPU write data\r\n");
  244.     for(i=0; i<BUFFER_SIZE; i++)
  245.     {
  246.       *(u32*)(PSRAM_ADDR + 4*i) = TxBuffer[i];
  247.           }
  248.     printf("DMA Read data\r\n");
  249.     PSRAMDMARead(RxBuffer,PSRAM_ADDR,BUFFER_SIZE,PSRAM_MEMORYSIZE_32bit,DMA_BRST_NUM2,DMA_PAUSE_TIM0 );
  250.     if(memcmp(TxBuffer, RxBuffer, BUFFER_SIZE))
  251.     {
  252.       printf("  fail\n\r");
  253.       for(int k=0;k<BUFFER_SIZE;k++)
  254.       {
  255.         if(TxBuffer[k]!=RxBuffer[k])
  256.         {
  257.           printf(" TxBuffer[%d]=%x\n\r",k,TxBuffer[k]);
  258.           printf(" RxBuffer[%d]=%x\n\r",k,RxBuffer[k]);
  259.         }
  260.       }
  261.       break;
  262.     }
  263.     else
  264.     {
  265.       times++;
  266.       printf("sucess times:%d\r\n",times);  
  267.     }
  268.         }
  269.   while(1);
  270. }
  最近版本的 MounRiver_Studio 都可以支持GUI设计。






打赏榜单

21ic小管家 打赏了 40.00 元 2026-07-06
理由:赞助论坛原创主题帖活动奖励

袁胜富 发表于 2026-7-1 15:19 | 显示全部楼层
请问在表达什么,点屏了?
袁胜富 发表于 2026-7-1 15:21 | 显示全部楼层
官方回复目前PSRAM暂不能作为LTDC的显存
 楼主| abner_ma 发表于 2026-7-3 16:44 | 显示全部楼层
袁胜富 发表于 2026-7-1 15:19
请问在表达什么,点屏了?

在打板子  ,后续公开测试
 楼主| abner_ma 发表于 2026-7-3 16:52 | 显示全部楼层
袁胜富 发表于 2026-7-1 15:21
官方回复目前PSRAM暂不能作为LTDC的显存

可以的
深渊之海 发表于 2026-7-29 14:04 | 显示全部楼层

期待楼主的测试结果,看看到底怎么用的
EchoInSilence 发表于 2026-7-17 10:51 | 显示全部楼层
期待楼主更新帖子
她已醉 发表于 2026-9-1 21:23 | 显示全部楼层
想问下PSRAM的带宽实际能跑到多少?200MHz主频下DMA搬运会不会和CPU抢总线影响GUI响应?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:项目经理
简介:资深嵌入式开发工程师

142

主题

244

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部
0