MCC(Microchip Code Configuration)を使ってUSBホスト機能を実装しようとしていきなりハマった件。
以下のようにUSBHostTasks()
というAPIが用意されている。メインループ内で適切なタイミングでコールすると、接続されたUSBデバイスとの接続処理などをよろしくやってくれる。(データのやり取りはまた別)
// main.c
int main(void)
{
SYSTEM_Initialize();
USBHostInit(0);
while (1)
{
USBHostTasks();
:
}
return -1;
}
ほかのサンプルソースなどを見てもおおかた上のようなコードになっているので、どんなものかコールしてみたところ、エラーが発生してしまって正しく動作しない。
デバッグ実行して問題個所を確認すると、以下のコードで問題が発生していた。pEndpoint0
に対して、USB_MALLOCでメモリを動的に確保してポインタに設定している。
// usb_host.c
bool USBHostInit( unsigned long flags )
{
// Allocate space for Endpoint 0. We will initialize it in the state machine,
// so we can reinitialize when another device connects. If the Endpoint 0
// node already exists, free all other allocated memory.
if (usbDeviceInfo.pEndpoint0 == NULL)
{
if ((usbDeviceInfo.pEndpoint0 = (USB_ENDPOINT_INFO*)USB_MALLOC( sizeof(USB_ENDPOINT_INFO) )) == NULL)
{
printf("[USBHostInit]: Cannot allocate for endpoint 0.\r\n");
return false;
}
USB_MALLOCは単純にmalloc
をマクロ化しているだけである。XC8コンパイラでは、動的にメモリを確保することはできないが、XC16からできるらしい。知りませんでした。ただ私の環境だと、malloc()がNULLを返してしまってエラーになっている模様。もちろんデータメモリも十分に空きがある。(USB_ENDPOINT_INFOは34バイトぐらい)
#ifndef USB_MALLOC
#define USB_MALLOC(size) malloc(size)
#endif
ヒープサイズを指定する
通常C言語のmallocやC++などのnew演算子で確保されるデータは、ヒープ領域に確保される。通常のPCで動作するプログラム作成では、このサイズを気にする必要はほとんどない。そういえば、PICはどうなんだ?と調べたところ、XC16コンパイラの設定やドキュメントにありました。
ここの「10.13 動的メモリ割り当て」に記述があった。規定値はゼロで、mallocなど動的に確保する場合は、指定しろと。
ちなみにMLAのホストサンプルプログラムのコンパイラ設定にもちゃっかりヒープサイズが指定されてました。(2000バイトほど)
真似して指定したところ、malloc()
でちゃんと領域確保できるようになった。
「ちゃんと教えてくれないと分からん!」と思ったけど、そういえばワーニングが表示されてました。。
そういうことだったのね。。