0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

rt-thread 驅(qū)動(dòng)篇(一) serialX 框架理論

出出 ? 來源:出出 ? 作者:出出 ? 2022-06-21 10:37 ? 次閱讀

前言

苦串口驅(qū)動(dòng)久矣!

現(xiàn)狀

串口驅(qū)動(dòng)三種工作模式:輪詢、中斷、DMA

輪詢模式占用 CPU 最高,但是實(shí)現(xiàn)也是最簡單的;DMA 占用 CPU 最少,實(shí)現(xiàn)也是最麻煩的;中斷模式居中。

原串口驅(qū)動(dòng)有以下幾個(gè)問題:
1. 中斷模式,接收有緩存,發(fā)送沒緩存
2. 中斷模式,讀操作是非阻塞的,沒有阻塞讀;寫操作因?yàn)闆]有緩存,只能阻塞寫,沒有非阻塞寫。
3. 中斷接收過程,每往發(fā)送寄存器填充一個(gè)字符,就使用完成量等待發(fā)送完成中斷,通過完成量進(jìn)行進(jìn)程調(diào)度次數(shù)和發(fā)送數(shù)據(jù)量同樣多!
4. DMA 模式比較復(fù)雜,在實(shí)現(xiàn)上更復(fù)雜。
1. 首先,接收有兩種緩存方案,一種沒有緩存,借用應(yīng)用層的內(nèi)存直接做 DMA 接收緩存;一種有緩存,用的和中斷模式下相同的 fifo 數(shù)據(jù)結(jié)構(gòu)。發(fā)送只有一種緩存方式,把應(yīng)用層內(nèi)存放到數(shù)據(jù)隊(duì)列里做發(fā)送緩存。
2. 無論哪種緩存方案,都沒有考慮阻塞的問題。而是拋給串口驅(qū)動(dòng)一個(gè)內(nèi)存地址,就返回到應(yīng)用層了。應(yīng)用層要么動(dòng)用 `rt_device_set_rx_indicate` `rt_device_set_tx_complete` 做同步——退化成 poll 模式,失去了 DMA 的優(yōu)勢;要么繼續(xù)干其它工作——拋給串口驅(qū)動(dòng)的內(nèi)存可能引入隱患。
3. 為了防止 DMA 工作的時(shí)候又有新的讀寫需求,

對串口驅(qū)動(dòng)的期望

輪詢模式不在今天討論計(jì)劃內(nèi)。下面所有的討論都只涉及中斷和 DMA 兩種模式。

  • 無論哪種工作模式,都應(yīng)該有至少一級緩存機(jī)制。
  • 無論哪種工作模式,都應(yīng)該可以設(shè)置成阻塞或者非阻塞。
  • 默認(rèn)是阻塞 io 模式;如果想用非阻塞工作模式,可以通過 open 或者 control 修改。
  • 讀寫阻塞特性是同步的,不存在阻塞寫非阻塞讀或者非阻塞寫阻塞讀兩種模式。
  • 阻塞讀的過程是,沒有數(shù)據(jù)永久阻塞;有數(shù)據(jù)無論多少(小于等于期望數(shù)據(jù)量),返回讀取的數(shù)據(jù)量。
  • 阻塞寫的過程是,緩存空間為 0 阻塞等待緩存被釋放;緩存空間不足先填滿緩存,繼續(xù)等待緩存被釋放;緩存空間足夠,把應(yīng)用層數(shù)據(jù)拷貝到驅(qū)動(dòng)緩存。最后返回搬到緩存的數(shù)據(jù)量。
  • 非阻塞讀的過程是,沒有數(shù)據(jù)返回 0;有數(shù)據(jù),從 fifo 拷貝數(shù)據(jù)到應(yīng)用層提供的內(nèi)存,返回拷貝的數(shù)據(jù)量。
  • 非阻塞寫的過程是,緩存為 0 ,返回 0;緩存不足返回寫成功了多少數(shù)據(jù);緩存足夠,把數(shù)據(jù)搬移完,返回寫成功的數(shù)據(jù)量。
  • 無論是輪詢、中斷、DMA 哪種模式,都應(yīng)該可以實(shí)現(xiàn) STREAM 特性。

中斷模式下的理論實(shí)踐

