简体   繁体   English

如何在不使用预制 ESP 库的情况下配置 SPI 3 线半双工主模式?

[英]How To Configure SPI 3 Line Half Duplex Master Mode Without using Premade ESP Libraries?

I'm working on building out some custom drivers for the ESP-Wroom-32.我正在为 ESP-Wroom-32 构建一些自定义驱动程序。

After trying to use the pre-made arduino and esp32 driver code without success, I've decided to just build the libraries from scratch.在尝试使用预制的 arduino 和 esp32 驱动程序代码但没有成功之后,我决定从头开始构建这些库。

I'm trying to control a Gc9a01 LCD screen, which I've been able to successfully drive using an STM32 processor.我正在尝试控制 Gc9a01 LCD 屏幕,我已经能够使用 STM32 处理器成功驱动它。

For the life of me, I cannot identify what's broken/not working.对于我的生活,我无法确定什么坏了/不工作。

I know for certain that I'm accessing the correct memory addresses, as I can validate the default register values.我确信我正在访问正确的 memory 地址,因为我可以验证默认寄存器值。

I'm fairly certain that I've configured the SPI interface incorrectly;我很确定我没有正确配置 SPI 接口; I'm not getting any response out of my LCD screen, which I know works.我的 LCD 屏幕没有任何响应,我知道它可以工作。

Below is my source code for my SPI driver and link to the technical manual, I know that basically nobody knows how this works;下面是我的 SPI 驱动程序的源代码和技术手册的链接,我知道基本上没有人知道它是如何工作的; but if any gurus out there can provide some insight to my process, specifically some insight into the 3-line half duplex master mode initlaization function and the spi send function, I'd be able to move forward.但如果有任何专家可以对我的过程提供一些见解,特别是对 3 线半双工主模式初始化 function 和 spi 发送 function 的一些见解,我将能够继续前进。

esp32_reference_manual esp32_reference_manual

SPI Code SPI代码

/*
 *  Structs contining register bit positions
 * */
struct spi_user_reg{
    const uint32_t address = BT_ESP32_SPI_USER_REG;
    const uint32_t spi_doutdin = 0;
    const uint32_t spi_cs_hold = 4;
    const uint32_t spi_cs_setup = 5;
    const uint32_t spi_clk_i_edge = 6;
    const uint32_t spi_clk_out_edge = 7;
    const uint32_t spi_rd_byte_order = 10;
    const uint32_t spi_wr_byte_order = 11;
    const uint32_t spi_fwrite_duel = 12;
    const uint32_t spi_fwrite_quad = 13;
    const uint32_t spi_fwrite_dio = 14;
    const uint32_t spi_fwrite_qio = 15;
    const uint32_t spi_sio = 16;
    const uint32_t spi_usr_miso_highpart = 24;
    const uint32_t spi_usr_mosi_highpart = 25;
    const uint32_t spi_usr_dummy_idle = 26;
    const uint32_t spi_usr_mosi= 27;
    const uint32_t spi_usr_miso = 28;
    const uint32_t spi_usr_dummy = 29;
    const uint32_t spi_usr_addr = 30;
    const uint32_t spi_usr_command = 31;
};

struct spi_slv_rdbuf_dlen_reg{
    const uint32_t address = BT_ESP32_SPI_SLV_RDBUF_DLEN_REG;
    const uint32_t spi_slv_rdbuf_dbitlen_low = 0;
    const uint32_t spi_slv_rdbuf_dbitlen_high = 23;
};

struct spi_slv_wrbuf_dlen_reg{
        const uint32_t address = BT_ESP32_SPI_SLV_WRBUF_DLEN_REG;
        const uint32_t spi_slv_wrbuf_dbitlen_low = 0;
    const uint32_t spi_slv_wrbuf_dbitlen_high = 23;
};

struct spi_miso_dlen_reg{
    const uint32_t address = BT_ESP32_SPI_MISO_DLEN_REG;
    const uint32_t spi_usr_miso_dbitlen_low = 0;
    const uint32_t spi_usr_miso_dbitlen_high = 23;
};

struct spi_mosi_dlen_reg{
    const uint32_t address = BT_ESP32_SPI_MOSI_DLEN_REG;
    const uint32_t spi_usr_mosi_dbitlen_start = 0;
    const uint32_t spi_usr_mosi_dbitlen_end = 23;
};

struct spi_addr_reg{
    const uint32_t address = BT_ESP32_SPI_ADDR_REG;
};

