【原理学习】rt-thread SPI 双向DMA驱动的开发

问题描述

之前开发程序的时候是直接使用的 硬件 SPI 采用 DMA 方式来释放CPU,但是一直没有使用 rt_thread 原来的 DMA 历程,原因是原生的 drv_spi 驱动,实际上没有发挥DMA的真实性能,虽然开启DMA但是还是要等数据发送完成之后才释放CPU:

当发送数据较长,且比较密集的时候如果采用死等的方发送数据就会导致数据发送性能极差,如何将这个死等的时间释放出来且发送和接收数据需要灵活可控
先看电路图:
在这里插入图片描述
说明:此时SPI是通讯的交互的重点,十分密集
IRQ_NRF1: 值做个32的一中断通知管脚,从机有数据上报的时候需要通过此引脚,通知32来读取数据
CE_NRF1: 表示从机设备是否繁忙,若果繁忙在主发送数据无效(暂时还未使用)
其他就是正常的SPI管脚

第一步释放驱动的死等时间

static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
   
    HAL_StatusTypeDef state;
    rt_size_t message_length, already_send_length;
    rt_uint16_t send_length;
    rt_uint8_t *recv_buf;
    const rt_uint8_t *send_buf;

    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(device->bus != RT_NULL);
    RT_ASSERT(device->bus->parent.user_data != RT_NULL);
    RT_ASSERT(message != RT_NULL);

    struct stm32_spi *spi_drv =  rt_container_of(device->bus, struct stm32_spi, spi_bus);
    SPI_HandleTypeDef *spi_handle = &spi_drv->handle;
    struct stm32_hw_spi_cs *cs = device->parent.user_data;

    if (message->cs_take)
    {
   
        LOG_D("%s transfer nss set 0 ", spi_drv->config->bus_name);
        HAL_GPIO_WritePin(cs->GPIOx, cs->GPIO_Pin, GPIO_PIN_RESET);
    }

    LOG_D("%s transfer prepare and start", spi_drv->config->bus_name);
    LOG_D("%s sendbuf: %X, recvbuf: %X, length: %d",
          spi_drv->config->bus_name,
          (uint32_t)message->send_buf,
          (uint32_t)message->recv_buf, message->length);

    message_length = message->length;
    recv_buf = message->recv_buf;
    send_buf = message->send_buf;
    while (message_length)
    {
   
        /* the HAL library use uint16 to save the data length */
        if (message_length > 65535)
        {
   
            send_length = 65535;
            message_length = message_length - 65535;
        }
        else
        {
   
            send_length = message_length;
            message_length = 0;
        }

        /* calculate the start address */
        already_send_length = message->length - send_length - message_length;
        send_buf = (rt_uint8_t *)message->send_buf + already_send_length;
        recv_buf = (rt_uint8_t *)message->recv_buf + already_send_length;

        /* start once data exchange in DMA mode */
        if (message->send_buf && message->recv_buf)
        {
   
            if ((spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG) && (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG))
            {
   
                state = HAL_SPI_TransmitReceive_DMA(spi_handle, (uint8_t *)send_buf, (uint8_t *)recv_buf, send_length);
            }
            else
            {
   
                state = HAL_SPI_TransmitReceive(spi_handle, (uint8_t *)send_buf, (uint8_t *)recv_buf, send_length, 1000);
            }
        }
        else if (message->send_buf)
        {
   
            if (spi_drv->spi_dma_flag & SPI_USING_TX_DMA_FLAG)
            {
   
                state = HAL_SPI_Transmit_DMA(spi_handle, (uint8_t *)send_buf, send_length);
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值