乐鑫PSRAM64H搭载ESP32 硬件设计 个人设计经历分享(PSRAM不工作)

乐鑫PSRAM64H搭载ESP32 硬件设计 个人设计经历分享(PSRAM不工作)

背景

在使用esp32的过程中,我希望可以在设备上运行轻量级的神经网络,或者对拍摄的图片进行本地的处理,而ESP32-S只有内部的不到300K的堆内存default memory,这种大小的内存(RAM)显然不能完成我们的需求,所以决定添加板载的PSRAM芯片。

芯片数据

PSRAM64H datasheet
具体可以参考链接,PSRAM64与PSRAM64H 之间的区别大致只有电源电压的关系,在这里我的MCU使用为3.3V,为节省一个电压转换电路,直接使用PSRAM64H作为我的扩展内存芯片。
PSRAM64H常用封装
上面链接为立创中提供的原理图库与PCB封装,需要可以直接下载。 购买方式在此不做说明,既然你已经看到了这篇博客,说明你已经遇到了问题,或者找到了这款芯片。

原理图设计

PSRAM部分的原理图设计
原理图设计具体如图,在网络上没有找到任何的PSRAM硬件设计指南,此处参考了ESP32-CAM开发板的设计,经实际测试,此原理图可用。

设计中遇到的问题

在软件开发中,我使用的是PlatformIO平台,arduino框架,并非ESP-IDF

通电后,查询可用内存中,显示PSRAM部分可用为0。

  1. 物理连接不良
    如果 ESP32 和 PSRAM 芯片之间的连线(如 SPI 总线等)存在松动、断路或者短路的情况,那么 ESP32 可能无法正确识别和访问 PSRAM,从而导致查询时显示 PSRAM 可用为 0。(一般情况不会出现此类问题) 如果出现,可能会出现报错,PSRAM ID read error: 0x00ffffff 如果出现此类情况,你大概率使用的是IDF开发,此时你需要手动设置SPI模式从4线模式,变为8线模式。
menuconfig->Component config ->ESP PSRAM->Support of external,SPI-connected RAM
menuconfig->Component config ->ESP PSRAM->SPI RAM config->
Mode (QUAD/OCT) of SPI RAM chip in use (Octal Mode PSRAM)->Octal Mode PSRAM
  1. 引脚配置错误
    ESP32 的引脚需要正确配置才能与 PSRAM 进行通信。如果引脚功能设置错误,例如将原本用于 PSRAM 通信的引脚设置为了其他功能。 请根据你的设计 留出IO16 17引脚,正确配置PSRAM。

  2. 未正确初始化
    此问题是常见的无法使用psram的出现情况。

spiram: SPI SRAM memory test fail. 
8593/131072 writes failed,
first @ 3F800140

可能产生此类报错。
在主控模块初始化PSRAM时,会经过以下几个环节,全部通过后,会成功初始化PSRAM,可以使用。

esp_spiram_init();
esp_spiram_init_cache();
esp_spiram_test();
esp_spiram_add_to_heapalloc();

上文的报错中,产生错误为esp_spiram_test();返回了false,导致初始化失败。

bool esp_spiram_test()
{
    volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
    size_t p;
    size_t s=spiram_size_usable_for_malloc();
    int errct=0;
    int initial_err=-1;
    for (p=0; p<(s/sizeof(int)); p+=8) {
        spiram[p]=p^0xAAAAAAAA;
    }
    for (p=0; p<(s/sizeof(int)); p+=8) {
        if (spiram[p]!=(p^0xAAAAAAAA)) {
            errct++;
            if (errct==1) initial_err=p*4;
        }
    }
    if (errct) {
        ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s/32, initial_err+SOC_EXTRAM_DATA_LOW);
        return false;
    } else {
        ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
        return true;
    }
}

大部分版本中,esp_spiram_test()函数内容是这样的,所以说明,此芯片在对某一地址写入时,产生了写入失败。 经过详细排查原因如下。

esp_spiram_test()失败原因

