《RT-Thread驅動框架分析》-Pin驅動

簡要

  • 接下來作一個專輯《RT-Thread驅動框架分析》,我會按照本身的理解來描述每個驅動。有不對的歡迎隨時來懟我。web

  • RT-Thread的版本分爲兩大類,一個是完整版本,一個是nano版本。而驅動框架是相對於完整版本的。因此要了解驅動框架,只能在完整版上了解。微信

  • RT-Thread提供了不少驅動框架,好比常見的外設驅動:I2C, SPI等。還有網絡相關的WLAN驅動等。網絡

  • 驅動框架分析,主要以STM32來分析。框架

驅動分析

API簡要說明

  • RT-Thread的pin驅動爲上層應用提供兩套不一樣的API,一套是對接設備驅動框架。一套是封裝好的API,用戶層能夠直接使用。接下來咱們來分析一下這兩套API的使用,以及實現。

pin框架層次

  1. 用戶訪問的方式的接口不一樣,訪問的層次是不同的。編輯器

  2. 層次結構以下:函數

  1. 從上面的圖能夠看出,對於不一樣芯片,用戶層的接口是統一的,而對於驅動層來講,只須要對接好相應的回調函數。學習

  2. 經過統一的接口,應用開發人不須要知道底層驅動,也減小造輪子的時間。flex

GPIO驅動層

  1. 驅動層的任務主要有:①對接底層硬件,②對芯片的GPIO統一編號,③註冊下面描述的6個回調函數。ui

  2. 驅動層中,咱們特別關注一個結構體rt_pin_ops,以下:url

/* pin.h */
struct rt_pin_ops
{

    void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
    void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
    int (*pin_read)(struct rt_device *device, rt_base_t pin);

    /* TODO: add GPIO interrupt */
    rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                      rt_uint32_t mode, void (*hdr)(void *args), void *args);
    rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
    rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
};
  1. 咱們只須要對接好這幾個6個回調函數就行了,描述以下:
API 描述
pin_mode 設置引腳模式
pin_write 設置引腳電平
pin_read 讀取引腳電平
pin_attach_irq 綁定引腳中斷回調函數
pin_irq_enable 使能引腳中斷
pin_detach_irq 脫離引腳中斷回調函數
  1. stm32爲例,對接相應的OPS結構體,以下:
const static struct rt_pin_ops _stm32_pin_ops =
{

    stm32_pin_mode,
    stm32_pin_write,
    stm32_pin_read,
    stm32_pin_attach_irq,
    stm32_pin_dettach_irq,
    stm32_pin_irq_enable,
};
  1. 註冊pin相應的回調函數,以下:
int rt_hw_pin_init(void)
{
    ......

    return rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);
}

PIN設備驅動層

  1. 這一層主要起到承上啓下的,爲上層應用提供統一的API,爲下層驅動,提供註冊函數。

  2. 其中註冊函數以下:

int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _hw_pin.parent.type         = RT_Device_Class_Miscellaneous;
    _hw_pin.parent.rx_indicate  = RT_NULL;
    _hw_pin.parent.tx_complete  = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    _hw_pin.parent.ops          = &pin_ops;
#else
    _hw_pin.parent.init         = RT_NULL;
    _hw_pin.parent.open         = RT_NULL;
    _hw_pin.parent.close        = RT_NULL;
    _hw_pin.parent.read         = _pin_read;
    _hw_pin.parent.write        = _pin_write;
    _hw_pin.parent.control      = _pin_control;
#endif

    _hw_pin.ops                 = ops;
    _hw_pin.parent.user_data    = user_data;

    /* register a character device */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);

    return 0;
}
  1. 前面咱們談到RT-Thread的pin設備提供了兩套API,可是最終調用的接口都是執行註冊的回調函數。

  2. 簡單的理解就是兩套API,只是不一樣的訪問方式。

RTT 爲上層應用封裝好的API描述

  1. 從官方的文檔中心中,有詳細的描述這套API的使用方法。這套API是直接暴露給用戶層調用的。

  2. RT-Thread提供的pin設備管理接口來訪問GPIO,接口以下:

