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

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

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

Ardupilot移植的深入細(xì)節(jié)分享

RTThread物聯(lián)網(wǎng)操作系統(tǒng) ? 來源:驚覺嵌入式 ? 作者:驚覺嵌入式 ? 2021-04-30 16:14 ? 次閱讀

接Ardupilot移植經(jīng)驗(yàn)分享(2)

深入細(xì)節(jié)

是時(shí)候深入具體的HAL接口了。筆者并不打算一一講解所有的接口,而是挑選一些有代表性的來分析,主要的內(nèi)容是:

分析HAL接口的含義,包括功能,入?yún)⒓胺祷刂档木唧w含義。

分析HAL_PX4的實(shí)現(xiàn),看看有沒有可借鑒之處。

調(diào)度接口

AP_HAL::Scheduler提供了程序調(diào)度相關(guān)的接口。主要分為兩類:

延時(shí)函數(shù)

注冊回調(diào)

延時(shí)函數(shù)有3個(gè),1個(gè)毫秒級(jí)延時(shí),2個(gè)微秒級(jí)延時(shí)。這里的延時(shí)可不是死等,而是睡眠一段時(shí)間,在此期間讓出CPU的使用權(quán)以執(zhí)行其他的線程。

virtual void delay(uint16_t ms) = 0;

virtual void delay_microseconds(uint16_t us) = 0;

virtual void delay_microseconds_boost(uint16_t us) { delay_microseconds(us); }

看似簡單的delay

大家可能會(huì)覺得,delay是最簡單的,delay_microseconds會(huì)比較復(fù)雜。因?yàn)橥ǔ碚f,毫秒級(jí)延時(shí)是RTOS的基礎(chǔ)API,比如RT-Thread的rt_thread_mdelay。

rt_err_t rt_thread_mdelay(rt_int32_t ms);

不過Scheduler::delay除了簡單的睡眠延時(shí),還多了一項(xiàng)任務(wù)。這就要先提到注冊回調(diào)接口中的一個(gè):

typedef void(*Proc)(void);

virtual void register_delay_callback(AP_HAL::Proc, uint16_t min_time_ms) = 0;

這接口的功能是:注冊一個(gè)延時(shí)回調(diào)。當(dāng)某個(gè)線程調(diào)用delay進(jìn)行延時(shí)時(shí),若延時(shí)的時(shí)間大于min_time_ms,則delay函數(shù)將會(huì)調(diào)用這個(gè)延時(shí)回調(diào)。

這延時(shí)回調(diào)的意義是,當(dāng)你睡眠的時(shí)候,正好可以執(zhí)行某一個(gè)指定的任務(wù),不要浪費(fèi)時(shí)間。你可能會(huì)想,RTOS的延時(shí)本就會(huì)讓出CPU,本就會(huì)讓別的線程得以執(zhí)行,何必多此一舉呢?我們看看是誰注冊了這個(gè)回調(diào)。

其中之一是mavlink模塊。

hal.scheduler-》register_delay_callback(mavlink_delay_cb_static, 5);

7b10b000-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

注釋里面說明了原因,這是為了在長時(shí)間的初始化函數(shù)(setup)中能進(jìn)行MAVLink交互。主要的MAVLink任務(wù)是在loop()中的AP_Scheduler調(diào)度系統(tǒng)中執(zhí)行,就是紅圈部分(不過紅圈里面沒提到MAVLink,不要介意哈)。setup()是順序執(zhí)行一系列的初始化函數(shù),想在它里面去進(jìn)行MAVLink任務(wù),就靠這register_delay_callback了。

7b43b7ca-a7f7-11eb-9728-12bb97331649.png

我們再看看PX4的實(shí)現(xiàn)。延時(shí)的功能依賴于一個(gè)微秒級(jí)延時(shí)的接口delay_microseconds_semaphore,不過它每次只延時(shí)1000微秒,多余的時(shí)間會(huì)去執(zhí)行延時(shí)回調(diào)。

7b7388a6-a7f7-11eb-9728-12bb97331649.png

微秒級(jí)延時(shí)delay_microseconds

筆者當(dāng)初看到這接口時(shí),有些頭疼。因?yàn)镽T-Thread并沒有微秒級(jí)別的延時(shí)函數(shù),再強(qiáng)調(diào)一遍,這不是死等,是要睡眠讓權(quán)的。

