Example: Write / Read to IPS6404 PSRAM (8 MB)

Post your cool example code here.
User avatar
Vassilis
Posts: 181
Joined: Wed Feb 27, 2019 5:09 pm
Answers: 2
Location: Thessaloniki, Greece
OS: Linux, Win10, MacOS
IDE: Arduino 1.8.9
Core: Roger, STM official
Board: Bluepill, Maple mini, STM32F4xx
Contact:

Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by Vassilis » Mon May 06, 2019 4:03 pm

Write/Read to IPS6404 PSRAM - 8 MB (8 MegaBytes Pseudo Static RAM)

Source code example:

Code: Select all

/**
 * 
 * IPS6404 8 MB PSRAM (SPI SRAM) Write/Read example
 * 
 * (c) 2019 by Vassilis Serasidis <avrsite@yahoo.gr>
 *   Home: https://www.serasidis.gr
 *  Forum: https://mcu.selfip.com , https://www.stm32duino.com
 * 
 * Target: STM32F103C8 (Bluepill) at 72 MHz
 *   Core: STM official (https://github.com/stm32duino/Arduino_Core_STM32)
 *    IDE: Arduino 1.8.9
 */

#include <SPI.h>

#define PSRAM_CS  	PA4
#define BUFFER_LENGTH	8192
#define WRITE_TO_PSRAM	0x02
#define READ_FROM_PSRAM	0x03

uint32_t tmr;
uint8_t tmp_buffer[BUFFER_LENGTH];

/***************************************************
 * 
 **************************************************/
void setup() {
  pinMode(PSRAM_CS, OUTPUT);
  digitalWrite(PSRAM_CS, HIGH);
  
  Serial.begin(9600);
  SPI.begin();
  SPI.beginTransaction(SPISettings(72000000, MSBFIRST, SPI_MODE0));
  
  psram_reset();  //Reset the PSRAM chip
}


/***************************************************
 * 
 **************************************************/
void loop() {

  psram_read_id();

  /* Fill the temporary buffer with data */
  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    tmp_buffer[i] = i;
  }
  
  /* Write 8192 byte buffer to PSRAM */
  Serial.print("Writing ");
  Serial.print(BUFFER_LENGTH);
  Serial.print(" bytes   to PSRAM (");
  tmr = millis();
  psram_data(WRITE_TO_PSRAM, 0, tmp_buffer, BUFFER_LENGTH); //Write <tmp_buffer> to PSRAM
  tmr = (millis() - tmr);
  Serial.print(tmr);
  Serial.println(" ms)");

  /* Clear temporary buffer */
  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    tmp_buffer[i] = 0xff;
  }
  
  /* Read 8192 bytes from PSRAM */
  Serial.print("Reading "); 
  Serial.print(BUFFER_LENGTH);
  Serial.print(" bytes from PSRAM (");
  tmr = millis();
  psram_data(READ_FROM_PSRAM, 0, tmp_buffer, BUFFER_LENGTH); //Read data from PSRAM to <tmp_buffer>
  tmr = (millis() - tmr);
  Serial.print(tmr);
  Serial.println(" ms)");
  
  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    if((i%16) == 0){  //Change line every 16 bytes
      Serial.println();
    }

    if(tmp_buffer[i] < 0x10){ //Print an ASCII zero in case the value is lower than 0x10 
      Serial.write('0');
    }
    Serial.print(tmp_buffer[i], HEX);
    Serial.write(' ');
  }
  
  Serial.println("\n\nComplete !\n\n");
  
  delay(1000);
}


/***************************************************
 * 
 **************************************************/
uint8_t psram_read_id(){

  uint8_t data;
  
  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x9F);

  Serial.print("ID: ");
  for(int i=0;i<6;i++){
    data = SPI.transfer(0xff);
    if(data < 0x10){
      Serial.write('0');
    }
    Serial.print(data, HEX);
    Serial.write(' ');
  }
  digitalWrite(PSRAM_CS, HIGH);
  Serial.println();
}


/***************************************************
 * 
 **************************************************/
void psram_reset(){
  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x66);
  digitalWrite(PSRAM_CS, HIGH);
  
  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x99);
  digitalWrite(PSRAM_CS, HIGH);
}

/***************************************************
 * Read or Write <len> bytes from/to PSRAM
 **************************************************/
