2013-02-17 71 views
5

我正在爲STM32F3 mc(STM32F3-Discovery)編寫嵌入式代碼。我需要輸出一些數據到UART,並且我正在使用DMA,因爲這使我可以專注於傳感器讀取和數據處理,而不是等待字節傳輸完成。然而,問題是,我必須結合:格式化打印到循環緩衝區

  1. 格式化輸出(即一些由printf函數)
  2. 多個連續打印(出現以前的打印完成之前)

,所以我想着一個循環緩衝器。但我不認爲我知道如何讓sprintf尊重緩衝區的末尾,並繼續寫入緩衝區的開始。我當然可以創建另一個臨時緩衝區,在那裏打印,然後逐字節複製,但對我來說看起來並不高雅。

+1

有趣的需求,但我不認爲你會比'格式化成臨時緩衝區,然後通過適當的複製功能複製到循環緩衝區'做得更好。 – 2013-02-17 21:48:41

回答

2

一個解決方案可以是實現您自己的sprintf,它可以使用環形緩衝區。不幸的是,這不會幫助你解決一個更基本的問題:如果你的環形緩衝器已滿並且你調用sprintf,你會怎麼做?

如果你的內存情況能負擔得起,我建議對這個問題的另一個解決方案:

的想法是基於緩衝區的兩個鏈接列表(一個列表中的空閒緩衝區,一個列表,發送隊列) 。緩衝區大小相同,因此可以存儲最差情況下的長度字符串。這些緩衝區構建了一個簡單的堆,其中分配/解除分配只是將空閒隊列或傳輸列表中的元素出隊/隊列化。

擁有相同大小的緩衝區可以確保您不會遭受像「checkerboarding」這樣的外部碎片效應,同時動態分配內存。爲這項工作建立自己的堆也將使您完全控制可用於傳輸任務的總緩衝區大小。

如下我能想象這樣運行:

  1. 您可以從空閒列表中分配一個緩衝區的數據呈現到。
  2. 使用渲染功能(suchas的sprintf)呈現在緩衝區中的數據
  3. 附加到被髮送到傳輸隊列中的數據(並在必要時觸發傳輸)

對於DMA傳輸你處理傳輸結束IRQ。在那裏你移動剛轉移到「空閒列表」的緩衝區,並設置隊列中下一個緩衝區的傳輸。

該解決方案將不會是內存efficientiest但運行效率好,你只寫內存一次,分配/釋放僅讀取/存儲的指針地方。當然,您必須確保您的應用程序和IRQ之間的競爭條件不會分配/釋放。

也許這個想法給你一個靈感來解決您的要求。你可以近似

1

的方法之一是分配您的printf緩衝高達2倍的ringbuffer的大小,然後用上半年的環形緩衝區。檢測溢出,將後半部分的溢出複製回到前部(環部分)。這樣的事情:

void xprintf(const char *format, ...) 
{ 
    int written; 
    va_list args; 
    va_start(args, format); 
    written = vsnprintf(buffer, HALF_BUFFER_SIZE, format, args); 
    va_end(args); 
    if (buffer + written > bufferStart + HALF_BUFFER_SIZE) 
    { // time to wrap 
    int overflow = (buffer + written) - (bufferStart + HALF_BUFFER_SIZE); 
    memmove(bufferStart, bufferStart + HALF_BUFFER_SIZE, overflow; 
    buffer = bufferStart + overflow; 
    } 
}