<?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[FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡]]></title><description><![CDATA[<p>FR8008G-U 蓝牙和LVGL同时跑，由于蓝牙协议栈基本上把内部RAM用完了，所以LVGL只能在PSRAM上运行，但是在PSRAM上运行比在内部RAM运行慢，我测试了下慢了将近6倍，请问PSRAM还有没有提升空间？或者还有其他办法解决上面LVGL和蓝牙同时跑内部RAM用完的问题，以下是我的PSRAM配置pmu_ioldosw_ctrl(true);</p>
<pre><code>__SYSTEM_GPIO_CLK_ENABLE();
system_regs-&gt;mdm_qspi_cfg.qspi_ref_128m_en = 1; // configure qspi reference clock to 128MHz
system_regs-&gt;mdm_qspi_cfg.qspi_ref_clk_sel = 1; // qspi is used for internal flash, set its reference clock to 96MHz
// system_enable_internal_flash_q_read(0x01);
system_set_internal_flash_clock_div(0);

// configure PSRAM pin and init PSRAM
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_0, PORTC0_FUNC_QSPI0_IO3);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_1, PORTC1_FUNC_QSPI0_SCLK0);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_QSPI0_CSN0);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_QSPI0_IO1);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_4, PORTC4_FUNC_QSPI0_IO2);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_QSPI0_IO0);
psram_init(PSRAM_CLK_SEL_COREH_96M);
</code></pre>
<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;</p>
<p>#ifdef INLINE<br />
#undef INLINE<br />
#endif<br />
#define INLINE</p>
<p>#define PSRAM_ENABLE_Q_MODE             1<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 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 = 1;<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_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;      
    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);
</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;
    *(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;      
}

psram_cache_enable();

return true;
</code></pre>
<p>}</p>
]]></description><link>http://www.freqchip.net:4567/topic/1886/fr8008g-u-蓝牙和lvgl同时运行-lvgl使用外部psram运行比较卡</link><generator>RSS for Node</generator><lastBuildDate>Wed, 09 Sep 2026 06:42:21 GMT</lastBuildDate><atom:link href="http://www.freqchip.net:4567/topic/1886.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 11 Aug 2026 09:36:05 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡 on Invalid Date]]></title><description><![CDATA[<p>FR8008G-U 蓝牙和LVGL同时跑，由于蓝牙协议栈基本上把内部RAM用完了，所以LVGL只能在PSRAM上运行，但是在PSRAM上运行比在内部RAM运行慢，我测试了下慢了将近6倍，请问PSRAM还有没有提升空间？或者还有其他办法解决上面LVGL和蓝牙同时跑内部RAM用完的问题，以下是我的PSRAM配置pmu_ioldosw_ctrl(true);</p>
<pre><code>__SYSTEM_GPIO_CLK_ENABLE();
system_regs-&gt;mdm_qspi_cfg.qspi_ref_128m_en = 1; // configure qspi reference clock to 128MHz
system_regs-&gt;mdm_qspi_cfg.qspi_ref_clk_sel = 1; // qspi is used for internal flash, set its reference clock to 96MHz
// system_enable_internal_flash_q_read(0x01);
system_set_internal_flash_clock_div(0);

// configure PSRAM pin and init PSRAM
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_0, PORTC0_FUNC_QSPI0_IO3);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_1, PORTC1_FUNC_QSPI0_SCLK0);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_QSPI0_CSN0);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_QSPI0_IO1);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_4, PORTC4_FUNC_QSPI0_IO2);
system_set_port_mux(GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_QSPI0_IO0);
psram_init(PSRAM_CLK_SEL_COREH_96M);
</code></pre>
<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;</p>
<p>#ifdef INLINE<br />
#undef INLINE<br />
#endif<br />
#define INLINE</p>
<p>#define PSRAM_ENABLE_Q_MODE             1<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 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 = 1;<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_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;      
    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);
</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;
    *(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;      
}

psram_cache_enable();

return true;
</code></pre>
<p>}</p>
]]></description><link>http://www.freqchip.net:4567/post/4613</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4613</guid><dc:creator><![CDATA[hejun]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Reply to FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡 on Invalid Date]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="http://www.freqchip.net:4567/uid/2009">@hejun</a><br />
<img src="/assets/uploads/files/1787217930713-5a69fe4f-99d3-40e2-95d9-622129e4d627-%E5%9B%BE%E7%89%87-resized.png" alt="0_1787217931959_5a69fe4f-99d3-40e2-95d9-622129e4d627-图片.png" class="img-responsive img-markdown" /></p>
<p>最高可以192m</p>
]]></description><link>http://www.freqchip.net:4567/post/4614</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4614</guid><dc:creator><![CDATA[ZR]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Reply to FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡 on Invalid Date]]></title><description><![CDATA[<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;</p>
<p>#ifdef INLINE<br />
#undef INLINE<br />
#endif<br />
#define INLINE</p>
<p>#define PSRAM_ENABLE_Q_MODE             1<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 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;<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_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;      
    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);
</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;
    *(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;      
    co_printf(&quot;psram_delay:%d\r\n&quot;, psram_delay);
}

psram_cache_enable();