作为内存芯片PSRAM64H的时钟信号相对复杂,较易受到干扰,同时,高速读写时,四条IO线,同时按照时钟周期进行工作,但PSRAM规格说明书中,并没有提出明确的布线要求;经过测试,在布线过程中,尽可能保证PSRAM的四条IO线长度差别尽可能小,可以解决此问题;同时clk线避免与强干扰源距离太近。

重新布线打样后,问题解决。

setupserial running on core 1
setup running on core 1
PSRAM size: 8388608 bytes
Internal free size: 4453063
Deafult free size: 4453063

还可能遇到的问题

主控模块成功识别PSRAM,程序执行时,申请PSRAM重启

具体可能的表现如下

  if (esp_spiram_test()){
    mySerial.println("esp_spiram_test() ok");
  }
//成功返回testok
heap_caps_get_free_size(MALLOC_CAP_8BIT)
heap_caps_get_free_size(MALLOC_CAP_SPIRAM)
//两个函数都能同时获取到 PSram的空间大小
//但在通过函数申请psram芯片所提供的空间时候,发生重启
(uint8_t *)heap_caps_calloc(MEMORY_SIZE, sizeof(uint8_t), MALLOC_CAP_SPIRAM);

进一步测试

#include <Arduino.h>  
#include <esp_system.h>  
#include <esp_spiram.h>  

  
// 假设要分配的内存大小为1024字节  
#define MEMORY_SIZE 1024  
  
// 串口初始化(使用Serial对象)  
void initSerial() {  
  Serial.begin(115200);  
  while (!Serial) {  
    // 等待串口连接  
  }  
}  
  
void setup() {  
  initSerial();  
  
  // 测试PSRAM  
  if (esp_spiram_test()) {  
    Serial.println("esp_spiram_test() ok");  
  } else {  
    Serial.println("PSRAM test failed!");  
    while (1); // 停止执行,如果PSRAM测试失败  
  }  
  delay(3000);  
  size_t max_free_size = heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL);  
  printf("Maximum free heap size (internal RAM): %zu bytes\n", max_free_size);  
  // 获取并输出PSRAM大小  
  int psram_size = esp_spiram_get_size();  
  Serial.printf("PSRAM size: %d bytes\n", psram_size);  
  
  // 输出内部堆、SPIRAM等内存区域的空闲大小  
  Serial.println("Internal free size (8-bit):");  
  Serial.printf("%d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT));  
  Serial.println("SPIRAM free size:");  
  Serial.printf("%d\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));  
  Serial.println("Default free size:");  
  Serial.printf("%d\n", heap_caps_get_free_size(MALLOC_CAP_DEFAULT));  
  
  // 输出复位原因  
  esp_reset_reason_t reset_reason = esp_reset_reason();  
  Serial.println("Reset reason:");  
  switch (reset_reason) {  
    // ... (复位原因的输出代码与之前相同)  
  }  
  
  // 使用heap_caps_calloc从PSRAM中分配内存  
  uint8_t* psramMemory = (uint8_t*)heap_caps_calloc(MEMORY_SIZE, sizeof(uint8_t), MALLOC_CAP_SPIRAM);  
  if (psramMemory == NULL) {  
    Serial.println("Failed to allocate memory from SPIRAM!");  
    return;  
  }  
  
  // 初始化内存内容  
  for (int i = 0; i < MEMORY_SIZE; i++) {  
    psramMemory[i] = 'A' + (i % 26); // 循环写入A-Z  
  }  
  
  // 输出分配内存后的SPIRAM空闲大小  
  Serial.printf("SPIRAM free size after allocation: %d\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));  
  
  // 通过串口输出内存内容的一部分  
  Serial.print("Memory content: ");  
  for (int i = 0; i < 64 && i < MEMORY_SIZE; i++) {  
    Serial.print((char)psramMemory[i]); 
  }  
  Serial.println();  
  
  // 释放内存  
  heap_caps_free(psramMemory); // 使用heap_caps_free来释放由heap_caps_calloc分配的内存  
  
  // 输出释放内存后的SPIRAM空闲大小  
  Serial.printf("SPIRAM free size after release: %d\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));  
}  
  
void loop() {  

}

产生如下的报错信息。

RX:esp_spiram_test() ok

RX:Maximum free heap size (internal RAM): 340996 bytes
PSRAM size: 8388608 bytes
Internal free size (8-bit):
4470923
SPIRAM free size:
4192123
Default free size:
4470923
Reset reason:

Guru Meditation Error: Core  1 panic'ed (StoreProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x4008c0ac  PS      : 0x00060a33  A0      : 0x8008ddc0  A1      : 0x3ffb21a0  
A2      : 0xaaaaaaaa  A3      : 0xb33fffff  A4      : 0x0000cdcd  A5      : 0x00060a23  
A6      : 0x00060a20  A7      : 0x0000abab  A8      : 0x0000abab  A9      : 0xffffffff  
A10     : 0x00000001  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00000000  
A14     : 0x6b2aaaaa  A15     : 0x003fffff  SAR     : 0x00000004  EXCCAUSE: 0x0000001d  
EXCVADDR: 0xaaaaaaaa  LBEG    : 0x40087695  LEND    : 0x400876a5  LCOUNT  : 0xffffffff  


Backtrace: 0x4008c0a9:0x3ffb21a0 0x4008ddbd:0x3ffb21e0 0x4008df25:0x3ffb2200 0x4008392c:0x3ffb2220 0x40083b5b:0x3ffb2250 0x400d1585:0x3ffb2270 0x400d35b6:0x3ffb2290


ELF file SHA256: 4d5f31689b7db5de

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13232
load:0x40080400,len:3028
entry 0x400805e4

Guru Meditation Error: Core 1 panic’ed (StoreProhibited)
它表明 ESP32 或 ESP32-S 系列芯片的核心 1 遇到了一个存储禁止(StoreProhibited)的异常。这通常意味着程序试图写入一个不允许写入的内存地址。

查看报错信息 0xaaaaaaaa ,是一个非法写入的地址,超出了PSRAM的地址范围。

解决方法

尝试简单的delay,避免高频写,可以有效避免此类情况。

### ESP32-S3与PSRAM的使用教程及编程接口 #### 硬件连接 对于ESP32-S3模组而言,其外部扩展了PSRAM来增加可用内存空间。具体到型号如ESP32-S3-WROOM-1-N16R8,该模块配置了8MB Octal PSRAM用于增强数据处理能力[^2]。 当涉及到硬件连接时,由于大多数商用ESP32-S3开发板已经集成了必要的电路设计以支持PSRAM功能,因此用户无需额外考虑复杂的连线问题。然而,在自定义设计中,则需注意确保PSRAM的数据线、地址线以及控制信号能够正确无误地对接至ESP32-S3对应的引脚上,并保持良好的电气特性匹配。 #### 编程接口概述 为了充分利用这些附加资源,Espressif提供了专门针对PSRAM的操作API集合,允许开发者轻松访问并管理这部分存储区域内的数据。这类函数主要集中在`esp_psram.h`头文件下,涵盖了初始化设置、读写操作等多个方面。 #### 初始化过程 在应用程序启动初期,应当调用特定的功能完成对PSRAM的支持加载: ```c #include "esp_psram.h" void setup() { // 启动前检测是否有外挂psram存在 if (!esp_psram_init()) { Serial.println("Failed to initialize PSRAM"); while (true); } } ``` 这段代码片段展示了如何验证是否存在有效的PSRAM设备并与之建立联系;如果失败则进入死循环等待调试介入[^1]。 #### 数据交互示例 一旦完成了上述准备工作之后,就可以像对待常规SRAM那样执行各种形式的数据交换动作了。下面给出了一段简单的例子用来说明怎样向PSRAM内写入一段字符串再将其取出显示出来: ```cpp char *data = NULL; // 动态分配一块位于PSRAM中的缓冲区 data = heap_caps_malloc(strlen("Hello, PSRAM!") + 1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); strcpy(data, "Hello, PSRAM!"); Serial.print("Data from PSRAM: "); Serial.println(data); free(data); // 记得释放再需要的空间 ``` 这里利用到了`heap_caps_malloc()`这个特殊的内存分配器,它可以根据指定的能力标志位(Capability Flags),在这里是指定为仅限于SPI RAM范围内的位置来进行动态分配工作。而后续通过标准库函数实现了基本的文字拷贝和打印输出逻辑[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值