99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

程序小白
認(rèn)證:優(yōu)質(zhì)創(chuàng)作者
所在專題目錄 查看專題
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之uart中斷處理④
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之淺析注冊(cè)機(jī)制⑤
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之SPI原理①
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之SPI對(duì)象創(chuàng)建②
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之SPI總線操作方法③
RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之HWTIMER開發(fā)①
作者動(dòng)態(tài) 更多
基于stm32采用PWM驅(qū)動(dòng)伺服控制器學(xué)習(xí)筆記
05-13 15:25
基于STM32驅(qū)動(dòng)TM1638學(xué)習(xí)筆記——軟件篇
04-19 12:42
基于TM1638驅(qū)動(dòng)8位數(shù)碼管設(shè)計(jì)分享
02-24 11:26
RT-Thread驅(qū)動(dòng)之路: Studio創(chuàng)建FAL分區(qū)⑤
01-02 08:30
RT-Thread驅(qū)動(dòng)之路: Studio 掛載通用SPI flash④
2024-12-23 13:41

RT-Thread驅(qū)動(dòng)之路:stm32設(shè)備驅(qū)動(dòng)開發(fā)之SPI總線操作方法③


      有了SPI總線設(shè)備對(duì)象,還需要實(shí)現(xiàn)總線的操作方法,操作方法的函數(shù)指針定義已經(jīng)在SPI總線設(shè)備框架中給出了:

/**
 * SPI operators
 */
struct rt_spi_ops
{
    rt_err_t (*configure)(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
    rt_uint32_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message);
};

      configure:有兩個(gè)輸入?yún)?shù),其作用就是根據(jù)configuration配置參數(shù)配置SPI總線設(shè)備的傳輸數(shù)據(jù)寬度、時(shí)鐘極性、時(shí)鐘相位和總線速率等參數(shù),最后調(diào)用HAL庫初始化SPI總線。其stm32的實(shí)現(xiàn)代碼如下:

/**
 * SPI configuration structure
 */
struct rt_spi_configuration
{
    rt_uint8_t mode;
    rt_uint8_t data_width;
    rt_uint16_t reserved;

    rt_uint32_t max_hz;
};
static rt_err_t spi_configure(struct rt_spi_device *device,
                              struct rt_spi_configuration *configuration)
{
    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(configuration != RT_NULL);

    struct stm32_spi *spi_drv =  rt_container_of(device->bus, struct stm32_spi, spi_bus);
    spi_drv->cfg = configuration;

    return stm32_spi_init(spi_drv, configuration);
}
static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configuration *cfg)
{
    RT_ASSERT(spi_drv != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    SPI_HandleTypeDef *spi_handle = &spi_drv->handle;

    if (cfg->mode & RT_SPI_SLAVE)
    {
        spi_handle->Init.Mode = SPI_MODE_SLAVE;
    }
    else
    {
        spi_handle->Init.Mode = SPI_MODE_MASTER;
    }

    if (cfg->mode & RT_SPI_3WIRE)
    {
        spi_handle->Init.Direction = SPI_DIRECTION_1LINE;
    }
    else
    {
        spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
    }

    if (cfg->data_width == 8)
    {
        spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
        spi_handle->TxXferSize = 8;
        spi_handle->RxXferSize = 8;
    }
    else if (cfg->data_width == 16)
    {
        spi_handle->Init.DataSize = SPI_DATASIZE_16BIT;
    }
    else
    {
        return RT_EIO;
    }

    if (cfg->mode & RT_SPI_CPHA)
    {
        spi_handle->Init.CLKPhase = SPI_PHASE_2EDGE;
    }
    else
    {
        spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;
    }

    if (cfg->mode & RT_SPI_CPOL)
    {
        spi_handle->Init.CLKPolarity = SPI_POLARITY_HIGH;
    }
    else
    {
        spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
    }

    if (cfg->mode & RT_SPI_NO_CS)
    {
        spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;
    }
    else
    {
        spi_handle->Init.NSS = SPI_NSS_SOFT;
    }
    ...
    if (HAL_SPI_Init(spi_handle) != HAL_OK)
    {
        return RT_EIO;
    }
    ...
}

      當(dāng)你需要更換MCU的時(shí)候,你就需要重寫上述的驅(qū)動(dòng)部分代碼了。接下來看下xfer:用于傳輸數(shù)據(jù),通過xger方法對(duì)SPI總線的控制來完成一條message的傳輸,這里的傳輸肯能是雙向的 也可能是單向的,也就是所謂的單雙工,最終都是通過stm32的hal庫來實(shí)現(xiàn),直接看代碼:

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 && !(device->config.mode & RT_SPI_NO_CS))
    {
        HAL_GPIO_WritePin(cs->GPIOx, cs->GPIO_Pin, GPIO_PIN_RESET);
    }
	...
    while (message_length)
    {


        /* 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);
            }
            else
            {
                state = HAL_SPI_Transmit(spi_handle, (uint8_t *)send_buf, send_length, 1000);
            }

            if (message->cs_release && (device->config.mode & RT_SPI_3WIRE))
            {
                /* release the CS by disable SPI when using 3 wires SPI */
                __HAL_SPI_DISABLE(spi_handle);
            }
        }
        else
        {
            memset((uint8_t *)recv_buf, 0xff, send_length);
            if (spi_drv->spi_dma_flag & SPI_USING_RX_DMA_FLAG)
            {
                state = HAL_SPI_Receive_DMA(spi_handle, (uint8_t *)recv_buf, send_length);
            }
            else
            {
                /* clear the old error flag */
                __HAL_SPI_CLEAR_OVRFLAG(spi_handle);
                state = HAL_SPI_Receive(spi_handle, (uint8_t *)recv_buf, send_length, 1000);
            }
        }

        if (state != HAL_OK)
        {
            LOG_I("spi transfer error : %d", state);
            message->length = 0;
            spi_handle->State = HAL_SPI_STATE_READY;
        }
        else
        {
            LOG_D("%s transfer done", spi_drv->config->bus_name);
        }
        while (HAL_SPI_GetState(spi_handle) != HAL_SPI_STATE_READY);
    }

    if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS))
    {
        HAL_GPIO_WritePin(cs->GPIOx, cs->GPIO_Pin, GPIO_PIN_SET);
    }

    return message->length;
}

      這里刪減了一些不影響函數(shù)主要功能的代碼,主要體現(xiàn)函數(shù)的功能,根據(jù)message中recv_buf和send_buf判斷是全雙工還是半雙工發(fā)送接收數(shù)據(jù),調(diào)用hal庫函數(shù)完成數(shù)據(jù)的傳輸,最后釋放cs引腳。 最后就是完成SPI總線設(shè)備注冊(cè)到操作系統(tǒng)中,需要定義rt_spi_ops來完成初始化時(shí)注冊(cè)借口中的ops參數(shù):