注:以下實(shí)現(xiàn)是在 NUC970 上完成的,有些特性可能不是通用的。例如,串口外設(shè)自帶硬件 fifo ,uart1 是高速 uart 設(shè)備,fifo 有 64 字節(jié)。uart3 的 fifo 就只有 16 字節(jié)。

定義緩存數(shù)據(jù)結(jié)構(gòu)

為實(shí)現(xiàn)上述需求,接收和發(fā)送都需要有如下一個(gè) fifo

struct rt_serial_fifo
{
   rt_uint32_t buf_sz;
   /* software fifo buffer */
   rt_uint8_t *buffer;
   rt_uint16_t put_index, get_index;

   rt_bool_t is_full;
};

> 注:別問我為啥不用 ringbuffer

大部分還是借用 `struct rt_serial_rx_fifo` 的實(shí)現(xiàn)的。增加了個(gè) `buf_sz` 由 fifo 自己維護(hù)自己的緩存容量

針對 fifo 特意定義了三個(gè)函數(shù),
`rt_forceinline rt_size_t _serial_fifo_calc_data_len(struct rt_serial_fifo *fifo)` 計(jì)算 fifo 中寫入的數(shù)據(jù)量
`rt_forceinline void _serial_fifo_push_data(struct rt_serial_fifo *fifo, rt_uint8_t ch)` 壓入一個(gè)數(shù)據(jù)(不完整實(shí)現(xiàn),具體見下文)
`rt_forceinline rt_uint8_t _serial_fifo_pop_data(struct rt_serial_fifo *fifo)` 彈出一個(gè)數(shù)據(jù)(不完整實(shí)現(xiàn),具體見下文)

讀設(shè)備過程

讀設(shè)備對應(yīng)中斷接收。

rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length)
{
   rt_size_t len, size;
   struct rt_serial_fifo* rx_fifo;
   rt_base_t level;
   RT_ASSERT(serial != RT_NULL);

   rx_fifo = (struct rt_serial_fifo*) serial->serial_rx;
   RT_ASSERT(rx_fifo != RT_NULL);

   /* disable interrupt */
   level = rt_hw_interrupt_disable();

   len = _serial_fifo_calc_data_len(rx_fifo);

   if ((len == 0) &&                // non-blocking io mode
       (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
       /* enable interrupt */
       rt_hw_interrupt_enable(level);
       return 0;
   }
   if ((len == 0) &&                // blocking io mode
       (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) != RT_DEVICE_OFLAG_NONBLOCKING) {
       do {
           /* enable interrupt */
           rt_hw_interrupt_enable(level);

           rt_completion_wait(&(serial->completion_rx), RT_WAITING_FOREVER);

           /* disable interrupt */
           level = rt_hw_interrupt_disable();

           len = _serial_fifo_calc_data_len(rx_fifo);
       } while(len == 0);
   }

   if (len > length) {
       len = length;
   }

   /* read from software FIFO */
   for (size = 0; size < len; size++)
   {
       /* otherwise there's the data: */
       *data = _serial_fifo_pop_data(rx_fifo);
       data++;
   }

   rx_fifo->is_full = RT_FALSE;

   /* enable interrupt */
   rt_hw_interrupt_enable(level);

   return size;
}

簡單說明就是:關(guān)中斷,計(jì)算緩存數(shù)據(jù)量,如果為空判斷是否需要阻塞??截愅陻?shù)據(jù),開中斷。
這里需要注意的是,拷貝完數(shù)據(jù)后 fifo 必然不會(huì)是 full 的,`rx_fifo->is_full = RT_FALSE` 這句沒有加在 `_serial_fifo_pop_data` 函數(shù),所以上面說它的實(shí)現(xiàn)是不完整的。

寫設(shè)備過程

寫設(shè)備對應(yīng)中斷發(fā)送

rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length)
{
   rt_size_t len, length_t, size;
   struct rt_serial_fifo *tx_fifo;
   rt_base_t level;
   rt_uint8_t last_char = 0;
   RT_ASSERT(serial != RT_NULL);

   tx_fifo = (struct rt_serial_fifo*) serial->serial_tx;
   RT_ASSERT(tx_fifo != RT_NULL);

   size = 0;
   do {
       length_t = length - size;
       /* disable interrupt */
       level = rt_hw_interrupt_disable();

       len = tx_fifo->buf_sz - _serial_fifo_calc_data_len(tx_fifo);

       if ((len == 0) &&                // non-blocking io mode
           (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) == RT_DEVICE_OFLAG_NONBLOCKING) {
           /* enable interrupt */
           rt_hw_interrupt_enable(level);
           break;
       }

       if ((len == 0) &&                // blocking io mode
           (serial->parent.open_flag & RT_DEVICE_OFLAG_NONBLOCKING) != RT_DEVICE_OFLAG_NONBLOCKING) {
           /* enable interrupt */
           rt_hw_interrupt_enable(level);

           rt_completion_wait(&(serial->completion_tx), RT_WAITING_FOREVER);

           continue;
       }

       if (len > length_t) {
           len = length_t;
       }
       /* copy to software FIFO */
       while (len > 0)
       {
           /*
            * to be polite with serial console add a line feed
            * to the carriage return character
            */
           if (*data == 'n' &&
               (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM) == RT_DEVICE_FLAG_STREAM &&
               last_char != 'r')
           {
               _serial_fifo_push_data(tx_fifo, 'r');

               len--;
               if (len == 0) break;
               last_char = 0;
           } else if (*data == 'r') {
               last_char = 'r';
           } else {
               last_char = 0;
           }

           _serial_fifo_push_data(tx_fifo, *data);

           data++; len--; size++;
       }

       /* if the next position is read index, discard this 'read char' */
       if (tx_fifo->put_index == tx_fifo->get_index)
       {
           tx_fifo->is_full = RT_TRUE;
       }

       // TODO: start tx
       serial->ops->start_tx(serial);

       /* enable interrupt */
       rt_hw_interrupt_enable(level);
   } while(size < length);

   return size;
}

簡單說明就是:關(guān)中斷,計(jì)算 fifo 剩余容量,如果空間不足判斷是否阻塞。拷貝數(shù)據(jù),開中斷。
如果數(shù)據(jù)沒拷貝完,繼續(xù)上述過程,直到所有數(shù)據(jù)拷貝完成。
上述函數(shù)也實(shí)現(xiàn)了 STREAM 打開模式,檢查 “r”“n” 不完整的問題。

特別注意:上述函數(shù)并沒有執(zhí)行寫“發(fā)送寄存器”的操作,開中斷前,這里執(zhí)行了一句 `serial->ops->start_tx(serial)` 用于開啟發(fā)送過程(這個(gè)的實(shí)現(xiàn)可能在不同芯片上略有差異)。

中斷接收

       while (1) {
           ch = serial->ops->getc(serial);
           if (ch == -1) break;
           /* if fifo is full, discard one byte first */
           if (rx_fifo->is_full == RT_TRUE) {
               rx_fifo->get_index += 1;
               if (rx_fifo->get_index >= rx_fifo->buf_sz) rx_fifo->get_index = 0;
           }
           /* push a new data */
           _serial_fifo_push_data(rx_fifo, ch);

           /* if put index equal to read index, fifo is full */
           if (rx_fifo->put_index == rx_fifo->get_index)
           {
               rx_fifo->is_full = RT_TRUE;
           }
       }

       rt_completion_done(&(serial->completion_rx));

注:這里的 while 循環(huán)是因?yàn)?uart 外設(shè)自帶硬件 fifo。

簡單講就是,有接收中斷,就往接收 fifo 中壓入數(shù)據(jù),如果 fifo 是滿的,丟棄掉舊數(shù)據(jù)。

中斷發(fā)送

       /* calucate fifo data size */
       len = _serial_fifo_calc_data_len(tx_fifo);
       if (len == 0) {
           // TODO: stop tx
           serial->ops->stop_tx(serial);
           rt_completion_done(&(serial->completion_tx));
           break;
       }
       if (len > 64) {
           len = 64;
       }
       /* read from software FIFO */
       while (len > 0) {
           /* pop one byte data */
           ch = _serial_fifo_pop_data(tx_fifo);

           serial->ops->putc(serial, ch);
           len--;
       }
       tx_fifo->is_full = RT_FALSE;

先計(jì)算是否還有數(shù)據(jù)要發(fā)送,如果沒有,調(diào)用 `serial->ops->stop_tx(serial)` 對應(yīng)上面的 `serial->ops->start_tx(serial)` 。
因?yàn)橛布詭?fifo ,這里最多可以連續(xù)寫 64 個(gè)字節(jié)。
因?yàn)榘l(fā)送 fifo 是往外彈出數(shù)據(jù)的,最后肯定是非滿的。