struct spi_slave1_reg{
    const uint32_t address = BT_ESP32_SPI_SLAVE1_REG;
    const uint32_t spi_slv_rdbuf_dummy_en = 0;
    const uint32_t spi_slv_wrbuf_dummy_en = 1;
    const uint32_t spi_slv_rdsta_dummy_en = 2;
    const uint32_t spi_slv_wrsta_dummy_en = 3;
    const uint32_t spi_slv_wr_addr_bitlen_stat = 4;
    const uint32_t spi_slv_wr_addr_bitlen_end = 9;
    const uint32_t spi_slv_rd_addr_bitlen_start = 10;
    const uint32_t spi_slv_rd_addr_bitlen_end = 15;
    const uint32_t spi_slv_status_readback = 25;
    const uint32_t spi_slv_status_fast_en = 26;
    const uint32_t spi_slv_status_bitlen_start = 27;
    const uint32_t spi_slv_status_bitlen_end = 31;
};

struct spi_clock_reg{
    const uint32_t address = BT_ESP32_SPI_CLOCK_REG;
    const uint32_t spi_clkcnt_l_start = 0;
    const uint32_t spi_clkcnt_l_end = 5;
    const uint32_t spi_clkcnt_h_start = 6;
    const uint32_t spi_clkcnt_h_end = 11;
    const uint32_t spi_clkcnt_n_start = 12;
    const uint32_t spi_clkcnt_n_end = 17;
    const uint32_t spi_clkdiv_pre_start = 18;
    const uint32_t spi_clkdiv_pre_end = 30;
    const uint32_t spi_clk_equ_sysclk = 31;
};

struct spi_pin_reg{
    const uint32_t address = BT_ESP32_SPI_PIN_REG;
    const uint32_t spi_cs0_dis = 0;
    const uint32_t spi_cs1_dis = 1;
    const uint32_t spi_cs2_dis = 2;
    const uint32_t spi_ck_dis = 3;
    const uint32_t spi_master_cs_pol_start = 11;
    const uint32_t spi_master_cs_pol_end = 13;
    const uint32_t spi_ck_idle_edge = 29;
    const uint32_t spi_cs_keep_active = 30;
};

struct spi_ctrl2_reg{
    const uint32_t address = BT_ESP32_SPI_CTRL2_REG;
    const uint32_t spi_setup_time_start = 0;
    const uint32_t spi_setup_time_end = 3;
    const uint32_t spi_hold_time_start = 4;
    const uint32_t spi_hold_time_end = 7;
    const uint32_t spi_ck_out_high_mode_start = 12;
    const uint32_t spi_ck_out_high_mode_end = 15;
    const uint32_t spi_miso_delay_mode_start = 16;
    const uint32_t spi_miso_delay_mode_end = 17;
    const uint32_t spi_miso_delay_num_start = 18;
    const uint32_t spi_miso_delay_num_end = 20;
    const uint32_t spi_mosi_delay_mode_start = 21;
    const uint32_t spi_mosi_delay_mode_end = 22;
    const uint32_t spi_mosi_delay_num_start = 23;
    const uint32_t spi_mosi_delay_num_end = 25;
    const uint32_t spi_cs_delay_mod_start = 26;
    const uint32_t spi_cs_delay_mod_end = 27;
    const uint32_t spi_cs_delay_num_start = 28;
    const uint32_t spi_cs_delay_num_end = 31;
};

struct spi_cmd_reg{
    const uint32_t address = BT_ESP32_SPI_CMD_REG;
    const uint32_t spi_usr = 18;
};

struct spi_user2_reg{
    const uint32_t address = BT_ESP32_SPI_USER2_REG;
    const uint32_t spi_usr_command_value_start = 0;
    const uint32_t spi_usr_command_value_end = 15;
    const uint32_t spi_usr_command_bitlen_start = 28;
    const uint32_t spi_usr_command_bitlen_end = 31;
};

struct spi_ctrl_reg{
    const uint32_t address = BT_ESP32_SPI_CTRL_REG;
    const uint32_t spi_fastrd_mode = 13;
    const uint32_t spi_fread_dual = 14;
    const uint32_t spi_fread_quad = 20;
    const uint32_t spi_wp = 21;
    const uint32_t spi_fread_dio = 23;
    const uint32_t spi_fread_qio = 24;
    const uint32_t spi_rd_bit_order = 25;
    const uint32_t spi_wr_bit_order = 26;
};

