压榨k210性能,LCD传图CPU占用时间从12ms降低到400us(st7789)

        在点亮k210后,我就开始思考怎么压榨出其中的全部性能,通过增加了几个sdk的驱动函数,我成功的从LCD图片传输的任务中为CPU解放了大量时间。如何点亮的可以看K210 Standalone SDK,用C点亮野火K210-优快云博客

        检查SDK可以发现,在spi_send_data_normal_dma这个函数中,启动dma通道后,紧接着就调用了dmac_wait_done来等待dma传输完成。但这完全是没有必要的,我们可以通过中断来完成后续寄存器的处理,让CPU能处理其它任务,而不必等待。

        为此我实现了一个不等待的spi传输。

typedef struct _local_callback_data_t
{
    volatile spi_t *spi_handle;
    sysctl_dma_channel_t channel_num;
    spi_device_num_t spi_num;
    void (*cb)(void);
} local_callback_data_t;
static local_callback_data_t local_callback_data;

static int dmac_irq_callback(void *ctx)
{
    local_callback_data_t *data = (local_callback_data_t *)ctx;
    dmac_irq_unregister(data->channel_num);
    plic_irq_unregister(IRQN_SPI0_INTERRUPT + data->spi_num);
    
    volatile spi_t *spi_handle = data->spi_handle;
    uint32_t cnt = 0;
    while((spi_handle->sr & 0x05) != 0x04)
        ;
    spi_handle->ser = 0x00;
    spi_handle->ssienr = 0x00;

    if(data->cb)
    {
        data->cb();
    }
    return 0;
}

/// @brief 发送数据,DMA启动后不等待,数据格式为SPI_TRANS_INT,
///        但由用户在外部提前打包好,本函数不进行打包
void spi_send_data_normal_dma_no_blocking(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select,
                                                           const void *tx_buff, size_t tx_len, void (*callback)(void))
{
    configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
    spi_set_tmod(spi_num, SPI_TMOD_TRANS);
    volatile spi_t *spi_handle = spi[spi_num];
    uint32_t *buf = (uint32_t *)tx_buff;

    spi_handle->dmacr = 0x2; /*enable dma transmit*/
    spi_handle->ssienr = 0x01;

    sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2);

    local_callback_data.cb = callback;
    local_callback_data.spi_handle = spi_handle;
    local_callback_data.channel_num = channel_num;
    local_callback_data.spi_num = spi_num;
    dmac_irq_register(channel_num, dmac_irq_callback, &local_callback_data, 1);
    // plic_irq_register(IRQN_SPI0_INTERRUPT + spi_num, dmac_irq_callback, &local_callback_data);
    dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
                         DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len);
    spi_handle->ser = 1U << chip_select;
}

        接口参数与spi_send_data_normal_dma基本相同,但是删去了最后的spi_transfer_width参数,改为一个回调函数,这以为这它只能以4字节为单位传输。由于函数比较简陋,因此想要知道传输是否完成,只能通过在回调函数中进行操作。

        然后在st7789.c文件中,也要添加相应的函数。

void tft_write_word_no_blocking(uint32_t *data_buf, uint32_t length, void (*callback)(void))
{
    set_dcx_data();
    if(!standard_spi)
    {
        spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);

        spi_init_non_standard(SPI_CHANNEL, 0 /*instrction length*/, 32 /*address length*/, 0 /*wait cycles*/,
                              SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
        spi_send_data_normal_dma_no_blocking(SPI_DMA_CH, SPI_CHANNEL, LCD_SPI_SLAVE_SELECT, data_buf, length, callback);
    } else
    {
        spi_init(SPI_CHANNEL, standard_work_mode, SPI_FF_STANDARD, 32, 0);
        spi_send_data_normal_dma_no_blocking(SPI_DMA_CH, SPI_CHANNEL, LCD_SPI_SLAVE_SELECT, data_buf, length, callback);
    }
}

        实际就是原本的函数,稍作修改就行了。

        最后实现lcd绘制函数即可。

static void mcu_lcd_draw_picture_no_blocking(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint8_t *ptr, void (*callback)(void))
{
    g_lcd_display_buff = (uint16_t *)ptr;
    lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
    g_pixs_draw_pic_size = width * height;

    if(g_pixs_draw_pic_size % 2)
    {
        tft_write_half((uint16_t *)ptr, g_pixs_draw_pic_size);
    }
    if(g_pixs_draw_pic_size > 0)
    {
        // tft_write_word((uint32_t *)ptr, g_pixs_draw_pic_size / 2);
        tft_write_word_no_blocking((uint32_t *)ptr, g_pixs_draw_pic_size / 2, callback);

        // tft_write_half(g_lcd_display_buff, g_pixs_draw_pic_size);
        // tft_write_half_packed_no_blocking((uint32_t *)g_lcd_display_buff, g_pixs_draw_pic_size, callback);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值