直接看PX4的實(shí)現(xiàn):

void PX4Scheduler::delay_microseconds(uint16_t usec)

{

perf_begin(_perf_delay);

delay_microseconds_semaphore(usec);

perf_end(_perf_delay);

}

這是上節(jié)提到的delay_microseconds_semaphore的馬甲,脫了它:

7b82352c-a7f7-11eb-9728-12bb97331649.png

該函數(shù)使用hrt_call_after和信號(hào)量來完成微秒級(jí)睡眠的功能。hrt是High-resolution timer的縮寫,高精度定時(shí)器。

調(diào)用hrt_call_after注冊一個(gè)定時(shí)器回調(diào),定時(shí)時(shí)間是usec,單位微秒?;卣{(diào)函數(shù)是信號(hào)量發(fā)送函數(shù)sem_post,回調(diào)參數(shù)是信號(hào)量wait_semaphore。

使用sem_wait等待信號(hào)量wait_semaphore,此時(shí)當(dāng)前線程會(huì)堵塞,進(jìn)入睡眠狀態(tài)。

到達(dá)定時(shí)時(shí)間后,底層就執(zhí)行這個(gè)回調(diào),即sem_post(&wait_semaphore)。

sem_wait接收到了信號(hào)量wait_semaphore,該線程被喚醒。

結(jié)合時(shí)序圖來理解:

7bb9300e-a7f7-11eb-9728-12bb97331649.png

微秒級(jí)的延時(shí)函數(shù),依賴于微秒級(jí)的定時(shí)回調(diào),也就是hrt_call_after:

/**

* Call callout(arg) after delay has elapsed.

*

* If callout is NULL, this can be used to implement a timeout by testing the call

* with hrt_called()。

*/

__EXPORT extern void hrt_call_after(struct hrt_call *entry, hrt_abstime delay, hrt_callout callout, void *arg);

hrt_call_after屬于pixhawk底層的接口。筆者一度以為是Nuttx提供的功能,并且為RT-Thread沒有相應(yīng)功能而煩惱。關(guān)于定時(shí)器,RT-Thread有類似的功能,那就是rt_timer,不過這是毫秒級(jí)的。

rt_timer_t rt_timer_create(const char *name,

void (*timeout)(void *parameter),

void *parameter,

rt_tick_t time,

rt_uint8_t flag)

可能你會(huì)想,一般單片機(jī)里面不是都有硬件定時(shí)器嗎?實(shí)現(xiàn)微秒級(jí)的定時(shí)功能很簡單啊。確實(shí)簡單,也不簡單。因?yàn)閔rt_call_after提供的定時(shí)功能是要支持并發(fā)的,千言萬語不如一圖:

7bde807a-a7f7-11eb-9728-12bb97331649.png

至于pixhawk的實(shí)現(xiàn)以及筆者的移植,將專門出一篇文章來講解。

delay_microseconds_boost

這個(gè)同樣依賴于hrt_call_after,只是在睡眠的時(shí)候提高了優(yōu)先級(jí),以使得自己可在第一時(shí)間被喚醒。

注冊回調(diào)

virtual void register_timer_process(AP_HAL::MemberProc) = 0;

virtual void register_io_process(AP_HAL::MemberProc) = 0;

相對來說,這兩接口就簡單的多了。它們用于注冊在timer線程和io線程中運(yùn)行的回調(diào)函數(shù)。

7c070de2-a7f7-11eb-9728-12bb97331649.png

注冊函數(shù)將回調(diào)指針加入到數(shù)組中。

7c17077e-a7f7-11eb-9728-12bb97331649.png

在相應(yīng)線程中,定時(shí)的一一執(zhí)行。

7c46c72a-a7f7-11eb-9728-12bb97331649.png

那么,這線程是怎么創(chuàng)建的呢?PX4Scheduler的初始化函數(shù)中,會(huì)創(chuàng)建許多線程。

void PX4Scheduler::init()

{

_main_task_pid = getpid();

// setup the timer thread - this will call tasks at 1kHz

pthread_attr_t thread_attr;

struct sched_param param;

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_TIMER_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_timer_thread_ctx, &thread_attr, &PX4Scheduler::_timer_thread, this);