struct spi_slave_reg{
    uint32_t address = BT_ESP32_SPI_SLAVE_REG;
    uint32_t spi_slv_rd_buf_done = 0;
    uint32_t spi_slv_wr_buf_done = 1;
    uint32_t spi_slv_rd_sta_done = 2;
    uint32_t spi_slv_wr_sta_done = 3;
    uint32_t spi_trans_done = 4;
    uint32_t spi_slv_rd_buf_inten = 5;
    uint32_t spi_slv_wr_buf_inten = 6;
    uint32_t spi_slv_rd_sta_inten = 7;
    uint32_t spi_slv_wr_sta_inten = 8;
    uint32_t spi_trans_inten = 9;
        uint32_t spi_cs_i_mode_start = 10;
    uint32_t spi_cs_i_mode_end = 11;
        uint32_t spi_slv_last_command_start = 17;
    uint32_t spi_slv_last_command_end = 19;
        uint32_t spi_slv_last_state_start = 20;
    uint32_t spi_slv_last_state_end = 22;
    uint32_t spi_trans_cnt_start = 23;
    uint32_t spi_trans_cnt_end = 26; 
    uint32_t spi_slv_cmd_defome = 27;
    uint32_t spi_slv_wr_rd_sta_en = 28;
    uint32_t spi_slv_wr_rd_buf_en = 29;
    uint32_t spi_slave_mode = 30;
    uint32_t spi_sync_reset = 31;
};

struct spi_ext2_reg{
    uint32_t address = BT_ESP32_SPI_EXT2_REG;
    uint32_t spi_st_start = 0;
    uint32_t spi_st_end = 2;
};

struct spi_dma_conf_reg{
    uint32_t address = BT_ESP32_SPI_DMA_CONF_REG;
    uint32_t spi_in_rst = 2;
    uint32_t spi_out_rst = 3;
    uint32_t spi_ahbm_fifo_rst = 4;
    uint32_t spi_ahbm_rst = 5;
    uint32_t spi_out_eof_mode = 9;
    uint32_t spi_outdscr_burst_en = 10;
    uint32_t spi_indscr_burst_en = 11;
    uint32_t spi_out_data_burst_en = 12;
    uint32_t spi_dma_rx_stop = 14;
    uint32_t spi_dma_tx_stop = 15;
    uint32_t spi_dma_continue = 16;
};

struct spi_dma_out_link_reg{
    uint32_t address = BT_ESP32_SPI_DMA_OUT_LINK_REG;
    uint32_t spi_outlink_addr_start = 0;
    uint32_t spi_outlink_addr_end = 19;
    uint32_t spi_outlink_stop = 28;
    uint32_t spi_outlink_start = 29;
    uint32_t spi_outlink_restart = 30;

};

struct spi_dma_in_link_reg{
    uint32_t address = BT_ESP32_SPI_DMA_IN_LINK_REG;
    uint32_t spi_inlink_addr_start = 0;
        uint32_t spi_inlink_addr_end = 19;
    uint32_t spi_inlink_auto_ret = 20;
        uint32_t spi_inlink_stop = 28;
        uint32_t spi_inlink_start = 29;
        uint32_t spi_inlink_restart = 30;
};

struct spi_dma_status_reg{
    uint32_t address = BT_ESP32_SPI_DMA_STATUS_REG;
    uint32_t spi_dma_rx_en = 0;
    uint32_t spi_dma_tx_en = 1;
};

class Esp32Spi;

class Esp32Spi : public BtEsp32Register{
private:
    int mosi = -1;
    int miso = -1;
    int clk = -1;
    int cs = -1;
    uint32_t SPIx = BT_ESP32_PERF_SPI3;
    bool GPSPI = false;
    bool QSQPI = false;
    bool threeLineMaster = false;

    int bitcount = 0;

    struct spi_user_reg spiUserReg;
    struct spi_slave1_reg spiSlave1Reg;
    struct spi_addr_reg spiAddrReg;
    struct spi_mosi_dlen_reg spiMosiDlenReg;
    struct spi_miso_dlen_reg spiMisoDlenReg;
    struct spi_slv_wrbuf_dlen_reg spiSlvWebufDlenReg;
    struct spi_slv_rdbuf_dlen_reg spiSlvRdbufDlenReg;
    struct spi_clock_reg spiClockReg;
    struct spi_pin_reg spiPinReg;
    struct spi_ctrl2_reg spiCtrl2Reg;
    struct spi_cmd_reg spiCmdReg;
    struct spi_user2_reg spiUser2Reg;
    struct spi_ctrl_reg spiCtrlReg;
    struct spi_slave_reg spiSlaveReg;
    struct spi_ext2_reg spiExt2Reg;
    struct spi_dma_conf_reg spiDmaConfReg;
    struct spi_dma_out_link_reg spiDmaOutLinkReg;
    struct spi_dma_in_link_reg spiDmaInLinkReg;
    struct spi_dma_status_reg spiDmaStatusReg;

