MCUME/MCUME_pico2/psram/psram_spi.pio

159 wiersze
6.8 KiB
Plaintext
Executable File

; rp2040-psram
;
; Copyright © 2023 Ian Scott
;
; Permission is hereby granted, free of charge, to any person obtaining a copy of
; this software and associated documentation files (the “Software”), to deal in
; the Software without restriction, including without limitation the rights to
; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
; of the Software, and to permit persons to whom the Software is furnished to do
; so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in all
; copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.
; SPI, customized as the PSRAM chips like to implement it:
; - Data is always written first, then optionally read
; Depending on PCB layout, introduce fudge factor:
; - Reads in high speed mode need an extra clock cycle to synchronize
; - Reads are done on the falling edge of SCK when > 83MHz
.program spi_psram_fudge
.side_set 2 ; sideset bit 1 is SCK, bit 0 is CS
begin:
out x, 8 side 0b01 ; x = number of bits to output. CS deasserted
out y, 8 side 0b01 ; y = number of bits to input
jmp x--, writeloop side 0b01 ; Pre-decement x by 1 so loop has correct number of iterations
writeloop: ; Put the data and rise the clock!!!!
out pins, 1 side 0b00 ; Write value on pin on lower clock. CS asserted
jmp x--, writeloop side 0b10 ; Raise clock: this is when PSRAM reads the value. Loop if we have more to write
jmp !y, begin side 0b00 ; If this is a write-only operation, jump back to beginning
nop side 0b10 ; Fudge factor of extra clock cycle; the PSRAM needs 1 extra for output to start appearing
jmp readloop_mid side 0b00 ; Jump to middle of readloop to decrement y and get right clock phase
readloop:
in pins, 1 side 0b00 ; Read value on pin, lower clock. Datasheet says to read on falling edge > 83MHz
readloop_mid:
jmp y--, readloop side 0b10 ; Raise clock. Loop if we have more to read
% c-sdk {
#include "hardware/gpio.h"
static inline void pio_spi_psram_cs_init(bool init_done, PIO pio, uint sm, uint prog_offs, uint n_bits, float clkdiv, bool fudge, uint pin_cs, uint pin_mosi, uint pin_miso) {
pio_sm_set_enabled(pio, sm, false);
pio_sm_clear_fifos(pio, sm);
pio_sm_restart(pio, sm);
pio_sm_config c;
c = spi_psram_fudge_program_get_default_config(prog_offs);
sm_config_set_out_pins(&c, pin_mosi, 1);
sm_config_set_in_pins(&c, pin_miso);
sm_config_set_sideset_pins(&c, pin_cs);
sm_config_set_out_shift(&c, false, true, n_bits);
sm_config_set_in_shift(&c, false, true, n_bits);
sm_config_set_clkdiv(&c, clkdiv);
pio_sm_set_consecutive_pindirs(pio, sm, pin_cs, 2, true);
pio_sm_set_consecutive_pindirs(pio, sm, pin_mosi, 1, true);
pio_sm_set_consecutive_pindirs(pio, sm, pin_miso, 1, false);
pio_gpio_init(pio, pin_mosi);
pio_gpio_init(pio, pin_miso);
pio_gpio_init(pio, pin_cs);
pio_gpio_init(pio, pin_cs + 1);
hw_set_bits(&pio->input_sync_bypass, 1u << pin_miso);
if (!init_done) {
pio_sm_init(pio, sm, prog_offs, &c);
}
pio_sm_set_enabled(pio, sm, true);
}
%}
.program qspi_psram
.side_set 2
begin:
out x, 8 side 0b01 ; x = number of nibbles to output. CS deasserted
out y, 8 side 0b01 ; y = number of nibbles to input
jmp x--, writeloop side 0b01 ; Pre-decement x by 1 so loop has correct number of iterations
writeloop:
out pins, 4 side 0b00 ; Write value on pins on lower clock. CS asserted
jmp x--, writeloop side 0b10 ; Raise clock: this is when PSRAM reads the value. Loop if we have more to write
jmp !y, begin side 0b00 ; If this is a write-only operation, jump back to beginning
nop side 0b10 ; 1
nop side 0b00
nop side 0b10 ; 2
nop side 0b00
nop side 0b10 ; 3
nop side 0b00
nop side 0b10 ; 4
nop side 0b00 ; data to read is put now by PSRAM
nop side 0b10
set pindirs 0 side 0b00 ; Fudge factor of extra clock cycle; the PSRAM needs 1 extra for output to start appearing
jmp readloop_mid side 0b10 ; Jump to middle of readloop to decrement y and get right clock phase
readloop:
in pins, 4 side 0b10 ; Read value on s, lower clock. Datasheet says to read on falling edge > 83MHz
readloop_mid:
jmp y--, readloop side 0b00 ; Raise clock. Loop if we have more to read
set pindirs 0xF side 0b01
; set pindirs 0 side 0b00 ; data to read is put now by PSRAM
; nop side 0b10 ; Fudge factor of extra clock cycle; the PSRAM needs 1 extra for output to start appearing
; jmp readloop_mid side 0b00 ; Jump to middle of readloop to decrement y and get right clock phase
;readloop:
; in pins, 4 side 0b00 ; Read value on s, lower clock. Datasheet says to read on falling edge > 83MHz
;readloop_mid:
; jmp y--, readloop side 0b10 ; Raise clock. Loop if we have more to read
; set pindirs 0xF side 0b00
% c-sdk {
#include "hardware/gpio.h"
static inline void pio_qspi_psram_cs_init(bool init_done, PIO pio, uint sm, uint prog_offs, uint n_bits, float clkdiv, uint pin_cs, uint pin_sio0) {
pio_sm_set_enabled(pio, sm, false);
pio_sm_clear_fifos(pio, sm);
pio_sm_restart(pio, sm);
pio_sm_config c;
c = qspi_psram_program_get_default_config(prog_offs);
sm_config_set_out_pins(&c, pin_sio0, 4);
sm_config_set_in_pins(&c, pin_sio0);
sm_config_set_set_pins(&c, pin_sio0, 4);
sm_config_set_sideset_pins(&c, pin_cs);
sm_config_set_out_shift(&c, false, true, n_bits);
sm_config_set_in_shift(&c, false, true, n_bits);
sm_config_set_clkdiv(&c, clkdiv);
pio_sm_set_consecutive_pindirs(pio, sm, pin_cs, 2, true);
pio_sm_set_consecutive_pindirs(pio, sm, pin_sio0, 4, true);
pio_gpio_init(pio, pin_sio0);
pio_gpio_init(pio, pin_sio0 + 1);
pio_gpio_init(pio, pin_sio0 + 2);
pio_gpio_init(pio, pin_sio0 + 3);
pio_gpio_init(pio, pin_cs);
pio_gpio_init(pio, pin_cs + 1);
hw_set_bits(&pio->input_sync_bypass, 0xfu << pin_sio0);
if (!init_done) {
pio_sm_init(pio, sm, prog_offs, &c);
}
pio_sm_set_enabled(pio, sm, true);
}
%}