// the UART thread runs at a medium priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_UART_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_uart_thread_ctx, &thread_attr, &PX4Scheduler::_uart_thread, this);

// the IO thread runs at lower priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_IO_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_io_thread_ctx, &thread_attr, &PX4Scheduler::_io_thread, this);

// the storage thread runs at just above IO priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 1024);

param.sched_priority = APM_STORAGE_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_storage_thread_ctx, &thread_attr, &PX4Scheduler::_storage_thread, this);

}

pthread_attr_init,pthread_create,這些是POSIX的線程接口,由Nuttx提供。POSIX 是 “Portable Operating System Interface”(可移植操作系統(tǒng)接口) 的縮寫,POSIX 是 IEEE Computer Society 為了提高不同操作系統(tǒng)的兼容性和應(yīng)用程序的可移植性而制定的一套標(biāo)準(zhǔn)。

好消息是,RT-Thread從3.0版本開始提供POSIX接口。所以,當(dāng)我們移植的時(shí)候,很多地方可以參考AP_HAL_PX4的代碼,甚至是直接復(fù)制它的代碼。

串口驅(qū)動(dòng)

AP_HAL的串口驅(qū)動(dòng)框架由4個(gè)類組成,層層分工明確。

Print的功能,如其名稱,負(fù)責(zé)打印輸出。write系列為最底層的字節(jié)輸出接口,需要由具體的HAL平臺(tái)實(shí)現(xiàn)。print和println系列提供打印功能。所謂的打印,比如打印float,就是以字符格式輸出float。筆者只列了幾個(gè)print接口,實(shí)際上遠(yuǎn)比這個(gè)多。

Stream定義了輸入接口,available返回接收緩存中的字節(jié)數(shù),read用于讀取輸入。

BetterStream添加了格式化輸出的接口,即大家熟悉的printf系列。

UARTDriver引入了與串口相關(guān)的接口,begin用于配置波特率、輸入輸出緩存,set_flow_control和get_flow_control與流控相關(guān)。

7c5553ee-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

除了print系列函數(shù)由AP_HAL中的類實(shí)現(xiàn),其他的功能,比如read, write, begin, flow_control,都要由具體的HAL平臺(tái)實(shí)現(xiàn)。PX4UARTDriver就是具體的實(shí)現(xiàn)類。

串口綁定

Ardupilot有6個(gè)串口,定義在AP_HAL::HAL之中。

AP_HAL::UARTDriver* uartA;

AP_HAL::UARTDriver* uartB;

AP_HAL::UARTDriver* uartC;

AP_HAL::UARTDriver* uartD;

AP_HAL::UARTDriver* uartE;

AP_HAL::UARTDriver* uartF;

PX4UARTDriver構(gòu)造函數(shù)和set_device_path用于與具體的底層串口相綁定。HAL_PX4_Class.c中定義了綁定關(guān)系:

// 3 UART drivers, for GPS plus two mavlink-enabled devices

static PX4UARTDriver uartADriver(UARTA_DEFAULT_DEVICE, “APM_uartA”);

static PX4UARTDriver uartBDriver(UARTB_DEFAULT_DEVICE, “APM_uartB”);

static PX4UARTDriver uartCDriver(UARTC_DEFAULT_DEVICE, “APM_uartC”);

static PX4UARTDriver uartDDriver(UARTD_DEFAULT_DEVICE, “APM_uartD”);

static PX4UARTDriver uartEDriver(UARTE_DEFAULT_DEVICE, “APM_uartE”);

static PX4UARTDriver uartFDriver(UARTF_DEFAULT_DEVICE, “APM_uartF”);

read和write的實(shí)現(xiàn)

大家可能認(rèn)為串口的讀寫是非常簡單的操作。其實(shí)不然,Ardupilot作為一個(gè)對實(shí)時(shí)要求很高的飛控程序,在應(yīng)用層調(diào)用串口讀寫函數(shù)時(shí),是不允許堵塞的。這需要一些額外的工作來實(shí)現(xiàn)。

PX4UARTDriver使用接收緩存和發(fā)送緩存來實(shí)現(xiàn)異步讀寫。