    void setClock(uint32_t ildeEdge, uint32_t outEdge, uint32_t misoDelayMode, uint32_t misoDelayNum, uint32_t mosiDelayMode, uint32_t mosiDelayNum){
        uint32_t SPI_PIN_REG = BtEsp32Register::getRegisterX(this->spiPinReg.address);
                SPI_PIN_REG = BtEsp32Register::setBit(SPI_PIN_REG, this->spiPinReg.spi_ck_idle_edge, 0, ildeEdge);
                BtEsp32Register::setRegisterX(this->spiPinReg.address, SPI_PIN_REG);

                uint32_t SPI_USER_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_clk_out_edge, 0, outEdge);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USER_REG);

                uint32_t SPI_CTRL2_REG = BtEsp32Register::getRegisterX(this->spiCtrl2Reg.address);
                SPI_CTRL2_REG = BtEsp32Register::setBit(SPI_CTRL2_REG, this->spiCtrl2Reg.spi_miso_delay_mode_start, this->spiCtrl2Reg.spi_miso_delay_mode_end, misoDelayMode);
                SPI_CTRL2_REG = BtEsp32Register::setBit(SPI_CTRL2_REG, this->spiCtrl2Reg.spi_miso_delay_num_start, this->spiCtrl2Reg.spi_miso_delay_num_end, misoDelayNum);
                SPI_CTRL2_REG = BtEsp32Register::setBit(SPI_CTRL2_REG, this->spiCtrl2Reg.spi_mosi_delay_mode_start, this->spiCtrl2Reg.spi_mosi_delay_mode_end, mosiDelayMode);
                SPI_CTRL2_REG = BtEsp32Register::setBit(SPI_CTRL2_REG, this->spiCtrl2Reg.spi_mosi_delay_num_start, this->spiCtrl2Reg.spi_mosi_delay_num_end, mosiDelayNum);
                BtEsp32Register::setRegisterX(this->spiCtrl2Reg.address, SPI_CTRL2_REG);

    }

    /*
     * CPOL=0, CPHA=0
     * */
    void clockMode0(bool isMaster){
        if(isMaster)
            this->setClock(0, 0, 2, 0, 0, 0);
    }

    /*
     * CPOL=0 CPHA=1
     * */
    void clockMode1(bool isMaster){
        if(isMaster){
            this->setClock(0, 1, 1, 0, 0, 0);
        }
        }

    /*
     * CPOL=1 CPHA=0
     * */
    void clockMode2(bool isMaster){
        if(isMaster){
            this->setClock(1, 1, 1, 0, 0, 0);
        }
        }

    /*
     * CPOL=1 CPHA=1
     * */
    void clockMode3(bool isMaster){
        if(isMaster){
            this->setClock(1, 0, 2, 0, 0, 0);
        }
        }
