<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[为什么FR8008GPU用不了QSPI的四线psram，只能用单线读取]]></title><description><![CDATA[<p>#include &lt;stdint.h&gt;<br />
#include &lt;stdbool.h&gt;</p>
<p>#include &quot;plf.h&quot;<br />
#include &quot;driver_system.h&quot;<br />
#include &quot;driver_psram.h&quot;</p>
<p>#include &quot;co_log.h&quot;<br />
#include &quot;co_printf.h&quot;<br />
#include &quot;driver_gpio.h&quot;<br />
#include &quot;sys_utils.h&quot;<br />
#include &quot;bsp_psram.h&quot;</p>
<p>#undef LOG_LOCAL_LEVEL<br />
#define LOG_LOCAL_LEVEL        (LOG_LEVEL_INFO)<br />
static const char *psram_tag = &quot;psram&quot;;</p>
<p>#define PSRAM_BASE              QSPI1_DAC_ADDRESS</p>
<p>extern void psram_reset(void);<br />
extern void psram_set_delay(uint8_t d);<br />
extern void psram_set_ahb_trigger(uint32_t addr);<br />
extern void psram_set_frame(uint8_t r_op, uint8_t r_it, uint8_t r_at, uint8_t r_dt, uint8_t r_dummy,<br />
uint8_t w_op, uint8_t w_at, uint8_t w_dt, uint8_t w_dummy);</p>
<p>static void psram_pins_qspi0(void)<br />
{<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_0, PORTC0_FUNC_QSPI0_IO3);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_1, PORTC1_FUNC_QSPI0_SCLK0);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_QSPI0_CSN0);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_QSPI0_IO1);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_4, PORTC4_FUNC_QSPI0_IO2);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_QSPI0_IO0);<br />
}</p>
<p>static void psram_lines_gpio_check(void)<br />
{<br />
GPIO_InitTypeDef io;<br />
__SYSTEM_GPIO_CLK_ENABLE();</p>
<pre><code>LOG_INFO(psram_tag, &quot;line check: PORTC mux=%08x&quot;, system_regs-&gt;port_mux[2]);

for (uint8_t pin = 0; pin &lt; 6; pin++)
{
    system_set_port_mux(GPIO_PORT_C, pin, PORT_FUNC_GPIO);
    io.Mode = GPIO_MODE_INPUT;
    io.Pull = GPIO_PULLUP;
    io.Pin  = (GPIO_PIN_0 &lt;&lt; pin);
    gpio_init(GPIO_C, &amp;io);
    co_delay_100us(1); 
    uint8_t up = gpio_read_pin(GPIO_C, (GPIO_PIN_0 &lt;&lt; pin)) ? 1 : 0;

    io.Pull = GPIO_PULLDOWN;
    gpio_init(GPIO_C, &amp;io);
    co_delay_100us(1);
    uint8_t dn = gpio_read_pin(GPIO_C, (GPIO_PIN_0 &lt;&lt; pin)) ? 1 : 0;

    co_printf(&quot;psram line PC%d: pullup=%d pulldown=%d %s\r\n&quot;, pin, up, dn,
              (up == 1 &amp;&amp; dn == 0) ? &quot;ok&quot; : &quot;!!&quot;);
}

io.Mode = GPIO_MODE_INPUT;
io.Pin  = GPIO_PIN_2;
io.Pull = GPIO_PULLUP;
gpio_init(GPIO_D, &amp;io);
uint8_t cup = gpio_read_pin(GPIO_D, GPIO_PIN_2) ? 1 : 0;
io.Pull = GPIO_PULLDOWN;
gpio_init(GPIO_D, &amp;io);
uint8_t cdn = gpio_read_pin(GPIO_D, GPIO_PIN_2) ? 1 : 0;
co_printf(&quot;psram ctrl PD2: pullup=%d pulldown=%d\r\n&quot;, cup, cdn);
</code></pre>
<p>}</p>
<p>bool bsp_psram_init(void)<br />
{<br />
co_delay_100us(500);</p>
<pre><code>psram_lines_gpio_check(); 

__SYSTEM_GPIO_CLK_ENABLE();
/* 参考例程(lvgl_knob_open_demo)同款参考时钟配置 */
system_regs-&gt;mdm_qspi_cfg.qspi_ref_128m_en = 1;
system_regs-&gt;mdm_qspi_cfg.qspi_ref_clk_sel = 1;
system_set_internal_flash_clock_div(1); 

psram_pins_qspi0();

(void)psram_init(PSRAM_CLK_SEL_COREH_96M);
system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en = 1;
system_regs-&gt;mdm_qspi_cfg.qspi0_hclk_en = 1;
psram_set_ahb_trigger(PSRAM_BASE);

volatile uint8_t *img = (volatile uint8_t *)PSRAM_BASE;

for (int attempt = 0; attempt &lt; 3; attempt++)
{
    psram_reset();
    co_delay_100us(10);
    psram_set_frame(0x03, 0, 0, 0, 0, 0x02, 0, 0, 0);
    img[0] = 0x5Au;
    img[1] = 0xA5u;
    co_delay_100us(1);

    for (int d = 0; d &lt; 16; d++)
    {
        psram_set_delay((uint8_t)d);
        co_delay_100us(1);
        if (img[0] == 0x5Au &amp;&amp; img[1] == 0xA5u)
        {
            psram_set_delay((uint8_t)d);
            LOG_INFO(psram_tag, &quot;psram ready (spi, delay tap %d)&quot;, d);
            return true;
        }
    }
    LOG_INFO(psram_tag, &quot;spi scan fail attempt %d, retry&quot;, attempt);
}

LOG_INFO(psram_tag, &quot;psram init FAIL (spi x3)&quot;);
return false;
</code></pre>
<p>}</p>
<p>#include &lt;stdint.h&gt;<br />
#include &lt;string.h&gt;</p>
<p>#include &quot;plf.h&quot;<br />
#include &quot;driver_qspi.h&quot;<br />
#include &quot;driver_psram.h&quot;<br />
#include &quot;driver_system.h&quot;<br />
#include &quot;driver_pmu.h&quot;<br />
#include &quot;driver_cache.h&quot;</p>
<p>#include &quot;co_printf.h&quot;<br />
#include &quot;sys_utils.h&quot;</p>
<p>#ifdef INLINE<br />
#undef INLINE<br />
#endif<br />
#define INLINE</p>
<p>#define PSRAM_ENABLE_Q_MODE             1   /* TEST: all-quad framing at slow clock */<br />
#define PSRAM_CLK_DIV_SEL               QSPI_BAUDRATE_DIV_2<br />
#define PSRAM_BASE                      QSPI1_DAC_ADDRESS</p>
<p>#define PSRAM_READ_IDENTIFICATION       0x9F</p>
<p>#define PSRAM_READ_OPCODE               0x03<br />
#define PSRAM_FAST_READ_OPCODE          0x0B<br />
#define PSRAM_FAST_QUAL_READ_OPCODE     0xEB</p>
<p>#define PSRAM_PAGE_PROGRAM_OPCODE       0x02<br />
#define PSRAM_PAGE_QUAL_PROGRAM_OPCODE  0x38</p>
<p>#define PSRAM_ENTER_QUAD_MODE_OPCODE    0x35<br />
#define PSRAM_EXIT_QUAD_MODE_OPCODE     0xF5</p>
<p>#define PSRAM_RESET_ENABLE_OPCODE       0x66<br />
#define PSRAM_RESET_OPCODE              0x99</p>
<p>#define QSPI0_STIG_MAX_SINGLE_LEN       8<br />
#define QSPI0_STIG_BANK_DEPTH           128</p>
<p>#define QSPI0_HIGH_SPEED                1<br />
uint8_t psram_delay = 0xFF;<br />
static const struct qspi_stig_reg_t psram_read_id_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 3,<br />
.enable_read = 1,<br />
.opcode = PSRAM_READ_IDENTIFICATION,<br />
};</p>
<p>static const struct qspi_stig_reg_t enter_quad_mode_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_ENTER_QUAD_MODE_OPCODE,<br />
};</p>
<p>static const struct qspi_stig_reg_t reset_enable_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_RESET_ENABLE_OPCODE,<br />
};</p>
<p>static const struct qspi_stig_reg_t reset_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_RESET_OPCODE,<br />
};</p>
<p>//static const struct qspi_stig_reg_t exit_quad_mode_cmd = {<br />
//    .enable_bank = 0,<br />
//    .dummy_cycles = 0,<br />
//    .write_bytes = 0,<br />
//    .enable_write = 0,<br />
//    .addr_bytes = 0,<br />
//    .enable_mode = 0,<br />
//    .enable_cmd_addr = 0,<br />
//    .read_bytes = 0,<br />
//    .enable_read = 0,<br />
//    .opcode = PSRAM_EXIT_QUAD_MODE_OPCODE,<br />
//};</p>
<p>volatile struct qspi_regs_t *qspi0_ctrl = (volatile struct qspi_regs_t *)QSPI0_APB_BASE;</p>
<p>INLINE void qspi0_cfg_set_enable(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_cpol(uint8_t high)<br />
{<br />
qspi0_ctrl-&gt;config.cpol = high;<br />
}</p>
<p>INLINE void qspi0_cfg_set_cpha(uint8_t rising)<br />
{<br />
qspi0_ctrl-&gt;config.cpha = rising;<br />
}</p>
<p>INLINE void qspi0_cfg_set_hold(uint8_t hold)<br />
{<br />
qspi0_ctrl-&gt;config.hold_pin = hold;<br />
}</p>
<p>INLINE void qspi0_cfg_set_reset(uint8_t reset)<br />
{<br />
qspi0_ctrl-&gt;config.reset_pin = reset;<br />
}</p>
<p>INLINE void qspi0_cfg_set_reset_sel(uint8_t dedicated)<br />
{<br />
qspi0_ctrl-&gt;config.reset_pin_conf = dedicated;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_dac(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_DAC = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_legacy(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_legacy = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_write_protect(uint8_t wp)<br />
{<br />
qspi0_ctrl-&gt;config.write_en_pin = wp;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_remap(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_AHB_remap = en;<br />
}</p>
<p>static void qspi0_cfg_set_baudrate(uint8_t baudrate);</p>
<p>INLINE void qspi0_cfg_set_enable_AHB_decoder(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_AHB_decoder = en;<br />
}</p>
<p>INLINE int qspi0_is_busy(void)<br />
{<br />
return (qspi0_ctrl-&gt;config.status == 0);<br />
}</p>
<p>INLINE void qspi0_read_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;read_conf.opcode_no_XIP = opcode;<br />
}</p>
<p>INLINE void qspi0_read_set_instruction_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.instruction_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_address_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.addr_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_data_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.data_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_mode_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;read_conf.enable_mode = en;<br />
}</p>
<p>INLINE void qspi0_read_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;read_conf.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_write_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;write_conf.opcode = opcode;<br />
}</p>
<p>INLINE void qspi0_write_set_wel_dis(uint8_t disable)<br />
{<br />
qspi0_ctrl-&gt;write_conf.disable_WEL = disable;<br />
}</p>
<p>INLINE void qspi0_write_set_address_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;write_conf.addr_type = type;<br />
}</p>
<p>INLINE void qspi0_write_set_data_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;write_conf.data_type = type;<br />
}</p>
<p>INLINE void qspi0_write_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;write_conf.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_set_remap_address(uint32_t address)<br />
{<br />
qspi0_ctrl-&gt;remap_address = address;<br />
}</p>
<p>INLINE void qspi0_set_mode_bit(uint8_t mode)<br />
{<br />
qspi0_ctrl-&gt;mode_bits = (uint32_t)mode;<br />
}</p>
<p>INLINE void qspi0_poll_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.opcode_poll = opcode;<br />
}</p>
<p>INLINE void qspi0_poll_set_bit_index(uint8_t index)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_bit_index = index;<br />
}</p>
<p>INLINE void qspi0_poll_set_polarity(uint8_t pol)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_polarity = pol;<br />
}</p>
<p>INLINE void qspi0_poll_set_disable(uint8_t dis)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.disable_poll = dis;<br />
}</p>
<p>INLINE void qspi0_poll_set_expire(uint8_t en, uint32_t duration)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.enable_expiration = en;<br />
if(en) {<br />
qspi0_ctrl-&gt;poll_expiration = duration;<br />
}<br />
}</p>
<p>INLINE void qspi0_poll_set_poll_count(uint8_t count)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_count = count;<br />
}</p>
<p>INLINE void qspi0_poll_set_poll_delay(uint8_t delay)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_repetition_delay = delay;<br />
}</p>
<p>INLINE void qspi0_set_cmd_addr(uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;cmd_address = addr;<br />
}</p>
<p>INLINE void qspi0_stig_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.opcode = opcode;<br />
}</p>
<p>INLINE void qspi0_stig_set_read_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_read = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_read_bytes(uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.read_bytes = bytes;<br />
}</p>
<p>INLINE void qspi0_stig_set_addr(uint8_t en, uint8_t bytes, uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_cmd_addr = en;<br />
qspi0_ctrl-&gt;cmd_ctrl.addr_bytes = bytes;<br />
if(en) {<br />
qspi0_ctrl-&gt;cmd_address = addr;<br />
}<br />
}</p>
<p>INLINE void qspi0_stig_set_mode_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_mode = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_write_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_write = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_write_bytes(uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.write_bytes = bytes;<br />
}</p>
<p>INLINE void qspi0_stig_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_stig_set_mem_bank(uint8_t en, uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_bank = en;<br />
if(en) {<br />
qspi0_ctrl-&gt;cmd_ctrl_mem.mem_bank_req_bytes = bytes;<br />
}<br />
}</p>
<p>static void qspi0_cfg_set_baudrate(uint8_t baudrate)<br />
{<br />
qspi0_ctrl-&gt;config.baud_rate = baudrate;<br />
}</p>
<p>static const struct qspi_stig_reg_t psram_stig_read_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 2,           /* QSPI_STIG_ADDR_BYTES_3 <em>/<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 1,<br />
.read_bytes = 3,<br />
.enable_read = 1,<br />
.opcode = PSRAM_READ_OPCODE,          /</em> 0x03 */<br />
};</p>
<p>static const struct qspi_stig_reg_t psram_stig_write_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 3,<br />
.enable_write = 1,<br />
.addr_bytes = 2,           /* QSPI_STIG_ADDR_BYTES_3 <em>/<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 1,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_PAGE_PROGRAM_OPCODE,  /</em> 0x02 */<br />
};</p>
<p>static int qspi0_stig_cmd(struct qspi_stig_reg_t cmd, enum qspi_stig_cmd_type_t type, int len, uint8_t *buffer)<br />
{<br />
uint32_t tmp_u32[2];<br />
uint8_t *tmp_u8 = (uint8_t *)tmp_u32;</p>
<pre><code>if(type == QSPI_STIG_CMD_BANK_READ) {
    if(QSPI0_STIG_BANK_DEPTH &lt; len) {
        return -1;
    }
}
else {
    if(QSPI0_STIG_MAX_SINGLE_LEN &lt; len) {
        return -1;
    }
}

while(qspi0_is_busy());

if(type == QSPI_STIG_CMD_EXE) {
    qspi0_ctrl-&gt;cmd_ctrl = cmd;
    qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
    while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
}
else {
    if(type == QSPI_STIG_CMD_WRITE) {
        memcpy(tmp_u8, buffer, len);
        qspi0_ctrl-&gt;write_data_L = tmp_u32[0];
        qspi0_ctrl-&gt;write_data_H = tmp_u32[1];
        cmd.write_bytes = len - 1;
        qspi0_ctrl-&gt;cmd_ctrl = cmd;
        qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
        while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
    }
    else {
        cmd.read_bytes = len - 1;
        qspi0_ctrl-&gt;cmd_ctrl = cmd;
        qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
        while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
        if(type == QSPI_STIG_CMD_READ) {
            tmp_u32[0] = qspi0_ctrl-&gt;read_data_L;
            tmp_u32[1] = qspi0_ctrl-&gt;read_data_H;
            //co_printf(&quot;READ_L: 0x%08x, READ_H: 0x%08x.\r\n&quot;, tmp_u32[0], tmp_u32[1]);
            memcpy(buffer, tmp_u8, len);
        }
        else {
            //TBD, BANK READ
        }
    }
}

return 0;
</code></pre>
<p>}</p>
<p>void psram_enter_quad(void)<br />
{<br />
qspi0_stig_cmd(enter_quad_mode_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
}</p>
<p>uint32_t psram_read_id(void)<br />
{<br />
uint32_t flash_id;<br />
qspi0_stig_cmd(psram_read_id_cmd, QSPI_STIG_CMD_READ,  3, (uint8_t *)&amp;flash_id);<br />
return (flash_id&amp;0xffffff);<br />
}</p>
<p>static void psram_controller_init(uint16_t page_boundary)<br />
{<br />
while(qspi0_is_busy());</p>
<p>#if PSRAM_ENABLE_Q_MODE == 1<br />
qspi0_read_set_opcode(PSRAM_FAST_READ_OPCODE);<br />
qspi0_read_set_instruction_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_address_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_data_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_dummy_cycles(4);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);//8 bits data after addr</p>
<pre><code>qspi0_write_set_opcode(PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
qspi0_write_set_address_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_data_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_dummy_cycles(0);
</code></pre>
<p>#else<br />
qspi0_read_set_opcode(PSRAM_FAST_QUAL_READ_OPCODE);	<br />
qspi0_read_set_instruction_type(QSPI_WIRE_TYPE_STAND);<br />
qspi0_read_set_address_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_data_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_dummy_cycles(6);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);//8 bits data after addr</p>
<pre><code>qspi0_write_set_opcode(PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
qspi0_write_set_address_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_data_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_dummy_cycles(0);
</code></pre>
<p>#endif</p>
<pre><code>//init configuration register
qspi0_cfg_set_cpol(0);
qspi0_cfg_set_cpha(0);
qspi0_cfg_set_enable_dac(1);
qspi0_cfg_set_enable_legacy(0);
qspi0_cfg_set_enable_remap(1);
</code></pre>
<p>#if QSPI0_HIGH_SPEED<br />
qspi0_cfg_set_baudrate(PSRAM_CLK_DIV_SEL);<br />
#else<br />
qspi0_cfg_set_baudrate(QSPI_BAUDRATE_DIV_32);<br />
#endif<br />
qspi0_cfg_set_enable_AHB_decoder(1);<br />
qspi0_write_set_wel_dis(1);<br />
qspi0_poll_set_disable(1);</p>
<p>#if QSPI0_HIGH_SPEED<br />
qspi0_ctrl-&gt;read_cap.delay_capture = 3;<br />
#else<br />
qspi0_ctrl-&gt;read_cap.delay_capture = 0;<br />
#endif<br />
qspi0_ctrl-&gt;read_cap.enable_loopback_clk = 1;<br />
qspi0_ctrl-&gt;delay.sel_start_offset = 2;<br />
qspi0_ctrl-&gt;delay.sel_end_offset = 2;<br />
qspi0_ctrl-&gt;delay.sel_dessert = 2;<br />
qspi0_ctrl-&gt;cs_ctrl.rd_brk_en = 1;<br />
qspi0_ctrl-&gt;cs_ctrl.disable_cs_after_first_byte = 0;  /* forum-verified working value for quad PSRAM (was 1 in SDK) <em>/<br />
qspi0_ctrl-&gt;cs_ctrl.page_boundary_protect_en = 1;<br />
qspi0_ctrl-&gt;cs_ctrl.page_boundary = page_boundary;<br />
qspi0_set_remap_address(QSPI1_DAC_ADDRESS);<br />
qspi0_ctrl-&gt;AHB_trigger_address = PSRAM_BASE;  /</em> DAC window trigger (old project set it; default points elsewhere) */<br />
qspi0_cfg_set_enable(1);<br />
}</p>
<p>void psram_cache_enable(void)<br />
{<br />
__CACHE_FLUSH(CACHE);<br />
__CACHE_WR_MODE_SET(CACHE, CACHE_WR_WRITE_THROUGH);<br />
__CACHE_ADDR_RANGEx_BANK_SET(CACHE, 0, 0x0000);<br />
__CACHE_ADDR_RANGEx_MASK_SET(CACHE, 0, 0x0000);<br />
__CACHE_ADDR_RANGEx_POL_SET(CACHE, 0, CACHE_POL_CACHABLE);<br />
__CACHE_ADDR_RANGEx_ENABLE(CACHE, 0);<br />
__CACHE_ENABLE(CACHE);<br />
}</p>
<p>bool psram_init(enum psram_clk_sel_t clk_sel)<br />
{<br />
uint32_t ref_clk;</p>
<pre><code>if (clk_sel &gt;= PSRAM_CLK_SEL_MAX) {
    return false;
}

switch (clk_sel) {
    case PSRAM_CLK_SEL_COREH_48M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 0;
        ref_clk = 48000000;
        break;
    case PSRAM_CLK_SEL_COREH_96M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 1;
        ref_clk = 96000000;
        break;      
    case PSRAM_CLK_SEL_COREH_192M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 2;
        ref_clk = 192000000;
        break;
    default:
        return false;
}
system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en=1;
system_regs-&gt;mdm_qspi_cfg.qspi0_hclk_en=1;
system_regs-&gt;mdm_qspi_cfg.qspi0_io_ctl_oen=0;

if(psram_delay == 0xFF)
{
    qspi0_stig_cmd(reset_enable_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
    qspi0_stig_cmd(reset_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
    co_delay_10us(20);  /* 200us reset recovery before quad entry */
    /* serial write magic @0 while die in SPI mode (baseline) */
    {
        uint32_t magic = 0xc3c3c3c3;
        uint32_t chk = 0;
        qspi0_ctrl-&gt;cmd_address = 0;
        qspi0_stig_cmd(psram_stig_write_cmd, QSPI_STIG_CMD_WRITE, 4, (uint8_t *)&amp;magic);
        qspi0_ctrl-&gt;cmd_address = 0;
        qspi0_stig_cmd(psram_stig_read_cmd, QSPI_STIG_CMD_READ, 4, (uint8_t *)&amp;chk);
        co_printf(&quot;psram serial w/r chk=%x\r\n&quot;, chk);
    }
</code></pre>
<p>#if PSRAM_ENABLE_Q_MODE == 1<br />
psram_enter_quad();<br />
#endif  // PSRAM_ENABLE_Q_MODE == 1<br />
}</p>
<pre><code>/* about 100 bytes can be transmitted during 8us when QSPI clock is 24MHz */
ref_clk /= ((PSRAM_CLK_DIV_SEL+1) * 2);
uint32_t bytes = ref_clk / 240000;
uint32_t boundary_cfg = 1 &lt;&lt; (31 - __CLZ(bytes));
if (boundary_cfg &gt;= 0x100) {
    boundary_cfg = 0x100;
}
psram_controller_init(boundary_cfg);

if(psram_delay != 0xFF)
{
    qspi0_ctrl-&gt;read_cap.delay_capture = psram_delay;
}
else
{
    /* detect read capture delay configuration */
    uint8_t delay_lower, delay_upper, index;
    /* QUAD READ test v2: sweep dummy cycles x capture taps.
       Serial-written c3c3c3c3 @0 must appear via quad DAC read. Log non-zero only. */
    {
        static const uint8_t dummies[] = {4, 2, 6, 8, 0, 3, 5, 1, 7};
        uint8_t found = 0;
        for (uint8_t di = 0; di &lt; sizeof(dummies) &amp;&amp; !found; di++) {
            qspi0_read_set_dummy_cycles(dummies[di]);
            for (index = 0; index &lt; 16; index++) {
                while(qspi0_is_busy());
                qspi0_ctrl-&gt;read_cap.delay_capture = index;
                uint32_t dbg = *(volatile uint32_t *)(PSRAM_BASE);
                if (dbg != 0) {
                    co_printf(&quot;psram qt(d=%d,t=%d)=%x\r\n&quot;, dummies[di], index, dbg);
                }
                if (dbg == 0xc3c3c3c3) {
                    co_printf(&quot;psram QUAD READ OK (dummy=%d tap=%d)\r\n&quot;, dummies[di], index);
                    found = 1;
                    break;
                }
            }
        }
        if (!found) {
            co_printf(&quot;psram QUAD READ DEAD (9 dummies x 16 taps)\r\n&quot;);
        }
    }
    /* QUAD WRITE test: write via quad DAC @4, verify via SERIAL read @4 */
    {
        *(volatile uint32_t *)(PSRAM_BASE + 4) = 0x5a5a5a5a;
        while(qspi0_is_busy());
        uint32_t chk4 = 0;
        qspi0_ctrl-&gt;cmd_address = 4;
        qspi0_stig_cmd(psram_stig_read_cmd, QSPI_STIG_CMD_READ, 4, (uint8_t *)&amp;chk4);
        co_printf(&quot;psram quad w @4, serial sees=%x %s\r\n&quot;, chk4,
                  (chk4 == 0x5a5a5a5a) ? &quot;QUAD WRITE OK&quot; : &quot;QUAD WRITE DEAD&quot;);
    }
    *(volatile uint32_t *)(PSRAM_BASE) = 0x5a5a5a5a;
    while(qspi0_is_busy());

    for (index = 0; index &lt; 16; index++) {
        while(qspi0_is_busy());
        qspi0_ctrl-&gt;read_cap.delay_capture = index;
        if (*(volatile uint32_t *)(PSRAM_BASE) == 0x5a5a5a5a) {
            break;
        }
    }
    if (index == 16) {
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en=0;
        return false;
    }
    else {
        delay_lower = index;
    }
    for (; index &lt; 16; index++) {
        while(qspi0_is_busy());        
        qspi0_ctrl-&gt;read_cap.delay_capture = index;
        delay_upper = index;
        if (*(volatile uint32_t *)(PSRAM_BASE) != 0x5a5a5a5a) {
            break;
        }
    }
    
    psram_delay = ((delay_lower + delay_upper)&gt;&gt;1);
    while(qspi0_is_busy());
    qspi0_ctrl-&gt;read_cap.delay_capture = psram_delay;      
}
return true;
</code></pre>
<p>}</p>
<p>/* ---- old-project helpers restored: the only PSRAM path proven on this</p>
<ul>
<li>
<pre><code> board+die (single-lane DAC, verified working on FR8008GPU 2026-10-27).
</code></pre>
</li>
<li>
<pre><code> SDK quad framings (all-quad and 1-4-4) both fail on this die. ---- */
</code></pre>
</li>
</ul>
<p>void psram_reset(void)<br />
{<br />
qspi0_stig_cmd(reset_enable_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
qspi0_stig_cmd(reset_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
}</p>
<p>void psram_set_delay(uint8_t d)<br />
{<br />
qspi0_ctrl-&gt;read_cap.delay_capture = d;<br />
}</p>
<p>void psram_set_ahb_trigger(uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;AHB_trigger_address = addr;<br />
}</p>
<p>void psram_set_frame(uint8_t r_op, uint8_t r_it, uint8_t r_at, uint8_t r_dt, uint8_t r_dummy,<br />
uint8_t w_op, uint8_t w_at, uint8_t w_dt, uint8_t w_dummy)<br />
{<br />
qspi0_read_set_opcode(r_op);<br />
qspi0_read_set_instruction_type(r_it);<br />
qspi0_read_set_address_type(r_at);<br />
qspi0_read_set_data_type(r_dt);<br />
qspi0_read_set_dummy_cycles(r_dummy);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);<br />
qspi0_write_set_opcode(w_op);<br />
qspi0_write_set_address_type(w_at);<br />
qspi0_write_set_data_type(w_dt);<br />
qspi0_write_set_dummy_cycles(w_dummy);<br />
}</p>
]]></description><link>http://www.freqchip.net:4567/topic/1924/为什么fr8008gpu用不了qspi的四线psram-只能用单线读取</link><generator>RSS for Node</generator><lastBuildDate>Wed, 28 Oct 2026 08:29:45 GMT</lastBuildDate><atom:link href="http://www.freqchip.net:4567/topic/1924.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 28 Oct 2026 01:43:04 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 为什么FR8008GPU用不了QSPI的四线psram，只能用单线读取 on Invalid Date]]></title><description><![CDATA[<p>#include &lt;stdint.h&gt;<br />
#include &lt;stdbool.h&gt;</p>
<p>#include &quot;plf.h&quot;<br />
#include &quot;driver_system.h&quot;<br />
#include &quot;driver_psram.h&quot;</p>
<p>#include &quot;co_log.h&quot;<br />
#include &quot;co_printf.h&quot;<br />
#include &quot;driver_gpio.h&quot;<br />
#include &quot;sys_utils.h&quot;<br />
#include &quot;bsp_psram.h&quot;</p>
<p>#undef LOG_LOCAL_LEVEL<br />
#define LOG_LOCAL_LEVEL        (LOG_LEVEL_INFO)<br />
static const char *psram_tag = &quot;psram&quot;;</p>
<p>#define PSRAM_BASE              QSPI1_DAC_ADDRESS</p>
<p>extern void psram_reset(void);<br />
extern void psram_set_delay(uint8_t d);<br />
extern void psram_set_ahb_trigger(uint32_t addr);<br />
extern void psram_set_frame(uint8_t r_op, uint8_t r_it, uint8_t r_at, uint8_t r_dt, uint8_t r_dummy,<br />
uint8_t w_op, uint8_t w_at, uint8_t w_dt, uint8_t w_dummy);</p>
<p>static void psram_pins_qspi0(void)<br />
{<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_0, PORTC0_FUNC_QSPI0_IO3);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_1, PORTC1_FUNC_QSPI0_SCLK0);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_QSPI0_CSN0);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_QSPI0_IO1);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_4, PORTC4_FUNC_QSPI0_IO2);<br />
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_QSPI0_IO0);<br />
}</p>
<p>static void psram_lines_gpio_check(void)<br />
{<br />
GPIO_InitTypeDef io;<br />
__SYSTEM_GPIO_CLK_ENABLE();</p>
<pre><code>LOG_INFO(psram_tag, &quot;line check: PORTC mux=%08x&quot;, system_regs-&gt;port_mux[2]);

for (uint8_t pin = 0; pin &lt; 6; pin++)
{
    system_set_port_mux(GPIO_PORT_C, pin, PORT_FUNC_GPIO);
    io.Mode = GPIO_MODE_INPUT;
    io.Pull = GPIO_PULLUP;
    io.Pin  = (GPIO_PIN_0 &lt;&lt; pin);
    gpio_init(GPIO_C, &amp;io);
    co_delay_100us(1); 
    uint8_t up = gpio_read_pin(GPIO_C, (GPIO_PIN_0 &lt;&lt; pin)) ? 1 : 0;

    io.Pull = GPIO_PULLDOWN;
    gpio_init(GPIO_C, &amp;io);
    co_delay_100us(1);
    uint8_t dn = gpio_read_pin(GPIO_C, (GPIO_PIN_0 &lt;&lt; pin)) ? 1 : 0;

    co_printf(&quot;psram line PC%d: pullup=%d pulldown=%d %s\r\n&quot;, pin, up, dn,
              (up == 1 &amp;&amp; dn == 0) ? &quot;ok&quot; : &quot;!!&quot;);
}

io.Mode = GPIO_MODE_INPUT;
io.Pin  = GPIO_PIN_2;
io.Pull = GPIO_PULLUP;
gpio_init(GPIO_D, &amp;io);
uint8_t cup = gpio_read_pin(GPIO_D, GPIO_PIN_2) ? 1 : 0;
io.Pull = GPIO_PULLDOWN;
gpio_init(GPIO_D, &amp;io);
uint8_t cdn = gpio_read_pin(GPIO_D, GPIO_PIN_2) ? 1 : 0;
co_printf(&quot;psram ctrl PD2: pullup=%d pulldown=%d\r\n&quot;, cup, cdn);
</code></pre>
<p>}</p>
<p>bool bsp_psram_init(void)<br />
{<br />
co_delay_100us(500);</p>
<pre><code>psram_lines_gpio_check(); 

__SYSTEM_GPIO_CLK_ENABLE();
/* 参考例程(lvgl_knob_open_demo)同款参考时钟配置 */
system_regs-&gt;mdm_qspi_cfg.qspi_ref_128m_en = 1;
system_regs-&gt;mdm_qspi_cfg.qspi_ref_clk_sel = 1;
system_set_internal_flash_clock_div(1); 

psram_pins_qspi0();

(void)psram_init(PSRAM_CLK_SEL_COREH_96M);
system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en = 1;
system_regs-&gt;mdm_qspi_cfg.qspi0_hclk_en = 1;
psram_set_ahb_trigger(PSRAM_BASE);

volatile uint8_t *img = (volatile uint8_t *)PSRAM_BASE;

for (int attempt = 0; attempt &lt; 3; attempt++)
{
    psram_reset();
    co_delay_100us(10);
    psram_set_frame(0x03, 0, 0, 0, 0, 0x02, 0, 0, 0);
    img[0] = 0x5Au;
    img[1] = 0xA5u;
    co_delay_100us(1);

    for (int d = 0; d &lt; 16; d++)
    {
        psram_set_delay((uint8_t)d);
        co_delay_100us(1);
        if (img[0] == 0x5Au &amp;&amp; img[1] == 0xA5u)
        {
            psram_set_delay((uint8_t)d);
            LOG_INFO(psram_tag, &quot;psram ready (spi, delay tap %d)&quot;, d);
            return true;
        }
    }
    LOG_INFO(psram_tag, &quot;spi scan fail attempt %d, retry&quot;, attempt);
}

LOG_INFO(psram_tag, &quot;psram init FAIL (spi x3)&quot;);
return false;
</code></pre>
<p>}</p>
<p>#include &lt;stdint.h&gt;<br />
#include &lt;string.h&gt;</p>
<p>#include &quot;plf.h&quot;<br />
#include &quot;driver_qspi.h&quot;<br />
#include &quot;driver_psram.h&quot;<br />
#include &quot;driver_system.h&quot;<br />
#include &quot;driver_pmu.h&quot;<br />
#include &quot;driver_cache.h&quot;</p>
<p>#include &quot;co_printf.h&quot;<br />
#include &quot;sys_utils.h&quot;</p>
<p>#ifdef INLINE<br />
#undef INLINE<br />
#endif<br />
#define INLINE</p>
<p>#define PSRAM_ENABLE_Q_MODE             1   /* TEST: all-quad framing at slow clock */<br />
#define PSRAM_CLK_DIV_SEL               QSPI_BAUDRATE_DIV_2<br />
#define PSRAM_BASE                      QSPI1_DAC_ADDRESS</p>
<p>#define PSRAM_READ_IDENTIFICATION       0x9F</p>
<p>#define PSRAM_READ_OPCODE               0x03<br />
#define PSRAM_FAST_READ_OPCODE          0x0B<br />
#define PSRAM_FAST_QUAL_READ_OPCODE     0xEB</p>
<p>#define PSRAM_PAGE_PROGRAM_OPCODE       0x02<br />
#define PSRAM_PAGE_QUAL_PROGRAM_OPCODE  0x38</p>
<p>#define PSRAM_ENTER_QUAD_MODE_OPCODE    0x35<br />
#define PSRAM_EXIT_QUAD_MODE_OPCODE     0xF5</p>
<p>#define PSRAM_RESET_ENABLE_OPCODE       0x66<br />
#define PSRAM_RESET_OPCODE              0x99</p>
<p>#define QSPI0_STIG_MAX_SINGLE_LEN       8<br />
#define QSPI0_STIG_BANK_DEPTH           128</p>
<p>#define QSPI0_HIGH_SPEED                1<br />
uint8_t psram_delay = 0xFF;<br />
static const struct qspi_stig_reg_t psram_read_id_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 3,<br />
.enable_read = 1,<br />
.opcode = PSRAM_READ_IDENTIFICATION,<br />
};</p>
<p>static const struct qspi_stig_reg_t enter_quad_mode_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_ENTER_QUAD_MODE_OPCODE,<br />
};</p>
<p>static const struct qspi_stig_reg_t reset_enable_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_RESET_ENABLE_OPCODE,<br />
};</p>
<p>static const struct qspi_stig_reg_t reset_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 0,<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 0,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_RESET_OPCODE,<br />
};</p>
<p>//static const struct qspi_stig_reg_t exit_quad_mode_cmd = {<br />
//    .enable_bank = 0,<br />
//    .dummy_cycles = 0,<br />
//    .write_bytes = 0,<br />
//    .enable_write = 0,<br />
//    .addr_bytes = 0,<br />
//    .enable_mode = 0,<br />
//    .enable_cmd_addr = 0,<br />
//    .read_bytes = 0,<br />
//    .enable_read = 0,<br />
//    .opcode = PSRAM_EXIT_QUAD_MODE_OPCODE,<br />
//};</p>
<p>volatile struct qspi_regs_t *qspi0_ctrl = (volatile struct qspi_regs_t *)QSPI0_APB_BASE;</p>
<p>INLINE void qspi0_cfg_set_enable(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_cpol(uint8_t high)<br />
{<br />
qspi0_ctrl-&gt;config.cpol = high;<br />
}</p>
<p>INLINE void qspi0_cfg_set_cpha(uint8_t rising)<br />
{<br />
qspi0_ctrl-&gt;config.cpha = rising;<br />
}</p>
<p>INLINE void qspi0_cfg_set_hold(uint8_t hold)<br />
{<br />
qspi0_ctrl-&gt;config.hold_pin = hold;<br />
}</p>
<p>INLINE void qspi0_cfg_set_reset(uint8_t reset)<br />
{<br />
qspi0_ctrl-&gt;config.reset_pin = reset;<br />
}</p>
<p>INLINE void qspi0_cfg_set_reset_sel(uint8_t dedicated)<br />
{<br />
qspi0_ctrl-&gt;config.reset_pin_conf = dedicated;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_dac(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_DAC = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_legacy(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_legacy = en;<br />
}</p>
<p>INLINE void qspi0_cfg_set_write_protect(uint8_t wp)<br />
{<br />
qspi0_ctrl-&gt;config.write_en_pin = wp;<br />
}</p>
<p>INLINE void qspi0_cfg_set_enable_remap(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_AHB_remap = en;<br />
}</p>
<p>static void qspi0_cfg_set_baudrate(uint8_t baudrate);</p>
<p>INLINE void qspi0_cfg_set_enable_AHB_decoder(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;config.enable_AHB_decoder = en;<br />
}</p>
<p>INLINE int qspi0_is_busy(void)<br />
{<br />
return (qspi0_ctrl-&gt;config.status == 0);<br />
}</p>
<p>INLINE void qspi0_read_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;read_conf.opcode_no_XIP = opcode;<br />
}</p>
<p>INLINE void qspi0_read_set_instruction_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.instruction_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_address_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.addr_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_data_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;read_conf.data_type = type;<br />
}</p>
<p>INLINE void qspi0_read_set_mode_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;read_conf.enable_mode = en;<br />
}</p>
<p>INLINE void qspi0_read_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;read_conf.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_write_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;write_conf.opcode = opcode;<br />
}</p>
<p>INLINE void qspi0_write_set_wel_dis(uint8_t disable)<br />
{<br />
qspi0_ctrl-&gt;write_conf.disable_WEL = disable;<br />
}</p>
<p>INLINE void qspi0_write_set_address_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;write_conf.addr_type = type;<br />
}</p>
<p>INLINE void qspi0_write_set_data_type(uint8_t type)<br />
{<br />
qspi0_ctrl-&gt;write_conf.data_type = type;<br />
}</p>
<p>INLINE void qspi0_write_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;write_conf.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_set_remap_address(uint32_t address)<br />
{<br />
qspi0_ctrl-&gt;remap_address = address;<br />
}</p>
<p>INLINE void qspi0_set_mode_bit(uint8_t mode)<br />
{<br />
qspi0_ctrl-&gt;mode_bits = (uint32_t)mode;<br />
}</p>
<p>INLINE void qspi0_poll_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.opcode_poll = opcode;<br />
}</p>
<p>INLINE void qspi0_poll_set_bit_index(uint8_t index)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_bit_index = index;<br />
}</p>
<p>INLINE void qspi0_poll_set_polarity(uint8_t pol)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_polarity = pol;<br />
}</p>
<p>INLINE void qspi0_poll_set_disable(uint8_t dis)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.disable_poll = dis;<br />
}</p>
<p>INLINE void qspi0_poll_set_expire(uint8_t en, uint32_t duration)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.enable_expiration = en;<br />
if(en) {<br />
qspi0_ctrl-&gt;poll_expiration = duration;<br />
}<br />
}</p>
<p>INLINE void qspi0_poll_set_poll_count(uint8_t count)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_count = count;<br />
}</p>
<p>INLINE void qspi0_poll_set_poll_delay(uint8_t delay)<br />
{<br />
qspi0_ctrl-&gt;poll_cfg.poll_repetition_delay = delay;<br />
}</p>
<p>INLINE void qspi0_set_cmd_addr(uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;cmd_address = addr;<br />
}</p>
<p>INLINE void qspi0_stig_set_opcode(uint8_t opcode)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.opcode = opcode;<br />
}</p>
<p>INLINE void qspi0_stig_set_read_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_read = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_read_bytes(uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.read_bytes = bytes;<br />
}</p>
<p>INLINE void qspi0_stig_set_addr(uint8_t en, uint8_t bytes, uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_cmd_addr = en;<br />
qspi0_ctrl-&gt;cmd_ctrl.addr_bytes = bytes;<br />
if(en) {<br />
qspi0_ctrl-&gt;cmd_address = addr;<br />
}<br />
}</p>
<p>INLINE void qspi0_stig_set_mode_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_mode = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_write_en(uint8_t en)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_write = en;<br />
}</p>
<p>INLINE void qspi0_stig_set_write_bytes(uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.write_bytes = bytes;<br />
}</p>
<p>INLINE void qspi0_stig_set_dummy_cycles(uint8_t cycles)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.dummy_cycles = cycles;<br />
}</p>
<p>INLINE void qspi0_stig_set_mem_bank(uint8_t en, uint8_t bytes)<br />
{<br />
qspi0_ctrl-&gt;cmd_ctrl.enable_bank = en;<br />
if(en) {<br />
qspi0_ctrl-&gt;cmd_ctrl_mem.mem_bank_req_bytes = bytes;<br />
}<br />
}</p>
<p>static void qspi0_cfg_set_baudrate(uint8_t baudrate)<br />
{<br />
qspi0_ctrl-&gt;config.baud_rate = baudrate;<br />
}</p>
<p>static const struct qspi_stig_reg_t psram_stig_read_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 0,<br />
.enable_write = 0,<br />
.addr_bytes = 2,           /* QSPI_STIG_ADDR_BYTES_3 <em>/<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 1,<br />
.read_bytes = 3,<br />
.enable_read = 1,<br />
.opcode = PSRAM_READ_OPCODE,          /</em> 0x03 */<br />
};</p>
<p>static const struct qspi_stig_reg_t psram_stig_write_cmd = {<br />
.enable_bank = 0,<br />
.dummy_cycles = 0,<br />
.write_bytes = 3,<br />
.enable_write = 1,<br />
.addr_bytes = 2,           /* QSPI_STIG_ADDR_BYTES_3 <em>/<br />
.enable_mode = 0,<br />
.enable_cmd_addr = 1,<br />
.read_bytes = 0,<br />
.enable_read = 0,<br />
.opcode = PSRAM_PAGE_PROGRAM_OPCODE,  /</em> 0x02 */<br />
};</p>
<p>static int qspi0_stig_cmd(struct qspi_stig_reg_t cmd, enum qspi_stig_cmd_type_t type, int len, uint8_t *buffer)<br />
{<br />
uint32_t tmp_u32[2];<br />
uint8_t *tmp_u8 = (uint8_t *)tmp_u32;</p>
<pre><code>if(type == QSPI_STIG_CMD_BANK_READ) {
    if(QSPI0_STIG_BANK_DEPTH &lt; len) {
        return -1;
    }
}
else {
    if(QSPI0_STIG_MAX_SINGLE_LEN &lt; len) {
        return -1;
    }
}

while(qspi0_is_busy());

if(type == QSPI_STIG_CMD_EXE) {
    qspi0_ctrl-&gt;cmd_ctrl = cmd;
    qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
    while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
}
else {
    if(type == QSPI_STIG_CMD_WRITE) {
        memcpy(tmp_u8, buffer, len);
        qspi0_ctrl-&gt;write_data_L = tmp_u32[0];
        qspi0_ctrl-&gt;write_data_H = tmp_u32[1];
        cmd.write_bytes = len - 1;
        qspi0_ctrl-&gt;cmd_ctrl = cmd;
        qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
        while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
    }
    else {
        cmd.read_bytes = len - 1;
        qspi0_ctrl-&gt;cmd_ctrl = cmd;
        qspi0_ctrl-&gt;cmd_ctrl.execute = 1;
        while(qspi0_ctrl-&gt;cmd_ctrl.progress_status);
        if(type == QSPI_STIG_CMD_READ) {
            tmp_u32[0] = qspi0_ctrl-&gt;read_data_L;
            tmp_u32[1] = qspi0_ctrl-&gt;read_data_H;
            //co_printf(&quot;READ_L: 0x%08x, READ_H: 0x%08x.\r\n&quot;, tmp_u32[0], tmp_u32[1]);
            memcpy(buffer, tmp_u8, len);
        }
        else {
            //TBD, BANK READ
        }
    }
}

return 0;
</code></pre>
<p>}</p>
<p>void psram_enter_quad(void)<br />
{<br />
qspi0_stig_cmd(enter_quad_mode_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
}</p>
<p>uint32_t psram_read_id(void)<br />
{<br />
uint32_t flash_id;<br />
qspi0_stig_cmd(psram_read_id_cmd, QSPI_STIG_CMD_READ,  3, (uint8_t *)&amp;flash_id);<br />
return (flash_id&amp;0xffffff);<br />
}</p>
<p>static void psram_controller_init(uint16_t page_boundary)<br />
{<br />
while(qspi0_is_busy());</p>
<p>#if PSRAM_ENABLE_Q_MODE == 1<br />
qspi0_read_set_opcode(PSRAM_FAST_READ_OPCODE);<br />
qspi0_read_set_instruction_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_address_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_data_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_dummy_cycles(4);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);//8 bits data after addr</p>
<pre><code>qspi0_write_set_opcode(PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
qspi0_write_set_address_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_data_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_dummy_cycles(0);
</code></pre>
<p>#else<br />
qspi0_read_set_opcode(PSRAM_FAST_QUAL_READ_OPCODE);	<br />
qspi0_read_set_instruction_type(QSPI_WIRE_TYPE_STAND);<br />
qspi0_read_set_address_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_data_type(QSPI_WIRE_TYPE_QIO);<br />
qspi0_read_set_dummy_cycles(6);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);//8 bits data after addr</p>
<pre><code>qspi0_write_set_opcode(PSRAM_PAGE_QUAL_PROGRAM_OPCODE);
qspi0_write_set_address_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_data_type(QSPI_WIRE_TYPE_QIO);
qspi0_write_set_dummy_cycles(0);
</code></pre>
<p>#endif</p>
<pre><code>//init configuration register
qspi0_cfg_set_cpol(0);
qspi0_cfg_set_cpha(0);
qspi0_cfg_set_enable_dac(1);
qspi0_cfg_set_enable_legacy(0);
qspi0_cfg_set_enable_remap(1);
</code></pre>
<p>#if QSPI0_HIGH_SPEED<br />
qspi0_cfg_set_baudrate(PSRAM_CLK_DIV_SEL);<br />
#else<br />
qspi0_cfg_set_baudrate(QSPI_BAUDRATE_DIV_32);<br />
#endif<br />
qspi0_cfg_set_enable_AHB_decoder(1);<br />
qspi0_write_set_wel_dis(1);<br />
qspi0_poll_set_disable(1);</p>
<p>#if QSPI0_HIGH_SPEED<br />
qspi0_ctrl-&gt;read_cap.delay_capture = 3;<br />
#else<br />
qspi0_ctrl-&gt;read_cap.delay_capture = 0;<br />
#endif<br />
qspi0_ctrl-&gt;read_cap.enable_loopback_clk = 1;<br />
qspi0_ctrl-&gt;delay.sel_start_offset = 2;<br />
qspi0_ctrl-&gt;delay.sel_end_offset = 2;<br />
qspi0_ctrl-&gt;delay.sel_dessert = 2;<br />
qspi0_ctrl-&gt;cs_ctrl.rd_brk_en = 1;<br />
qspi0_ctrl-&gt;cs_ctrl.disable_cs_after_first_byte = 0;  /* forum-verified working value for quad PSRAM (was 1 in SDK) <em>/<br />
qspi0_ctrl-&gt;cs_ctrl.page_boundary_protect_en = 1;<br />
qspi0_ctrl-&gt;cs_ctrl.page_boundary = page_boundary;<br />
qspi0_set_remap_address(QSPI1_DAC_ADDRESS);<br />
qspi0_ctrl-&gt;AHB_trigger_address = PSRAM_BASE;  /</em> DAC window trigger (old project set it; default points elsewhere) */<br />
qspi0_cfg_set_enable(1);<br />
}</p>
<p>void psram_cache_enable(void)<br />
{<br />
__CACHE_FLUSH(CACHE);<br />
__CACHE_WR_MODE_SET(CACHE, CACHE_WR_WRITE_THROUGH);<br />
__CACHE_ADDR_RANGEx_BANK_SET(CACHE, 0, 0x0000);<br />
__CACHE_ADDR_RANGEx_MASK_SET(CACHE, 0, 0x0000);<br />
__CACHE_ADDR_RANGEx_POL_SET(CACHE, 0, CACHE_POL_CACHABLE);<br />
__CACHE_ADDR_RANGEx_ENABLE(CACHE, 0);<br />
__CACHE_ENABLE(CACHE);<br />
}</p>
<p>bool psram_init(enum psram_clk_sel_t clk_sel)<br />
{<br />
uint32_t ref_clk;</p>
<pre><code>if (clk_sel &gt;= PSRAM_CLK_SEL_MAX) {
    return false;
}

switch (clk_sel) {
    case PSRAM_CLK_SEL_COREH_48M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 0;
        ref_clk = 48000000;
        break;
    case PSRAM_CLK_SEL_COREH_96M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 1;
        ref_clk = 96000000;
        break;      
    case PSRAM_CLK_SEL_COREH_192M:
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_sel = 2;
        ref_clk = 192000000;
        break;
    default:
        return false;
}
system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en=1;
system_regs-&gt;mdm_qspi_cfg.qspi0_hclk_en=1;
system_regs-&gt;mdm_qspi_cfg.qspi0_io_ctl_oen=0;

if(psram_delay == 0xFF)
{
    qspi0_stig_cmd(reset_enable_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
    qspi0_stig_cmd(reset_cmd, QSPI_STIG_CMD_EXE, 0, NULL);
    co_delay_10us(20);  /* 200us reset recovery before quad entry */
    /* serial write magic @0 while die in SPI mode (baseline) */
    {
        uint32_t magic = 0xc3c3c3c3;
        uint32_t chk = 0;
        qspi0_ctrl-&gt;cmd_address = 0;
        qspi0_stig_cmd(psram_stig_write_cmd, QSPI_STIG_CMD_WRITE, 4, (uint8_t *)&amp;magic);
        qspi0_ctrl-&gt;cmd_address = 0;
        qspi0_stig_cmd(psram_stig_read_cmd, QSPI_STIG_CMD_READ, 4, (uint8_t *)&amp;chk);
        co_printf(&quot;psram serial w/r chk=%x\r\n&quot;, chk);
    }
</code></pre>
<p>#if PSRAM_ENABLE_Q_MODE == 1<br />
psram_enter_quad();<br />
#endif  // PSRAM_ENABLE_Q_MODE == 1<br />
}</p>
<pre><code>/* about 100 bytes can be transmitted during 8us when QSPI clock is 24MHz */
ref_clk /= ((PSRAM_CLK_DIV_SEL+1) * 2);
uint32_t bytes = ref_clk / 240000;
uint32_t boundary_cfg = 1 &lt;&lt; (31 - __CLZ(bytes));
if (boundary_cfg &gt;= 0x100) {
    boundary_cfg = 0x100;
}
psram_controller_init(boundary_cfg);

if(psram_delay != 0xFF)
{
    qspi0_ctrl-&gt;read_cap.delay_capture = psram_delay;
}
else
{
    /* detect read capture delay configuration */
    uint8_t delay_lower, delay_upper, index;
    /* QUAD READ test v2: sweep dummy cycles x capture taps.
       Serial-written c3c3c3c3 @0 must appear via quad DAC read. Log non-zero only. */
    {
        static const uint8_t dummies[] = {4, 2, 6, 8, 0, 3, 5, 1, 7};
        uint8_t found = 0;
        for (uint8_t di = 0; di &lt; sizeof(dummies) &amp;&amp; !found; di++) {
            qspi0_read_set_dummy_cycles(dummies[di]);
            for (index = 0; index &lt; 16; index++) {
                while(qspi0_is_busy());
                qspi0_ctrl-&gt;read_cap.delay_capture = index;
                uint32_t dbg = *(volatile uint32_t *)(PSRAM_BASE);
                if (dbg != 0) {
                    co_printf(&quot;psram qt(d=%d,t=%d)=%x\r\n&quot;, dummies[di], index, dbg);
                }
                if (dbg == 0xc3c3c3c3) {
                    co_printf(&quot;psram QUAD READ OK (dummy=%d tap=%d)\r\n&quot;, dummies[di], index);
                    found = 1;
                    break;
                }
            }
        }
        if (!found) {
            co_printf(&quot;psram QUAD READ DEAD (9 dummies x 16 taps)\r\n&quot;);
        }
    }
    /* QUAD WRITE test: write via quad DAC @4, verify via SERIAL read @4 */
    {
        *(volatile uint32_t *)(PSRAM_BASE + 4) = 0x5a5a5a5a;
        while(qspi0_is_busy());
        uint32_t chk4 = 0;
        qspi0_ctrl-&gt;cmd_address = 4;
        qspi0_stig_cmd(psram_stig_read_cmd, QSPI_STIG_CMD_READ, 4, (uint8_t *)&amp;chk4);
        co_printf(&quot;psram quad w @4, serial sees=%x %s\r\n&quot;, chk4,
                  (chk4 == 0x5a5a5a5a) ? &quot;QUAD WRITE OK&quot; : &quot;QUAD WRITE DEAD&quot;);
    }
    *(volatile uint32_t *)(PSRAM_BASE) = 0x5a5a5a5a;
    while(qspi0_is_busy());

    for (index = 0; index &lt; 16; index++) {
        while(qspi0_is_busy());
        qspi0_ctrl-&gt;read_cap.delay_capture = index;
        if (*(volatile uint32_t *)(PSRAM_BASE) == 0x5a5a5a5a) {
            break;
        }
    }
    if (index == 16) {
        system_regs-&gt;mdm_qspi_cfg.qspi0_ref_clk_en=0;
        return false;
    }
    else {
        delay_lower = index;
    }
    for (; index &lt; 16; index++) {
        while(qspi0_is_busy());        
        qspi0_ctrl-&gt;read_cap.delay_capture = index;
        delay_upper = index;
        if (*(volatile uint32_t *)(PSRAM_BASE) != 0x5a5a5a5a) {
            break;
        }
    }
    
    psram_delay = ((delay_lower + delay_upper)&gt;&gt;1);
    while(qspi0_is_busy());
    qspi0_ctrl-&gt;read_cap.delay_capture = psram_delay;      
}
return true;
</code></pre>
<p>}</p>
<p>/* ---- old-project helpers restored: the only PSRAM path proven on this</p>
<ul>
<li>
<pre><code> board+die (single-lane DAC, verified working on FR8008GPU 2026-10-27).
</code></pre>
</li>
<li>
<pre><code> SDK quad framings (all-quad and 1-4-4) both fail on this die. ---- */
</code></pre>
</li>
</ul>
<p>void psram_reset(void)<br />
{<br />
qspi0_stig_cmd(reset_enable_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
qspi0_stig_cmd(reset_cmd, QSPI_STIG_CMD_EXE, 0, NULL);<br />
}</p>
<p>void psram_set_delay(uint8_t d)<br />
{<br />
qspi0_ctrl-&gt;read_cap.delay_capture = d;<br />
}</p>
<p>void psram_set_ahb_trigger(uint32_t addr)<br />
{<br />
qspi0_ctrl-&gt;AHB_trigger_address = addr;<br />
}</p>
<p>void psram_set_frame(uint8_t r_op, uint8_t r_it, uint8_t r_at, uint8_t r_dt, uint8_t r_dummy,<br />
uint8_t w_op, uint8_t w_at, uint8_t w_dt, uint8_t w_dummy)<br />
{<br />
qspi0_read_set_opcode(r_op);<br />
qspi0_read_set_instruction_type(r_it);<br />
qspi0_read_set_address_type(r_at);<br />
qspi0_read_set_data_type(r_dt);<br />
qspi0_read_set_dummy_cycles(r_dummy);<br />
qspi0_read_set_mode_en(0);<br />
qspi0_set_mode_bit(0);<br />
qspi0_write_set_opcode(w_op);<br />
qspi0_write_set_address_type(w_at);<br />
qspi0_write_set_data_type(w_dt);<br />
qspi0_write_set_dummy_cycles(w_dummy);<br />
}</p>
]]></description><link>http://www.freqchip.net:4567/post/4720</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4720</guid><dc:creator><![CDATA[游泳圈]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>