先日、STM32CubeMXがアップデートされたのと時期を同じくして、STM32CubeProgrammerも更新されていました。USB経由だとSTM32F7とつながらない問題も修正されたようなので、これを機会に以前から気になっていた問題を調べて見ることにしました。
上図は、Nucleo-F767 をDFUでブートして、STM32CubeProgrammerと接続した状態です。USBで接続した後、Device Descriptorや Config DescriptorからSerial NumberやらFirmware Versionやらの情報を引き出していることがわかります。ところが、Device ID (0x0451)をどうやって調べているのかが不明でした。Device Descriptorにも Config Descriptorにも該当する情報は含まれていません。もしかして隠しDescriptorが存在しており、それをアクセスして取得しているのではないかとも想像して、Wiresharkを使ってUSBパケットをキャプチャして調べてみたのですが、やはりそのような情報を取得している様子はありませんでした。一体、どうやってDevice IDを取得しているのか?
Device IDはレジスタを読みだして取得することができます。Enumeration時のDescrptorの読み出しではなく、DFUのプロトコルを使って取得しているのかもしれないと思い調べてみましたが、やはりそのような形跡はありません。STM32の UART BootloaderプロトコルではGet IDというコマンドが用意されており、このコマンドを用いることでDevice IDが取得できるようになっているのですが、DFUのプロトコルにはそのようなコマンドは用意されていないのです。
なぜ、Device IDの取得方法にこだわっているのかというと、それは自分でDFUローダを作った場合にもSTM32CubeProgrammerを使いたいと思ったからです。実際に、CubeMXを使ってUSB DFUを使用するプロジェクトを作成して動かしてみると、次の図に示すようにDevice IDが不明であるためにSTM32CubeProgrammerが使用できないのです。
このように、CubeMXで作成したUSB DFUが、そのままではCubeProgrammerでは動作しない訳で、ツール群としての整合性が取れていないではありませんか。Device IDさえ取得できればCubeProgrammerでの書き込みが行えるはずなのに。。。。
いろいろと調べてみましたが、結論としてはUSBのenumeration手順やDFUプロトコルではDevice ID情報を取得していないということがわかりました。それでは、CubeProgrammerはどうやって、Device IDを知ることができるのか? 直接情報を取得していないからには、他の情報からDevice IDを推定しているとしか思えません。
そこで思い当たったのが、DFUのInterface中に存在するDescriptorです。
DFUブートした時には、上図の上半分のようにFlashの構成だけでなく、Option ByteやOTP Memoryの領域の情報もAlt Interfaceとして表現されています。それに対して、CubeMXで機械的に生成しただけのDFUコードでは、Flash構成を表現するAlt Interfaceしか現れていないのです。もしかすると、CubeProgrammerはこれらの Alt Interfaceが表現するフラッシュメモリの構成からDevice IDを推定しているのかもしれません。
推測を確かめるために、DFUのスタックを改造して複数のAlt Interfaceをサポートできるようにして、Option Bytesを表現するAlt InterfaceのDescriptorを追加。もちろん、該当部分のFlashの読み出しもできるようにコードを追加してやりました。すると....
予想した通り、CubeProgrammer はFlashとOption Bytesの構成方法からDevice IDを推定しているようです。これで自作のDFU Loaderを使った場合でもCubeProgrammerでの書き込みが行えるようになりました。
上図は、Nucleo-F767 をDFUでブートして、STM32CubeProgrammerと接続した状態です。USBで接続した後、Device Descriptorや Config DescriptorからSerial NumberやらFirmware Versionやらの情報を引き出していることがわかります。ところが、Device ID (0x0451)をどうやって調べているのかが不明でした。Device Descriptorにも Config Descriptorにも該当する情報は含まれていません。もしかして隠しDescriptorが存在しており、それをアクセスして取得しているのではないかとも想像して、Wiresharkを使ってUSBパケットをキャプチャして調べてみたのですが、やはりそのような情報を取得している様子はありませんでした。一体、どうやってDevice IDを取得しているのか?
Device IDはレジスタを読みだして取得することができます。Enumeration時のDescrptorの読み出しではなく、DFUのプロトコルを使って取得しているのかもしれないと思い調べてみましたが、やはりそのような形跡はありません。STM32の UART BootloaderプロトコルではGet IDというコマンドが用意されており、このコマンドを用いることでDevice IDが取得できるようになっているのですが、DFUのプロトコルにはそのようなコマンドは用意されていないのです。
なぜ、Device IDの取得方法にこだわっているのかというと、それは自分でDFUローダを作った場合にもSTM32CubeProgrammerを使いたいと思ったからです。実際に、CubeMXを使ってUSB DFUを使用するプロジェクトを作成して動かしてみると、次の図に示すようにDevice IDが不明であるためにSTM32CubeProgrammerが使用できないのです。
このように、CubeMXで作成したUSB DFUが、そのままではCubeProgrammerでは動作しない訳で、ツール群としての整合性が取れていないではありませんか。Device IDさえ取得できればCubeProgrammerでの書き込みが行えるはずなのに。。。。
いろいろと調べてみましたが、結論としてはUSBのenumeration手順やDFUプロトコルではDevice ID情報を取得していないということがわかりました。それでは、CubeProgrammerはどうやって、Device IDを知ることができるのか? 直接情報を取得していないからには、他の情報からDevice IDを推定しているとしか思えません。
そこで思い当たったのが、DFUのInterface中に存在するDescriptorです。
DFUブートした時には、上図の上半分のようにFlashの構成だけでなく、Option ByteやOTP Memoryの領域の情報もAlt Interfaceとして表現されています。それに対して、CubeMXで機械的に生成しただけのDFUコードでは、Flash構成を表現するAlt Interfaceしか現れていないのです。もしかすると、CubeProgrammerはこれらの Alt Interfaceが表現するフラッシュメモリの構成からDevice IDを推定しているのかもしれません。
推測を確かめるために、DFUのスタックを改造して複数のAlt Interfaceをサポートできるようにして、Option Bytesを表現するAlt InterfaceのDescriptorを追加。もちろん、該当部分のFlashの読み出しもできるようにコードを追加してやりました。すると....
予想した通り、CubeProgrammer はFlashとOption Bytesの構成方法からDevice IDを推定しているようです。これで自作のDFU Loaderを使った場合でもCubeProgrammerでの書き込みが行えるようになりました。