public:

    void debug(void){
        uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
        printf("SPI_USR_REG : 0x%x\n", SPI_USR_REG);
    }


    Esp32Spi() : BtEsp32Register(BT_ESP32_PERF_SPI3){
        
    }

    void setSpiPins(int miso, int mosi, int clk, int cs){
        this->miso = miso;
        this->mosi = mosi;
        this->clk = clk;
        this->cs = cs;
    }

    void setSpiX(uint32_t spix){
        this->SPIx = spix;
    }

    void setTransaction(int val){
        uint32_t reg = BtEsp32Register::getRegisterX(this->spiCmdReg.address);
        reg = BtEsp32Register::setBit(reg, this->spiCmdReg.spi_usr, 0, val);
        BtEsp32Register::setRegisterX(this->spiCmdReg.address, reg);
    }

    void pushToDataBuffer(int page, uint32_t value){
        if(page < 0 || page> 15)
            page = 0;
        uint32_t reg = BtEsp32Register::getRegisterX(BT_ESP32_SPI_WX_REG(page));
        reg = BtEsp32Register::setBit(reg, 0, 31, value);
        BtEsp32Register::setRegisterX(BT_ESP32_SPI_WX_REG(page), reg);
    }

    uint32_t pullFromDataBuffer(int page){
        if(page < 0 || page> 15)
                        page = 0;
                uint32_t reg = BtEsp32Register::getRegisterX(BT_ESP32_SPI_WX_REG(page));
        return reg;
    }


    /**/
    void send16(uint16_t value){
        this->pushToDataBuffer(0, value);
        this->setCommand(7, value);
        this->setTransaction(1);
    }

    uint32_t getSpiState(){
        uint32_t reg = BtEsp32Register::getRegisterX(this->spiExt2Reg.address);
        reg = BtEsp32Register::setBit(reg, 3, 31, 0);
        return reg;
    }

    void setDummyIdlePhase(int val){
                uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_dummy_idle, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
        }

    void setDummyPhase(int val){
        uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_dummy, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
    }

    void setAddressPhase(int val){
                uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_addr, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
        }

    void setMisoPhase(int val){
                uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_miso, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
        }

    void setMosiPhase(int val){
        uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_mosi, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
    }

    void setCommandPhase(int val){
        uint32_t SPI_USR_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
                SPI_USR_REG = BtEsp32Register::setBit(SPI_USR_REG, this->spiUserReg.spi_usr_command, 0, val);
                BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USR_REG);
    }

    void setCommand(int len, int command){
        uint32_t reg = BtEsp32Register::getRegisterX(this->spiUser2Reg.address);
        reg = BtEsp32Register::setBit(
            reg, 
            this->spiUser2Reg.spi_usr_command_bitlen_start, 
            this->spiUser2Reg.spi_usr_command_bitlen_end, 
            len
        );
        reg = BtEsp32Register::setBit(
                        reg,
                        this->spiUser2Reg.spi_usr_command_value_start,
                        this->spiUser2Reg.spi_usr_command_value_end,
                        command
                );
        BtEsp32Register::setRegisterX(this->spiUser2Reg.address, command);
    }

    void setMosiLen(int len){
        uint32_t reg = BtEsp32Register::getRegisterX(this->spiMosiDlenReg.address);
        reg = BtEsp32Register::setBit(
            reg, 
            this->spiMosiDlenReg.spi_usr_mosi_dbitlen_start, 
            this->spiMosiDlenReg.spi_usr_mosi_dbitlen_end, 
            len
        );
        BtEsp32Register::setRegisterX(this->spiMosiDlenReg.address, reg);
    }

    void setChipSignal(int chipId, int val){
        uint32_t reg = BtEsp32Register::getRegisterX(this->spiPinReg.address);
        switch(chipId){
            case 0:
                reg = BtEsp32Register::setBit(reg, this->spiPinReg.spi_cs0_dis, 0, val);
                break;
            case 1:
                reg = BtEsp32Register::setBit(reg, this->spiPinReg.spi_cs1_dis, 0, val);
                break;
            case 2:
                reg = BtEsp32Register::setBit(reg, this->spiPinReg.spi_cs2_dis, 0, val);
                break;
        }
        BtEsp32Register::setRegisterX(this->spiPinReg.address, reg);
    }

    /*
     * - This function must enable "GP-SPI" mode.
     * - This function must enable the "programmable clock".
     * */
    void initSpiThreeLineMaster(uint32_t spix, int bitCount, bool useMsb, int mode, bool useLittleEndian){
        this->SPIx = spix;
        BtEsp32Register::updateBaseAddr(spix);
        this->threeLineMaster = true;
        this->bitcount = bitCount;
        
        printf("Configuring 3-line master mode\n");

        // Configure CTRL Reg
        uint32_t SPI_CTRL_REG = BtEsp32Register::getRegisterX(this->spiCtrlReg.address);
        SPI_CTRL_REG = BtEsp32Register::setBit(SPI_CTRL_REG, this->spiCtrlReg.spi_wr_bit_order, 0, (useMsb == true ? 0 : 1));
        BtEsp32Register::setRegisterX(this->spiCtrlReg.address, SPI_CTRL_REG);
        
        // Configure SPI clock reg
        uint32_t SPI_CLOCK_REG = BtEsp32Register::getRegisterX(this->spiClockReg.address);
        SPI_CLOCK_REG = BtEsp32Register::setBit(SPI_CLOCK_REG, this->spiClockReg.spi_clk_equ_sysclk, 0, 0);
        SPI_CLOCK_REG = BtEsp32Register::setBit(SPI_CLOCK_REG, 
            this->spiClockReg.spi_clkdiv_pre_start, 
            this->spiClockReg.spi_clkdiv_pre_end, 
            1
        ); // Can only be set if spi_clk_equ_sysclk is 0.
        SPI_CLOCK_REG = BtEsp32Register::setBit(SPI_CLOCK_REG,
                        this->spiClockReg.spi_clkcnt_n_start,
                        this->spiClockReg.spi_clkcnt_n_end,
                        0
                ); // Can only be set if spi_clk_equ_sysclk is 0.
        SPI_CLOCK_REG = BtEsp32Register::setBit(SPI_CLOCK_REG,
                        this->spiClockReg.spi_clkcnt_h_start,
                        this->spiClockReg.spi_clkcnt_h_end,
                        0
                ); // Can only be set if spi_clk_equ_sysclk is 0.
        SPI_CLOCK_REG = BtEsp32Register::setBit(SPI_CLOCK_REG,
                        this->spiClockReg.spi_clkcnt_l_start,
                        this->spiClockReg.spi_clkcnt_l_end,
                        0
                ); // Can only be set if spi_clk_equ_sysclk is 0.
        BtEsp32Register::setRegisterX(this->spiClockReg.address, SPI_CLOCK_REG);
        

        // Configure SPI USER REG
        uint32_t SPI_USER_REG = BtEsp32Register::getRegisterX(this->spiUserReg.address);
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_command, 0, 1);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_addr, 0, 1);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_dummy, 0, 1);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_miso, 0, 0);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_mosi, 0, 1);
                SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_dummy_idle, 0, 0);
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_sio, 0, 1);
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_mosi_highpart, 0, 0);
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_usr_miso_highpart, 0, 0);
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_wr_byte_order, 0, (useLittleEndian == true ? 0 : 1));
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_rd_byte_order, 0, (useLittleEndian == true ? 0 : 1));
        SPI_USER_REG = BtEsp32Register::setBit(SPI_USER_REG, this->spiUserReg.spi_doutdin, 0, 0);
        BtEsp32Register::setRegisterX(this->spiUserReg.address, SPI_USER_REG);

        this->setCommand(7, 0x06); // <-- Causes a panic
        this->setMosiLen(bitCount);
            
        // Configure spi slave reg
        uint32_t SPI_SLAVE_REG = BtEsp32Register::getRegisterX(this->spiSlaveReg.address);
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_slave_mode, 0, 0); // master mode
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_trans_inten, 0, 0);
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_slv_wr_sta_inten, 0, 0);
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_slv_rd_sta_inten, 0, 0);
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_slv_wr_buf_inten, 0, 0);
        SPI_SLAVE_REG = BtEsp32Register::setBit(SPI_SLAVE_REG, this->spiSlaveReg.spi_slv_rd_buf_inten, 0, 0);
        BtEsp32Register::setRegisterX(this->spiSlaveReg.address, SPI_SLAVE_REG);
        
        /*
         * Set the clock mode. 
         * */
        switch(mode){
            case 0: 
                this->clockMode0(true);
                break;
            case 1:
                this->clockMode1(true);
                break;
            case 2:
                this->clockMode2(true);
                break;
            case 3:
                this->clockMode3(true);
                break;
        }
        this->setDummyPhase(0);
        
    }
};

