EZ-USB FX3でEndPointを追加する
特電Artix-7ボード上のEZ-USB FX3でUSB-JTAGを実現するため、FX3にEndPointを追加することにしました。
現在、このFX3はEndpoint1(と0x81)をそれぞれOUT用とIN用のSlaveFIFOに使っています。これらのEndPointのデータはハード的に処理されてFPGAに送られるので、CPUが関与できません。
そこで、CPUが自由に操作できるEndPointを2つ追加しようというわけです。
そのためにはまず、ディスクリプタを書き換えて、EndPointを2つ作りました。1個分を示します。SuperSpeedだとcompanion descriptorというのが必要なようです。
/* Endpoint descriptor for producer EP */ 0x07, /* Descriptor size */ CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ 0x04, /* Endpoint address and description */ CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ 0x00,0x04, /* Max packet size = 1024 bytes */ 0x00, /* Servicing interval for data transfers : 0 for bulk */ /* Super speed endpoint companion descriptor for producer EP */ 0x06, /* Descriptor size */ CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ 0x00, /* Max no. of packets in a burst : 0: burst 1 packet at a time */ 0x00, /* Max streams for bulk EP = 0 (No streams) */ 0x00,0x00, /* Service interval for the EP : 0 for bulk */
エンドポイントの番号は、OUT用が0x04、IN用が0x88にしました。
それから、ファームウェアでもEndPointの設定をします。
CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg)); epCfg.enable = CyTrue; epCfg.epType = CY_U3P_USB_EP_BULK; epCfg.burstLen = 1; epCfg.streams = 0; epCfg.pcktSize = size; CyU3PSetEpConfig(CY_FX_EP_MYPRODUCER, &epCfg); // 0x04 EP4 OUT
CyU3PSetEpConfig(CY_FX_EP_MYCONSUMER, &epCfg); // 0x88 EP8 IN
ここで、CY_FX_EP_MYPRODUCERは0x04、CY_FX_EP_MYCONSUMERは0x88です。
これで、EndPoint4と8が作られ、それぞれBulkOUTとBuldInとしてセットアップされます。
次にdmaの設定を行います。CPUがデータを処理したい場合でもDMAを使います。
FX3ではProducerとかConsumerという用語が出てくるのですが、BulkInの場合はProducerはCPUのプログラムで、ConsumerはUSBのEndPointです。
// EndPoint EP8 INの設定 dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE; dmaCfg.notification = 0; dmaCfg.cb = NULL; dmaCfg.prodHeader = 0; dmaCfg.prodFooter = 0; dmaCfg.consHeader = 0; dmaCfg.prodAvailCount = 0; dmaCfg.prodSckId = CY_U3P_CPU_SOCKET_PROD; dmaCfg.consSckId = CY_FX_EP_MYCONSUMER_SOCKET; // <= CY_U3P_UIB_SOCKET_CONS_8 apiRetStatus = CyU3PDmaChannelCreate (&glChHandleBulkLpOut, CY_U3P_DMA_TYPE_MANUAL_OUT, &dmaCfg); CyU3PUsbFlushEp(CY_FX_EP_MYCONSUMER); // 0x88 apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleBulkLpOut, 0);
prodSckIdとconsSckIdは上のリストのように設定します。consSckIdに設定されているCY_FX_EP_MYCONSUMER_SOCKETは、マクロ定義でCY_U3P_UIB_SOCKET_CONS_8にしています。こうすると、8番のEndPointに割り当てられるのだと思います。
ちなみに、USB Managerで見るとこうなっています。
これをどうやって使うかというと、SlFifoAppThread_Entryの中で、
int i; CyU3PDmaChannelGetBuffer (&glChHandleBulkLpOut, &inBuf_p, CYU3P_WAIT_FOREVER); for(i=0;i<1024;i++) { inBuf_p.buffer[i] = i; } CyU3PDmaChannelCommitBuffer (&glChHandleBulkLpOut, 1024, 0);
とするようです。つまり、バッファが空きになるまで待って、空いたらデータを詰めて、それからCommitします。
上のリストはBulkInの場合ですが、BulkOutの場合も同様でCyU3PDmaChannelCommitBufferの代わりにCyU3PDmaChannelDiscardBufferを使えばよいようです。
これで、EndPointに入ったデータをCPUで読んだり、CPUからデータをセットしてINパケットに乗せることができるようになります。
| 固定リンク
コメント