void psram_data(uint8_t cmd, uint32_t address, uint8_t *buf, uint32_t len){

  uint8_t data;
  
  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(cmd);

  SPI.transfer((uint8_t)((address >> 16) & 0xFF));  //Address [23:16]
  SPI.transfer((uint8_t)((address >> 8) & 0xFF));   //Address [15:8]
  SPI.transfer((uint8_t)(address & 0xFF));          //Address [7:0]
  SPI.transfer(buf, len);
  
  digitalWrite(PSRAM_CS, HIGH);
}

Output:

Code: Select all

ID: FF FF FE 0D 5D 46 
Writing 8192 bytes   to PSRAM (11 ms)
Reading 8192 bytes from PSRAM (11 ms)

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 
...
...
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF 
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF 
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF 

Complete !

-Vassilis Serasidis

User avatar
mack
Posts: 37
Joined: Fri Mar 08, 2019 7:59 pm
Location: Australia
OS: Windows 10
IDE: Arduino 188
Core: Roger (BluePill),StevStrong (F407 Black)
Board: BluePill,F407 Black

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by mack » Thu Aug 15, 2019 9:26 pm

Thanks for this snippet Vassilis, I didn't know of this part and I'll be trying it out soon. :D

Cheers
Andrew

ag123
Posts: 243
Joined: Thu Mar 07, 2019 6:15 am
OS: linux
IDE: eclipse, arduino 1.8.5
Core: Roger's
Board: Maple mini, Bluepill

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by ag123 » Sat Jan 11, 2020 4:26 pm

hi Vassilis,

thanks for posting this code ! :)
would you cross post this in stm32duino forum as well?
i recently soldered one on the pads at bottom that is intended for spi flash on the F401 black pill
viewtopic.php?f=25&t=138#p1199
they are the same pinouts, hence it is a perfect place to solder this

if i managed to make this work (e.g. in steve's libmaple core), i'd post my code as follow-up to this too ;)
if it turns out to be useful, perhaps we'd make it a library after all
it is rather easy to solder this on F401 black pill, that gives the pill F401 or pill F411
8 MB of SPI PSRAM !

there is a lot of uses for this 8MB PSRAM, primary because usb full speed is a mere 12 Mbps and there are overheads.
and if one use usb-serial, that is well below 1 Mbps
while SPI can easily go to say 30-50 mhz or may be higher !
this would make it possible to store away data first in the 8MB PSRAM
and later stream it across usb

and i think it can easily be used as a video buffer, perhaps we'd be able to store away a full even up to 1024x768x4 bytes (about 3 MB)
of a still picture frame - so it'd be useful for many things including like camera picture buffer or even video buffers

it can also be used to store away adc inputs or gpio data and later stream that over usb

i think PSRAM has a constraint that we can't pull /CS (chip select) down for more than 8us or it'd lose memory and there needs to be a pause between the next /CS period. but nevertheless, this is still pretty useful
Last edited by ag123 on Sat Jan 11, 2020 5:00 pm, edited 2 times in total.

ag123
Posts: 243
Joined: Thu Mar 07, 2019 6:15 am
OS: linux
IDE: eclipse, arduino 1.8.5
Core: Roger's
Board: Maple mini, Bluepill

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by ag123 » Sat Jan 11, 2020 4:55 pm


ag123
Posts: 243
Joined: Thu Mar 07, 2019 6:15 am
OS: linux
IDE: eclipse, arduino 1.8.5
Core: Roger's
Board: Maple mini, Bluepill

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by ag123 » Sat Jan 11, 2020 5:04 pm

i actually looked at usb 2.0 high speed, but for that it takes interfacing that 50mhz x 8 bits parallel ULPI interface.
that limits it to hardware support in the bigger chips. and at those speeds, any capacitance to grounds etc would work like near shorts, long wires become antennas/transmission wires and the wiring requirements would be pretty high to the usb high speed transceiver that it takes placing on a pcb with short paths to achieve it.

so this is nearly a next best option to usb high speed

one way to overcome that 8us limit and subsequent refresh could be to use say like 2 PSRAM in an interleaved configuration.
that is cumbersome as there is only set of pads on the black pill f401/f411

other ways to get around this problem is to use the sram to complement this or time the transfers so that they are interleaved say between adc dma and maybe dma to spi - psram

User avatar
Pito
Posts: 27
Joined: Thu Mar 07, 2019 6:48 pm
Location: Rapa Nui
OS: Win7
IDE: Arduino, Sloeber, Uecide
Core: Roger
Board: Blue_Black_MM_103xx_407xx

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by Pito » Sun Jan 12, 2020 1:15 pm