LCD Code液晶代码

#include "./defines.h"

class Esp32Gc9a01{
private:
    uint32_t dc;    
    uint32_t cs;    
    uint32_t sck;   
    uint32_t miso;  
    uint32_t mosi;  
    uint32_t res;   
    uint32_t blk;   

    uint32_t spix;
    
    Esp32Spi spi;
    Esp32Gpio gpio;
    Esp32Dport dport;
public:

    void debug(){
        this->spi.debug();
    }
    int startScreen(){
        printf("Starting screen\n");
        this->gpio.simpleOutput(this->blk, 1);
        this->gpio.simpleOutput(this->cs, 1);
        this->gpio.simpleOutput(this->res, 1);
        btSleep(10000);
        this->gpio.simpleOutput(this->res, 0);
            btSleep(100);
        this->gpio.simpleOutput(this->res, 1);
        btSleep(100);


        this->writeCommand(GC9A01_CMD_InnerRegisterEnable1);
        this->writeCommand(GC9A01_CMD_InnerRegisterEnable2);


        this->writeCommand(GC9A01_CMD_DisplayFunctionControl);
            this->writeData(0x00);
            this->writeData(0b00100000);

            this->writeCommand(GC9A01_CMD_MemoryAccessControl);
            this->writeData(0x48);

        this->writeCommand(GC9A01_CMD_PixelFormatSet);
            this->writeData(GC9A01_12_PIXEL);

        this->writeCommand(GC9A01_CMD_PowerCriterionControl);
        this->writeData(0x00000000);

            this->writeCommand(GC9A01_CMD_Vreg1aVoltageControl);
            this->writeData(0x3c);

            this->writeCommand(GC9A01_CMD_Vreg1bVoltageControl);
            this->writeData(0x3c);

            this->writeCommand(GC9A01_CMD_Vreg2aVoltageControl);
            this->writeData(0x28);

            this->writeCommand(GC9A01_CMD_SetGamma1);
            this->writeData(0x45);
            this->writeData(0x09);
            this->writeData(0x08);
            this->writeData(0x08);
            this->writeData(0x26);
            this->writeData(0x2a);

        this->writeCommand(GC9A01_CMD_SetGamma2);
            this->writeData(0x43);
            this->writeData(0x70);
            this->writeData(0x72);
            this->writeData(0x36);
            this->writeData(0x37);
            this->writeData(0x6f);

            this->writeCommand(GC9A01_CMD_SetGamma3);
            this->writeData(0x45);
            this->writeData(0x09);
            this->writeData(0x08);
            this->writeData(0x08);
            this->writeData(0x26);
            this->writeData(0x2a);

            this->writeCommand(GC9A01_CMD_SetGamma4);
            this->writeData(0x43);
            this->writeData(0x70);
            this->writeData(0x72);
            this->writeData(0x36);
            this->writeData(0x37);
            this->writeData(0x6f);


            this->writeCommand(GC9A01_CMD_FrameRate);
            this->writeData(GC9A01_FRAMERATE_8DOT_INVERSION);

        /*
         * War Crimes, these enable even and odd lines to be filled.
         * */
        this->writeCommand(0x66); // x
            this->writeData(0x3C);
            this->writeData(0x00);
            this->writeData(0xCD);
            this->writeData(0x67);
            this->writeData(0x45);
            this->writeData(0x45);
            this->writeData(0x10);
            this->writeData(0x00);
            this->writeData(0x00);
            this->writeData(0x00);

            this->writeCommand(0x67); // x
            this->writeData(0x00);
            this->writeData(0x3C);
            this->writeData(0x00);
            this->writeData(0x00);
            this->writeData(0x00);
            this->writeData(0x01);
            this->writeData(0x54);
            this->writeData(0x10);
            this->writeData(0x32);
            this->writeData(0x98);

            this->writeCommand(GC9A01_CMD_TearingEffectLineOn);
            this->writeCommand(GC9A01_CMD_DisplayInversionOn);

        this->writeCommand(GC9A01_CMD_InterfaceControl);
        this->writeData(0b11001011);
        this->writeCommand(GC9A01_CMD_Spi2DataControl);
            this->writeData(0b00101100);

        this->writeCommand(GC9A01_CMD_WriteCtrlDisplay);
        this->writeData(0b00101100);

        /*
         * Enable display
         * */
        this->writeCommand(GC9A01_CMD_NormalDisplayModeOn);
            this->writeCommand(GC9A01_CMD_SleepOut);
            btSleep(120);
            this->writeCommand(GC9A01_CMD_DisplayOn);
            btSleep(20);
    

    //  while(1){btSleep(1000);}
        return 1;

    }

