概要

ミーハーなので最近はIoTみたいなことをしている。簡単な無線通信をしたくて、TWESDKを使ってMonoStick(旧TocoStick)で動くプログラムを書いているのだが、動的にメモリを確保する方法を見つけるのに苦労したので記録しておく。

やりたいこと

いわゆるmallocを使った動的なメモリ確保。よくあるやつ。

#include <stdlib.h>
#include <string.h>

void func(void) {
    uint8 bufLen = 16;
    char* buf = (char*)malloc((sizeof char) * buflen); // ここ
    strcpy(buf, "foobar");
}

TWESDKで開発していると、上記をやってもmallocがメモリを確保してくれず、常にNULLを返してくる。

解決方法

#include <stdlib.h>
#include <string.h>
#include <Heap.h>

void func(void) {
    uint8 bufLen = 16;
    char* buf = (char*)pvHeap_Alloc(NULL, bufLen, true); // ここ
    strcpy(buf, "foobar");
}

Heap.hTWESDK/516x/Components/Boot/Include/にある。TWESDKに含まれるサンプルはここをインクルードディレクトリに含めていないので、Makefileを書き換えてここを読めるようにする必要がある。

おそらく多くの人がサンプルに沿ってTWESDK/Wks_ToCoNet/[PROJECT_NAME]/[PROJECT_NAME]/Source/にメインとなるソースを置いて作業していると思うので、これに沿って説明する。この場合、TWESDK/Wks_ToCoNet/[PROJECT_NAME]/[PROJECT_NAME]/Build/Makefile 内の該当箇所に以下の一行を追加する。

# インクルードディレクトリのみを追加指定したい場合は、-I オプションとして
# INCFLAGS に追加します。
# 
#INCFLAGS += -I../dummy
INCFLAGS += -I$(COMPONENTS_BASE_DIR)/Boot/Include

以上で動的にメモリを確保できる。

pvHeap_Alloc()のシグネチャはvoid *pvHeap_Alloc(void *pvPointer, uint32 u32BytesNeeded, bool_t bClear) となってるわけだけど、pvPointerに何を渡したら良いのか正直分からない。とりあえずNULLにしたら動いたんだけど...。あと、たぶんbCleartrueにしたら確保したメモリをゼロクリアしてくれるんだと思うけど未検証。

感想

mallocはOSのシステムコールを呼んでメモリを確保するわけだけれども、こういったマイコンだとOSが載っているわけでは無いし、直接マイコン(今回の場合はJN5164)のAPIを叩いてメモリを確保しないとだめですよーということなのだと思うけど、組み込み系はよくわからない...。

ところで、TWESDKは特定のディレクトリ構成でないと動かなかったり、コードがシステムハンガリアンだったり、関数名や変数名内の単語が省略されまくってたりで読みづらくてかなりつらい。その上にドキュメントが不足しているしでさらにつらい。

今回、サンプルを見ても動的にメモリを確保しているものが無かったし、Webで探しても(そもそも情報が少ないのだけど)事例が見つからなくて死ぬかと思った。仕方なくソース頑張って追ったりgrepしてたらなんだかんだで解決したので良かった。最初そのまんまmallocでgrepしてたのだけど、途中でふとheapでgrepすることを思いついたので優勝した。

とりあえずメモリを確保できたものの、この方法が正しいのか分からないのでもし詳しい方がいらっしゃたら教えていただけるとありがたい。