static const struct rt_spi_ops stm_spi_ops =
{
    .configure = spi_configure,
    .xfer = spixfer,
};

static int rt_hw_spi_bus_init(void)
{
    rt_err_t result;
    for (int i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++)
    {
        spi_bus_obj[i].config = &spi_config[i];
        spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i];
        spi_bus_obj[i].handle.Instance = spi_config[i].Instance;
        result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &stm_spi_ops);
        RT_ASSERT(result == RT_EOK);

        LOG_D("%s bus init done", spi_config[i].bus_name);
    }

    return result;
}

          到這里就是關(guān)于SPI驅(qū)動(dòng)部分的核心代碼講解完畢了,當(dāng)然還有attach、DMA、SPI_IRQHandler部分源碼沒有詳細(xì)的羅列,這一部分就交給對(duì)驅(qū)動(dòng)感興趣的小伙伴去源碼里探索吧。

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 5
收藏 6
關(guān)注 151
成為作者 賺取收益
全部留言
0/200
  • chaochao1545 01-02 08:41
    對(duì)我很有幫助
    回復(fù)
主站蜘蛛池模板: 免费av网站在线观看 | 国产亚洲精品麻豆一区二区 | 波多野结衣高潮喷水在线观看 | 免费人成视频网站在线18 | 国产日韩精品SUV | 好大好硬好爽18禁视频免费 | 日本一二不卡 | 亚洲日本高清成人aⅴ片 | 久久国产午夜精品理论片推荐 | 亚洲精品熟女国产 | 狠狠久久永久免费观看 | 国产欧美日韩综合 | 国内精品国产成人国产三级李采潭 | 国产真实乱偷精品视频免 | 亚洲成AV人影院在线观看网 | AV无码无在线观看免费 | 国产精品国三级国产av | 曰本人做爰大片免费观看 | 色欲狠狠躁天天躁无码中文字幕 | 免费A级毛片AV无码 爱情岛论坛自拍亚洲品质极速福利 | 天堂国产一区 | 4399理论片午午伦夜理片 | 精品少妇XXXX | 视频精品中文字幕一区二区 | 亚洲精品无码久久久久AV老牛 | 国产av无码专区亚洲avjulia | 欧美九九九 | 日韩一区国产在线观看 | 日韩视频一二三 | 任你操在线精品 | 亚洲V国产V天堂A无码二区 | 琪琪午夜成人理论福利片美容院 | 久久天堂一区二区三区 | a在线免费看 | 国产美女91视频 | 中文字幕免费精品一区高清 | 成人极品视频 | 激情校园另类小说图片 | 亚洲精品综合网 | 国内毛片毛片毛片毛片毛片 | 在线天堂资源www中文 |