    void setBackgroundColor(uint16_t color, int xMax, int yMax){
        this->setWindowSize(0, xMax, 0, yMax);
        this->writeCommand(GC9A01_CMD_MemoryWrite);
        for(int i=0; i<xMax*yMax; i++){
            this->writeData(color);
            this->writeData(color>>8);
        }
    }

    void drawPixel(uint16_t color, int x, int y){
        int pixelSize = 1;
        this->setWindowSize(x, x+pixelSize, y, y+pixelSize);
        this->writeCommand(GC9A01_CMD_MemoryWrite);
        for(int j=0; j<pixelSize*pixelSize; j++){
            this->writeData(color);
            this->writeData(color>>8);
        }
        
    }

    void initPins(uint32_t spix, uint32_t _dc, uint32_t _cs, uint32_t _sck, uint32_t _miso, uint32_t _mosi, uint32_t _res, uint32_t _blk){
        this->dc = _dc;
        this->cs = _cs;
        this->sck = _sck;
        this->miso = _miso;
        this->mosi = _mosi;
        this->res = _res;
        this->blk = _blk;
        this->spi.setSpiPins(this->miso, this->mosi, this->sck, this->cs);
        this->spix = spix;


        this->gpio.configureOutputPeriph(this->mosi, BT_ESP32_VSPID_OUT);
        this->gpio.configureOutputPeriph(this->sck, BT_ESP32_VSPICLK_OUT_MUX);
        this->gpio.configureOutputPeriph(this->cs, BT_ESP32_VSPICS0_OUT);

        this->gpio.setPinSimpleOut(this->dc);
        this->gpio.setPinSimpleOut(this->res);
        this->gpio.setPinSimpleOut(this->blk);

        // Validate that the below is being set properly.
        int spiTarget = this->dport.dportPeripRstEnReg.dport_spi3_rst;
        this->dport.setPerphReset(spiTarget, 1);
        this->dport.setPerphReset(spiTarget, 0);
        this->dport.setSpiDmaChannel(3, 0);
        this->dport.setPeripheralClock(this->dport.dportPeripClkEnReg.dport_spi3_clk_en, 1);

        int mode = 3;
                int bitCount = 8;
                bool msb = true;
        bool littleEndian = true;
        // Validate the below configures as expected.
                this->spi.initSpiThreeLineMaster(spix, bitCount, msb, mode, littleEndian);

        printf("Initilized...\n");
    };

