PSRAM example
Hello,
I took a look at this demo and wanted to try to interact with the P2 edge's 32MB of Ram:
https://forums.parallax.com/discussion/176083/3d-teapot-demo/p1
I did read some of the code in this thread and referenced the manual. The program does compile but I feel like i'm missing something to write the letter A to the psram and then read it back:
' sets the system clock frequency _CLKFREQ = 180_000_000 ' set the receiving pin for input to the P2 microcontroller RX_PIN = 63 ' set the transmission pin for output from the P2 microcontroller TX_PIN = 62 ' set the baud mode to support 2000000 baud BAUD_RATE = 2_000_000 ' set the serial clock period for the baud rate based on the system clock frequency (_CLKFREQ) SERIAL_CLOCK = ( _CLKFREQ / BAUD_RATE ) ' calculate a bit period value for the serial communication baud rate. BIT_PERIOD = (( SERIAL_CLOCK << 16 ) & $FFFFFC00 ) + ( 8 - 1 ) ' PSRAM Pin Definitions P_PSRAM_D = 40 ' Data bus (4-bit, P40-P43) P_PSRAM_CLK = 56 ' PSRAM Clock P_PSRAM_CE = 57 ' PSRAM Chip Enable ' Constants PSRAM_ADDR = $000000 ' Address to store 'A' in PSRAM dat org 0 ' start assembling code from address 0 asmclk ' use the system clock (_CLKFREQ) for timing-related calculations ' Configure RX smart pin wrpin ##(P_ASYNC_RX | P_HIGH_15K), #RX_PIN ' configure the RX pin as a smart pin for asynchronous serial reception wxpin ##BIT_PERIOD, #RX_PIN ' set the correct timing for receiving bits at the correct speed wypin #1, #RX_PIN ' Enable the smart pin dirh #RX_PIN ' sets the direction of the RX pin to high ' Configure TX smart pin wrpin ##(P_ASYNC_TX | P_OE), #TX_PIN ' configure the TX pin as a smart pin for asynchronous serial transmission wxpin ##BIT_PERIOD, #TX_PIN ' set the correct timing for transmitting bits at the correct speed wypin #1, #TX_PIN ' Enable the smart pin transmitter dirh #TX_PIN ' sets the direction of the TX pin to high .start ' Initialize system call #.psram_init ' Initialize PSRAM ' Write letter 'A' to PSRAM mov tmp1, #$41 call #.write_psram ' Read back letter 'A' from PSRAM call #.read_psram ' Send output to PST call #.uart_tx_char ' End program loop jmp #.done '------------------------------------------------------------ ' Initialize PSRAM '------------------------------------------------------------ .psram_init ' Activate PSRAM to prepare for operations drvl #P_PSRAM_CE ' Activate PSRAM (low active) ret '------------------------------------------------------------ ' Write to PSRAM (Full 8-bit mode) '------------------------------------------------------------ .write_psram ' Set address (PSRAM_ADDR = 0x000000) mov tmp2, #PSRAM_ADDR ' Enable PSRAM drvl #P_PSRAM_CE ' Write Data (8-bit split into 4-bit nibbles) mov tmp0, tmp1 ' Copy the 8-bit value and tmp1, ##$F ' Mask the lower 4 bits (lower nibble) mov outa, tmp1 wrpin ##%01, #P_PSRAM_D ' Configure P40-P43 as outputs drvl #P_PSRAM_CLK call #.clock_pulse drvh #P_PSRAM_CLK ' Write second nibble (upper 4 bits) shr tmp0, #4 ' Shift right by 4 to get the upper nibble and tmp0, ##$F ' Mask the upper 4 bits mov outa, tmp0 wrpin ##%01, #P_PSRAM_D ' Configure P40-P43 as outputs drvl #P_PSRAM_CLK call #.clock_pulse drvh #P_PSRAM_CLK ' Disable PSRAM drvh #P_PSRAM_CE ret '------------------------------------------------------------ ' Read from PSRAM (Full 8-bit mode) '------------------------------------------------------------ .read_psram ' Enable PSRAM drvl #P_PSRAM_CE ' Set Data Bus as Input wrpin ##%00, #P_PSRAM_D ' Configure P40-P43 as inputs dirl #P_PSRAM_D ' Set direction to input ' Clock Pulse Before Reading call #.clock_pulse ' Read lower nibble (first 4 bits) rdpin tmp3, #P_PSRAM_D ' Read data from P40-P43 and tmp3, ##$F ' Mask only the 4-bit value ' Shift to make room for the upper nibble shl tmp3, #4 ' Shift left to clear the lower nibble ' Clock Pulse Before Reading Upper nibble call #.clock_pulse ' Read upper nibble (next 4 bits) rdpin tmp4, #P_PSRAM_D ' Read data from P40-P43 and tmp4, ##$F ' Mask only the 4-bit value or tmp3, tmp4 ' Combine the two nibbles (upper + lower) ' Send the read value for debugging call #.uart_tx_char ' Send value through UART ' Disable PSRAM drvh #P_PSRAM_CE ret .data_error ' Handle the error (e.g., signal failure via UART or LED) call #.uart_tx_char ' Send an error message ret '------------------------------------------------------------ ' UART Send Character (t3 contains data) '------------------------------------------------------------ .uart_tx_char wypin tmp3, #TX_PIN ' Send character nop waitx ##5000 ' Small delay for stability ret '------------------------------------------------------------ ' Clock Pulse Routine '------------------------------------------------------------ .clock_pulse drvl #P_PSRAM_CLK nop drvh #P_PSRAM_CLK ret .done '------------------------------------------------------------ ' Variable Registers '------------------------------------------------------------ tmp0 res 1 ' tmp1 res 1 ' tmp2 res 1 ' tmp3 res 1 ' tmp4 res 1 '
Comments
It doesn't work quite so easily:
See also:
I have had great success with psram.spin2 and psram16drv.spin2 found at
https://www.parallax.com/package/p2-solar-panel-code/
This driver pair allows burst reads and writes; longer reads and writes achieve greater efficiency. For example, moving 64 longs at at time yields 100 MB/s. Huge thanks to Michael Mulholland for developing these drivers! (I use flexspin/flexprop, which may be required, not sure.)
Roger Loh wrote those two particular files - https://forums.parallax.com/discussion/171176/memory-drivers-for-p2-psram-sram-hyperram-was-hyperram-driver-for-p2/p1
This was all helpful to get me a little closer.
Right now, i fixed things so the output at least works. I get the character ?, but i still need to do the streamer. Also replaced the rdpin's with some rdbytes an the same for the writing. I tested the read a bit to make sure it at least works with these lines:
'this is a test
'mov tmp3, #"A"
At this point in the code, it prints A if i uncomment the mov, otherwise I get the ?. The PSRAM's datasheet was extremely helpful. I'll keep plugging away at it though.
RDBYTE is also not the correct instruction for this.
You want
GETBYTE x, INA+(P_PSRAM_D/32),#(P_PSRAM_D/8)&3
. That will grab a byte from the I/O port.Though I would recommend getting a grip on the basics of PASM programming before trying to mess with something harder like the PSRAM.
That might not be a bad idea, will do. Thank you!
@cgracey made a super simple PSRAM driver. He is using it for VGA in this thread:
https://forums.parallax.com/discussion/175725/anti-aliased-24-bits-per-pixel-hdmi/p1
@Rayman
Wow, I’m gonna bookmark this and have a closer look. I took a quick scan of it and noticed it has all the parts in here and even the streamer. I might give it another shot. Thank you!!!
After this though I might go back to some of the simpler add ons and general assembly language as suggested. I think I got ahead of myself when I was able a lot things working so quickly.
It looks like there is a bug with the number of clocks generate in Chip's driver code. I've not tested it but it looks like the
add pb,len
should be amov pb,len
instead. Amusingly it probably doesn't really matter a lot since the clock can probably be left running unbroken anyway.