*クールなテープのアイデアを提供してくれた@grafalexに感謝します
USBが好きな人はいません
プログラミングマイクロコントローラーの研究を進めていくうちに、USBは間違いなく非回路デバイス接続のメインインターフェイスであるため、マスターする必要があることに気づきました。しかし、オープンワールドには関連資料が少ないことがわかりました。さまざまなフォーラムを分析した後、プロジェクトでUSBが人気がない理由を次のように定式化しました。
@jaiprakashは、USBデバイスの必須のVID値を多額のお金で購入する必要があることを思い出させました。
ほとんどのプロジェクトで高速データ送信の必要性がありません。
おなじみのUARTインターフェースと比較して、規格自体と開発が非常に複雑です。既製のUSB <-> UARTアダプターをデバイスに追加する方が安価です。
Windows / Linuxドライバー開発スキルの欠如。
その結果、開発者はほとんどUARTを使用することを好みます(ハードウェアコンバーターを介して、またはせいぜい、コードがCubeMXによって正常に生成されるVCPデバイスを作成することによって)。私は、C ++言語テンプレートを使用するラインを継続しながら、少なくとも基本的なレベルでUSBを理解しようと決心しました。この投稿では、デバイスエンドポイント間でリソース(つまり、バッファメモリとレジスタ)を割り当てるための適用方法について説明します。
重複の問題
USBデバイスを実装するプログラムの主な要素はエンドポイントです。ホストは特定のエンドポイントと通信します。デバイスには、制御が行われる番号0のエンドポイント、列挙段階でのさまざまな記述子の要求、アドレスの割り当て、構成の選択、およびその他すべての制御が含まれている必要があります。エンドポイントの概念の詳細と、原則としてUSBの基本的な知識は、microsinリソースの「USBin NutShell」の翻訳に記載されています(作業を行ってくれた人たちに感謝します。彼らは非常に便利な仕事をしました)。 。
Stm32F0/F1 - Packet Memory Area (PMA), . USB- , , . , K, "" K+1, ... , N. ( N - ). : 100% .
, ( ) , runtime compile-time, :
. . (ADDRn_TX, COUNTn_TX, ADDRn_RX, COUNTn_RX), , runtime .
, EPnR ( , , ).
:
(0..16).
(Control, Interrupt, Bulk, Isochronous).
(In, Out).
.
, .
:
(EPnR).
.
( ).
: N . , , :
, , .
, .
"" .
:
template<typename... AllEndpoints,
typename... BidirectionalAndBulkDoubleBufferedEndpoints,
typename... RxEndpoints,
typename... BulkDoubleBufferedTxEndpoints>
class EndpointsManagerBase<TypeList<AllEndpoints...>,
TypeList<BidirectionalAndBulkDoubleBufferedEndpoints...>,
TypeList<RxEndpoints...>,
TypeList<BulkDoubleBufferedTxEndpoints...>>
{
//
using AllEndpointsList = TypeList<AllEndpoints...>;
///
static const auto BdtSize = 8 * (EndpointEPRn<GetType_t<sizeof...(AllEndpoints) - 1, AllEndpointsList>, AllEndpointsList>::RegisterNumber + 1);
///
template<typename Endpoint>
static constexpr uint32_t BufferOffset = BdtSize + OffsetOfBuffer<TypeIndex<Endpoint, AllEndpointsList>::value, AllEndpointsList>::value;
///
template<typename Endpoint>
static constexpr uint32_t BdtCellOffset =
EndpointEPRn<Endpoint, AllEndpointsList>::RegisterNumber * 8
+ (Endpoint::Type == EndpointType::Control
|| Endpoint::Type == EndpointType::ControlStatusOut
|| Endpoint::Type == EndpointType::BulkDoubleBuffered
|| Endpoint::Direction == EndpointDirection::Out
|| Endpoint::Direction == EndpointDirection::Bidirectional
? 0
: 4);
/// USB
static const uint32_t BdtBase = PmaBufferBase;
public:
/// ""
template<typename Endpoint>
using ExtendEndpoint =
typename Select<Endpoint::Type == EndpointType::Control || Endpoint::Type == EndpointType::ControlStatusOut,
ControlEndpoint<Endpoint,
typename EndpointEPRn<Endpoint, TypeList<AllEndpoints...>>::type,
PmaBufferBase + BufferOffset<Endpoint>, // TxBuffer
PmaBufferBase + BdtCellOffset<Endpoint> + 2, // TxCount
PmaBufferBase + BufferOffset<Endpoint> + Endpoint::MaxPacketSize, // RxBuffer
PmaBufferBase + BdtCellOffset<Endpoint> + 6>, //RxCount
typename Select<Endpoint::Direction == EndpointDirection::Bidirectional,
BidirectionalEndpoint<Endpoint,
typename EndpointEPRn<Endpoint, TypeList<AllEndpoints...>>::type,
PmaBufferBase + BufferOffset<Endpoint>, // TxBuffer
PmaBufferBase + BdtCellOffset<Endpoint> + 2, // TxCount
PmaBufferBase + BufferOffset<Endpoint> + Endpoint::MaxPacketSize, // RxBuffer
PmaBufferBase + BdtCellOffset<Endpoint> + 6>, //RxCount
... //
void>::value>::value;
static void Init()
{
memset(reinterpret_cast<void*>(BdtBase), 0x00, BdtSize);
//
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<AllEndpoints>)) = BufferOffset<AllEndpoints>), ...);
//
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<BidirectionalAndBulkDoubleBufferedEndpoints> + 4)) = (BufferOffset<BidirectionalAndBulkDoubleBufferedEndpoints> + BidirectionalAndBulkDoubleBufferedEndpoints::MaxPacketSize)), ...);
// COUNTn_RX (Rx, Out)
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<RxEndpoints> + 2)) = (RxEndpoints::MaxPacketSize <= 62
? (RxEndpoints::MaxPacketSize / 2) << 10
: 0x8000 | (RxEndpoints::MaxPacketSize / 32) << 10)), ...);
// COUNTn_RX
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<BidirectionalAndBulkDoubleBufferedEndpoints> + 6)) = (BidirectionalAndBulkDoubleBufferedEndpoints::MaxPacketSize <= 62
? (BidirectionalAndBulkDoubleBufferedEndpoints::MaxPacketSize / 2) << 10
: 0x8000 | (BidirectionalAndBulkDoubleBufferedEndpoints::MaxPacketSize / 32) << 10)), ...);
// COUNTn_RX Tx (, , )
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<BulkDoubleBufferedTxEndpoints> + 2)) = 0), ...);
((*(reinterpret_cast<uint16_t*>(BdtBase + BdtCellOffset<BulkDoubleBufferedTxEndpoints> + 6)) = 0), ...);
}
};
template<typename Endpoints>
using EndpointsManager = EndpointsManagerBase<SortedUniqueEndpoints<Endpoints>,
typename Sample<IsBidirectionalOrBulkDoubleBufferedEndpoint, SortedUniqueEndpoints<Endpoints>>::type,
typename Sample<IsOutEndpoint, SortedUniqueEndpoints<Endpoints>>::type,
typename Sample<IsBulkDoubleBufferedTxEndpoint, SortedUniqueEndpoints<Endpoints>>::type>;
template<typename... Endpoints>
using EndpointsInitializer = EndpointsManagerBase<SortedUniqueEndpoints<TypeList<Endpoints...>>,
TypeList<>,
TypeList<>,
TypeList<>>;
, :
EndpointEPRn - , EPnR . : . , .
BufferOffset - , . , N 0, ..., N-1.
SortedUniqueEndpoints - , + . USB /, Device.
IsBidirectionalOrBulkDoubleBufferedEndpoint, IsOutEndpoint, IsBulkDoubleBufferedTxEndpoint - .
:
using DefaultEp0 = ZeroEndpointBase<64>;
using LedsControlEpBase = OutEndpointBase<1, EndpointType::Interrupt, 64, 32>;
//
using EpInitializer = EndpointsInitializer<DefaultEp0, LedsControlEpBase>;
// EpInitializer .
// , ,
using Ep0 = EpInitializer::ExtendEndpoint<DefaultEp0>;
using LedsControlEp = EpInitializer::ExtendEndpoint<LedsControlEpBase>;
// , .
using Hid = HidInterface<0, 0, 0, 0, HidDesc, LedsControlEp>;
using Config = HidConfiguration<0, 250, false, false, Report, Hid>;
using MyDevice = Device<0x0200, DeviceClass::InterfaceSpecified, 0, 0, 0x0483, 0x5711, 0, Ep0, Config>;
Device , :
template<
...
typename _Ep0,
typename... _Configurations>
class DeviceBase : public _Ep0
{
using This = DeviceBase<_Regs, _IRQNumber, _ClockCtrl, _UsbVersion, _Class, _SubClass, _Protocol, _VendorId, _ProductId, _DeviceReleaseNumber, _Ep0, _Configurations...>;
using Endpoints = Append_t<typename _Configurations::Endpoints...>;
using Configurations = TypeList<_Configurations...>;
using EpBufferManager = EndpointsManager<Append_t<_Ep0, Endpoints>>;
// Device
using EpHandlers = EndpointHandlers<Append_t<This, Endpoints>>;
public:
static void Enable()
{
_ClockCtrl::Enable();
//
EpBufferManager::Init();
C++ :
, , , ( HID-, , 2400 ).
, .
, , . "" USB.
* . C++, , .
USB . , - - , USB, , - . , . , USB , , "" , .
この投稿は、一般的なUSBに関連するライブラリの一部ではなく、エンドポイント間でリソースを分散するための小さいながらも重要なモジュールに向けられました。質問やコメントをいただければ幸いです。
あなたは(はんだ付けミニUSBとディスコがありますので、私は、唯一のF072RBT6に、これまでUSBをテストしてい)コード全体を表示することができ、ここで。少なくともMKシリーズF0とF1では夏までにUSBを打ち負かしたいと思っています。私はF4を見ました-すべてがそこに涼しく(OTGサポートがあります)そして難しいです。