SPI3 can not exceed 32Mbit/s ?



  • I want to store para in extern dataflash and read it out instant by quad ios,but when set more than 32Mbits/s by function

    spi_set_clk_rate(spi_bus_no, 32000000); in w25qxx.c

    it then will blocked in function

    spi_receive_data_normal_dma(dma_send_channel_num, dma_receive_channel_num, spi_num, chip_select, write_cmd, cmd_len, read_buf, v_recv_len); in spi.c

    the manual say it will get 45mbits/s,what limit the speed and why blocked.



  • @loboris thank you very much!
    i assume the cause is dma need more then 10cycles to complete a transaction! the evidences are:
    1.when receive less bytes than 32 ,the transfer is ok,the data are stored in fifo.
    2.when transfer more bytes at 40Mbits/s,the spi->risr regitster bit3 will be set,where norm operation will not set,but i have no register definition. i think the fifo is overrun,dma will loss some bytes.
    3.when set the DATALENGTH to 32bits, transfer 4bytes at a dma transaction, no problem appear. this will decrease the transaction times by factor 4!
    4.this assumption also explain when raise spi rate,the quad io mode fail first,then then daul fail. the code will run endless in waiting dma done .
    am i right???



  • #define PLL0_MAX_OUTPUT_FREQ    988000000UL
    #define PLL1_MAX_OUTPUT_FREQ    400000000UL
    #define PLL2_MAX_OUTPUT_FREQ    45100000UL
    #define CPU_MAX_FREQ            (PLL0_MAX_OUTPUT_FREQ / 2)
    #define KPU_MAX_FREQ            PLL1_MAX_OUTPUT_FREQ
    
    // 83 MHz max speed results in SPI3 clocks:
    // 82.333 MHz at PLL0 = 988 MHz (115 us for 4096 bytes read)
    // 67.166 MHz at PLL0 = 806 MHz (142 us for 4096 bytes read)
    #define WQ25QXX_MAX_SPEED                   83000000
    // SPI3 clock for sending/reading commands
    #define SPI_STAND_CLOCK_RATE                20000000
    
    // ==== Basic initialization ====
    sysctl_pll_set_freq(SYSCTL_PLL0, PLL0_MAX_OUTPUT_FREQ);
    sysctl_pll_set_freq(SYSCTL_PLL1, PLL1_MAX_OUTPUT_FREQ);
    sysctl_pll_set_freq(SYSCTL_PLL2, PLL2_MAX_OUTPUT_FREQ);
    sysctl_clock_set_threshold(SYSCTL_THRESHOLD_AI, 0);
    // Set SPI3 clock to PLL0 / 2
    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 0);
    sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI3, 0);
    sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1);
    
    //---------------------------------------------------------------------
    uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate)
    {
        configASSERT(mode < 3);
        work_trans_mode = mode;
        uint8_t manuf_id, device_id;
        w25qxx_actual_speed = clock_rate;
        w25qxx_flash_speed = clock_rate;
        if ((sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) < 200000000) && (clock_rate > 20000000)) {
            // At cpu frequency < 200 MHz, flash spi clock must be <= 20 MHz!
            clock_rate = 20000000;
        }
        else if ((sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) < 400000000) && (clock_rate > 40000000)) {
            // At cpu frequency < 400 MHz, flash spi clock must be <= 40 MHz!
            clock_rate = 40000000;
        }
    
        spi_stand = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_STANDARD, CHIP_SELECT, FRAME_LENGTH);
        w25qxx_actual_speed = (uint32_t)spi_dev_set_clock_rate(spi_stand, SPI_STAND_CLOCK_RATE);
    
        w25qxx_read_id(&manuf_id, &device_id);
        if ((manuf_id != 0xEF && manuf_id != 0xC8) || (device_id != 0x17 && device_id != 0x16)) {
            if (w25qxx_debug) LOGE("w25qxx_init", "Unsupported manuf_id: 0x%02x, device_id:0x%02x", manuf_id, device_id);
            return 0;
        }
        if (w25qxx_debug) LOGD("w25qxx_init", "manuf_id:0x%02x, device_id:0x%02x", manuf_id, device_id);
        switch (work_trans_mode)
        {
            case SPI_FF_DUAL:
                spi_adapter = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_DUAL, CHIP_SELECT, FRAME_LENGTH_DUAL);
                spi_dev_config_non_standard(spi_adapter, INSTRUCTION_LENGTH, ADDRESS_LENGTH, WAIT_CYCLE, SPI_AITM_STANDARD);
                w25qxx_actual_speed = spi_dev_set_clock_rate(spi_adapter, clock_rate);
                break;
            case SPI_FF_QUAD:
                spi_adapter = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_QUAD, CHIP_SELECT, FRAME_LENGTH_QUAD);
                spi_dev_config_non_standard(spi_adapter, INSTRUCTION_LENGTH, ADDRESS_LENGTH, WAIT_CYCLE, SPI_AITM_STANDARD);
                w25qxx_actual_speed = spi_dev_set_clock_rate(spi_adapter, clock_rate);
    
                spi_adapter_wr = spi_get_device(spi_in, SPI_MODE_0, SPI_FF_QUAD, CHIP_SELECT, FRAME_LENGTH_QUAD);
                spi_dev_config_non_standard(spi_adapter_wr, INSTRUCTION_LENGTH, ADDRESS_LENGTH, 0, SPI_AITM_STANDARD);
                spi_dev_set_clock_rate(spi_adapter_wr, clock_rate);
    
                if (w25qxx_enable_quad_mode() != W25QXX_OK) return 0;
                break;
            case SPI_FF_STANDARD:
            default:
                spi_adapter = spi_stand;
                break;
        }
        return w25qxx_actual_speed;
    }
    
    handle_t flash_spi = io_open("/dev/spi3");
    configASSERT(flash_spi);
    uint32_t res = w25qxx_init(flash_spi, SPI_FF_QUAD, WQ25QXX_MAX_SPEED);
    configASSERT(res);
    

    w25qxx.c

    Flash test function, written as MicroPython C function, but should be easily converted to pure C.



  • This post is deleted!


  • @loboris I got a interesting result,
    when i set more higher rate ,as 40Mbits/s,quad read test fail,but dual read test pass,
    when set even higer rate,as 60Mbits/s,dual read even fail,but standard read pass,
    what can cause such problem? just change rate can got different result???????



  • This post is deleted!


  • I'm successfully using Flash with 80 MHz clock (~40 MBytes/second transfer in QOUT SPI mode).
    I'm using my modified FreeRTOS SDK and a different SPI3 initialization.
    I've tested it extensively and it works without issues.
    You can check my MicroPython for K210 project for more detailes.
    I'll try to make a stand-alone demo if I'll find some free time.