write是將數(shù)據(jù)寫入到發(fā)送緩存_writebuf之中。_writebuf是一個(gè)隊(duì)列,實(shí)質(zhì)上是環(huán)形數(shù)組RingBuffer。

/*

write one byte to the buffer

*/

size_t PX4UARTDriver::write(uint8_t c)

{

if (_uart_owner_pid != getpid()){

return 0;

}

if (!_initialised) {

try_initialise();

return 0;

}

while (_writebuf.space() == 0) {

if (_nonblocking_writes) {

return 0;

}

hal.scheduler-》delay(1);

}

return _writebuf.write(&c, 1);

}

read從接收緩存中提取數(shù)據(jù),若沒有則返回-1。

/*

read one byte from the read buffer

*/

int16_t PX4UARTDriver::read()

{

if (_uart_owner_pid != getpid()){

return -1;

}

if (!_initialised) {

try_initialise();

return -1;

}

uint8_t byte;

if (!_readbuf.read_byte(&byte)) {

return -1;

}

return byte;

}

將發(fā)送緩存的數(shù)據(jù)寫入串口和從串口接收數(shù)據(jù)以填充接收緩存的工作,在PX4UARTDriver::_timer_tick函數(shù)中實(shí)現(xiàn)。而所有串口的_timer_tick由一個(gè)統(tǒng)一的串口線程來調(diào)度。

void *PX4Scheduler::_uart_thread(void *arg)

{

PX4Scheduler *sched = (PX4Scheduler *)arg;

pthread_setname_np(pthread_self(), “apm_uart”);

while (!sched-》_hal_initialized) {

poll(nullptr, 0, 1);

}

while (!_px4_thread_should_exit) {

sched-》delay_microseconds_semaphore(1000);

// process any pending serial bytes

((PX4UARTDriver *)hal.uartA)-》_timer_tick();

((PX4UARTDriver *)hal.uartB)-》_timer_tick();

((PX4UARTDriver *)hal.uartC)-》_timer_tick();

((PX4UARTDriver *)hal.uartD)-》_timer_tick();

((PX4UARTDriver *)hal.uartE)-》_timer_tick();

((PX4UARTDriver *)hal.uartF)-》_timer_tick();

}

return nullptr;

}

看過前面高清大圖的,應(yīng)該對這個(gè)有印象:

7c61c5b6-a7f7-11eb-9728-12bb97331649.png

SPI和I2C驅(qū)動(dòng)

我們再看兩個(gè)驅(qū)動(dòng),SPI驅(qū)動(dòng)和I2C驅(qū)動(dòng)。這兩個(gè)驅(qū)動(dòng)有很多共同之處:

都有總線的概念,一條總線掛接許多設(shè)備。

都有主從概念,每次傳輸由主機(jī)發(fā)起,由從機(jī)應(yīng)答。

正是由于它們非常相似,Ardupilot提取出它們的共同之處,抽象成一個(gè)基類AP_HAL::Device。下圖是Device的類圖,并非包含其所有內(nèi)容,僅列出了一些重要的元素。

7c6e6f3c-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

UML圖示說明

上圖為UML類圖。前面提到類圖的語法,這里做一點(diǎn)補(bǔ)充。

變量和函數(shù)左邊有顏色的符號(hào)表示訪問權(quán)限,綠色圓圈是public,黃色菱形是protected。

斜體函數(shù)為純虛函數(shù),需要由子類實(shí)現(xiàn)。

transfer

Ardupilot的I2C和SPI驅(qū)動(dòng)主要是用于與傳感器通信,所以Device類提供了兩個(gè)常用的接口:read_register和write_register,并且實(shí)現(xiàn)了它們。當(dāng)然,這是基于transfer接口實(shí)現(xiàn)的,而transfer交由子類來實(shí)現(xiàn),畢竟SPI和I2C的實(shí)現(xiàn)是不同的。

/*

* Core transfer function. This does a single bus transaction which

* sends send_len bytes and receives recv_len bytes back from the slave.

*

* Return: true on a successful transfer, false on failure.

*/

virtual bool transfer(const uint8_t *send, uint32_t send_len,

uint8_t *recv, uint32_t recv_len) = 0;

對于I2C來說,transfer實(shí)現(xiàn)的是先寫后讀。而對于SPI來說,transfer內(nèi)部是同時(shí)讀寫。

