#include "iopins.h" #ifdef HAS_PSRAM /* PSRAM driver for IPS6404 */ #include "psram_t.h" #include #include #include "hardware/spi.h" #include "psram_spi.h" #ifdef PSCACHE Page PSRAM_T::pages[MAX_PAGES]; uint8_t PSRAM_T::nbPages=0; int8_t PSRAM_T::top=0; int8_t PSRAM_T::last=0; #endif static psram_spi_inst_t psram_spi; static psram_spi_inst_t psram_qspi; static bool qspi=false; void psram_spi_init_clkdiv(psram_spi_inst_t * spi, PIO pio, int sm, float clkdiv, bool fudge, bool qspi) { spi->pio = pio; spi->sm = sm; /* gpio_set_drive_strength(PSRAM_CS, GPIO_DRIVE_STRENGTH_4MA); gpio_set_drive_strength(PSRAM_SCLK, GPIO_DRIVE_STRENGTH_4MA); gpio_set_drive_strength(PSRAM_SIO0, GPIO_DRIVE_STRENGTH_4MA); gpio_set_drive_strength(PSRAM_SIO0+1, GPIO_DRIVE_STRENGTH_4MA); gpio_set_drive_strength(PSRAM_SIO0+2, GPIO_DRIVE_STRENGTH_4MA); gpio_set_drive_strength(PSRAM_SIO0+3, GPIO_DRIVE_STRENGTH_4MA); */ /* gpio_set_slew_rate(PSRAM_CS, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate(PSRAM_SCLK, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate(PSRAM_SIO0, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate(PSRAM_SIO0+1, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate(PSRAM_SIO0+2, GPIO_SLEW_RATE_FAST); gpio_set_slew_rate(PSRAM_SIO0+3, GPIO_SLEW_RATE_FAST); */ if (!qspi) { spi->qspi=false; pio_spi_psram_cs_init(spi->init_done, spi->pio, spi->sm, pio_add_program(spi->pio, &spi_psram_fudge_program), 8 /*n_bits*/, clkdiv, fudge, PSRAM_CS, PSRAM_MOSI, PSRAM_MISO); spi->write_dma_chan = PSR_DMA_CHANNEL; spi->read_dma_chan = PSR_DMA_CHANNEL+1; } else { spi->qspi=true; pio_qspi_psram_cs_init(spi->init_done, spi->pio, spi->sm, pio_add_program(spi->pio,&qspi_psram_program), 8 /*n_bits*/, clkdiv, PSRAM_CS, PSRAM_SIO0); spi->write_dma_chan = PSR_DMA_CHANNEL+2; spi->read_dma_chan = PSR_DMA_CHANNEL+3; } if (!spi->init_done) { spi->init_done = true; // Write DMA channel setup dma_channel_abort( spi->write_dma_chan); spi->write_dma_chan_config = dma_channel_get_default_config(spi->write_dma_chan); channel_config_set_transfer_data_size(&spi->write_dma_chan_config, DMA_SIZE_8); channel_config_set_read_increment(&spi->write_dma_chan_config, true); channel_config_set_write_increment(&spi->write_dma_chan_config, false); channel_config_set_dreq(&spi->write_dma_chan_config, pio_get_dreq(spi->pio, spi->sm, true)); dma_channel_set_write_addr(spi->write_dma_chan, &spi->pio->txf[spi->sm], false); dma_channel_set_config(spi->write_dma_chan, &spi->write_dma_chan_config, false); // Read DMA channel setup dma_channel_abort( spi->read_dma_chan); spi->read_dma_chan_config = dma_channel_get_default_config(spi->read_dma_chan); channel_config_set_transfer_data_size(&spi->read_dma_chan_config, DMA_SIZE_8); channel_config_set_read_increment(&spi->read_dma_chan_config, false); channel_config_set_write_increment(&spi->read_dma_chan_config, true); channel_config_set_dreq(&spi->read_dma_chan_config, pio_get_dreq(spi->pio, spi->sm, false)); dma_channel_set_read_addr(spi->read_dma_chan, &spi->pio->rxf[spi->sm], false); dma_channel_set_config(spi->read_dma_chan, &spi->read_dma_chan_config, false); } }; PSRAM_T::PSRAM_T(uint8_t cs, uint8_t mosi, uint8_t sclk, uint8_t miso) { #ifdef PSCACHE nbPages = 0; top = 0; last = 0; #endif } void PSRAM_T::begin(void) { #ifdef QSPIONLY psram_spi_init_clkdiv(&psram_qspi, pio2, 0, 1.0, true, true); qspi = true; reset(); pio_spi_cmd_dma_blocking(&psram_qspi, 0x35u); // enter quad command #else #ifndef SPIONLY psram_spi_init_clkdiv(&psram_qspi, pio1, 0, 1.0, true, true); #endif psram_spi_init_clkdiv(&psram_spi, pio2, 0, 1.0, true, false); reset(); #endif } void PSRAM_T::reset(void) { if (qspi) pio_spi_cmd_dma_blocking(&psram_qspi, 0x66u); // Reset enable command else pio_spi_cmd_dma_blocking(&psram_spi, 0x66u); // Reset enable command busy_wait_us(50); if (qspi) pio_spi_cmd_dma_blocking(&psram_qspi, 0x99u); // Reset command else pio_spi_cmd_dma_blocking(&psram_spi, 0x99u); // Reset command busy_wait_us(100); //if (qspi) // pio_spi_cmd_dma_blocking(&psram_qspi, 0xc0u); // wrap boundary toggle //else // pio_spi_cmd_dma_blocking(&psram_spi, 0xc0u); // wrap boundary toggle } void PSRAM_T::spi_mode(void) { #if defined(SPIONLY) || defined(QSPIONLY) #else pio_spi_cmd_dma_blocking(&psram_qspi, 0xf5u); // exit quad command psram_spi_init_clkdiv(&psram_spi, pio2, 0, 1.0, true, false); //busy_wait_us(100); qspi = false; #endif } void PSRAM_T::qspi_mode(void) { #if defined(SPIONLY) || defined(QSPIONLY) #else if (qspi) pio_spi_cmd_dma_blocking(&psram_qspi, 0x35u); // enter quad command else pio_spi_cmd_dma_blocking(&psram_spi, 0x35u); // enter quad command psram_spi_init_clkdiv(&psram_qspi, pio1, 0, 1.0, true, true); //busy_wait_us(100); qspi = true; #endif } uint8_t PSRAM_T::psram_read(uint32_t addr) { if (qspi) return psram_read8(&psram_qspi, addr); else return psram_read8(&psram_spi, addr); } uint16_t PSRAM_T::psram_read_w(uint32_t addr) { if (qspi) { //uint16_t a = psram_read8(&psram_qspi, addr+1) << 8; //a |= psram_read8(&psram_qspi, addr); //return a; return psram_read16(&psram_qspi, addr); } else return psram_read16(&psram_spi, addr); } void PSRAM_T::psram_read_n(uint32_t addr, uint8_t * dstpt, int n) { if (qspi) return psram_readn(&psram_qspi, addr, dstpt, n); else return psram_readn(&psram_spi, addr, dstpt, n); } void PSRAM_T::psram_write(uint32_t addr, uint8_t val) { if (qspi) psram_write8(&psram_qspi, addr, val); else psram_write8(&psram_spi, addr, val); } void PSRAM_T::psram_write_w(uint32_t addr, uint16_t val) { if (qspi) psram_write16(&psram_qspi, addr, val); else psram_write16(&psram_spi, addr, val); } //void PSRAM_T::psram_write_n(uint32_t addr, uint8_t * val, int n) //{ // psram_writen(&psram_spi, addr, val, n); //} void PSRAM_T::pswrite(uint32_t addr, uint8_t val) { psram_write(addr, val); #ifdef PSCACHE uint32_t curPage=addr&(~(PAGE_SIZE-1)); for (int i=0; i>8 ; break; } } #endif } #endif