Pukao Hats Cleaning Services, Ltd.

ag123
Posts: 243
Joined: Thu Mar 07, 2019 6:15 am
OS: linux
IDE: eclipse, arduino 1.8.5
Core: Roger's
Board: Maple mini, Bluepill

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by ag123 » Sun Jan 12, 2020 8:22 pm

thanks! i'd check that out

btw one of the datasheets
http://platform.digiic.com/Docs/Product ... RAM%20.pdf

interestingly the other datasheet is from expressif
https://www.espressif.com/sites/default ... eet_en.pdf

User avatar
Pito
Posts: 27
Joined: Thu Mar 07, 2019 6:48 pm
Location: Rapa Nui
OS: Win7
IDE: Arduino, Sloeber, Uecide
Core: Roger
Board: Blue_Black_MM_103xx_407xx

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by Pito » Mon Jan 13, 2020 8:33 am

THe /CE low pulse width limitation to 8usec max is a serious issue, imho.
I worked with 8MByte psram in past (parallel one) and the 8us limitation was for the width of /RD and /WR signals - that was not a problem, however.
Pukao Hats Cleaning Services, Ltd.

ag123
Posts: 243
Joined: Thu Mar 07, 2019 6:15 am
OS: linux
IDE: eclipse, arduino 1.8.5
Core: Roger's
Board: Maple mini, Bluepill

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by ag123 » Mon Jan 13, 2020 2:13 pm

just like to say that Vassilis's code works in (steve's) libmaple core on STM32F401 black pill !
the one with a boot0 button
viewtopic.php?f=25&p=1645#p1624

my blackpill version has the pads for a SPI flash at bottom. the pins are compatible with spi psram.
those pads goes to SPI 1. PA4 .. PA7
there are 3 SPI h/w on F401, so there are still room to add an SPI ILI9341 + another SDFat :lol:

here is my edited verrsion of the code, the key changes is Spisettings needs to be 84 Mhz instead of 72 Mhz.
then there is a big catch that left me trying to figure out for a few hours.
uint8_t psram_read_id() is declared to return uint8_t, but in the original codes, nothing is returned.
when i run the codes, the run keep terminating on return at psram_read_id() and goes back to loop() directly, by passing all the other codes !
in the end the fix is to return a value e.g. 0 and the whole thing runs !

i made my codes run on serial command
r - run

Code: Select all

/**
 *
 * IPS6404 8 MB PSRAM (SPI SRAM) Write/Read example
 *
 * (c) 2019 by Vassilis Serasidis <avrsite@yahoo.gr>
 *   Home: https://www.serasidis.gr
 *  Forum: https://mcu.selfip.com , https://www.stm32duino.com
 *
 * Target: STM32F103C8 (Bluepill) at 72 MHz
 *   Core: STM official (https://github.com/stm32duino/Arduino_Core_STM32)
 *    IDE: Arduino 1.8.9
 */
#include <Arduino.h>
#include <usb_serial.h>
#include "SPI.h"

#define PSRAM_CS  	PA4
#define BUFFER_LENGTH	8192
#define WRITE_TO_PSRAM	0x02
#define READ_FROM_PSRAM	0x03

uint32_t tmr;
uint8_t tmp_buffer[BUFFER_LENGTH];
uint8_t led = 0;

uint8_t psram_read_id();
void psram_reset();
void psram_data(uint8_t cmd, uint32_t address, uint8_t *buf, uint32_t len);
void blinks();
void chkcmd();



/***************************************************
 *
 **************************************************/
void setup() {
  //SerialUSB.begin(0);
  Serial.begin();
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  pinMode(PSRAM_CS, OUTPUT);
  digitalWrite(PSRAM_CS, HIGH);

  //Serial.begin(9600);
  SPI.begin();
  SPI.beginTransaction(SPISettings(84000000, MSBFIRST, SPI_MODE0));
  chkcmd();
  Serial.println();
  blinks();

}


/***************************************************
 *
 **************************************************/