未說明的問題

對于串口設(shè)備來講,接收是非預(yù)期的,所以串口接收中斷必須一直開著。發(fā)送就不一樣了,沒有發(fā)送數(shù)據(jù)的時(shí)候是可以不開發(fā)送中斷的。
上文中提到的兩個(gè) ops `start_tx` `stop_tx` 正是開發(fā)送中斷使能,關(guān)發(fā)送中斷使能。另外,它倆還有更重要的作用。

在 NUC970 的設(shè)計(jì)上,只要發(fā)送寄存器為空就會(huì)有發(fā)送完成中斷,并不是發(fā)送完最后一個(gè)字節(jié)才產(chǎn)生。正因?yàn)檫@個(gè)特性,當(dāng)開發(fā)送中斷使能的時(shí)候會(huì)立馬進(jìn)入中斷。在中斷里判斷是否有數(shù)據(jù)要發(fā)送,剛好可以作為“啟動(dòng)發(fā)送”。

對于其它芯片,如果發(fā)送中斷的含義是“發(fā)送完最后一個(gè)字節(jié)”,僅僅使能發(fā)送中斷還不夠,還需要軟件觸發(fā)發(fā)送中斷。這是發(fā)送不同于接收的最重要的地方。

DMA 模式下的實(shí)現(xiàn)探討

為什么上一節(jié)叫實(shí)踐,這一節(jié)變成探討了?
第一,筆者還沒時(shí)間在 NUC970 上完成 DMA 的部分。
第二,有了上面中斷模式的鋪墊,DMA 模式也是輕車熟路。不覺得 NUC970 的硬件 fifo 就是 DMA 的翻版嗎?

DMA 模式需要二級緩存機(jī)制。第一級緩存和中斷模式用的 fifo 一樣。這樣 read write 兩個(gè)函數(shù)的實(shí)現(xiàn)可以是一樣的。
在此基礎(chǔ)上,增加一個(gè)數(shù)組。如下是完整串口設(shè)備定義:

struct rt_serial_device
{
   struct rt_device          parent;
   const struct rt_uart_ops *ops;
   struct serial_configure   config;

   void *serial_rx;
   void *serial_tx;

   rt_uint8_t serial_dma_rx[64];
   rt_uint8_t serial_dma_tx[64];

   cb_serial_tx _cb_tx;
   cb_serial_rx _cb_rx;

   struct rt_completion completion_tx;
   struct rt_completion completion_rx;
};
typedef struct rt_serial_device rt_serial_t;

這兩個(gè)數(shù)組作為 DMA 收發(fā)過程的緩存。

發(fā)送數(shù)據(jù)時(shí),從 serial_tx 的 fifo 拷貝數(shù)據(jù)到 serial_dma_tx ,啟動(dòng) DMA。發(fā)送完成后判斷 serial_tx 的 fifo 是否還有數(shù)據(jù),有數(shù)據(jù)繼續(xù)拷貝,直到 fifo 為空關(guān)閉 DMA 發(fā)送。

接收數(shù)據(jù)時(shí),在 DMA 中斷里拷貝 `serial_dma_rx` 所有數(shù)據(jù)到 serial_rx 的 fifo 。如果 DMA 中斷分完成一半中斷和全部傳輸完成兩種中斷??梢苑殖蓛纱沃袛?,每次只處理一半數(shù)據(jù),這樣每次往 fifo 倒騰數(shù)據(jù)的時(shí)候,還有一半緩沖區(qū)可用,也不至于會(huì)擔(dān)心倉促。

我們需要做的工作只有“怎么安全有效啟動(dòng) DMA 發(fā)送”。

底層驅(qū)動(dòng)

以上都是串口設(shè)備驅(qū)動(dòng)框架部分,下面說說和芯片操作緊密相關(guān)的部分

