關于kfifo
kfifo是內核里面的一個First In First Out數據結構,它采用環形循環隊列的數據結構來實現;它提供一個無邊界的字節流服務,最重要的一點是,它使用并行無鎖編程技術,即當它用于只有一個入隊線程和一個出隊線程的場情時,兩個線程可以并發操作,而不需要任何加鎖行為,就可以保證kfifo的線程安全。
具體什么是環形緩沖區,請看我以前的文章
說明
關于kfifo的相關概念我不會介紹,有興趣可以看他的相關文檔,我只將其實現過程移植重寫,移植到適用stm32開發板上,并且按照我個人習慣重新命名,RingBuff->意為環形緩沖區
RingBuff_t
環形緩沖區的結構體成員變量,具體含義看注釋。
buffer: 用于存放數據的緩存
size: buffer空間的大小
in, out: 和buffer一起構成一個循環隊列。 in指向buffer中隊頭,而且out指向buffer中的隊尾
typedef struct ringbuff
{
uint8_t *buffer; /* 數據區域 */
uint32_t size; /* 環形緩沖區大小 */
uint32_t in; /* 數據入隊指針 (in % size) */
uint32_t out; /* 數據出隊指針 (out % size) */
#if USE_MUTEX
MUTEX_T *mutex; /* 支持rtos的互斥 */
#endif
}RingBuff_t ;
Create_RingBuff
創建一個環形緩沖區,為了適應后續對緩沖區入隊出隊的高效操作,環形緩沖區的大小應為2^n字節,
如果不是這個大小,則系統默認裁剪以對應緩沖區字節。
當然還可以優化,不過我目前并未做,思路如下:如果系統支持動態分配內存,則向上對齊,避免浪費內存空間,否則就按照我默認的向下對齊,當內存越大,對齊導致內存泄漏則會越多。對齊采用的函數是roundup_pow_of_two。如果系統支持互斥量,那么還將創建一個互斥量用來做互斥訪問,防止多線程同時使用導致數據丟失。
/************************************************************
* @brief Create_RingBuff
* @param rb:環形緩沖區句柄
* buffer:環形緩沖區的數據區域
* size:環形緩沖區的大小,緩沖區大小要為2^n
* @return err_t:ERR_OK表示創建成功,其他表示失敗
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 用于創建一個環形緩沖區
***********************************************************/
err_t Create_RingBuff(RingBuff_t* rb,
uint8_t *buffer,
uint32_t size
)
{
if((rb == NULL)||(buffer == NULL)||(size == 0))
{
PRINT_ERR("data is null!");
return ERR_NULL;
}
PRINT_DEBUG("ringbuff size is %d!",size);
/* 緩沖區大小必須為2^n字節,系統會強制轉換,
否則可能會導致指針訪問非法地址。
空間大小越大,強轉時丟失內存越多 */
if(size&(size - 1))
{
size = roundup_pow_of_two(size);
PRINT_DEBUG("change ringbuff size is %d!",size);
}
rb->buffer = buffer;
rb->size = size;
rb->in = rb->out = 0;
#if USE_MUTEX
/* 創建信號量不成功 */
if(!create_mutex(rb->mutex))
{
PRINT_ERR("create mutex fail!");
ASSERT(ASSERT_ERR);
return ERR_NOK;
}
#endif
PRINT_DEBUG("create ringBuff ok!");
return ERR_OK;
}
roundup_pow_of_two
/************************************************************
* @brief roundup_pow_of_two
* @param size:傳遞進來的數據長度
* @return size:返回處理之后的數據長度
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 用于處理數據,使數據長度必須為 2^n
* 如果不是,則轉換,丟棄多余部分,如
* roundup_pow_of_two(66) -> 返回 64
***********************************************************/
static unsigned long roundup_pow_of_two(unsigned long x)
{
return (1 << (fls(x-1)-1)); //向下對齊
//return (1UL << fls(x - 1)); //向上對齊,用動態內存可用使用
}
Delete_RingBuff
刪除一個環形緩沖區,刪除之后,緩沖區真正存儲地址是不會被改變的(目前我是使用自定義數組做緩沖區的),但是刪除之后,就無法對緩沖區進行讀寫操作。并且如果支持os的話,創建的互斥量會被刪除。
/************************************************************
* @brief Delete_RingBuff
* @param rb:環形緩沖區句柄
* @return err_t:ERR_OK表示成功,其他表示失敗
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 刪除一個環形緩沖區
***********************************************************/
err_t Delete_RingBuff(RingBuff_t *rb)
{
if(rb == NULL)
{
PRINT_ERR("ringbuff is null!");
return ERR_NULL;
}
rb->buffer = NULL;
rb->size = 0;
rb->in = rb->out = 0;
#if USE_MUTEX
if(!deleta_mutex(rb->mutex))
{
PRINT_DEBUG("deleta mutex is fail!");
return ERR_NOK;
}
#endif
return ERR_OK;
}
Write_RingBuff
向環形緩沖區寫入指定數據,支持線程互斥訪問。用戶想要寫入緩沖區的數據長度不一定是真正入隊的長度,在完成的時候還要看看返回值是否與用戶需要的長度一致~
這個函數很有意思,也是比較高效的入隊操作,將指定區域的數據拷貝到指定的緩沖區中,過程看注釋即可
/************************************************************
* @brief Write_RingBuff
* @param rb:環形緩沖區句柄
* @param wbuff:寫入的數據起始地址
* @param len:寫入數據的長度(字節)
* @return len:實際寫入數據的長度(字節)
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 這個函數會從buff空間拷貝len字節長度的數據到
rb環形緩沖區中的空閑空間。
***********************************************************/
uint32_t Write_RingBuff(RingBuff_t *rb,
uint8_t *wbuff,
uint32_t len)
{
uint32_t l;
#if USE_MUTEX
/* 請求互斥量,成功才能進行ringbuff的訪問 */
if(!request_mutex(rb->mutex))
{
PRINT_DEBUG("request mutex fail!");
return 0;
}
else /* 獲取互斥量成功 */
{
#endif
len = min(len, rb->size - rb->in + rb->out);
/* 第一部分的拷貝:從環形緩沖區寫入數據直至緩沖區最后一個地址 */
l = min(len, rb->size - (rb->in & (rb->size - 1)));
memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);
/* 如果溢出則在緩沖區頭寫入剩余的部分
如果沒溢出這句代碼相當于無效 */
memcpy(rb->buffer, wbuff + l, len - l);
rb->in += len;
PRINT_DEBUG("write ringBuff len is %d!",len);
#if USE_MUTEX
}
/* 釋放互斥量 */
release_mutex(rb->mutex);
#endif
return len;
}
Read_RingBuff
讀取緩沖區數據到指定區域,用戶指定讀取長度,用戶想要讀取的長度不一定是真正讀取的長度,在讀取完成的時候還要看看返回值是否與用戶需要的長度一致~也支持多線程互斥訪問。
也是緩沖區出隊的高效操作。過程看代碼注釋即可
/************************************************************
* @brief Read_RingBuff
* @param rb:環形緩沖區句柄
* @param wbuff:讀取數據保存的起始地址
* @param len:想要讀取數據的長度(字節)
* @return len:實際讀取數據的長度(字節)
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 這個函數會從rb環形緩沖區中的數據區域拷貝len字節
長度的數據到rbuff空間。
***********************************************************/
uint32_t Read_RingBuff(RingBuff_t *rb,
uint8_t *rbuff,
uint32_t len)
{
uint32_t l;
#if USE_MUTEX
/* 請求互斥量,成功才能進行ringbuff的訪問 */
if(!request_mutex(rb->mutex))
{
PRINT_DEBUG("request mutex fail!");
return 0;
}
else
{
#endif
len = min(len, rb->in - rb->out);
/* 第一部分的拷貝:從環形緩沖區讀取數據直至緩沖區最后一個 */
l = min(len, rb->size - (rb->out & (rb->size - 1)));
memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);
/* 如果溢出則在緩沖區頭讀取剩余的部分
如果沒溢出這句代碼相當于無效 */
memcpy(rbuff + l, rb->buffer, len - l);
rb->out += len;
PRINT_DEBUG("read ringBuff len is %d!",len);
#if USE_MUTEX
}
/* 釋放互斥量 */
release_mutex(rb->mutex);
#endif
return len;
}
獲取緩沖區信息
這些就比較簡單了,看看緩沖區可讀可寫的數據有多少
/************************************************************
* @brief CanRead_RingBuff
* @param rb:環形緩沖區句柄
* @return uint32:可讀數據長度 0 / len
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 可讀數據長度
***********************************************************/
uint32_t CanRead_RingBuff(RingBuff_t *rb)
{
if(NULL == rb)
{
PRINT_ERR("ringbuff is null!");
return 0;
}
if(rb->in == rb->out)
return 0;
if(rb->in > rb->out)
return (rb->in - rb->out);
return (rb->size - (rb->out - rb->in));
}
/************************************************************
* @brief CanRead_RingBuff
* @param rb:環形緩沖區句柄
* @return uint32:可寫數據長度 0 / len
* @author jiejie
* @github https://github.com/jiejieTop
* @date 2018-xx-xx
* @version v1.0
* @note 可寫數據長度
***********************************************************/
uint32_t CanWrite_RingBuff(RingBuff_t *rb)
{
if(NULL == rb)
{
PRINT_ERR("ringbuff is null!");
return 0;
}
return (rb->size - CanRead_RingBuff(rb));
}
附帶
這里的代碼我是用于測試的,隨便寫的
RingBuff_t ringbuff_handle;
uint8_t rb[64];
uint8_t res[64];
Create_RingBuff(&ringbuff_handle,
rb,
sizeof(rb));
Write_RingBuff(&ringbuff_handle,
res,
datapack.data_length);
PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));
Read_RingBuff(&ringbuff_handle,
res,
datapack.data_length);
支持多個os的互斥量操作
此處模仿了文件系統的互斥操作
#if USE_MUTEX
#define MUTEX_TIMEOUT 1000 /* 超時時間 */
#define MUTEX_T mutex_t /* 互斥量控制塊 */
#endif
/*********************************** mutex **************************************************/
上一篇:一種Cortex-M內核中的精確延時方法
下一篇:【干貨】老外的GitHub整理的stm32f4驅動庫
推薦閱讀
史海拾趣
MACOM公司上市后,成功募得了充足的資金,使其財務能力得到了顯著增強。這使得公司能夠有更多的資源進行研發、生產和市場推廣,進一步鞏固其在電子行業的地位。同時,上市也為MACOM帶來了更廣泛的投資者關注和市場認可,為其未來的發展提供了有力支持。
Emhiser Research非常注重創新管理和人才培養。公司建立了一套完善的研發流程和激勵機制,鼓勵員工提出創新性的想法和解決方案。同時,公司還積極與高校和研究機構合作,引進和培養了一批高素質的研發人才。這些人才不僅為公司帶來了源源不斷的創新動力,也為公司的長期發展奠定了堅實的基礎。
面對數字化浪潮的挑戰,EBK Kruger積極擁抱數字化轉型。公司引入了先進的ERP系統和智能制造技術,提高了生產效率和產品質量。同時,EBK Kruger還加強了對大數據和人工智能技術的研發和應用,為客戶提供了更加智能化和個性化的產品和服務。通過數字化轉型的推動,EBK Kruger在激烈的市場競爭中保持了領先地位。
隨著國內外市場的不斷拓展和客戶需求的不斷增長,DAQ Electronics LLC公司開始積極探索國際化發展道路。公司積極參加國際展會和技術交流活動,與全球同行建立了廣泛的聯系和合作。同時,公司也加大了對海外市場的投入力度,不斷拓展海外市場份額。這種國際化的發展戰略不僅為公司帶來了更多的商業機會和合作伙伴也為公司未來的發展提供了更廣闊的空間和機遇。
請注意,以上故事均為虛構內容,僅供參考。如有需要,建議直接聯系DAQ Electronics LLC公司獲取其真實的發展歷程和故事。
近年來,隨著環保意識的提高,ALCOA積極推動可持續發展和環保倡議。公司致力于減少生產過程中的能源消耗和廢棄物排放,同時也在研發更環保的鋁材和生產工藝。這些努力不僅提升了公司的社會形象,也為其在電子行業中的長期發展奠定了堅實的基礎。
以上五個故事,只是ALCOA公司發展歷程中的一部分。然而,這些故事足以展現出這家公司在電子行業中的卓越成就和持續創新的精神。
在快速發展的同時,固馳電子始終不忘履行社會責任。公司積極參與公益事業,關注環境保護和可持續發展。通過采用環保材料和節能技術,固馳電子努力降低生產過程中的能耗和排放,為構建綠色、低碳的生態環境貢獻力量。此外,公司還注重員工培訓和職業發展,為員工提供良好的工作環境和晉升機會,實現了企業與員工的共同成長。
1引言 世界電子產品已進入一個速度更快、密度更高、體積更薄、成本更低且要求更有效散熱的封裝時代。隨著無線電通信領域(如手機)的迅速商業化,對降低成本,提高性能有很大的壓力。LTCC(低溫共燒陶瓷)技術是一種低成本封裝的解決方法,具有 ...… 查看全部問答∨ |
|
3G商用業務的展開,不僅僅是通信技術的革新應用,3G技術也成為了信息化建設中的又一亮點。作為一項全新的技術,它將更深層次地融入到社會應用中去,在安防領域它也同樣引領這時代的潮流。 過去信息化建設的重點更多地放在傳統互聯網上,隨著3 ...… 查看全部問答∨ |
|
問題一: 第一步、客戶端發一個SYN, 第二步、服務器回一個SYN+ACK, 第三步、客戶端發一個ACK, seq_no=07CC50EA,ack_no=78BEEA98 此時三次握手搞定。接下來開始傳送IP數據包了,但是我想請問下, 當第三步不成功的情況下,客戶端發了一個ACK,而 ...… 查看全部問答∨ |
|
牛牛們,我最近使用Windows ce 6.0 + Visual Studio 2005進行cepc:x86的開發,大家知道ce6.0現在不為x86集成了emulator,我選用DMA后在download device時就出現"Error: invalid or missing ROM or Image". 后面我按照MSDN上的說法做一個flooby ...… 查看全部問答∨ |
|
Error: Flash Download failed - "Cortex-M3" 主芯片型號:STM32F103RET6 仿真器 :Jlink V8 Load "C:\\\\Users\\\\Administrator\\\\Desktop\\\\STM3210E-EVAL.axf" Set JLink Project File to "E:\\開發資料\\STM32\\STM32官網庫函數\\STM32F10x_StdPerip ...… 查看全部問答∨ |
設計資源 培訓 開發板 精華推薦
- Microchip直播:單片機編程不再難, 利用MPLAB®代碼配置器(MCC)實現快速開發
- 【EEWORLD第二十三屆】2011年02月社區明星人物揭曉!
- 走近 AI 重磅新品 STM32N6,解鎖在 MCU 部署高性能、節能型邊緣 AI!答題有好禮~還有開發板等你拿!
- 有獎直播:Microchip適用于CryptoAuthentication™系列的可信任平臺
- 直播已結束--STM32全球線上峰會 | 新品STM32N6重磅發布,50+開發板等你抽!
- 【已結束】 電感應用知識分享|MPS 有獎直播
- TI有獎直播:伺服驅動器中電流和電壓測量解決方案
- 學AM335X課程,贏超值BB-Black團購資格,更有DIY大獎賽預熱中!
- 有獎評測:平頭哥RISC-V低功耗板——RVB2601