    void setWindowSize(uint16_t x, uint16_t y, uint16_t _x, uint16_t _y){
            //set the X coordinates
            this->writeCommand(GC9A01_CMD_RowAddressSet);
            this->writeData((x>>8)&0xff);
            this->writeData(x & 0xff);
            this->writeData((y>>8)&0xff);
            this->writeData(y&0xff);

            //set the Y coordinates
            this->writeCommand(GC9A01_CMD_ColumnAddressSet);
            this->writeData((_x>>8)&0xff);
            this->writeData(_x & 0xff);
            this->writeData((_y>>8)&0xff);
            this->writeData(_y&0xff);
    }

    void startDrawing(){
        this->writeCommand(GC9A01_CMD_MemoryWrite);
    }

    void continueDrawing(void){
                this->writeCommand(GC9A01_CMD_WriteMemoryContinue);
        }

    void writeCommand(uint16_t command){
        // dc pin to 0
        this->gpio.simpleOutput(this->dc, 0);
        // set cs pin to 0
        this->gpio.simpleOutput(this->cs, 0);
        this->spi.setChipSignal(0, 0);
        // spi write
        this->spi.send16(command);
        // set cs pin to 1
        this->spi.setChipSignal(0, 1);
        this->gpio.simpleOutput(this->cs, 1);
    }
    void writeData(uint16_t data){
        // set dc pin to 1
        this->gpio.simpleOutput(this->dc, 1);
        // set cs pin to 0
        this->gpio.simpleOutput(this->cs, 0);
        this->spi.setChipSignal(0, 0);
        // spi write
        this->spi.send16(data);
        // set cs pin to 1
        this->spi.setChipSignal(0, 1);
        this->gpio.simpleOutput(this->cs, 1);
    }
};

Key Notes,重点说明,

  • The StartScreen function works as expected and fails because of the SPI send functions. StartScreen function 按预期工作,但由于 SPI 发送函数而失败。
  • The simpleOutput functions properly set the gpio pins to 0 or 1 respectively, the setChipSignal function was an experiemnt. simpleOutput 函数正确地将 gpio 引脚分别设置为 0 或 1,setChipSignal function 是一个实验。
  • The issue is somewhere in the spi send and initalize functions.问题出在 spi 发送和初始化函数中的某处。

After days of no sleep, I've figured it out.经过几天不睡觉,我想通了。

Here are some things you can try if you find yourself in having the same issue.如果您发现自己遇到同样的问题,可以尝试以下一些方法。

  • Make sure your clock modes are configured properly, this includes making sure the SPI_CLOCK_REG is proper.确保您的时钟模式配置正确,这包括确保 SPI_CLOCK_REG 正确。 Set spi_clk_equ_sysclk to 1.将 spi_clk_equ_sysclk 设置为 1。
  • Make sure you enable the PLL clock via the RTC registers.确保通过 RTC 寄存器启用 PLL 时钟。
  • For 3-line half duplex, you only need to enable the spi_usr_mosi bit, the other phases can be set to 0.对于 3 线半双工,只需要使能 spi_usr_mosi 位,其他阶段都可以设置为 0。
  • Make sure that your gpio code is properly handling gpio pins greater than 31. These pins use their own register to enable.确保您的 gpio 代码正确处理大于 31 的 gpio 引脚。这些引脚使用它们自己的寄存器来启用。

If you double check these things, assuming your code is similar to the example provided by the question, you should be able to resolve the issue like I have.如果你仔细检查这些东西,假设你的代码与问题提供的示例相似,你应该能够像我一样解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM