I'm trying to access the PSRAM on a Pimoroni pico plus 2 but im not very skilled in C++.
I'm using platform io.
platformio.ini:
[env:rpipico2]
platform = .git
build_flags = -fexceptions
board = rpipico2
board_build.core = earlephilhower
framework = arduino
lib_deps =
SPI
Things I've tried
1 - AndrewCapon's library
This library: , however the board would freeze when I called getInstance.
2 - Using lwmem directly
I was trying to do a simple routine of adding numbers to an array then printing them:
// ChatGPT slop:
#include <Arduino.h>
#include <lwmem/lwmem.h>
//---------------------------------------------------------------------------
// 1) Configure PSRAM region
// (Addresses/size may differ on your board)
//---------------------------------------------------------------------------
#define PSRAM_LOCATION (0x11000000) // Common base address on some Pico-like boards
#define PSRAM_SIZE (8 * 1024 * 1024) // Example: 8 MB PSRAM
static lwmem_region_t psram_regions[] = {
{(void *)PSRAM_LOCATION, PSRAM_SIZE},
{NULL, 0} // Terminator
};
//---------------------------------------------------------------------------
// 2) Global variables
//---------------------------------------------------------------------------
static int *myArray = nullptr; // Pointer to array in PSRAM
static size_t arraySize = 10; // How many elements in our array
static size_t currentIndex = 0; // Tracks where we write next
//---------------------------------------------------------------------------
// 3) Setup
//---------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
while (!Serial)
{
// Wait for Serial on some boards
}
delay(1000);
// Let lwmem know it can use our PSRAM region
lwmem_assignmem(psram_regions);
Serial.println("Assigned PSRAM region to lwmem.");
// Use calloc so the array is zero-initialized
myArray = (int *)lwmem_calloc(arraySize, sizeof(int));
if (!myArray)
{
Serial.println("PSRAM allocation failed!");
while (true)
{ /* halt */
}
}
Serial.println("Allocated zero-initialized array in PSRAM.");
// Print initial contents (should all be zero)
Serial.println("Initial array contents:");
for (size_t i = 0; i < arraySize; i++)
{
Serial.print(myArray[i]);
if (i < arraySize - 1)
{
Serial.print(", ");
}
}
Serial.println();
}
//---------------------------------------------------------------------------
// 4) Loop
//---------------------------------------------------------------------------
void loop()
{
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 5000)
{
lastPrint = millis();
// Store a random value in the array
int value = random(0, 1000); // Range: [0 .. 999]
myArray[currentIndex] = value;
Serial.print("Added ");
Serial.print(value);
Serial.print(" at index ");
Serial.println(currentIndex);
// Print entire array
Serial.print("Current array contents: ");
for (size_t i = 0; i < arraySize; i++)
{
Serial.print(myArray[i]);
if (i < arraySize - 1)
{
Serial.print(", ");
}
}
Serial.println();
// Move to next index, wrap around at the end
currentIndex = (currentIndex + 1) % arraySize;
}
}
Output was this so I figure the ram hasnt been mapped?
-initialized array in PSRAM.
Initial array contents:
0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
Added 933 at index 0
Current array contents: 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
Added 743 at index 1
Current array contents: 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
3 - Attempt to map the PSRAM
I asked ChatGPT to configure the PSRAM before running the same demo. It gave the following and when I ran it, I would get the same freezing behaviour as the first attempt.
// main.cpp
#include <Arduino.h>
// ============== Attempt to pull in Pico SDK hardware headers ==============
extern "C" {
#include <lwmem/lwmem.h>
}
#include "pico/stdlib.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/qmi.h"
#include "hardware/structs/xip_ctrl.h"
#include "hardware/sync.h"
#include "hardware/clocks.h"
// ------------- Config for your external PSRAM -------------
#define PIMORONI_PICO_PLUS2_PSRAM_CS_PIN 29
#define PSRAM_BASE_ADDR 0x11000000
#define PSRAM_SIZE_BYTES (8 * 1024 * 1024) // 8 MB example
// ------------- lwmem region for PSRAM -------------
static lwmem_region_t psram_regions[] = {
{ (void*)PSRAM_BASE_ADDR, PSRAM_SIZE_BYTES },
{ NULL, 0 }
};
// ------------- Mark function to (try to) place in ramfunc -------------
#define PSRAM_INIT_FN __attribute__((section(".ramfunc")))
// ------------- Minimal PSRAM init function -------------
PSRAM_INIT_FN bool psram_init_minimal(uint cs_pin) {
// 1) Setup CS pin for XIP
gpio_set_function(cs_pin, GPIO_FUNC_XIP_CS1);
// Disable interrupts
uint32_t save = save_and_disable_interrupts();
// Enter direct mode with safe divider
qmi_hw->direct_csr = (30 << QMI_DIRECT_CSR_CLKDIV_LSB) | QMI_DIRECT_CSR_EN_BITS;
while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) {
tight_loop_contents();
}
// Example: Send "QPI enable" command (0x35)
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
qmi_hw->direct_tx = 0x35;
// Wait for TX empty
while (!(qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS)) {
tight_loop_contents();
}
// Wait for not busy
while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) {
tight_loop_contents();
}
qmi_hw->direct_csr &= ~QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
// Setup M1 region
int clk_sys_hz = clock_get_hz(clk_sys);
int desired_psram_freq = 133000000;
int divisor = (clk_sys_hz + desired_psram_freq - 1) / desired_psram_freq;
if (divisor < 2) {
divisor = 2;
}
int rxdelay = divisor;
int max_select = 10;
int min_deselect = 2;
qmi_hw->m[1].timing =
(1 << QMI_M1_TIMING_COOLDOWN_LSB)
| (QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB)
| (max_select << QMI_M1_TIMING_MAX_SELECT_LSB)
| (min_deselect << QMI_M1_TIMING_MIN_DESELECT_LSB)
| (rxdelay << QMI_M1_TIMING_RXDELAY_LSB)
| (divisor << QMI_M1_TIMING_CLKDIV_LSB);
// QPI read: 0xEB
qmi_hw->m[1].rfmt =
(QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB)
| (QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB)
| (QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB)
| (QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB)
| (QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB)
| (QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB)
| (6 << QMI_M0_RFMT_DUMMY_LEN_LSB);
qmi_hw->m[1].rcmd = 0xEB;
// QPI write: 0x38
qmi_hw->m[1].wfmt =
(QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB)
| (QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB)
| (QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB)
| (QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB)
| (QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB)
| (QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB);
qmi_hw->m[1].wcmd = 0x38;
// Exit direct mode
qmi_hw->direct_csr = 0;
// Enable writes to M1
hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS);
restore_interrupts(save);
return true;
}
// ------------- Demo array -------------
static int* myArray = nullptr;
static size_t arraySize = 10;
static size_t currentIndex = 0;
// ------------- Setup -------------
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Starting Arduino + PSRAM + lwmem demo...");
// Attempt to init PSRAM
Serial.println("Initializing external PSRAM...");
if (!psram_init_minimal(PIMORONI_PICO_PLUS2_PSRAM_CS_PIN)) {
Serial.println("PSRAM init failed!");
while (true) { }
}
Serial.println("PSRAM init success (hopefully)!");
// Assign lwmem region
lwmem_assignmem(psram_regions);
Serial.println("Assigned lwmem to use PSRAM region.");
// Allocate array in PSRAM
myArray = (int*) lwmem_calloc(arraySize, sizeof(int));
if (!myArray) {
Serial.println("PSRAM allocation failed!");
while (true) { }
}
Serial.print("Allocated an array of ");
Serial.print(arraySize);
Serial.println(" integers in PSRAM.");
// Print initial contents
Serial.println("Initial array contents:");
for (size_t i = 0; i < arraySize; i++) {
Serial.print(myArray[i]);
if (i < arraySize - 1) Serial.print(", ");
}
Serial.println();
}
// ------------- Loop -------------
void loop() {
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 5000) {
lastPrint = millis();
// Store a random value
int val = random(0, 1000);
myArray[currentIndex] = val;
Serial.print("Wrote ");
Serial.print(val);
Serial.print(" at index ");
Serial.println(currentIndex);
// Print the whole array
Serial.print("Array: ");
for (size_t i = 0; i < arraySize; i++) {
Serial.print(myArray[i]);
if (i < arraySize - 1) Serial.print(", ");
}
Serial.println();
currentIndex = (currentIndex + 1) % arraySize;
}
}
ChatGPT suggested that using the Arduino framework is my issue because it interrupts the reading of the code from flash.
Unfortunately this is not my wheelhouse so im really struggling. A minimal working demo similar to the above would be so helpful but I can't find anything online.
I'm trying to access the PSRAM on a Pimoroni pico plus 2 but im not very skilled in C++.
I'm using platform io.
platformio.ini:
[env:rpipico2]
platform = https://github/maxgerhardt/platform-raspberrypi.git
build_flags = -fexceptions
board = rpipico2
board_build.core = earlephilhower
framework = arduino
lib_deps =
SPI
Things I've tried
1 - AndrewCapon's library
This library: https://github/AndrewCapon/PicoPlusPsram, however the board would freeze when I called getInstance.
2 - Using lwmem directly
I was trying to do a simple routine of adding numbers to an array then printing them:
// ChatGPT slop:
#include <Arduino.h>
#include <lwmem/lwmem.h>
//---------------------------------------------------------------------------
// 1) Configure PSRAM region
// (Addresses/size may differ on your board)
//---------------------------------------------------------------------------
#define PSRAM_LOCATION (0x11000000) // Common base address on some Pico-like boards
#define PSRAM_SIZE (8 * 1024 * 1024) // Example: 8 MB PSRAM
static lwmem_region_t psram_regions[] = {
{(void *)PSRAM_LOCATION, PSRAM_SIZE},
{NULL, 0} // Terminator
};
//---------------------------------------------------------------------------
// 2) Global variables
//---------------------------------------------------------------------------
static int *myArray = nullptr; // Pointer to array in PSRAM
static size_t arraySize = 10; // How many elements in our array
static size_t currentIndex = 0; // Tracks where we write next
//---------------------------------------------------------------------------
// 3) Setup
//---------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
while (!Serial)
{
// Wait for Serial on some boards
}
delay(1000);
// Let lwmem know it can use our PSRAM region
lwmem_assignmem(psram_regions);
Serial.println("Assigned PSRAM region to lwmem.");
// Use calloc so the array is zero-initialized
myArray = (int *)lwmem_calloc(arraySize, sizeof(int));
if (!myArray)
{
Serial.println("PSRAM allocation failed!");
while (true)
{ /* halt */
}
}
Serial.println("Allocated zero-initialized array in PSRAM.");
// Print initial contents (should all be zero)
Serial.println("Initial array contents:");
for (size_t i = 0; i < arraySize; i++)
{
Serial.print(myArray[i]);
if (i < arraySize - 1)
{
Serial.print(", ");
}
}
Serial.println();
}
//---------------------------------------------------------------------------
// 4) Loop
//---------------------------------------------------------------------------
void loop()
{
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 5000)
{
lastPrint = millis();
// Store a random value in the array
int value = random(0, 1000); // Range: [0 .. 999]
myArray[currentIndex] = value;
Serial.print("Added ");
Serial.print(value);
Serial.print(" at index ");
Serial.println(currentIndex);
// Print entire array
Serial.print("Current array contents: ");
for (size_t i = 0; i < arraySize; i++)
{
Serial.print(myArray[i]);
if (i < arraySize - 1)
{
Serial.print(", ");
}
}
Serial.println();
// Move to next index, wrap around at the end
currentIndex = (currentIndex + 1) % arraySize;
}
}
Output was this so I figure the ram hasnt been mapped?
-initialized array in PSRAM.
Initial array contents:
0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
Added 933 at index 0
Current array contents: 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
Added 743 at index 1
Current array contents: 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524, 0, -858993524
3 - Attempt to map the PSRAM
I asked ChatGPT to configure the PSRAM before running the same demo. It gave the following and when I ran it, I would get the same freezing behaviour as the first attempt.
// main.cpp
#include <Arduino.h>
// ============== Attempt to pull in Pico SDK hardware headers ==============
extern "C" {
#include <lwmem/lwmem.h>
}
#include "pico/stdlib.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/qmi.h"
#include "hardware/structs/xip_ctrl.h"
#include "hardware/sync.h"
#include "hardware/clocks.h"
// ------------- Config for your external PSRAM -------------
#define PIMORONI_PICO_PLUS2_PSRAM_CS_PIN 29
#define PSRAM_BASE_ADDR 0x11000000
#define PSRAM_SIZE_BYTES (8 * 1024 * 1024) // 8 MB example
// ------------- lwmem region for PSRAM -------------
static lwmem_region_t psram_regions[] = {
{ (void*)PSRAM_BASE_ADDR, PSRAM_SIZE_BYTES },
{ NULL, 0 }
};
// ------------- Mark function to (try to) place in ramfunc -------------
#define PSRAM_INIT_FN __attribute__((section(".ramfunc")))
// ------------- Minimal PSRAM init function -------------
PSRAM_INIT_FN bool psram_init_minimal(uint cs_pin) {
// 1) Setup CS pin for XIP
gpio_set_function(cs_pin, GPIO_FUNC_XIP_CS1);
// Disable interrupts
uint32_t save = save_and_disable_interrupts();
// Enter direct mode with safe divider
qmi_hw->direct_csr = (30 << QMI_DIRECT_CSR_CLKDIV_LSB) | QMI_DIRECT_CSR_EN_BITS;
while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) {
tight_loop_contents();
}
// Example: Send "QPI enable" command (0x35)
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
qmi_hw->direct_tx = 0x35;
// Wait for TX empty
while (!(qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS)) {
tight_loop_contents();
}
// Wait for not busy
while (qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) {
tight_loop_contents();
}
qmi_hw->direct_csr &= ~QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
// Setup M1 region
int clk_sys_hz = clock_get_hz(clk_sys);
int desired_psram_freq = 133000000;
int divisor = (clk_sys_hz + desired_psram_freq - 1) / desired_psram_freq;
if (divisor < 2) {
divisor = 2;
}
int rxdelay = divisor;
int max_select = 10;
int min_deselect = 2;
qmi_hw->m[1].timing =
(1 << QMI_M1_TIMING_COOLDOWN_LSB)
| (QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB)
| (max_select << QMI_M1_TIMING_MAX_SELECT_LSB)
| (min_deselect << QMI_M1_TIMING_MIN_DESELECT_LSB)
| (rxdelay << QMI_M1_TIMING_RXDELAY_LSB)
| (divisor << QMI_M1_TIMING_CLKDIV_LSB);
// QPI read: 0xEB
qmi_hw->m[1].rfmt =
(QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB)
| (QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB)
| (QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB)
| (QMI_M0_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_RFMT_DUMMY_WIDTH_LSB)
| (QMI_M0_RFMT_DATA_WIDTH_VALUE_Q << QMI_M0_RFMT_DATA_WIDTH_LSB)
| (QMI_M0_RFMT_PREFIX_LEN_VALUE_8 << QMI_M0_RFMT_PREFIX_LEN_LSB)
| (6 << QMI_M0_RFMT_DUMMY_LEN_LSB);
qmi_hw->m[1].rcmd = 0xEB;
// QPI write: 0x38
qmi_hw->m[1].wfmt =
(QMI_M0_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_PREFIX_WIDTH_LSB)
| (QMI_M0_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_WFMT_ADDR_WIDTH_LSB)
| (QMI_M0_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_WFMT_SUFFIX_WIDTH_LSB)
| (QMI_M0_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M0_WFMT_DUMMY_WIDTH_LSB)
| (QMI_M0_WFMT_DATA_WIDTH_VALUE_Q << QMI_M0_WFMT_DATA_WIDTH_LSB)
| (QMI_M0_WFMT_PREFIX_LEN_VALUE_8 << QMI_M0_WFMT_PREFIX_LEN_LSB);
qmi_hw->m[1].wcmd = 0x38;
// Exit direct mode
qmi_hw->direct_csr = 0;
// Enable writes to M1
hw_set_bits(&xip_ctrl_hw->ctrl, XIP_CTRL_WRITABLE_M1_BITS);
restore_interrupts(save);
return true;
}
// ------------- Demo array -------------
static int* myArray = nullptr;
static size_t arraySize = 10;
static size_t currentIndex = 0;
// ------------- Setup -------------
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Starting Arduino + PSRAM + lwmem demo...");
// Attempt to init PSRAM
Serial.println("Initializing external PSRAM...");
if (!psram_init_minimal(PIMORONI_PICO_PLUS2_PSRAM_CS_PIN)) {
Serial.println("PSRAM init failed!");
while (true) { }
}
Serial.println("PSRAM init success (hopefully)!");
// Assign lwmem region
lwmem_assignmem(psram_regions);
Serial.println("Assigned lwmem to use PSRAM region.");
// Allocate array in PSRAM
myArray = (int*) lwmem_calloc(arraySize, sizeof(int));
if (!myArray) {
Serial.println("PSRAM allocation failed!");
while (true) { }
}
Serial.print("Allocated an array of ");
Serial.print(arraySize);
Serial.println(" integers in PSRAM.");
// Print initial contents
Serial.println("Initial array contents:");
for (size_t i = 0; i < arraySize; i++) {
Serial.print(myArray[i]);
if (i < arraySize - 1) Serial.print(", ");
}
Serial.println();
}
// ------------- Loop -------------
void loop() {
static unsigned long lastPrint = 0;
if (millis() - lastPrint >= 5000) {
lastPrint = millis();
// Store a random value
int val = random(0, 1000);
myArray[currentIndex] = val;
Serial.print("Wrote ");
Serial.print(val);
Serial.print(" at index ");
Serial.println(currentIndex);
// Print the whole array
Serial.print("Array: ");
for (size_t i = 0; i < arraySize; i++) {
Serial.print(myArray[i]);
if (i < arraySize - 1) Serial.print(", ");
}
Serial.println();
currentIndex = (currentIndex + 1) % arraySize;
}
}
ChatGPT suggested that using the Arduino framework is my issue because it interrupts the reading of the code from flash.
Unfortunately this is not my wheelhouse so im really struggling. A minimal working demo similar to the above would be so helpful but I can't find anything online.
Share Improve this question edited Feb 3 at 9:47 Steve asked Feb 2 at 1:12 SteveSteve 5,0051 gold badge34 silver badges43 bronze badges 1 |2 Answers
Reset to default 0The answer was in the config
myArray[currentIndex]
immediately aftermyArray[currentIndex] = val;
instead of waiting for the loop that prints the entire array. If after assigning the value into the array you don't see the value, then start from there, as there would be something very suspicious if after you assign a value, you don't see it assigned. In other words, you could create a more minimal minimal reproducible example (and I am not an arduino programmer). – PaulMcKenzie Commented Feb 2 at 1:56