SPIDevice和I2CDevice

7c8186d0-a7f7-11eb-9728-12bb97331649.png

它們添加了自身獨(dú)有的接口。

SPIDevice添加了全雙工的傳輸接口transfer_fullduplex,與transfer接口所不同之處在于發(fā)送和接收緩存的長度一致。

I2CDevice中,set_address用于設(shè)置地址,set_split_transfers指定在先寫后讀的中間是否傳輸停止位。

Periodic Callback

Device的功能遠(yuǎn)不只是為SPI和I2C定義了統(tǒng)一的transfer接口。最重要的,是實(shí)現(xiàn)了應(yīng)用層訪問總線的串行化。SPI和I2C都是由一條總線掛接許多設(shè)備,無論是SPI或I2C,都不允許在同一時(shí)刻訪問多個(gè)設(shè)備。因此,Device提供了get_semaphore接口,以鎖定總線。當(dāng)然,這并不算是串行化,真正的串行化,是通過register_periodic_callback來實(shí)現(xiàn)。

virtual PeriodicHandle register_periodic_callback(uint32_t period_usec, PeriodicCb) = 0;

各傳感器驅(qū)動(dòng)通過register_periodic_callback注冊定時(shí)回調(diào),在回調(diào)之中訪問對應(yīng)的傳感器。同一總線的所有定時(shí)回調(diào)是在同一個(gè)線程中被執(zhí)行的,這就是串行化。

7d495e94-a7f7-11eb-9728-12bb97331649.png

PX4在實(shí)現(xiàn)時(shí),使用DeviceBus實(shí)現(xiàn)這個(gè)串行化的功能,其會(huì)為每一條總線創(chuàng)建一個(gè)線程。

7d9b24d6-a7f7-11eb-9728-12bb97331649.png

其內(nèi)部實(shí)現(xiàn),無非是創(chuàng)建線程,將回調(diào)添加到一個(gè)鏈表之中。在函數(shù)中,POSIX接口的調(diào)用清晰可見。筆者的意思是,可以直接拿來用啦。

7db1b5d4-a7f7-11eb-9728-12bb97331649.png

Manager

應(yīng)用層通過Device來訪問I2C和SPI設(shè)備,那么Device對象是哪來的呢?由I2CDeviceManager和SPIDeviceManager提供,而這兩個(gè)Manager的實(shí)例可通過HAL引用訪問。

7df3cc9e-a7f7-11eb-9728-12bb97331649.png

小結(jié)

SPI和I2C傳輸?shù)木唧w實(shí)現(xiàn),沒啥好說的。最值得說的,是Ardupilot抽象出了Device基類,為應(yīng)用層提供串行化的訪問功能。而這串行化,是靠創(chuàng)建線程和回調(diào)鏈表來實(shí)現(xiàn)。

是時(shí)候放一張高清大圖了:

7e8275b6-a7f7-11eb-9728-12bb97331649.png

總結(jié)

到目前為止,我們看了調(diào)度接口,串口驅(qū)動(dòng),SPI和I2C驅(qū)動(dòng)。調(diào)度接口中的微秒級(jí)延時(shí)接口非常關(guān)鍵,因?yàn)楹芏嗟胤绞褂昧怂?,并且它的?shí)現(xiàn)有些困難。至于串口、SPI等驅(qū)動(dòng)接口,只要我們理清了它們的層級(jí)關(guān)系,明確了各接口的作用,移植時(shí)不會(huì)有什么大問題。并且,這些驅(qū)動(dòng)接口的實(shí)現(xiàn),很多地方可以參考PX4的實(shí)現(xiàn),甚至是直接復(fù)制過來用。

原文標(biāo)題:Ardupilot移植經(jīng)驗(yàn)分享(3)

文章出處:【微信公眾號(hào):RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

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

    關(guān)注

    12

    文章

    1844

    瀏覽量

    85404
  • 串口
    +關(guān)注

    關(guān)注

    14

    文章

    1557

    瀏覽量

    76724

原文標(biāo)題:Ardupilot移植經(jīng)驗(yàn)分享(3)