void loop() {
  uint32_t chksum, chksum1;

  Serial.println("get ID");
  psram_read_id();

  psram_reset();  //Reset the PSRAM chip

  /* Fill the temporary buffer with data */
  chksum =0;
  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    tmp_buffer[i] = i;
    chksum ^= i;
  }

  /* Write 8192 byte buffer to PSRAM */
  Serial.print("Writing ");
  Serial.print(BUFFER_LENGTH);
  Serial.print(" bytes   to PSRAM (");
  tmr = millis();
  psram_data(WRITE_TO_PSRAM, 0, tmp_buffer, BUFFER_LENGTH); //Write <tmp_buffer> to PSRAM
  tmr = (millis() - tmr);
  Serial.print(tmr);
  Serial.println(" ms)");
  Serial.print("chksum:");
  Serial.println(chksum);

  /* Clear temporary buffer */
  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    tmp_buffer[i] = 0xff;
  }

  /* Read 8192 bytes from PSRAM */
  Serial.print("Reading ");
  Serial.print(BUFFER_LENGTH);
  Serial.print(" bytes from PSRAM (");
  tmr = millis();
  psram_data(READ_FROM_PSRAM, 0, tmp_buffer, BUFFER_LENGTH); //Read data from PSRAM to <tmp_buffer>
  tmr = (millis() - tmr);
  Serial.print(tmr);
  Serial.println(" ms)");
  chksum1 = 0;
  for(int i=0; i<BUFFER_LENGTH;i++) {
	  chksum1 ^= tmp_buffer[i];
  }
  Serial.print("chksum:");
  Serial.println(chksum1);
  if(chksum == chksum1) Serial.println("match!");

  for(uint32_t i=0;i<BUFFER_LENGTH;i++){
    if((i%16) == 0){  //Change line every 16 bytes
      Serial.println();
    }

    if(tmp_buffer[i] < 0x10){ //Print an ASCII zero in case the value is lower than 0x10
      Serial.write('0');
    }
    Serial.print(tmp_buffer[i], HEX);
    Serial.write(' ');
  }

  Serial.println("\n\nComplete !\n\n");

  //delay(1000);
  chkcmd();
  blinks();

}

/***************************************************
 *
 **************************************************/
uint8_t psram_read_id(){

  uint8_t data;

  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x9F);

  Serial.print("ID: ");
  for(int i=0;i<6;i++){
    data = SPI.transfer(0xff);
    if(data < 0x10){
      Serial.write('0');
    }
    Serial.print(data, HEX);
    Serial.write(' ');
  }
  digitalWrite(PSRAM_CS, HIGH);
  Serial.println();
  return 0;
}


/***************************************************
 *
 **************************************************/
void psram_reset(){
  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x66);
  digitalWrite(PSRAM_CS, HIGH);

  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(0x99);
  digitalWrite(PSRAM_CS, HIGH);
}

/***************************************************
 * Read or Write <len> bytes from/to PSRAM
 **************************************************/
void psram_data(uint8_t cmd, uint32_t address, uint8_t *buf, uint32_t len){

  uint8_t data;

  digitalWrite(PSRAM_CS, LOW);
  SPI.transfer(cmd);

  SPI.transfer((uint8_t)((address >> 16) & 0xFF));  //Address [23:16]
  SPI.transfer((uint8_t)((address >> 8) & 0xFF));   //Address [15:8]
  SPI.transfer((uint8_t)(address & 0xFF));          //Address [7:0]
  SPI.transfer(buf, len);

  digitalWrite(PSRAM_CS, HIGH);
}

void blinks() {
	for(int8_t i=0; i<10; i++) {
		digitalWrite(LED_BUILTIN, led);
		led = (~led) & 1;
		delay(100);
	}
}

void chkcmd() {
	  while(1) {
		  if(Serial.available()) {
			  char c = Serial.read();
			  if( c == 'r')
				  break;
		  }
		  asm("wfi");
	  }
}
results

Code: Select all

get ID
ID: 00 00 00 0D 5D 50
Writing 8192 bytes   to PSRAM (2 ms)
chksum:0
Reading 8192 bytes from PSRAM (3 ms)
chksum:0
match!

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
...
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

Complete !

4 MB per secs ! what is somewhat surprising is that /CS is held low for 2ms for the whole transfer and there is no data loss !
i added a simple xor checksum and verified that the written and read data match !
Last edited by ag123 on Mon Jan 13, 2020 2:29 pm, edited 2 times in total.

stevestrong
Posts: 87
Joined: Tue Mar 05, 2019 7:49 am
Location: Munich
OS: Win7 & 10
IDE: Arduino, Sloeber/Eclipse
Core: Libmaple
Board: Generic F103,F303,F401,F407,F411
Contact:

Re: Example: Write / Read to IPS6404 PSRAM (8 MB)

Post by stevestrong » Mon Jan 13, 2020 2:20 pm

Great!
Just a small note: you don't have to call SPI.begin() if you call SPI.beginTransaction(...).

Post Reply