API 描述
rt_pin_mode() 設置引腳模式
rt_pin_write() 設置引腳電平
rt_pin_read() 讀取引腳電平
rt_pin_attach_irq() 綁定引腳中斷回調函數
rt_pin_irq_enable() 使能引腳中斷
rt_pin_detach_irq() 脫離引腳中斷回調函數
  1. 該接口訪問的層次以下:
  1. 應用,經過點亮一顆燈來描述:
#define LED0_PIN    GET_PIN(I, 13)

int main(void)
{
    int count = 1;
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    while (count++)
    {
        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
    return RT_EOK;
}

經過設備驅動框架訪問pin設備描述

  1. RTT設備驅動框架提供了統一的API:
API 說明
rt_err_t  rt_device_init (rt_device_t dev) 設備初始化
rt_err_t  rt_device_open (rt_device_t dev, rt_uint16_t oflag) 打開設備
rt_err_t  rt_device_close(rt_device_t dev) 關閉設備
rt_size_t rt_device_read (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) 讀設備
rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) 寫設備
rt_err_t  rt_device_control(rt_device_t dev, int cmd, void *arg) 控制設備
  1. 若是你學習過Linux,你是否聽過一句話,一切設備皆文件。在Linux中對設備的訪問有以下接口open,read,write,close等,其實RTT提供的設備驅動API也是如此。

  2. 該接口訪問的層次以下:

  1. 如上圖所示,_pin_control()應該包含:GPIO的模式設置,中斷關聯,中斷使能,中斷分離。可是從實際的上_pin_control()中,只實現了GPIO的模式設置,若是要使用這組API須要本身增長相關實現:
static rt_err_t  _pin_control(rt_device_t dev, int cmd, void *args)
{
    struct rt_device_pin_mode *mode;
    struct rt_device_pin *pin = (struct rt_device_pin *)dev;

    /* check parameters */
    RT_ASSERT(pin != RT_NULL);

    mode = (struct rt_device_pin_mode *) args;
    if (mode == RT_NULL) return -RT_ERROR;

    pin->ops->pin_mode(dev, (rt_base_t)mode->pin, (rt_base_t)mode->mode);

    return 0;
}

  1. 應用,經過點亮一顆燈來描述:
#define LED_PIN     GET_PIN(I, 13)

int main(void)
{
    int count = 1;
    struct rt_device_pin *pin_dev = RT_NULL;

    pin_dev = (struct rt_device_pin *)rt_device_find("pin");
    rt_device_open((rt_device_t)pin_dev, RT_DEVICE_OFLAG_RDWR);
    pin_dev->ops->pin_mode(&pin_dev->parent, LED_PIN, PIN_MODE_OUTPUT);

    while (count++)
    {
        pin_dev->ops->pin_write(&pin_dev->parent, LED_PIN, PIN_HIGH);
        rt_thread_mdelay(1000);
        pin_dev->ops->pin_write(&pin_dev->parent, LED_PIN, PIN_LOW);
        rt_thread_mdelay(1000);
    }

    return RT_EOK;
}

總結

  • 其實不少人都在討論說,沒有Linux基礎,學RTT很痛苦。可是直接學Linux,若是你不去了解內核驅動代碼,會少不少樂趣。可是Linux的驅動框架更加複雜,分析更加痛苦。因此做者認爲,若是你學了RTT,再去學習Linux,分析驅動框架會更加簡單方便。

  • 做爲RTT的愛好者,我將對RTT驅動框架分析做爲一個系列。


關注微信公衆號『Rice嵌入式開發技術分享』,後臺回覆「微信」添加做者微信,備註」入羣「,即可邀請進入技術交流羣。


你能夠添加微信17775982065爲好友,註明:公司+姓名,拉進 RT-Thread 官方微信交流羣!



RT-Thread


讓物聯網終端的開發變得簡單、快速,芯片的價值獲得最大化發揮。Apache2.0協議,可免費在商業產品中使用,不須要公佈源碼,無潛在商業風險。





長按二維碼,關注咱們


 點擊閱讀原文進入RT-Thread官網
你點的每一個「在看」,我都認真當成了喜歡

本文分享自微信公衆號 - RTThread物聯網操做系統(RTThread)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索