newlib

Newlib

https://sourceware.org/newlib/

ARMの組み込み環境向け標準Cライブラリ RedHat社が管理している フリーのCライブラリ,ライセンスはGPLではいのでこれを組み込んでもソースコードの公開義務は発生しない.

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はここに示すサポート関数が必要. ここで言うサポート関数とはsbrkwrite,readのこと.
UARTなどのペリフェラルの関数にUARTの送受信関数を定義すると,newlibにより提供されるprintfがUARTを使って入出力のやり取りをできるようになる. stm32の場合,syscalls.csysmem.cというファイルでこれを定義してやる.

mallocの最も内側のルーチンでmalloc_rが呼び出される.(これはどんな環境で計測したんだろうか,多分Corex-Mのマイコン(stm32)と思うけど)

  • newlib 3.0.0はmain関数が呼び出されるより前にmallocを呼び出さない.
  • 単純な整数だとspritfmallocを呼ばない
  • %fを使うとspritfmallocを4回読んで計200byteくらい容量をもっていく(各タスクやスレッドで初めてsprintf呼び出した時)
  • printfや同様のIO関数はIO制御構造体に428byte割り当てる.

newlibをリエントラントにするために必要なもの

  • malloc/free/etcの同時実行を保護する.同時実行を保護するためにnewlbには__malloc_lock,__malloc_unlockhook(フック,鈎,横取り,止めおておく)するものが必要.
  • RTOSを使ったアプリケーションで,newlib内のmallocもといそれらの関数を完全に置き換えない場合.スレッドの安全性のために上記のlock,unlockの関数を提供する必要がある.
  • スレッドごとにリエントラントな構造をもつ.作成,初期化,クリーンアップするメカニズムに加えて,コンテキストが変わるごとに正しいリエントラント構造を示すように_impure_ptrを切り替える.←これが呼び出し先のポインタみたいなもの?

CubeMXで生成されたプロジェクトのバグ

  1. CubeMXでFreeRTOSのコードを生成すると__malloc_lock,__malloc_unlockが提供されないのでmallocやfreeのリエントラントをサポートしていない.これらの関数を直接読んだり,STのUSBデバイスを使おうとすると(初期の際に中でmalloc()を呼び出しているので)メモリが破壊される.
  2. mallocなどの関数のためにsbrkが使うヒープ領域が必要になるため,newlibは空き領域が必要になる.けどSTのFreeRTOSのsbrkは動かない.このためスケジューラ起動後のmalloc要求は動かない.

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のスケジューラを一時的に止めることでmallocfreeのスレッドセーフを担保する.

GNU Arm Embedded ToolchainはNewlibが実は2種類ある?

  • Newlib
  • Newlib-nano

--specs=nano.specsnewlib-nanoをリンク,だけどこれは実装が入っていない. よって下のどちらかで実装を一緒にリンクする必要がある模様.

--specs=nosys.specs libnosys,リンカエラーが出ないようにするだけの最低限の実装. -lnosysをMakefileで追加しておく必要あり?

--specs=rdimon.specs semihosting環境,ホスト環境に標準ライブラリの諸々の処理は任せる.なのでホスト環境にをつないでないと動かないので注意

CubeMXのいくつかのバージョンから、用意されているUSBスタック内でのメモリ確保がmallocによる動的なものではなく配列による静的な確保によるものに更新されている
Concern on the usage of malloc() on USB Host MSC driver library
STM32F446 DFU : Hard fault with free() function

参考文献

  • newlib.txt
  • 最終更新: 2023/12/03
  • by yuqlid