init 函數(shù),負(fù)責(zé)注冊設(shè)備到設(shè)備樹。
configure 函數(shù),負(fù)責(zé)串口外設(shè)初始化,包括波特率、數(shù)據(jù)位、流控等等。還有個(gè)重要的工作就是調(diào)用引腳復(fù)用配置函數(shù)。
control 函數(shù),使能禁用收發(fā)等中斷。
putc 函數(shù),負(fù)責(zé)寫發(fā)送寄存器,寫寄存器前一定先判斷發(fā)送寄存器是否可寫是否為空,阻塞等。
getc 函數(shù),負(fù)責(zé)讀接收寄存器,讀寄存器前一定先判斷是否有有效數(shù)據(jù),如果沒有返回 -1。
start_tx 函數(shù),使能發(fā)送中斷,如果發(fā)送寄存器為空,觸發(fā)發(fā)送中斷。(如果芯片沒有這個(gè)特性,需要想辦法觸發(fā)發(fā)送完成中斷)
stop_tx 函數(shù),禁用發(fā)送中斷。
中斷回調(diào)函數(shù),負(fù)責(zé)處理中斷,根據(jù)中斷狀態(tài)調(diào)用 `rt_hw_serial_isr` 函數(shù)。

實(shí)機(jī)驗(yàn)證

中斷模式在 NUC970 芯片下經(jīng)過**千萬級數(shù)據(jù)**收發(fā)測試的考驗(yàn)。測試環(huán)境有如下兩種:

1. 非阻塞 io;波特率 9600;串口調(diào)試工具:USR-TCP232 ,USR 出的調(diào)試工具。
串口調(diào)試工具定時(shí) 50ms 發(fā)送 30 個(gè)字符。NUC970 接收到數(shù)據(jù)后返回接收到的數(shù)據(jù)。
2. 阻塞 io;波特率 115200;串口調(diào)試工具:USR-TCP232 ,USR 出的調(diào)試工具。
串口調(diào)試工具定時(shí) 10ms 發(fā)送 30 個(gè)字符。NUC970 接收到數(shù)據(jù)后返回接收到的數(shù)據(jù)。(串口調(diào)試助手發(fā)送了 200w 字節(jié)數(shù)據(jù),接收到了相同個(gè)數(shù)字符?。?/p> image.png

結(jié)論

因?yàn)?NUC970 芯片的特殊性,上面雖說使用的是中斷模式,其實(shí)和 DMA 有點(diǎn)兒類似了。假如是沒收發(fā)一個(gè)字節(jié)數(shù)據(jù)各對應(yīng)一次中斷,中斷次數(shù)會(huì)比較多。

