SAM3マイコンは、それぞれのデバイスに固有の128ビットの識別番号を持っています。以前からUSBのDevice Desciptor中のシリアル番号情報を生成するために使ってみようと考えていたのですが、すっかり後回しになってしまっていました。これまでシリアル番号情報は
001
で決め打にしてあったのですが、いい加減ちゃんと生成しようと思い立ち作業開始。
まずはシリアル番号の読み出し動作を確認します。SAM3SではEEFCというフラッシュのコントローラに対してコマンドを送ることで0x80000番地からの16バイトに格納されている128ビットの識別番号が読み出せる仕掛けになっています。この読み出し処理をおこなうプログラムを書けばいいわけですが、フラッシュのコントローラを操作する都合上、そのコードはフラッシュから実行することができません。したがって、SRAMの空間にプログラムコードを配置して、実行してやる必要があります。
gccでの具体的な記述としては section attributeを指定することで、コードを配置するセクションを指定することができます。そして、指定したセクションをRAMに配置するようにリンカスクリプトを用意しなければなりませんが、調べてみるとCrossWorksではあらかじめ.fastというセクションがコードをRAMに配置するために用意されていました。そのため、次のようにコードを書いてビルドするだけでOK.
#define STUI 0x0e
#define SPUI 0x0f
/* To obtain 128bit uniq identifier, code needs to run out of RAM */
void get_uniq_identifier() __attribute__((section(".fast")));
void get_uniq_identifier(uint8_t *uniqId)
{
uint8_t *pUniq = (uint8_t *)0x80000;
int i;
ctl_global_interrupts_disable();
EFC->EEFC_FMR |= EEFC_FMR_SCOD;
EFC->EEFC_FCR = EEFC_FCR_FKEY(0x5a) | STUI;
while (EFC->EEFC_FSR & EEFC_FSR_FRDY) ;
for (i = 0; i < 16; i++)
*uniqId++ = *pUniq++;
EFC->EEFC_FCR = EEFC_FCR_FKEY(0x5a) | SPUI;
while ((EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0) ;
EFC->EEFC_FMR &= ~EEFC_FMR_SCOD;
ctl_global_interrupts_enable();
}
セクション名が.fastになっているのは、SRAMからは0ウエイトで命令を読み出して実行できるからでしょうね。実際に読み出してみるとこうなりました。
128ビットの番号とは言っても、実際にはアスキーコードで7桁の数字が2つ入っているようなので、文字列としても表示してみました。まぁ、これはこれで便利かもしれませんが。。
USB Device Descriptorのシリアル番号情報としては、こうして得られた固有識別番号の下7桁部分をそのまま借用することにしてみました。Mac OS Xにつなげてみると、次のようにttyデバイスが作成されました。
違うチップでも試してみましたが6桁分はちゃんと識別番号が反映されるのに、どういうわけか最後の一桁がいつも1になってしまいます。うーん、どうしてだろう? シリアル番号情報が正しく送信できていないように推測できますが、ubuntuにつないでlsusbした時にはちゃんと正しくシリアル番号が見えていました。