return true;
</code></pre>
<p>}<br />
1、当前SDK没有192M的配置 确认是可以直接改成192M？<br />
2、    uint32_t bytes = ref_clk / 240000; 请问这个240000是什么意思，是否可以调整？</p>
]]></description><link>http://www.freqchip.net:4567/post/4619</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4619</guid><dc:creator><![CDATA[lhj]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Reply to FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡 on Invalid Date]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="http://www.freqchip.net:4567/uid/1586">@zr</a> #include &quot;lvgl.h&quot;<br />
#include &quot;stdlib.h&quot;<br />
#include &quot;stdio.h&quot;<br />
#include &quot;gui_guider.h&quot;<br />
#include &quot;ui_manager.h&quot;<br />
#include &quot;ble_handle.h&quot;<br />
#include &quot;key_handle.h&quot;<br />
#include &quot;func.h&quot;<br />
#include &lt;math.h&gt;</p>
<p>#define BTN_HEIGHT       32     // 按键高度（固定，可根据需求调整）<br />
#define BTN_WIDTH        200    // 按键宽度<br />
#define PAGE_MAX_BTN     5      // 页面最大按钮数<br />
#define BTN_MAX_NUM      5      // 总共按钮数</p>
<p>static const char *btn_text[] = {<br />
&quot;device&quot;,<br />
&quot;Relief&quot;,<br />
&quot;20min&quot;,<br />
&quot;Favorite&quot;,<br />
&quot;Start&quot;,<br />
};</p>
<p>static void update_channel_info(void);</p>
<p>static uint8_t mainChoose_start_index = 0;  // 主界面起始选项起始下标</p>
<p>static lv_coord_t btn_y[BTN_MAX_NUM] = {45, 79, 114, 149, 184};<br />
static lv_coord_t btn_width[BTN_MAX_NUM] = {164, 200, 195, 149, 124};</p>
<p>static lv_style_t choose_btn;<br />
static lv_style_t nochoose_btn;<br />
static lv_style_t startnochoose_btn;</p>
<p>static lv_style_t style_arrow;<br />
static lv_style_t nostyle_arrow;<br />
static lv_obj_t *btn[BTN_MAX_NUM];</p>
<p>static lv_obj_t *btn_num_label[BTN_MAX_NUM] = {NULL};   // 数字标签指针<br />
static lv_obj_t *btn_text_label[BTN_MAX_NUM] = {NULL};  // 文本标签指针（全部按钮）<br />
static lv_obj_t *sym[BTN_MAX_NUM] = {NULL};</p>
<p>//static lv_obj_t *label;</p>
<p>static const lv_img_dsc_t * line_img[4] = {&amp;_01_alpha_196x4, &amp;_02_alpha_210x4, &amp;_03_alpha_202x4, &amp;_04_alpha_160x4};<br />
const lv_img_dsc_t * device_icon[3] = {&amp;_menu_device1_alpha_27x27, &amp;_menu_device2_alpha_27x27, &amp;_device_all_alpha_64x27};<br />
static uint8_t last_index = 0;<br />
static void btn_eventKey_callback(lv_event_t *e)<br />
{<br />
lv_obj_t *btn = lv_event_get_target(e);<br />
lv_event_code_t code = lv_event_get_code(e);<br />
uint32_t key = lv_event_get_key(e);<br />
uint8_t connect_status, num = (uint8_t)(uintptr_t)lv_obj_get_user_data(btn);<br />
lv_ui *ui = lv_event_get_user_data(e);<br />
struct DEVINFO *dev = get_dev();<br />
struct OUTINFO * current_out = get_out(dev-&gt;currentch);</p>
<pre><code>if (ui-&gt;choose_page == NULL)
    return;

if (code == LV_EVENT_KEY)
{
    switch(key)
    {
        case LV_KEY_ENTER:
            switch(num)
            {
                case 1: // 小模式
                {
                    last_index = num;
                    ui_manager_switch(SLAVEMODE_SCREEN, UI_ANIM_NONE, NULL);
                    break;
                }
                case 3: // 喜爱模式
                {
                    last_index = num;
                    ui_manager_switch(FAVORITE_CHOOSE_SCREEN, UI_ANIM_NONE, NULL);
                    break;
                }
                case 4: // 启动
                {
                    last_index = num;
                    ui_manager_switch(CONTROL_SCREEN, UI_ANIM_NONE, NULL);
                    break;
                }
                default:
                    break;
            }
            break;
        case LV_KEY_LEFT:
            switch(num)
            {
                case 0: // 设备
                {
                    connect_status = get_hosts_status(STATUS_TYPE_CONNECT);
                    if (connect_status == 0x03)
                    {
                        dev-&gt;currentch = get_nextDeviceId(dev-&gt;currentch, 1);
                        update_channel_info();
                    }
                    else if(connect_status &amp;&amp; (dev-&gt;currentch == MAX_CHANNEL))
                    {
                        if (connect_status == 0x01)
                        {
                            dev-&gt;currentch = 0;
                        }
                        else
                        {
                            dev-&gt;currentch = 1;
                        }
                        update_channel_info();
                    }
                    break;
                }
                case 1: // 小模式
                {
                    if (current_out-&gt;slave_mode &gt; MIN_SLAVE_MODE)
                        current_out-&gt;slave_mode--;
                    else
                        current_out-&gt;slave_mode = MAX_SLAVE_MODE - 1;
                    device_set_mode(current_out, current_out-&gt;master_mode, current_out-&gt;slave_mode);
                    mainPage_slavemode_update(current_out-&gt;master_mode, current_out-&gt;slave_mode);
                    // mainPage_strength_update(current_out-&gt;strength);
                    packet_ble_txdata(RUN_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                    break;
                }
                case 2: // 时间
                {
                    // ========== 减少5分钟（结果对齐到5的倍数） ==========
                    if (current_out-&gt;worktime &gt; MIN_WORK_TIME)
                    {
                        // 先转成分钟（向上取整），再对齐到5的倍数，最后减5
                        uint8_t minutes = (current_out-&gt;worktime + 59) / 60;
                        minutes = ((minutes + 4) / 5) * 5;   // 向上对齐到5的倍数
                        if (minutes &gt; 5)
                        {
                            current_out-&gt;setworktime = current_out-&gt;worktime = (minutes - 5) * 60;
                        }
                        else
                        {
                            current_out-&gt;setworktime = current_out-&gt;worktime = MAX_WORK_TIME;  // 回绕
                        }
                    }
                    else
                    {
                        current_out-&gt;setworktime = current_out-&gt;worktime = MAX_WORK_TIME;
                    }
                    mainPage_worktime_update(current_out-&gt;worktime);
                    packet_ble_txdata(TIME_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                    break;
                }
                // case 4: // 强度
                // {
                //     if (device_dec_strength(current_out))
                //     {
                //         mainPage_strength_update(current_out-&gt;strength);
                //         packet_ble_txdata(RUN_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                //     }
                //     else    // 没有处理任何操作直接return,防止调用sync_setChannelInfo
                //         return;
                //     break;
                // }
                default:
                    break;
            }
            break;
        case LV_KEY_RIGHT:
        {
            switch(num)
            {
                case 0: // 设备
                {
                    connect_status = get_hosts_status(STATUS_TYPE_CONNECT);
                    if (connect_status == 0x03)
                    {
                        dev-&gt;currentch = get_nextDeviceId(dev-&gt;currentch, 0);
                        update_channel_info();
                    }
                    else if(connect_status &amp;&amp; (dev-&gt;currentch == MAX_CHANNEL))
                    {
                        if (connect_status == 0x01)
                        {
                            dev-&gt;currentch = 0;
                        }
                        else
                        {
                            dev-&gt;currentch = 1;
                        }
                        update_channel_info();
                    }
                    break;
                }
                case 1: // 小模式
                {
                    current_out-&gt;slave_mode++;
                    current_out-&gt;slave_mode = current_out-&gt;slave_mode % MAX_SLAVE_MODE;
                    device_set_mode(current_out, current_out-&gt;master_mode, current_out-&gt;slave_mode);
                    mainPage_slavemode_update(current_out-&gt;master_mode, current_out-&gt;slave_mode);
                    // mainPage_strength_update(current_out-&gt;strength);
                    packet_ble_txdata(RUN_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                    break;
                }
                case 2: // 时间
                {
                    // ========== 增加5分钟（结果对齐到5的倍数） ==========
                    if (current_out-&gt;worktime &lt; MAX_WORK_TIME)
                    {
                        // 先转成分钟（向上取整），再对齐到5的倍数，再加5
                        uint8_t minutes = (current_out-&gt;worktime + 59) / 60;
                        minutes = (minutes / 5) * 5;   // 向上对齐到5的倍数
                        if (minutes &lt;= (MAX_WORK_TIME / 60 - 5))
                        {
                            current_out-&gt;setworktime = current_out-&gt;worktime = (minutes + 5) * 60;
                        }
                        else
                        {
                            current_out-&gt;setworktime = current_out-&gt;worktime = MIN_WORK_TIME;  // 回绕
                        }
                    }
                    else
                    {
                        current_out-&gt;setworktime = current_out-&gt;worktime = MIN_WORK_TIME;
                    }
                    mainPage_worktime_update(current_out-&gt;worktime);
                    packet_ble_txdata(TIME_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                    break;
                }
                // case 4: // 强度
                // {
                //     if (device_add_strength(current_out))
                //     {
                //         mainPage_strength_update(current_out-&gt;strength);
                //         packet_ble_txdata(RUN_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
                //     }
                //     else    // 没有处理任何操作直接return,防止调用sync_setChannelInfo
                //         return;
                //     break;
                // }
                default:
                    break;
            }
            break;
        }
        case LV_KEY_DOUBLE:
        {
            current_out-&gt;pause = !current_out-&gt;pause;
            packet_ble_txdata(RUN_DPID, get_dev()-&gt;currentch == MAX_CHANNEL ? SYNC_DEVICE_ID : current_out-&gt;channel);
            mainPage_pause_update(current_out-&gt;pause);
            break;
        }
        default:
            return;
    }
    if (dev-&gt;currentch == MAX_CHANNEL &amp;&amp; (num != 0 || key == LV_KEY_DOUBLE))  // 同步通道下调整了设置,自动进入同步模式(设备切换除外)
        sync_setChannelInfo();
    else if (dev-&gt;currentch != MAX_CHANNEL &amp;&amp; (num != 0 || key == LV_KEY_DOUBLE))  // 独立通道下调整了设置,自动退出同步模式(设备切换除外)
        exit_syncMode();
}
</code></pre>
<p>}</p>
<p>void mainPage_device_update(uint8_t channel)<br />
{<br />
if (guider_ui.choose_page == NULL)<br />
return;<br />
lv_img_set_src(sym[0], device_icon[channel]);<br />
}</p>
<p>void mainPage_slavemode_update(uint8_t masterMode, uint8_t slaveMode)<br />
{<br />
if (guider_ui.choose_page == NULL)<br />
return;<br />
lv_label_set_text(btn_text_label[1], slave_btn_text[slaveMode]);<br />
}</p>
<p>void mainPage_worktime_update(uint16_t time)<br />
{<br />
uint8_t min = (time - 1) / 60 + 1;<br />
if (guider_ui.choose_page == NULL || btn_num_label[2] == NULL)<br />
return;<br />
lv_label_set_text_fmt(btn_num_label[2], &quot;%02d&quot;, min);<br />
}</p>
<p>void mainPage_mode_update(uint8_t slave_mode)<br />
{<br />
if (guider_ui.choose_page == NULL)<br />
return;<br />
mainPage_slavemode_update(0, slave_mode);<br />
}</p>
<p>// void mainPage_strength_update(uint16_t strength)<br />
// {<br />
//     if (guider_ui.choose_page == NULL)<br />
//         return;<br />
//     lv_label_set_text_fmt(btn_num_label[4], &quot;%02d&quot;, strength);<br />
// }</p>
<p>void mainPage_pause_update(uint8_t pause)<br />
{<br />
if (guider_ui.choose_page == NULL)<br />
return;<br />
if (pause)<br />
{<br />
lv_img_set_src(sym[2], &amp;_pause_alpha_18x18);<br />
lv_obj_set_style_img_recolor_opa(sym[2], LV_OPA_0, 0);<br />
}<br />
else<br />
{<br />
lv_img_set_src(sym[2], &amp;_time_alpha_18x18);<br />
lv_obj_set_style_img_recolor_opa(sym[2], LV_OPA_COVER, 0);<br />
}<br />
}</p>
<p>// CHOOSE_MENU的style初始化<br />
static void style_init(void)<br />
{<br />
lv_style_init(&amp;choose_btn);</p>
<pre><code>lv_style_set_radius(&amp;choose_btn, 50);
lv_style_set_bg_color(&amp;choose_btn, lv_color_hex(UI_MAIN_COLOR));
lv_style_set_bg_opa(&amp;choose_btn, 255);
lv_style_set_height(&amp;choose_btn, BTN_HEIGHT);
lv_style_set_text_align(&amp;choose_btn, LV_TEXT_ALIGN_CENTER);
lv_style_set_text_color(&amp;choose_btn, lv_color_hex(0x000000));
lv_style_set_shadow_opa(&amp;choose_btn, LV_OPA_TRANSP); // 阴影透明
lv_style_set_shadow_width(&amp;choose_btn, 0);           // 阴影宽度0
lv_style_set_border_opa(&amp;choose_btn, 0);
// 关闭过渡动画（关键）
lv_style_set_transition(&amp;choose_btn, NULL);

lv_style_init(&amp;nochoose_btn);

lv_style_set_radius(&amp;nochoose_btn, 50);
lv_style_set_bg_color(&amp;nochoose_btn, lv_color_hex(0x000000));
lv_style_set_bg_opa(&amp;nochoose_btn, 0);
lv_style_set_height(&amp;nochoose_btn, BTN_HEIGHT);
lv_style_set_text_align(&amp;nochoose_btn, LV_TEXT_ALIGN_CENTER);
lv_style_set_text_color(&amp;nochoose_btn, lv_color_hex(UI_MAIN_COLOR));
lv_style_set_shadow_opa(&amp;nochoose_btn, LV_OPA_TRANSP); // 阴影透明
lv_style_set_shadow_width(&amp;nochoose_btn, 0);           // 阴影宽度0
lv_style_set_border_opa(&amp;nochoose_btn, 0);
// 关闭过渡动画（关键）
lv_style_set_transition(&amp;nochoose_btn, NULL);

lv_style_init(&amp;startnochoose_btn);

lv_style_set_radius(&amp;startnochoose_btn, 50);
lv_style_set_bg_color(&amp;startnochoose_btn, lv_color_hex(0x000000));
lv_style_set_bg_opa(&amp;startnochoose_btn, 0);
lv_style_set_height(&amp;startnochoose_btn, BTN_HEIGHT);
lv_style_set_text_align(&amp;startnochoose_btn, LV_TEXT_ALIGN_CENTER);
lv_style_set_text_color(&amp;startnochoose_btn, lv_color_hex(UI_MAIN_COLOR));
lv_style_set_shadow_opa(&amp;startnochoose_btn, LV_OPA_TRANSP); // 阴影透明
lv_style_set_shadow_width(&amp;startnochoose_btn, 0);           // 阴影宽度0
lv_style_set_border_color(&amp;startnochoose_btn, lv_color_hex(UI_MAIN_COLOR));
lv_style_set_border_width(&amp;startnochoose_btn, 2);
lv_style_set_border_opa(&amp;startnochoose_btn, 255);
// 关闭过渡动画（关键）
lv_style_set_transition(&amp;startnochoose_btn, NULL);

lv_style_init(&amp;style_arrow);
lv_style_set_text_opa(&amp;style_arrow, 255);
// 关闭过渡动画（关键）
lv_style_set_transition(&amp;style_arrow, NULL);

lv_style_init(&amp;nostyle_arrow);
lv_style_set_text_opa(&amp;nostyle_arrow, 0);
// 关闭过渡动画（关键）
lv_style_set_transition(&amp;nostyle_arrow, NULL);
</code></pre>
<p>}</p>
<p>static void refresh_all_btn_pos(lv_ui *ui)<br />
{<br />
uint8_t index = 0;<br />
// 重置按钮位置<br />
for (index = 0; index &lt; BTN_MAX_NUM; index++)<br />
{<br />
if (index &gt;= (mainChoose_start_index + PAGE_MAX_BTN) || index &lt; mainChoose_start_index)<br />
{   // 超出屏幕显示数量的按钮放到屏幕外面<br />
lv_obj_set_size(btn[index], btn_width[index], 33);<br />
lv_obj_align(btn[index], LV_ALIGN_TOP_MID, 0, 0);<br />
lv_obj_set_y(btn[index], 250);<br />
}<br />
else<br />
{<br />
lv_obj_set_size(btn[index], btn_width[index - mainChoose_start_index], 33);<br />
lv_obj_align(btn[index], LV_ALIGN_TOP_MID, 0, 0);<br />
lv_obj_set_y(btn[index], btn_y[index - mainChoose_start_index]);<br />
}<br />
}<br />
}</p>
<p>// 更新子对象状态<br />
static void sync_focus_state_to_children(lv_obj_t *parent, lv_ui *ui) {<br />
// 判断父对象是否处于聚焦状态<br />
uint8_t index = 0;<br />
uint8_t num = 0;<br />
bool is_focused = lv_obj_has_state(parent, LV_STATE_FOCUSED);<br />
co_printf(&quot;sync_focus_state_to_children\r\n&quot;);<br />
// 遍历父对象的所有子对象（箭头、文字等）<br />
lv_obj_t *child = lv_obj_get_child(parent, 0);<br />
num = (uint8_t)(uintptr_t)lv_obj_get_user_data(parent);<br />
while(child != NULL) {<br />
if(is_focused) {<br />
// 子对象添加聚焦状态<br />
lv_obj_add_state(child, LV_STATE_FOCUSED);<br />
last_index = num;<br />
if (sym[num] != NULL)<br />
lv_obj_set_style_img_recolor(sym[num], lv_color_hex(0x000000), 0);<br />
} else {<br />
// 子对象清除聚焦状态<br />
lv_obj_clear_state(child, LV_STATE_FOCUSED);<br />
if (sym[num] != NULL)<br />
lv_obj_set_style_img_recolor(sym[num], lv_color_hex(UI_MAIN_COLOR), 0);<br />
}<br />
// 切换到下一个子对象<br />
child = lv_obj_get_child(parent, lv_obj_get_child_id(child) + 1);<br />
}<br />
if (is_focused)<br />
{   // 获取当前焦点下标<br />
num = (uint8_t)(uintptr_t)lv_obj_get_user_data(parent);<br />
// 根据当前焦点的下标判断是否移动起始下标<br />
if (num &lt; mainChoose_start_index)<br />
{<br />
mainChoose_start_index--;<br />
refresh_all_btn_pos(ui);<br />
}<br />
else if (num &gt;= (mainChoose_start_index + PAGE_MAX_BTN))<br />
{<br />
mainChoose_start_index++;<br />
refresh_all_btn_pos(ui);<br />
}<br />
}<br />
for (index = 0; index &lt; 3; index++)<br />
{<br />
// 隐藏当前选项的上一线条<br />
if ((num - mainChoose_start_index) == index)<br />
lv_obj_add_flag(ui-&gt;choose_page_img[index], LV_OBJ_FLAG_HIDDEN);<br />
else<br />
lv_obj_clear_flag(ui-&gt;choose_page_img[index], LV_OBJ_FLAG_HIDDEN);<br />
}<br />
}</p>
<p>// 按钮状态变化事件回调<br />
static void btn_state_change_cb(lv_event_t *e) {<br />
lv_obj_t *btn = lv_event_get_target(e);<br />
lv_event_code_t code = lv_event_get_code(e);<br />
lv_ui *ui = lv_event_get_user_data(e);<br />
if (ui-&gt;choose_page == NULL)<br />
return;<br />
sync_focus_state_to_children(btn, ui);<br />
}</p>
<p>static void update_channel_info(void)<br />
{<br />
struct OUTINFO * current_out = get_out(get_dev()-&gt;currentch);<br />
uint8_t min = (current_out-&gt;worktime - 1) / 60 + 1;</p>
<pre><code>lv_img_set_src(sym[0], device_icon[get_dev()-&gt;currentch]);
lv_label_set_text(btn_text_label[1], slave_btn_text[current_out-&gt;slave_mode]);
mainPage_pause_update(current_out-&gt;pause);
lv_label_set_text_fmt(btn_num_label[2], &quot;%02d&quot;, min);
lv_label_set_text(btn_text_label[2], &quot;min&quot;);
</code></pre>
<p>}</p>
<p>void create_mainChoose_page(lv_ui *ui)<br />
{<br />
uint8_t index = 0;<br />
struct OUTINFO * current_out = get_out(get_dev()-&gt;currentch);<br />
uint8_t min = (current_out-&gt;worktime - 1) / 60 + 1;</p>
<pre><code>const lv_coord_t line_x[4] = {23, 16, 20, 41}; 
const lv_coord_t line_y[4] = {78, 112, 147, 182};

co_printf(&quot;enter create_mainChoose_page\r\n&quot;);
style_init();

//Write codes choose_page
ui-&gt;choose_page = lv_obj_create(lv_scr_act());
lv_obj_remove_style_all(ui-&gt;choose_page);
lv_obj_set_size(ui-&gt;choose_page, 240, 240);
lv_obj_set_scrollbar_mode(ui-&gt;choose_page, LV_SCROLLBAR_MODE_OFF);

//Write style for choose_page, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui-&gt;choose_page, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui-&gt;choose_page, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(ui-&gt;choose_page, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);

//Write codes choose_page_img
for (index = 0; index &lt; 3; index++)
{
    ui-&gt;choose_page_img[index] = lv_img_create(ui-&gt;choose_page);
    lv_obj_add_flag(ui-&gt;choose_page_img[index], LV_OBJ_FLAG_CLICKABLE);
    lv_img_set_src(ui-&gt;choose_page_img[index], line_img[index]);
    lv_img_set_pivot(ui-&gt;choose_page_img[index], 50,50);
    lv_img_set_angle(ui-&gt;choose_page_img[index], 0);
    lv_obj_set_pos(ui-&gt;choose_page_img[index], line_x[index], line_y[index]);
    lv_obj_set_size(ui-&gt;choose_page_img[index], line_img[index]-&gt;header.w, line_img[index]-&gt;header.h);

    //Write style for choose_page_img, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
    lv_obj_set_style_img_recolor_opa(ui-&gt;choose_page_img[index], 0, LV_PART_MAIN|LV_STATE_DEFAULT);
    lv_obj_set_style_img_opa(ui-&gt;choose_page_img[index], 255, LV_PART_MAIN|LV_STATE_DEFAULT);
    lv_obj_set_style_radius(ui-&gt;choose_page_img[index], 0, LV_PART_MAIN|LV_STATE_DEFAULT);
    lv_obj_set_style_clip_corner(ui-&gt;choose_page_img[index], true, LV_PART_MAIN|LV_STATE_DEFAULT);
}
lv_obj_clear_flag(ui-&gt;choose_page, LV_OBJ_FLAG_SCROLLABLE);

for (index = 0; index &lt; BTN_MAX_NUM; index++)
{
    /**************
    ** 按键初始化（保持不变）
    **************/
    btn[index] = lv_btn_create(ui-&gt;choose_page);
    lv_obj_set_style_outline_width(btn[index], 0, LV_STATE_FOCUS_KEY);
    lv_obj_set_size(btn[index], btn_width[index - mainChoose_start_index], 33);
    lv_obj_align(btn[index], LV_ALIGN_TOP_MID, 0, 0);
    lv_obj_remove_style(btn[index], NULL, LV_STATE_PRESSED);    // 移除按下时的缩放动画
    
    if (index &gt;= (mainChoose_start_index + PAGE_MAX_BTN) || index &lt; mainChoose_start_index)
        lv_obj_set_y(btn[index], 250);
    else
        lv_obj_set_y(btn[index], btn_y[index - mainChoose_start_index]);
    
    lv_obj_set_user_data(btn[index], (void *)(uintptr_t)index);
    // lv_obj_add_style(btn[index], &amp;choose_btn, LV_STATE_FOCUSED); // 不能在这里设置样式，切换界面时选项会闪烁
    if (index == 4)
    {
        lv_obj_add_style(btn[index], &amp;startnochoose_btn, LV_STATE_DEFAULT);
    }
    else
    {
        lv_obj_add_style(btn[index], &amp;nochoose_btn, LV_STATE_DEFAULT);
    }
    
    // 设置flex布局（所有按钮统一用 SPACE_BETWEEN，保证左右箭头贴边）
    lv_obj_set_flex_flow(btn[index], LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(btn[index], LV_FLEX_ALIGN_SPACE_BETWEEN, 
                          LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
    lv_obj_set_style_pad_left(btn[index], 5, LV_STATE_DEFAULT);
    lv_obj_set_style_pad_right(btn[index], 5, LV_STATE_DEFAULT);
    
    // 添加事件回调（保持不变）
    lv_obj_add_event_cb(btn[index], btn_state_change_cb, LV_EVENT_FOCUSED, ui);
    lv_obj_add_event_cb(btn[index], btn_state_change_cb, LV_EVENT_DEFOCUSED, ui);
    lv_obj_add_event_cb(btn[index], btn_eventKey_callback, LV_EVENT_KEY, ui);

    /**************
    ** 左箭头（所有按钮都有）
    **************/
    lv_obj_t *arrow_left = lv_label_create(btn[index]);
    lv_label_set_text(arrow_left, &quot;\xE2\x97\x80&quot;);
    lv_obj_set_style_text_font(arrow_left, &amp;lv_font_SourceHanSerifSC_Regular_16, LV_STATE_DEFAULT);
    lv_obj_add_style(arrow_left, &amp;style_arrow, LV_STATE_FOCUSED);
    lv_obj_add_style(arrow_left, &amp;nostyle_arrow, LV_STATE_DEFAULT);
    if ((index == 3) || (index == 4))
    {
        lv_obj_add_style(arrow_left, &amp;nostyle_arrow, LV_STATE_FOCUSED);
    }

    /**************
    ** 中间内容区（区分处理）
    **************/
    if (index == 0)
    {
        lv_obj_t *mid = lv_obj_create(btn[index]);
        lv_obj_remove_style_all(mid);           // 去掉默认边框、背景
        lv_obj_set_size(mid, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
        lv_obj_set_flex_grow(mid, 1);           // 占据中间所有剩余空间
        lv_obj_set_flex_flow(mid, LV_FLEX_FLOW_ROW);
        lv_obj_set_flex_align(mid, LV_FLEX_ALIGN_CENTER,   // 水平居中
                              LV_FLEX_ALIGN_CENTER,         // 垂直居中
                              LV_FLEX_ALIGN_CENTER);
        
        sym[index] = lv_img_create(mid);
        lv_img_set_src(sym[index], device_icon[get_dev()-&gt;currentch]);
        // 重新着色
        set_img_recolor(sym[index], UI_MAIN_COLOR);
</code></pre>
<p>//            lv_obj_set_style_img_recolor(sym[index], lv_color_hex(UI_MAIN_COLOR), 0);<br />
//            lv_obj_set_style_img_recolor_opa(sym[index], LV_OPA_COVER, 0);<br />
}<br />
else if (index == 2)<br />
{<br />
// 特殊按钮：左箭头 | [符号 数字 文本] | 右箭头<br />
// 中间整体用一个容器包裹，内部居中对齐<br />
lv_obj_t *mid = lv_obj_create(btn[index]);<br />
lv_obj_remove_style_all(mid);           // 去掉默认边框、背景<br />
lv_obj_set_size(mid, LV_SIZE_CONTENT, LV_SIZE_CONTENT);<br />
lv_obj_set_flex_grow(mid, 1);           // 占据中间所有剩余空间<br />
lv_obj_set_flex_flow(mid, LV_FLEX_FLOW_ROW);<br />
lv_obj_set_flex_align(mid, LV_FLEX_ALIGN_CENTER,   // 水平居中<br />
LV_FLEX_ALIGN_CENTER,         // 垂直居中<br />
LV_FLEX_ALIGN_CENTER);<br />
lv_obj_set_style_pad_column(mid, 3, 0); // 符号/数字/文本之间的间距</p>
<pre><code>        // 1) 符号
        sym[index] = lv_img_create(mid);//lv_label_create(mid);
        // 重新着色
        set_img_recolor(sym[index], UI_MAIN_COLOR);
        if ((index == 2))
        {
            mainPage_pause_update(current_out-&gt;pause);
        }
</code></pre>
<p>//            lv_obj_set_style_img_recolor(sym[index], lv_color_hex(UI_MAIN_COLOR), 0);<br />
//            lv_obj_set_style_img_recolor_opa(sym[index], LV_OPA_COVER, 0);</p>
<pre><code>        // 2) 数字（可变，保存指针方便后续更新）
        if (index == 2) // 时间初始值
        {
            btn_num_label[index] = lv_label_create(mid);
            lv_obj_set_style_text_font(btn_num_label[index], &amp;lv_font_arialbd_20, 0);
            lv_label_set_text_fmt(btn_num_label[index], &quot;%02d&quot;, min);
        }
        
        // 3) 单位文本
        if ((index == 2))
        {
            btn_text_label[index] = lv_label_create(mid);
            lv_obj_set_style_text_font(btn_text_label[index], &amp;lv_font_Arial_16, 0);
            lv_label_set_text(btn_text_label[index], &quot;min&quot;);
        }
    }
    else
    {
        // 普通按钮：左箭头 | 文本 | 右箭头
        btn_text_label[index] = lv_label_create(btn[index]);
        switch(index)
        {
            case 1:
                lv_label_set_text(btn_text_label[index], slave_btn_text[current_out-&gt;slave_mode]);
                break;
            default:
                lv_label_set_text(btn_text_label[index], btn_text[index]);
                break;
        }
        lv_obj_set_style_text_font(btn_text_label[index], &amp;lv_font_arialbd_20, LV_STATE_DEFAULT);
        
        if (index != 4)
        {   // 除最后一项收藏按钮只有文本外,其余选项均采用flex布局
            lv_obj_set_flex_grow(btn_text_label[index], 1); // 文本标签占据按钮内所有剩余空间
</code></pre>
<p>//                lv_label_set_long_mode(btn_text_label[index], LV_LABEL_LONG_SCROLL);<br />
// 普通按钮文本在flex_grow后自然占据中间，配合SPACE_BETWEEN即可<br />
}<br />
}</p>
<pre><code>    /**************
    ** 右箭头（所有按钮都有）
    **************/
    lv_obj_t *arrow_right = lv_label_create(btn[index]);
    lv_label_set_text(arrow_right, &quot;\xE2\x96\xB6&quot;);
    lv_obj_set_style_text_font(arrow_right, &amp;lv_font_SourceHanSerifSC_Regular_16, LV_STATE_DEFAULT);
    lv_obj_add_style(arrow_right, &amp;style_arrow, LV_STATE_FOCUSED);
    lv_obj_add_style(arrow_right, &amp;nostyle_arrow, LV_STATE_DEFAULT);
    // 收藏按钮不需要左右箭头直接隐藏
    if ((index == 3) || (index == 4))
    {
        lv_obj_add_style(arrow_right, &amp;nostyle_arrow, LV_STATE_FOCUSED);
    }
    if ((index == 3) || (index == 4))
    {
        lv_obj_add_style(arrow_right, &amp;nostyle_arrow, LV_STATE_FOCUSED);
    }
}
lv_group_set_wrap(lv_group_get_default(), false);
lv_group_focus_obj(btn[last_index]);
for (index = 0; index &lt; BTN_MAX_NUM; index++)
{
    lv_obj_add_style(btn[index], &amp;choose_btn, LV_STATE_FOCUSED);
}
co_printf(&quot;exit create_mainChoose_page\r\n&quot;);
lv_obj_update_layout(ui-&gt;choose_page);
</code></pre>
<p>}</p>
<p>/// 创建开机页面UI<br />
static lv_obj_t *ui_mainChoose_create(void)<br />
{<br />
create_mainChoose_page(&amp;guider_ui);</p>
<pre><code>return guider_ui.choose_page;
</code></pre>
<p>}</p>
<p>/// 进入开机页面<br />
static void ui_mainChoose_enter(void* param)<br />
{<br />
(void)param;<br />
}</p>
<p>/// 退出开机页面<br />
static void ui_mainChoose_exit(void)<br />
{<br />
uint8_t i = 0;<br />
get_guiderUi_struct()-&gt;choose_page = NULL; //切换页面,置为NULL后续此界面的回调函数全停止处理防止读取到以及释放的资源<br />
lv_style_reset(&amp;choose_btn);<br />
lv_style_reset(&amp;nochoose_btn);<br />
lv_style_reset(&amp;style_arrow);<br />
lv_style_reset(&amp;nostyle_arrow);<br />
for (i = 0; i &lt; BTN_MAX_NUM; i++)<br />
{<br />
if (sym[i] != NULL)<br />
{<br />
lv_obj_del(sym[i]);<br />
sym[i] = NULL;<br />
}<br />
if (btn_num_label[i] != NULL)<br />
{<br />
lv_obj_del(btn_num_label[i]);<br />
btn_num_label[i] = NULL;<br />
}<br />
if (btn_text_label[i] != NULL)<br />
{<br />
lv_obj_del(btn_text_label[i]);<br />
btn_text_label[i] = NULL;<br />
}<br />
if (btn[i] != NULL)<br />
{<br />
lv_obj_del(btn[i]);<br />
btn[i] = NULL;<br />
}<br />
}<br />
}</p>
<p>/// 销毁开机页面<br />
static void ui_mainChoose_destroy(void)<br />
{<br />
//    lv_obj_del(label);<br />
}</p>
<p>/// 开机页面操作函数表<br />
const ui_page_ops_t ui_mainChoose_ops = {<br />
.create = ui_mainChoose_create,<br />
.enter = ui_mainChoose_enter,<br />
.exit = ui_mainChoose_exit,<br />
.destroy = ui_mainChoose_destroy<br />
};<br />
[16:11:18.388]收←◆enter create_mainChoose_page</p>
<p>[16:11:18.771]收←◆sync_focus_state_to_children</p>
<p>[16:11:18.995]收←◆sync_focus_state_to_children</p>
<p>[16:11:19.043]收←◆exit create_mainChoose_page<br />
LVGL生成一帧内部耗时太长，请问可以怎么改进优化，芯片FR800GP-U</p>
]]></description><link>http://www.freqchip.net:4567/post/4620</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4620</guid><dc:creator><![CDATA[lhj]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Reply to FR8008G-U 蓝牙和LVGL同时运行 LVGL使用外部PSRAM运行比较卡 on Invalid Date]]></title><description><![CDATA[<p>我用着感觉挺快的啊，你是不是设置有问题，我是直接用的demo然后改的自己的驱动 例程里面用了dma，不知道是不是因为这个，psram_init(PSRAM_CLK_SEL_COREH_192M);这个改成最高的，再试试，我之前不知道芯片内部有psram，我用ram直接驱动lvgl也是慢的蜗牛一样</p>
]]></description><link>http://www.freqchip.net:4567/post/4623</link><guid isPermaLink="true">http://www.freqchip.net:4567/post/4623</guid><dc:creator><![CDATA[yjx]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>