Additional PSRAM ID that works plus goodies

xxxajk

Well-known member
I have some ISSI PSRAM that is perfectly compatible with Teensy4.1 when the ISSI ID is checked, and you can even mix the two.
The ISSI PSRAM part number I tested is IS66WVR8M8FALL-104NLI and the ID for it is 0x5D9D. (Yes this is a 1.9v part, but works)
I ran all sorts of tests, none fail. Just works. The only thing "missing" in the commands is something that the SOC doesn't use, setting page sizes. As a bonus it provides a new command to go into a super deep sleep/power down mode that retains the contents, which could help with battery powered projects.
There is also a (yet untested) a possibility of using 16MB and the smaller 4MB chips, but I have not tested this yet. This could be accomplished by returning bits 45,46,47 which indicate the memory size.
010 == 32Mb (4MB)
011 == 64Mb (8MB)
100 == 128Mb (16MB)
the other 13 bit patterns are "reserved", i.e. shouldn't ever appear.

I patched like so:
C:
        uint32_t rid = flexspi2_psram_id(0);
        if (rid == 0x5D0D || rid == 0x5D9D) {
                // first PSRAM chip is present, look for a second PSRAM chip
                ...
                rid = flexspi2_psram_id(0);
                if (rid == 0x5D0D || rid == 0x5D9D) {
                        flexspi2_command(4, 0x800000);
                        // Two PSRAM chips are present, 16 MByte
...
 
Last edited:
Why use the 1.8V when there's 3.0V versions available?
It is what I happened to have on hand. BLL should work too. i think ISSI does binning based on the lowest voltage the chip can work at. The maximum voltages are still 3.6v on both, so technically no spec is violated.
 
The fixed 8MB size is hardcoded in other places besides the core, for example the LittleFS library.
 
Well, it shouldn’t be! There’s a perfectly good uint8_t external_psram_size which tells you how much PSRAM is available… I can’t see it hard-coded in LittleFS, though I confess I’ve only taken a cursory look; the LittleFS_RAM::begin() function takes a size parameter, and allocates from PSRAM, so that appears well-behaved.

I think there would be significant interest if the larger size parts could be made to work … @xxxajk, any chance you’d be looking into that?
 
Well, it shouldn’t be! There’s a perfectly good uint8_t external_psram_size which tells you how much PSRAM is available… I can’t see it hard-coded in LittleFS, though I confess I’ve only taken a cursory look; the LittleFS_RAM::begin() function takes a size parameter, and allocates from PSRAM, so that appears well-behaved.
That variable tells you the total size of available PSRAM. It doesn't tell you the size of the first chip only, which is needed to know the starting address of the second chip (which is the supported configuration for flash) in order to send it commands over IP.
 
The fixed 8MB size is hardcoded in other places besides the core, for example the LittleFS library.
LittleFS takes the users specified size for the 'RAM drive:
Code:
    LittleFS_RAM() { }
    bool begin(uint32_t size) {

Doesn't seem to be hardcoded there. Then the T_4.1 space for PSRAM is allocated as : return begin(extmem_malloc(size), size);

Just the global : extern uint8_t external_psram_size;
Is used to set and confirm the 'known' capacity on discovery.

So if extmem knows the details it would work for LittleFS
 
That variable tells you the total size of available PSRAM. It doesn't tell you the size of the first chip only, which is needed to know the starting address of the second chip (which is the supported configuration for flash) in order to send it commands over IP.
Surely this information is only needed within startup.c? Outside that, you want PSRAM to appear as a contiguous block of external_psram_size MB, which can be used via static allocation at compile time, with the rest usable via extmem_malloc(). I can't immediately see why the user should care what chip addresses the available memory are using (2x 8MB vs 1x 16MB, for example).

Yes, there seem to be a couple of options for LittleFS_RAM::begin(). You can either provide the size, in which case it's preferentially allocated in PSRAM, otherwise in heap; or you can provide the address and size of a [probably] statically allocated buffer.
 
Search LittleFS for "0x00800000" (equivalent to 8MB).
I'm sure OP understand the ramifications so I'm not going to waste my time informing others how FlexSPI works.
 
That's all right - I'd hate you to waste your time...

I did do a quick search. Nope, still not getting it ... all the references to the magic number 0x00800000 seem to be totally unrelated to LittleFS_RAM. They're in LittleFS_NAND, and LittleFS_QSPIFlash; oh, and one lonely line:
C++:
static const uint32_t flashBaseAddr = 0x00800000;
Why lonely? Because that symbol is never, ever, used anywhere in the code...
 
That's all right - I'd hate you to waste your time...

I did do a quick search. Nope, still not getting it ... all the references to the magic number 0x00800000 seem to be totally unrelated to LittleFS_RAM. They're in LittleFS_NAND, and LittleFS_QSPIFlash; oh, and one lonely line:
C++:
static const uint32_t flashBaseAddr = 0x00800000;
Why lonely? Because that symbol is never, ever, used anywhere in the code...
Look in startup.c and loader script.

startup.c: configure_external_ram(). Going to be a pain to change since its supports 2 psram chips and its been to long since I played with that section of code;

In imxrt1062_t41.ld: at the begininng:
Code:
ITCM (rwx):  ORIGIN = 0x00000000, LENGTH = 512K
    DTCM (rwx):  ORIGIN = 0x20000000, LENGTH = 512K
    RAM (rwx):   ORIGIN = 0x20200000, LENGTH = 512K
    FLASH (rwx): ORIGIN = 0x60000000, LENGTH = 7936K
    ERAM (rwx):  ORIGIN = 0x70000000, LENGTH = 16384K

again a long time. I thought somebody mentioned about looking in startup.c.
 
I think there are two or three separate discussions all intertwingled here!

Firstly, can startup.c (which yes, I did mention ... post #9) be tweaked to accommodate anything other than one or two 8MB parts? This looks like a bunch of FlexSPI2 register bashing, with indeed many mentions of "0x800000" which could mean "8MB" - a few comments or even a symbol with a meaningful name would be nice... I'd hope someone Skilled in the Art would find this fairly straightforward, unless there's something weird about the higher capacity parts which makes them awkward to drive.

Secondly, as you've pointed out, the linker script would need changing. Good call, presumably not hard to do.

Thirdly, LittleFS also having lots of instances of the magic 0x800000, and thus being "hardcoded for 8MB parts" (post #5). The instances are indeed present, but as noted in post #11 I don't think they're relevant to LittleFS_RAM. I could be wrong about this .. it's been known to occur :)
 
Thirdly, LittleFS also having lots of instances of the magic 0x800000, and thus being "hardcoded for 8MB parts" (post #5). The instances are indeed present, but as noted in post #11 I don't think they're relevant to LittleFS_RAM. I could be wrong about this .. it's been known to occur

Not quite true, its actually referring to the address that the LUT command needs to find the chip. For instance:
Code:
    FLEXSPI2_LUT32 = LUT0(CMD_SDR, PINS1, 0x9F) | LUT1(READ_SDR, PINS1, 1);
    FLEXSPI2_LUT33 = 0;

    flexspi2_ip_read(8, 0x00800000, buf, 3);

    //Serial.printf("Flash ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
    const struct chipinfo *info = chip_lookup(buf);

where `flex_ip_read` is defined in the
Code:
static void flexspi2_ip_read(uint32_t index, uint32_t addr, void *data, uint32_t length)
at about line626 in littleFS.cpp. I have forgotten alot about LUTs but the RM has a bunch of info on it. Oh if you are wondering the 8 in the IP is referring to LUT32 - each lut is 6 bytes. Getting out of comfort zone now but in startup.c you will see ` SCB_MPU_RBAR = 0x80000000 | REGION(i++); // SEMC: SDRAM, NAND, SRAM, etc` which is where the 0x8000000 come from.

Hope this helps - was a confusing as heck when I first worked with LittleFS and SDRAM stuff.
 
Seems if the startup and global for size were accounted for and extmem code updated then having more PSRAM should work - may need linker update not sure of the boundaries set there to allow for stacking the FLASH after it?

As posted the glance at LtilleFS RAM code just takes desired size and then the space requested is reserved in an alloc.
 
OOF! Sorry I poked the hornet's nest :)
I didn't do any modifications that would break things, however I do think that instead of using the uint8_t for the ram size in MB, that instead you should look at the two registers provided, and when nothing is detected, set those to zero!
The real show-stopper as I can see it is that the maximum region is set as 16MB. This needs to be changed to 64mb if one wanted to try to use two 32MB qspi-psram. Yes they exist in 32Mb, and yes I ended up being lucky that the 1.8v ones I use don't smoke.
 
I didn't do any modifications that would break things
It breaks LittleFS because you changed the size in FLSHA1CR0, which affects the address used to issue commands to a flash chip attached to the second port (whether or not there is a chip attached to the first port).
 
It breaks LittleFS because you changed the size in FLSHA1CR0, which affects the address used to issue commands to a flash chip attached to the second port (whether or not there is a chip attached to the first port).
Then, perhaps LittleFS needs to look at that register?
Sorry if that broke it. Never used or needed to use LittleFS considering there's USB and SD for storage, and that I use my own implementation for both. However that doesn't mean I do not see a use case for LittleFS, and obviously others do use it.
All things considered, if I only broke one thing, that's actually not too bad...
 
Ah, OK, I begin to see the light o_O This is where the poor orphaned
Code:
static const uint32_t flashBaseAddr = 0x00800000;
starts to make sense. It ought to have been set (maybe from FLSHA1CR0) and then used throughout the LittleFS code, not a bunch of magic 0x00800000 numbers.

So @xxxajkdo you have any plans to test the larger parts?
 
This is about larger PSRAM chips and LittleFS_RAM right?

The code for LittleFS_RAM gets a memory pointer - RAM2, PSRAM or SDRAM {seems that was tested?} when available - as long as the ?_malloc() works.

It has no inside hardcoded ties to any specific memory - beyond a working malloc. p#8.

LittleFS_RAM is all in the ...\arduino-1.8.19\hardware\teensy\avr\libraries\LittleFS\src\LittleFS.h file
 
Yes. But as @jmarsh has finally got through my thick skull, the LittleFS<various Flash> options are hard-coded to assume their base address is at +8MB into the FlexSPI2 memory map. Which is poor coding, but appears fixable.
 
Ah, now I see "if one wanted to try to use two 32MB" probably means 32 Mbit, which is actually 4 Mbyte. Or maybe I've misunderstood?

But I also see a lot of talk about the 8 Mbyte constants as a problem....

So please allow me to ask again, where can I buy any of these chips with more than 8 Mbyte size? I tried a search at Mouser (the only distributor I could find with stock) and only came up with the 4 Mbyte and 8 Mbyte sizes. Did I miss something?

I want to be clear that I will only consider changing Teensy startup code and linker script published by PJRC to accommodate larger chips when they are actually available on the market. I don't care about bit patterns are defined in "Table 6.2 ID Register" for chips that aren't available to buy. Until the chip larger than 8 Mbyte actually can be purchased, I'm considering all this discussion of supporting larger memory a "what if" conversation about future parts (that don't actually exist today).
 
Back
Top