但是,在應(yīng)用層來看,無論是中斷還是 DMA 都是一樣的——要么阻塞,要么非阻塞。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 中斷
    +關(guān)注

    關(guān)注

    5

    文章

    889

    瀏覽量

    41220
  • dma
    dma
    +關(guān)注

    關(guān)注

    3

    文章

    552

    瀏覽量

    99931
  • 串口驅(qū)動(dòng)
    +關(guān)注

    關(guān)注

    2

    文章

    81

    瀏覽量

    18503
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1239

    瀏覽量

    39435
  • serialX
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    799
收藏 人收藏

    評論

    相關(guān)推薦

    RT-Thread記錄(、版本開發(fā)環(huán)境及配合CubeMX)

    RT-Thread 學(xué)習(xí)記錄的第一篇文章,RT-Thread記錄(、RT-Thread 版本、RT-T
    的頭像 發(fā)表于 06-20 00:28 ?4925次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(<b class='flag-5'>一</b>、版本開發(fā)環(huán)境及配合CubeMX)

    rt-thread 驅(qū)動(dòng)(二) serialX 理論實(shí)現(xiàn)

    在前文章里,大致提出了我的串口驅(qū)動(dòng)框架理論。里面做了些對串口
    的頭像 發(fā)表于 06-22 09:03 ?5045次閱讀
    <b class='flag-5'>rt-thread</b> <b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>篇</b>(二) <b class='flag-5'>serialX</b> <b class='flag-5'>理論</b>實(shí)現(xiàn)

    rt-thread 驅(qū)動(dòng)(六)serialX弊端及解決方法

    serialX 作為個(gè)非阻塞串口驅(qū)動(dòng)框架,在遇到些異常時(shí),需要做些特殊處理,今天,筆者帶大
    的頭像 發(fā)表于 06-20 11:43 ?3147次閱讀

    基于RT-Thread的SPI通訊

    驅(qū)動(dòng)層的驅(qū)動(dòng)。(rt-thread的設(shè)備 I/O 模型有設(shè)備管理層、設(shè)備驅(qū)動(dòng)框架層、設(shè)備驅(qū)動(dòng)層)
    的頭像 發(fā)表于 08-22 09:28 ?1534次閱讀

    基于RT-Thread的RoboMaster電控框架設(shè)計(jì)

    由于 RT-Thread 穩(wěn)定高效的內(nèi)核,豐富的文檔教程,積極活躍的社區(qū)氛圍,以及設(shè)備驅(qū)動(dòng)框架、Kconfig、Scons、日志系統(tǒng)、海量的軟件包……很難不選擇 RT-Thread 進(jìn)
    發(fā)表于 09-06 15:21 ?563次閱讀

    【原創(chuàng)精選】RT-Thread征文精選技術(shù)文章合集

    軟件包)NO2 專欄作者 :出出簡介:rt-thread 研究。1. rt-thread 驅(qū)動(dòng)rt-thread
    發(fā)表于 07-26 14:56

    RT-Thread Studio驅(qū)動(dòng)SD卡

    RT-Thread Studio驅(qū)動(dòng)SD卡前言、創(chuàng)建基本工程1、創(chuàng)建Bootloader2、創(chuàng)建項(xiàng)目工程二、配置RT-Thread Settings三、代碼分析1.引入庫2.讀入數(shù)據(jù)
    發(fā)表于 12-27 19:13 ?20次下載
    <b class='flag-5'>RT-Thread</b> Studio<b class='flag-5'>驅(qū)動(dòng)</b>SD卡

    RT-Thread全球技術(shù)大會(huì):RT-Thread上的單元測試框架與運(yùn)行測試用例

    RT-Thread全球技術(shù)大會(huì):RT-Thread上的單元測試框架與運(yùn)行測試用例 ? ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:21 ?1502次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):<b class='flag-5'>RT-Thread</b>上的單元測試<b class='flag-5'>框架</b>與運(yùn)行測試用例

    rt-thread 驅(qū)動(dòng)(五)serialX 小試牛刀

    終于來到了 serialX 的實(shí)踐,期待很久了。
    的頭像 發(fā)表于 06-16 11:29 ?4279次閱讀
    <b class='flag-5'>rt-thread</b> <b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>篇</b>(五)<b class='flag-5'>serialX</b> 小試牛刀

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    RT-Thread文檔_utest 測試框架

    RT-Thread文檔_utest 測試框架
    發(fā)表于 02-22 18:43 ?2次下載
    <b class='flag-5'>RT-Thread</b>文檔_utest 測試<b class='flag-5'>框架</b>

    淺析RT-Thread設(shè)備驅(qū)動(dòng)框架

    RT-Thread 設(shè)備框架屬于組件和服務(wù)層,是基于 RT-Thread 內(nèi)核之上的上層軟件。設(shè)備框架是針對某類外設(shè),抽象出來的
    的頭像 發(fā)表于 08-07 15:39 ?1734次閱讀

    基于 RT-Thread 的 RoboMaster 電控框架

    由于 RT-Thread 穩(wěn)定高效的內(nèi)核,豐富的文檔教程,積極活躍的社區(qū)氛圍,以及設(shè)備驅(qū)動(dòng)框架、Kconfig、Scons、日志系統(tǒng)、海量的軟件包……很難不選擇 RT-Thread 進(jìn)
    的頭像 發(fā)表于 09-19 19:55 ?641次閱讀

    基于RT-Thread的RoboMaster電控框架(二)

    由于 RT-Thread 穩(wěn)定高效的內(nèi)核,豐富的文檔教程,積極活躍的社區(qū)氛圍,以及設(shè)備驅(qū)動(dòng)框架、Kconfig、Scons、日志系統(tǒng)、海量的軟件包
    的頭像 發(fā)表于 09-20 15:16 ?638次閱讀

    RT-Thread設(shè)備驅(qū)動(dòng)開發(fā)指南》基礎(chǔ)--以先楫bsp的hwtimer設(shè)備為例

    、概述(RT-Thread設(shè)備驅(qū)動(dòng)RT-Thread設(shè)備驅(qū)動(dòng)開發(fā)指南》書籍是
    的頭像 發(fā)表于 02-24 08:16 ?951次閱讀
    《<b class='flag-5'>RT-Thread</b>設(shè)備<b class='flag-5'>驅(qū)動(dòng)</b>開發(fā)指南》基礎(chǔ)<b class='flag-5'>篇</b>--以先楫bsp的hwtimer設(shè)備為例