Newlib
https://sourceware.org/newlib/
ARMの組み込み環境向け標準Cライブラリ RedHat社が管理している フリーのCライブラリ,ライセンスはGPLではいのでこれを組み込んでもソースコードの公開義務は発生しない.
CubeMXでFreeRTOSプロジェクト作った際のNewlibまわりに生じる問題
FreeRTOS Helpers
BUG: CubeMX FreeRTOS projects corrupt memory
http://www.nadler.com/embedded/newlibAndFreeRTOS.html
bug-cubemx-freertos-projects-corrupt-memory
newlib/malloc locking mechanism to be thread-safe
mallocを始めとしたnewlibの関数はリエントラントであり,実装するプラットフォーム側でリエントラントを含めた以下の環境を用意する必要あり
- スレッドセーフ
- スレッドのコンテキストスイッチ
- malloc,freeなどのメモリ管理
Newlibはここに示すサポート関数が必要.
ここで言うサポート関数とはsbrk
やwrite
,read
のこと.
UARTなどのペリフェラルの関数にUARTの送受信関数を定義すると,newlibにより提供されるprintf
がUARTを使って入出力のやり取りをできるようになる.
stm32の場合,syscalls.c
やsysmem.c
というファイルでこれを定義してやる.
malloc
の最も内側のルーチンでmalloc_r
が呼び出される.(これはどんな環境で計測したんだろうか,多分Corex-Mのマイコン(stm32)と思うけど)
- newlib 3.0.0はmain関数が呼び出されるより前に
malloc
を呼び出さない. - 単純な整数だと
spritf
はmalloc
を呼ばない %f
を使うとspritf
はmalloc
を4回読んで計200byteくらい容量をもっていく(各タスクやスレッドで初めてsprintf
呼び出した時)printf
や同様のIO関数はIO制御構造体に428byte割り当てる.
newlibをリエントラントにするために必要なもの
- malloc/free/etcの同時実行を保護する.同時実行を保護するためにnewlbには
__malloc_lock
,__malloc_unlock
hook(フック,鈎,横取り,止めおておく)するものが必要. - RTOSを使ったアプリケーションで,newlib内のmallocもといそれらの関数を完全に置き換えない場合.スレッドの安全性のために上記のlock,unlockの関数を提供する必要がある.
- スレッドごとにリエントラントな構造をもつ.作成,初期化,クリーンアップするメカニズムに加えて,コンテキストが変わるごとに正しいリエントラント構造を示すように
_impure_ptr
を切り替える.←これが呼び出し先のポインタみたいなもの?
CubeMXで生成されたプロジェクトのバグ
- CubeMXでFreeRTOSのコードを生成すると
__malloc_lock
,__malloc_unlock
が提供されないのでmallocやfreeのリエントラントをサポートしていない.これらの関数を直接読んだり,STのUSBデバイスを使おうとすると(初期の際に中でmalloc()を呼び出しているので)メモリが破壊される. malloc
などの関数のためにsbrk
が使うヒープ領域が必要になるため,newlibは空き領域が必要になる.けどSTのFreeRTOSのsbrk
は動かない.このためスケジューラ起動後のmalloc
要求は動かない.
FreeRTOSでのリエントラント
configUSE_NEWLIB_REENTRANT
というオプションがFreeRTOSにある。
configUSE_NEWLIB_REENTRANT
configUSE_NEWLIB_REENTRANTは、その値が1に設定されている場合、newlibの reent構造が作成された各タスクに割り当てられます。注Newlibのサポートは一般的な需要に含まれていますが、FreeRTOSメンテナー自身は使用していません。FreeRTOSは、結果として生じるnewlib操作に対して責任を負いません。ユーザーはnewlibに精通している必要があり、必要なスタブのシステム全体の実装を提供する必要があります。(執筆時点で)現在のnewlib設計は、ロックを提供する必要があるシステム全体のmalloc()を実装していることに注意してください。
newlibをリエントラントにするための構造体をタスクごとにくっつける.タスクごとに96byte追加.さらにここにnewlibが追加で割り当てる・ →その分それぞれのタスクのメモリ領域は増やして確保しとけってこと? 機能説いてはは用意してあるけどFreeRTOS側でそのへん責任取らないからよしなに使ってねというニュアンスを感じる.
FreeRTOSはheap_3
を使用するときに標準ライブラリmalloc()
とfree()
を使う.このためconfigTOTAL_HEAP_SIZE
の設定は意味をなさない.ヒープのサイズはリンカで定義.
ここでいう標準ライブラリとはツールチェインに付属している標準ライブラリということでいいのだろうか.
ARMならGNU Arm Embedded Toolchainに付属しているnewlibで提供されているmalloc()
とfree()
が使われるということ?
heap_3
はFreeRTOSのスケジューラを一時的に止めることでmalloc
やfree
のスレッドセーフを担保する.
GNU Arm Embedded ToolchainはNewlibが実は2種類ある?
- Newlib
- Newlib-nano
--specs=nano.specs
newlib-nanoをリンク,だけどこれは実装が入っていない.
よって下のどちらかで実装を一緒にリンクする必要がある模様.
--specs=nosys.specs
libnosys,リンカエラーが出ないようにするだけの最低限の実装. -lnosys
をMakefileで追加しておく必要あり?
--specs=rdimon.specs
semihosting環境,ホスト環境に標準ライブラリの諸々の処理は任せる.なのでホスト環境にをつないでないと動かないので注意
STのその後の対応
CubeMXのいくつかのバージョンから、用意されているUSBスタック内でのメモリ確保がmallocによる動的なものではなく配列による静的な確保によるものに更新されている
Concern on the usage of malloc() on USB Host MSC driver library
STM32F446 DFU : Hard fault with free() function