文章出處:【微信號(hào):RTThread,微信公眾號(hào):RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    臺(tái)積電分享 2nm 工藝深入細(xì)節(jié):功耗降低 35% 或性能提升15%!

    來源:IEEE 臺(tái)積電在本月早些時(shí)候于IEEE國際電子器件會(huì)議(IEDM)上公布了其N2(2nm級(jí))制程的更多細(xì)節(jié)。該新一代工藝節(jié)點(diǎn)承諾實(shí)現(xiàn)24%至35%的功耗降低或15%的性能提升(在相同電壓
    的頭像 發(fā)表于 12-16 09:57 ?241次閱讀
    臺(tái)積電分享 2nm 工藝<b class='flag-5'>深入</b><b class='flag-5'>細(xì)節(jié)</b>:功耗降低 35% 或性能提升15%!

    移植Mediapipe LLM Demo到Kotlin Multiplatform

    在今年的廈門和廣州 Google I/O Extended 上,我分享了《On-Device Model 集成 (KMP) 與用例》。本文是當(dāng)時(shí) Demo 的深入細(xì)節(jié)分析,同時(shí)也是后面幾篇同類型文章的開頭。
    的頭像 發(fā)表于 12-05 16:29 ?317次閱讀
    <b class='flag-5'>移植</b>Mediapipe LLM Demo到Kotlin Multiplatform

    多平臺(tái)FPGA工程快速移植與構(gòu)建

    作為一名FPGA工程師,經(jīng)常需要在多個(gè)FPGA設(shè)備之間移植項(xiàng)目,核心的問題是IP的管理和移植,今天通過安裝和使用 FuseSoC 在多個(gè) AMD FPGA 之間移植一個(gè)簡單的項(xiàng)目。從 AMD Spartan 7 更改為 AMD
    的頭像 發(fā)表于 11-20 16:12 ?1001次閱讀
    多平臺(tái)FPGA工程快速<b class='flag-5'>移植</b>與構(gòu)建

    深入解析Zephyr RTOS的技術(shù)細(xì)節(jié)

    ,Zephyr OS在嵌入式開發(fā)中的知名度逐漸增加,新的微控制器和開發(fā)板都支持Zephyr。本文將深入討論Zephyr RTOS的技術(shù)細(xì)節(jié)
    的頭像 發(fā)表于 10-22 16:47 ?630次閱讀
    <b class='flag-5'>深入</b>解析Zephyr RTOS的技術(shù)<b class='flag-5'>細(xì)節(jié)</b>

    Nordic-RT-Thread5.1.0移植筆記

    Nordic-RT-Thread5.1.0移植筆記
    的頭像 發(fā)表于 10-16 08:09 ?523次閱讀
    Nordic-RT-Thread5.1.0<b class='flag-5'>移植</b>筆記

    基于機(jī)智云移植STM32L496G代碼移植

    前言最近我拿到了STM32L496AGMCU,發(fā)現(xiàn)其擴(kuò)展版可以連接ESP-01S。我想嘗試將開發(fā)板連接到我們的機(jī)智云上,并根據(jù)機(jī)智云提供的文檔進(jìn)行程序移植。STM32CubeMX移植機(jī)智云自動(dòng)生成
    的頭像 發(fā)表于 09-20 08:05 ?472次閱讀
    基于機(jī)智云<b class='flag-5'>移植</b>STM32L496G代碼<b class='flag-5'>移植</b>

    【GD32 MCU 移植教程】9、從 STM32F10x 系列移植到 GD32F30x 系列

    對比、外設(shè)及性能對比以及從 STM32F10x 移植到 GD32F30x 的移植步驟,旨在讓開發(fā)者能夠快速從STM32F10x 移植到 GD32F30x,縮短研發(fā)周
    的頭像 發(fā)表于 09-07 09:57 ?889次閱讀
    【GD32 MCU <b class='flag-5'>移植</b>教程】9、從 STM32F10x 系列<b class='flag-5'>移植</b>到 GD32F30x 系列

    LED顯示屏的換幀頻率與刷新頻率:技術(shù)細(xì)節(jié)與市場發(fā)展

    在當(dāng)今數(shù)字化時(shí)代,LED顯示屏已成為信息傳遞和廣告宣傳的重要工具。然而,對于普通消費(fèi)者來說,LED顯示屏背后的技術(shù)細(xì)節(jié)可能仍然是一個(gè)謎。今天,我們將深入探討LED顯示屏中的兩個(gè)關(guān)鍵概念:換幀頻率和刷新頻率,以及它們之間的關(guān)系,帶領(lǐng)大家了解這些技術(shù)如何影響我們的視覺體驗(yàn)。
    的頭像 發(fā)表于 06-23 02:22 ?746次閱讀
    LED顯示屏的換幀頻率與刷新頻率:技術(shù)<b class='flag-5'>細(xì)節(jié)</b>與市場發(fā)展

    CC2500和CC1101移植說明

    主要通過如何移植、移植注意、關(guān)于芯片配置、如何生成導(dǎo)出配置四大步驟來說明CC2500和CC1101移植
    的頭像 發(fā)表于 06-15 14:32 ?644次閱讀
    CC2500和CC1101<b class='flag-5'>移植</b>說明

    如何移植FFmpeg

    的全方位解決方案,深入掌握FFmpeg已成為每一位多媒體開發(fā)工程師的必修課。今天就跟各位小伙伴分享一篇共創(chuàng)社的學(xué)習(xí)筆記,探討一下如何移植FFmpeg。配置交叉編譯環(huán)
    的頭像 發(fā)表于 06-07 15:28 ?1710次閱讀
    如何<b class='flag-5'>移植</b>FFmpeg

    深入了解目標(biāo)檢測深度學(xué)習(xí)算法的技術(shù)細(xì)節(jié)

    本文將討論目標(biāo)檢測的基本方法(窮盡搜索、R-CNN、FastR-CNN和FasterR-CNN),并嘗試?yán)斫饷總€(gè)模型的技術(shù)細(xì)節(jié)。為了讓經(jīng)驗(yàn)水平各不相同的讀者都能夠理解,文章不會(huì)使用任何公式來進(jìn)行講解
    的頭像 發(fā)表于 04-30 08:27 ?364次閱讀
    <b class='flag-5'>深入</b>了解目標(biāo)檢測深度學(xué)習(xí)算法的技術(shù)<b class='flag-5'>細(xì)節(jié)</b>

    細(xì)節(jié)控必備!東芝“顯微屏”電視Z700NF,打造專精細(xì)節(jié)的“顯微屏”電視

    對音畫細(xì)節(jié)的打磨,旨在解決用戶的觀影痛點(diǎn),提供極致還原的細(xì)節(jié)視聽享受。 1300nits Mini LED?亮度突破,細(xì)節(jié)盡現(xiàn) 用戶在觀看電視時(shí),常因亮度不足而錯(cuò)失畫面的細(xì)微之處。東芝電視Z700NF采用1300nits Min
    的頭像 發(fā)表于 04-19 13:31 ?356次閱讀

    鴻蒙開發(fā)實(shí)戰(zhàn):基于【Markwon】移植和開發(fā)

    本項(xiàng)目是基于開源項(xiàng)目**Markwon**進(jìn)行適用harmonyos的移植和開發(fā)的。
    的頭像 發(fā)表于 03-25 16:27 ?851次閱讀
    鴻蒙開發(fā)實(shí)戰(zhàn):基于【Markwon】<b class='flag-5'>移植</b>和開發(fā)

    鴻蒙ArkUI【開發(fā)移植Carbon】

    本項(xiàng)目是基于開源項(xiàng)目[Carbon]?進(jìn)行harmonyos化的移植和開發(fā)的。
    的頭像 發(fā)表于 03-25 15:41 ?539次閱讀
    鴻蒙ArkUI【開發(fā)<b class='flag-5'>移植</b>Carbon】

    【鴻蒙】標(biāo)準(zhǔn)系統(tǒng)移植指南

    標(biāo)準(zhǔn)系統(tǒng)移植指南 本文描述了移植一塊開發(fā)板的通用步驟,和具體芯片相關(guān)的詳細(xì)移植過程無法在此一一列舉。后續(xù)社區(qū)還會(huì)陸續(xù)發(fā)布開發(fā)板移植的實(shí)例供開發(fā)者參考。 定義開發(fā)板 本文以
    的頭像 發(fā)表于 02-27 14:36 ?963次閱讀
    【鴻蒙】標(biāo)準(zhǔn)系統(tǒng)<b class='flag-5'>移植</b>指南