[modernAVR] AVR-DU の USB周辺機能考察

AVR-LIBC + `AVR-Dx_DFP.2.4.286.atpack` で、AVR64DU28 と AVR64DU32 のエンジニアサンプル向け暫定対応ビルドが可能になった。実に2年以上のペンディング期間を経て、待望の AVR-DUシリーズ登場である。

え？何が待望だったかって？ 現時点ではまだ他に何も公開情報もない状態だが、取り下げ前のブリーフノート（2021/08）と、今回公開された ATpack中の ATDFファイルからは以下の情報が読み取れる。

> [DS40002328-A : AVR® DU Product Brief](https://askn37.github.io/documents/AVR-DU-Product-Brief-DS40002328.pdf)

- AVR-Dxシリコンベースの新世代AVR（俗に modernAVR）
  - フラッシュ搭載量は 16/32/64KiB の 3グレード。
  - 最大動作周波数は内蔵RCを使っても動作電圧 1.8V〜5.5V 全域で 32 MHz。オールインワン 8-bit MCU では最速クラスの 32 MIPS。
    - 当時のブリーフノートでは最大 24 MHzだが、公開 ATDFでは訂正されたように見える。まあ 32 MHz / 28 MHz 駆動は公称 5V駆動時制限でも不思議ではないが。
    - 逆に最低動作周波数は 512 Hz。それで使用する変人はそうそういないが、できるものはできる。
- USB 2.0 `Full-Speed`インタフェース周辺機能を 1器内蔵
  - 内蔵PLLで最低 48 MHz駆動。約3V以上投入時に動作可能。
    - 外付けの LDO を追加すれば、CPU動作電圧は独立して 1.8V〜5.5V で自由に設定できる。異なる電圧の GPIO と混在接続ができるのは大きなメリットだ。
  - 16 個のエンドポイントアドレス、1つの入力エンドポイントと 1つの出力エンドポイントがあり、最大 31エンドポイントに対応
  - 割込負荷とソフトウェア介入を軽減するマルチパケット転送。
- 製造予定外囲器
  - 32-pin VQFN 5x5 mm and TQFP 7x7 mm
  - 28-pin VQFN 4x4 mm, SPDIP and SSOP
  - 20-pin SOIC
  - 14-pin SOIC
    - なんと 14ピンと 20ピンの SOICパッケージ（Flash 32KiB以下）の製造予定（当時）がある。これは旧 ATMEL時代にも無かったトピックで、12年以上昔の PIC18F14K50 と競合する。残念ながら超小型の TSSOP/VQFN が予定されていないものの「C/C++言語でUSB変換器を自作できる」パッケージ選択肢が拡大する。

これだけだとまだちょっとそこまで便利だとは思わないだろう。だが AVR-Dx 譲りの周辺機能も備えているのがミソで；

- 周辺機能間通知のための EVSYS。
- 4組の LUT を備えた CCL。
- 2組の USART
  - 動作モード: 同期、非同期、単線駆動、RS-485、LIN従装置、SPI主装置、および IrDA
  - 分周比発生器、自動ボーレート、フレーム開始検出

> ※ USART1は（USB周辺機能で GPIO数が減らされたため）TxD:RxD ペア線のみ使用可能。

__EVSYS！CCL！同期！RS-485！__ これがあるから良いのだよ。全4本の信号線を使う 同期全二重 RS-485 をソフトウェア記述介在なしで駆動できる強力な MCUは、modernAVR の他にないからだ。このニッチなニーズと USB-IF が同時使用できる MCUを探すと、AVR-DU 一択なのである。

## ヘッダファイルから USB 周辺機能を読み解く

新たに追加された USB周辺機能だが、当然まだ世に出てない製品なので __LUFA Library__ のサポートなども下手したら数年先だ。__MPLAB X__ のサンプルコード追加もまだ先かもしれない。従ってこれを使おうと思ったら結構低階層レベルから USBドライバーを自力で書き起こせってことになる。まあ予習ということで、`ioavr64du32.h`から関係情報を紐解いてみよう。

### 割り込みベクターテーブル周辺

割り込みベクターテーブルには、二つのUSB周辺機能割り込みが設けられた。名称からして前者は「フレーム開始(SOF)、休止、再開、バス リセット、CRC、下溢れ、上溢れ不能応答、異常割り込み」を、後者は「転送単位処理完了割り込み」に使われるはずだ。

```cpp
/* USB0 interrupt vectors */
#define USB0_BUSEVENT_vect_num  7
#define USB0_BUSEVENT_vect      _VECTOR(7)  /*  */
#define USB0_TRNCOMPL_vect_num  8
#define USB0_TRNCOMPL_vect      _VECTOR(8)  /*  */
```

### FUSEビット周辺

`FUSE_SYSCFG1`に`FUSE_USBSINK`ビットが存在する。USB周辺機能用の内蔵レギュレータ起動設定だ。このビットは AVR_DB/DD では`FUSE_MVSYSCFG`であった位置にある。従って従来の複電圧対応機能と排他的に USB周辺機能が実装されたことが推測できる。

```cpp
/* Fuse Byte 6 (SYSCFG1) */
#define FUSE_SUT0      (unsigned char)_BV(0)  /* Startup Time Bit 0 */
#define FUSE_SUT1      (unsigned char)_BV(1)  /* Startup Time Bit 1 */
#define FUSE_SUT2      (unsigned char)_BV(2)  /* Startup Time Bit 2 */
#define FUSE_USBSINK   (unsigned char)_BV(3)  /* USB Voltage Regulator Current Sink Enable */
#define FUSE6_DEFAULT  (0x8)
#define FUSE_SYSCFG1_DEFAULT  (0x8)
```

### SYSCFG 周辺

`REVID`の近くに、`VUSBCTRL`IOレジスターが見つかる。これは`FUSE_USBSINK`ビットと対応する、内蔵レギュレーターの制御設定に違いない。

```cpp
/* System Configuration Registers */
// typedef struct SYSCFG_struct
register8_t VUSBCTRL;  /* USB Voltage System Control */

/* SYSCFG - System Configuration Registers */
#define SYSCFG_VUSBCTRL  _SFR_MEM8(0x0F06)

/* SYSCFG - System Configuration Registers */
/* SYSCFG.VUSBCTRL  bit masks and bit positions */
#define SYSCFG_USBVREG_bm  0x01  /* USB Voltage Regulator bit mask. */
#define SYSCFG_USBVREG_bp     0  /* USB Voltage Regulator bit position. */
```

### CLKCTRL 周辺

`CLKCTRL`には`USBPLLSTATUS`レジスタが追加されている。`PLL`でファイル内検索すると全部で以下の情報しか見つからないので、PLL位相同期回路は USB周辺機能からの自動制御だろう。

```cpp
/* Clock controller */
// typedef struct CLKCTRL_struct
register8_t USBPLLSTATUS;  /* PLL Status */

/* CLKCTRL - Clock controller */
#define CLKCTRL_USBPLLSTATUS  _SFR_MEM8(0x0085)

/* CLKCTRL.USBPLLSTATUS  bit masks and bit positions */
#define CLKCTRL_PLLS_bm  0x01  /* PLL Stable bit mask. */
#define CLKCTRL_PLLS_bp     0  /* PLL Stable bit position. */
```

### EVSYS ジェネレーター周辺

EVSYSチャネルジェネレーターに二つのイベントが設けられている。これはコメントにある通り USB周辺機能でバイト入出力が発生すると イベント発火させられることを示している。従って単純な応用として、EVSYS を介して直接 RX/TX インジケーター用 LED を明滅させることが出来ると理解できる。

```cpp
/* Channel generator select */
// typedef struct EVSYS_struct
EVSYS_CHANNEL_USB0_RX_gc = (0xC4<<0),  /* USB0 Data Byte Received */
EVSYS_CHANNEL_USB0_TX_gc = (0xC5<<0)   /* USB0 Data Byte Transmitted */
```

### USB 周辺機能レジスタ

流石に、USB 周辺機能レジスターは大量にある。コメントもインデントが整形されておらず読みづらかったから多少整形した。__ATmega32U2__ などが 4エンドポイント対応だったのに比べると、ステータスレジスタの数も4倍！

```cpp
#define USB_MAX_ENDPOINTS  16

/* USB Device Controller EP */
typedef struct USB_EP_struct
{
    register8_t STATUS;       /* Endpoint Status */
    register8_t CTRL;         /* Endpoint Control */
    _WORDREGISTER(CNT);       /* Endpoint Byte Count */
    _WORDREGISTER(DATAPTR);   /* Endpoint Data Pointer */
    _WORDREGISTER(MCNT);      /* Endpoint Multi-packet Byte Count */
} USB_EP_t;

/* USB Device Controller EP_PAIR */
typedef struct USB_EP_PAIR_struct
{
    USB_EP_t OUT;             /* USB Device Controller OUT */
    USB_EP_t IN;              /* USB Device Controller IN */
} USB_EP_PAIR_t;

/* USB Device Controller EP_TABLE */
typedef struct USB_EP_TABLE_struct
{
    register8_t FIFO[32];     /* FIFO Pointer Table */
    USB_EP_PAIR_t EP[16];     /* USB Device Controller EP */
    _WORDREGISTER(FRAMENUM);  /* FRAMENUM count */
} USB_EP_TABLE_t;

/* USB Device Controller STATUS */
typedef struct USB_STATUS_struct
{
    register8_t OUTCLR;  /* Endpoint n OUT Status Clear */
    register8_t OUTSET;  /* Endpoint n OUT Status Set */
    register8_t INCLR;   /* Endpoint n IN Status Clear */
    register8_t INSET;   /* Endpoint n IN Status Set */
} USB_STATUS_t;

/* USB Device Controller */
typedef struct USB_struct
{
    register8_t CTRLA;           /* Control A */
    register8_t CTRLB;           /* Control B */
    register8_t BUSSTATE;        /* Bus State */
    register8_t ADDR;            /* Address */
    register8_t FIFOWP;          /* FIFO Write Pointer */
    register8_t FIFORP;          /* FIFO Read Pointer */
    _WORDREGISTER(EPPTR);        /* Endpoint Configuration Table Pointer */
    register8_t INTCTRLA;        /* Interrupt Control A */
    register8_t INTCTRLB;        /* Interrupt Control B */
    register8_t INTFLAGSA;       /* Interrupt Flags A */
    register8_t INTFLAGSB;       /* Interrupt Flags B */
    register8_t reserved_1[52];
    USB_STATUS_t STATUS[16];     /* USB Device Controller STATUS */
} USB_t;

#define USB0 (*(USB_t *) 0x0C00) /* USB Device Controller */

/* USB (USB0) - USB Device Controller */
#define USB0_CTRLA            _SFR_MEM8(0x0C00)
#define USB0_CTRLB            _SFR_MEM8(0x0C01)
#define USB0_BUSSTATE         _SFR_MEM8(0x0C02)
#define USB0_ADDR             _SFR_MEM8(0x0C03)
#define USB0_FIFOWP           _SFR_MEM8(0x0C04)
#define USB0_FIFORP           _SFR_MEM8(0x0C05)
#define USB0_EPPTR            _SFR_MEM16(0x0C06)
#define USB0_EPPTRL           _SFR_MEM8(0x0C06)
#define USB0_EPPTRH           _SFR_MEM8(0x0C07)
#define USB0_INTCTRLA         _SFR_MEM8(0x0C08)
#define USB0_INTCTRLB         _SFR_MEM8(0x0C09)
#define USB0_INTFLAGSA        _SFR_MEM8(0x0C0A)
#define USB0_INTFLAGSB        _SFR_MEM8(0x0C0B)
#define USB0_STATUS0_OUTCLR   _SFR_MEM8(0x0C40)
#define USB0_STATUS0_OUTSET   _SFR_MEM8(0x0C41)
#define USB0_STATUS0_INCLR    _SFR_MEM8(0x0C42)
#define USB0_STATUS0_INSET    _SFR_MEM8(0x0C43)
// Omission //
#define USB0_STATUS15_OUTCLR  _SFR_MEM8(0x0C7C)
#define USB0_STATUS15_OUTSET  _SFR_MEM8(0x0C7D)
#define USB0_STATUS15_INCLR   _SFR_MEM8(0x0C7E)
#define USB0_STATUS15_INSET   _SFR_MEM8(0x0C7F)
```

続けて各レジスターの定義ビットを眺めるが、`#define`ショートカットは膨大なので一部要約して引用する。

```cpp
/* Data Size default select */
typedef enum USB_BUFSIZE_DEFAULT_enum
{
    USB_BUFSIZE_DEFAULT_BUF8_gc  = (0x00<<0),  /* 8 bytes buffer size */
    USB_BUFSIZE_DEFAULT_BUF16_gc = (0x01<<0),  /* 16 bytes buffer size */
    USB_BUFSIZE_DEFAULT_BUF32_gc = (0x02<<0),  /* 32 bytes buffer size */
    USB_BUFSIZE_DEFAULT_BUF64_gc = (0x03<<0)  /* 64 bytes buffer size */
} USB_BUFSIZE_DEFAULT_t;

/* Data Size isochronous select */
typedef enum USB_BUFSIZE_ISO_enum
{
    USB_BUFSIZE_ISO_BUF8_gc    = (0x00<<0),  /* 8 bytes buffer size */
    USB_BUFSIZE_ISO_BUF16_gc   = (0x01<<0),  /* 16 bytes buffer size */
    USB_BUFSIZE_ISO_BUF32_gc   = (0x02<<0),  /* 32 bytes buffer size */
    USB_BUFSIZE_ISO_BUF64_gc   = (0x03<<0),  /* 64 bytes buffer size */
    USB_BUFSIZE_ISO_BUF128_gc  = (0x04<<0),  /* 128 bytes buffer size */
    USB_BUFSIZE_ISO_BUF256_gc  = (0x05<<0),  /* 256 bytes buffer size */
    USB_BUFSIZE_ISO_BUF512_gc  = (0x06<<0),  /* 512 bytes buffer size */
    USB_BUFSIZE_ISO_BUF1023_gc = (0x07<<0)  /* 1023 bytes buffer size */
} USB_BUFSIZE_ISO_t;

/* Data Toggle select */
typedef enum USB_TOGGLE_enum
{
    USB_TOGGLE_DATA0_gc = (0x00<<0),  /* DATA0 PID in next transaction */
    USB_TOGGLE_DATA1_gc = (0x01<<0)  /* DATA1 PID in next transaction */
} USB_TOGGLE_t;

/* Endpoint type select */
typedef enum USB_TYPE_enum
{
    USB_TYPE_DISABLE_gc = (0x00<<6),  /* Endpoint Disabled */
    USB_TYPE_CONTROL_gc = (0x01<<6),  /* Control */
    USB_TYPE_BULKINT_gc = (0x02<<6),  /* Bulk or Interrupt */
    USB_TYPE_ISO_gc     = (0x03<<6)  /* Isochronous */
} USB_TYPE_t;

/* Endpoint Direction select */
typedef enum USB_DIR_enum
{
    USB_DIR_OUT_gc = (0x00<<3),  /* OUT Endpoint */
    USB_DIR_IN_gc  = (0x01<<3)  /* In Endpoint */
} USB_DIR_t;

/* USB - USB Device Controller */
/* USB.STATUS  bit masks and bit positions */
#define USB_TOGGLE_bm    0x01  /* Data Toggle bit mask. */
#define USB_BUSNAK_bm    0x02  /* Data Buffer NAK bit mask. */
#define USB_STALLED_bm   0x08  /* EP Stalled bit mask. */
#define USB_EPSETUP_bm   0x10  /* EP Setup Complete bit mask. */
#define USB_TRNCOMPL_bm  0x20  /* Transaction Complete bit mask. */
#define USB_UNFOVF_bm    0x40  /* Underflow/Overflow EP bit mask. */
#define USB_CRC_bm       0x80  /* CRC Error bit mask. */

/* USB.CTRL  bit masks and bit positions */
#define USB_BUFSIZE_DEFAULT_gm  0x03  /* Data Size default group mask. */
#define USB_DOSTALL_bm          0x04  /* Endpoint will respond with STALL bit mask. */
#define USB_BUFSIZE_ISO_gm      0x07  /* Data Size isochronous group mask. */
#define USB_TCDSBL_bm           0x08  /* TRNCOMPL Interrupt Disable bit mask. */
#define USB_AZLP_bm             0x10  /* Automatic zero length packet bit mask. */
#define USB_MULTIPKT_bm         0x20  /* Multipacket transfer enable bit mask. */
#define USB_TYPE_gm             0xC0  /* Endpoint type group mask. */

/* USB.CNT  bit masks and bit positions */
#define USB_CNT_gm      0xFFFF  /* Endpoint Byte Count group mask. */
#define USB_CNT_0_bm    (1<<0)  /* Endpoint Byte Count bit 0 mask. */
// Omission //
#define USB_CNT_15_bm  (1<<15)  /* Endpoint Byte Count bit 15 mask. */

/* USB.DATAPTR  bit masks and bit positions */
#define USB_DATAPTR_gm  0xFFFF  /* Endpoint data pointer group mask. */


/* USB.MCNT  bit masks and bit positions */
#define USB_MCNT_gm     0xFFFF  /* Multi-packet byte count group mask. */

/* USB.FIFO  bit masks and bit positions */
#define USB_DIR_bm        0x08  /* Endpoint Direction bit mask. */
#define USB_EPNUM_gm      0xF0  /* Endpoint Number group mask. */

/* USB.FRAMENUM  bit masks and bit positions */
#define USB_FRAMENUM_gm       0x7FF  /* Frame Number group mask. */
#define USB_FRAMENUM_0_bm    (1<<0)  /* Frame Number bit 0 mask. */
// Omission //
#define USB_FRAMENUM_10_bm  (1<<10)  /* Frame Number bit 10 mask. */
#define USB_FRAMEERR_bm      0x8000  /* Frame Error bit mask. */


/* USB.OUTCLR  bit masks and bit positions */
#define USB_RMWSTATUS_gm  0xFF  /* Read-Modify-Write Endpoint STATUS group mask. */

/* USB.OUTSET  bit masks and bit positions */
/* USB_RMWSTATUS  is already defined. */

/* USB.INCLR  bit masks and bit positions */
/* USB_RMWSTATUS  is already defined. */

/* USB.INSET  bit masks and bit positions */
/* USB_RMWSTATUS  is already defined. */


/* USB.CTRLA  bit masks and bit positions */
#define USB_MAXEP_gm      0x0F  /* Maximum Endpoint Address group mask. */
#define USB_STFRNUM_bm    0x10  /* Store Frame Number Enable bit mask. */
#define USB_FIFOEN_bm     0x20  /* Transaction Complete FIFO Enable bit mask. */
#define USB_ENABLE_bm     0x80  /* USB Enable bit mask. */

/* USB.CTRLB  bit masks and bit positions */
#define USB_ATTACH_bm     0x01  /* Attach bit mask. */
#define USB_GNAK_bm       0x02  /* Respond with NAK on all Endpoints bit mask. */
#define USB_GNAUTO_bm     0x04  /* Set GNAK Automatically after SETUP bit mask. */
#define USB_URESUME_bm    0x08  /* Send Upstream Resume bit mask. */

/* USB.BUSSTATE  bit masks and bit positions */
#define USB_BUSRST_bm     0x01  /* Bus Reset bit mask. */
#define USB_SUSPENDED_bm  0x02  /* Bus Suspended bit mask. */
#define USB_DRESUME_bm    0x04  /* Downstram Resume bit mask. */
/* USB_URESUME  is already defined. */
#define USB_WTRSM_bm      0x10  /* Wait Time Resume bit mask. */

/* USB.ADDR  bit masks and bit positions */
#define USB_ADDR_gm       0x7F  /* Device Address group mask. */

/* USB.FIFOWP  bit masks and bit positions */
#define USB_FIFOWP_gm     0x1F  /* FIFO Write Pointer group mask. */

/* USB.FIFORP  bit masks and bit positions */
#define USB_FIFORP_gm     0x1F  /* FIFO Read Pointer group mask. */

/* USB.EPPTR  bit masks and bit positions */
#define USB_EPPTR_gm    0xFFFF  /* Endpoint Configuration Table Pointer group mask. */

/* USB.INTCTRLA  bit masks and bit positions */
#define USB_OVF_bm        0x02  /* Overflow Interrupt Enable bit mask. */
#define USB_UNF_bm        0x04  /* Underflow Interrupt Enable bit mask. */
/* USB_STALLED  is already defined. */
#define USB_RESET_bm      0x10  /* Reset Interrupt Enable bit mask. */
#define USB_RESUME_bm     0x20  /* Resume Interrupt Enable bit mask. */
#define USB_SUSPEND_bm    0x40  /* Suspend Interrupt Enable bit mask. */
#define USB_SOF_bm        0x80  /* Start Of Frame Interrupt Enable bit mask. */

/* USB.INTCTRLB  bit masks and bit positions */
#define USB_SETUP_bm      0x01  /* SETUP Transaction Complete Interrupt Enable bit mask. */
#define USB_GNDONE_bm     0x02  /* GNAK Operation Done Interrupt Enable bit mask. */
/* USB_TRNCOMPL   is already defined. */

/* USB.INTFLAGSA  bit masks and bit positions */
/* USB_OVF        is already defined. */
/* USB_UNF        is already defined. */
/* USB_STALLED    is already defined. */
/* USB_RESET      is already defined. */
/* USB_RESUME     is already defined. */
/* USB_SUSPEND    is already defined. */
/* USB_SOF        is already defined. */

/* USB.INTFLAGSB  bit masks and bit positions */
/* USB_SETUP      is already defined. */
/* USB_GNDONE     is already defined. */
#define USB_RMWBUSY_bm  0x04  /* RMW Busy Flag bit mask. */
/* USB_TRNCOMPL   is already defined. */
```

## USBCTRL レジスターマップ

パッと見て簡単にわかるわけないので、レジスタービット定義を表にして整理する。

```plain
$0C00 USB0 (BASE) USB_struct
                   7       6       5        4       3       2        1       0
                +------+-------+--------+-------+-------+-------+---------+------+
  $00 CTRLA     |ENABLE|   -   | FIFOEN |STFRNUM|         MWXEP  3-0             |
                +------+-------+--------+-------+-------+-------+---------+------+
  $01 CTRLB     |  -   |   -   |   -    |   -   |URESUME|GNAUTO |  GNCAK  |ATTACH|
                +------+-------+--------+-------+-------+-------+---------+------+
  $02 BUSSTATE  |  -   |   -   |   -    |   -   | WTRSM |DRESUME|SUSPENDED|BUSRST|
                +------+-------+--------+-------+-------+-------+---------+------+
  $03 ADDR      |  -   |                                   ADDR  6-0             |
                +------+-------+--------+-------+-------+-------+---------+------+
  $04 FIFOWP    |  -   |   -   |   -    |                FIFOWP  4-0             |
                +------+-------+--------+-------+-------+-------+---------+------+
  $05 FIFORP    |  -   |   -   |   -    |                FIFORP  4-0             |
                +------+-------+--------+-------+-------+-------+---------+------+
  $06 EPPTRL    |                                         EPPTR  7-0             |
     (EPPTR)    +------+-------+--------+-------+-------+-------+---------+------+
  $07 EPPTRH    |                                         EPPTR 15-8             |
                +------+-------+--------+-------+-------+-------+---------+------+
  $08 INTCTRLA  | SOF  |SUSPEND| RESUME | RESET |STALLED|  UNF  |   OVF   |  -   |
                +------+-------+--------+-------+-------+-------+---------+------+
  $09 INTCTRLB  |  -   |   -   |TRNCOMPL|   -   |   -   |   -   |  GNDONE |SETUP |
                +------+-------+--------+-------+-------+-------+---------+------+
  $0A INTFLAGSA | SOF  |SUSPEND| RESUME | RESET |STALLED|  UNF  |   OVF   |  -   |
                +------+-------+--------+-------+-------+-------+---------+------+
  $0B INTFLAGSB |      |       |TRNCOMPL|       |       |RMWBUSY|  GNDONE |SETUP |
                +------+-------+--------+-------+-------+-------+---------+------+

$0C40 USB0_STATUS0 (BASE) USB_STATUS_struct[16]
                   7       6       5        4       3       2        1       0
                +------+-------+--------+-------+-------+-------+---------+------+
  $00 OUTCLR    |                         RMWSTATUS 7-0                          |
                +------+-------+--------+-------+-------+-------+---------+------+
  $01 OUTSET    |                         RMWSTATUS 7-0                          |
                +------+-------+--------+-------+-------+-------+---------+------+
  $02 INCLR     |                         RMWSTATUS 7-0                          |
                +------+-------+--------+-------+-------+-------+---------+------+
  $03 INSET     |                         RMWSTATUS 7-0                          |
                +------+-------+--------+-------+-------+-------+---------+------+
```

`INTCTRLA[AB]`と`INTFLAGS[AB]`については、割り込みベクターが`USB0_BUSEVENT`と`USB0_TRNCOMPL`の2本なので、まあなんとなくわかる。

`OVF`は Isochronous エンドポイントのオーバーフロー、`UNF`は同アンダーフローだろう。`STALLED`は "Stalled"（停止中）の意味で、LED制御とは関係ない。

`USB0_STATUS[0-15]`は GPIOで使われる "Read-Modify-Write" レジスター構成そのまんまだが、、、これはちょっと用途がわからない。いや、エンドポイントテーブルの SRAMは USBCTRLが常に握ってるからアトミックなのか。STATUS バイトは直接 ST命令で書き換えたりせず、これを使ってビット操作しろってことだ。だから名称が`USB0_STATUS[0-15]`なのね。

## USB エンドポイント設定テーブル

`USB_EP_TABLE_t` 構造体は内部レジスターに直接紐付いていない、エンドポイント構造体を表す。`USB_EP_t`と`USB_EP_PAIR_t`とが入れ子になっており、全長は 290 byte（`32 + (8 x 2) x 16 + 2`） ある。SRAM内で確保して`USB0_EPPTR`ワードレジスタにその構造体アドレスを渡すはずだ。

> この種の実装での 静的 SRAM領域確保は `".initN"` で SP を変更し、C/C++言語の管理範囲外に置くと楽。

```
USB_EP_TABLE_t
                   7       6       5        4       3       2        1       0
                +------+-------+--------+-------+-------+-------+---------+------+
$0000 FIFO[32]  |           EPNUM 3-0           |  DIR  |   -   |    -    |  -   |
                +------+-------+--------+-------+-------+-------+---------+------+

USB_EP_PAIR_t[16]

  EP_t OUT0     +------+-------+--------+-------+-------+-------+---------+------+
$0020 STATUS    | CRC  |UNFPVF |TRNCOMPL|EPSETUP|STALLED|   -   | BUSNAK  |TOGGLE|
                +------+-------+--------+-------+-------+-------+---------+------+
                |              |        |       |       |  USB_BUFSIZE_ISO 3-0   |
      CTRL      |   TYPE 1-0   |MULTIPKT| AZLP  |TCDSBL +-------+---------+------+
                |              |        |       |       |DOSTALL|BUFSIZE_DEFAULT |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                            CNT  7-0                            |
      CNT[HL]   +------+-------+--------+-------+-------+-------+---------+------+
                |                            CNT 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                        DATAPTR  7-0                            |
    DATAPTR[HL] +------+-------+--------+-------+-------+-------+---------+------+
                |                        DATAPTR 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                           MCNT  7-0                            |
      MCNT[HL]  +------+-------+--------+-------+-------+-------+---------+------+
                |                           MCNT 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+

  EP_t IN0      +------+-------+--------+-------+-------+-------+---------+------+
$0028 STATUS    | CRC  |UNFPVF |TRNCOMPL|EPSETUP|STALLED|   -   | BUSNAK  |TOGGLE|
                +------+-------+--------+-------+-------+-------+---------+------+
                |              |        |       |       |  USB_BUFSIZE_ISO 3-0   |
      CTRL      |   TYPE 1-0   |MULTIPKT| AZLP  |TCDSBL +-------+---------+------+
                |              |        |       |       |DOSTALL|BUFSIZE_DEFAULT |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                            CNT  7-0                            |
      CNT[HL]   +------+-------+--------+-------+-------+-------+---------+------+
                |                            CNT 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                        DATAPTR  7-0                            |
    DATAPTR[HL] +------+-------+--------+-------+-------+-------+---------+------+
                |                        DATAPTR 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+
                |                           MCNT  7-0                            |
      MCNT[HL]  +------+-------+--------+-------+-------+-------+---------+------+
                |                           MCNT 15-8                            |
                +------+-------+--------+-------+-------+-------+---------+------+

$0030 OUT1 + IN1                                                                 |
      :                                                                          |
$0110 OUT15 + IN15                                                               |

                +--------+-----+--------+-------+-------+-------+---------+------+
$0120           |                                           FRAMENUM  7-0        |
    FRAMENUM[HL]+--------+-----+--------+-------+-------+-------+---------+------+
$0121           |FRAMEERR|  -  |   -    |   -   |  -    |   FRAMENUM 10-8        |
                +--------+-----+--------+-------+-------+-------+---------+------+
```

`FIFO`は`FIFOWP`と`FIFORP`の各 5ビットのインデックスで管理される 32バイトの リングバッファだね。完了エンドポイントの番号と入出力方向を記憶しておいてくれるものだ。その実体が`USB_EP_PAIR_t[16]`にある。`FIFO`のビットマスクは詰まるところそのテーブル番地の意味を説明しているだけで、下位 3bitがゼロで埋まってるなら単純なインデックスオフセットだと解釈できる。

普通の`DATA`レジスターが見当たらないと思ったら、ここに`DATAPTR`ワード定義がある。あれ、っていうことはこれ DMA転送やってくれるの？と思って __XMEGA AU手引書__ を確認したら、かなりの部分が似ているように見える。なるほど、これはこの時の実装がベースなのかな。だが`Low-Speed`切り替えフラグっぽいのやキャリブレーションレジスタがないので互換性があるようでもない・・・そういやブリーフノートに`Low-Speed`の言及がないな。え、__これは`Full-Speed`専用なのか！__ 時代だなあ・・・

## まとめ

- __XMEGA AU手引書__ が重要な参考になりそう。
- USB 1.1 `Low-Speed`が必要なら不適。
- __MPLAB X__ で応用実装サンプルコードが公開されるまでは、USB 実装は手が出ないかも（＾＾；

> けど試験用基板の設計はできる。

## 関連リンク

リンク先は全て __AVR.jp__ の オンライン PDF。 

- [XMEGA AU手引書](https://avr.jp/user/DS/PDF/xmegaAU.pdf)
- [AVR4900 : ASF - USB装置階層](https://avr.jp/user/AN/PDF/AN2681.pdf)
- [AVR4901 : ASF - USB供給者クラス応用](https://avr.jp/user/AN/PDF/AVR4901.pdf)
- [AVR4902 : ASF - USB複合装置](https://avr.jp/user/AN/PDF/AVR4902.pdf)
- [AVR4903 : ASF - USB装置HIDマウス応用](https://avr.jp/user/AN/PDF/AVR4903.pdf)
- [AVR4904 : ASF - USB装置HIDキーボード応用](https://avr.jp/user/AN/PDF/AVR4904.pdf)
- [AVR4905 : ASF - USB標準HID装置](https://avr.jp/user/AN/PDF/AVR4905.pdf)
- [AVR4907 : ASF - USB装置CDC応用](https://avr.jp/user/AN/PDF/AVR4907.pdf)
- [AVR4920 : ASF - USB装置階層 - 適合と性能係数](https://avr.jp/user/AN/PDF/AVR4920.pdf)
- [AVR4921 : ASF - USB装置階層 - ASF V1とV2間の違い](https://avr.jp/user/AN/PDF/AVR4921.pdf)
- [AVR4950 : ASF - USBホスト階層](https://avr.jp/user/AN/PDF/AVR4950.pdf) -- 残りの AVR495x : ASF V2 シリーズは未出／未訳。

## Copyright and Contact

Twitter(X): [@askn37](https://twitter.com/askn37) \
BlueSky Social: [@multix.jp](https://bsky.app/profile/multix.jp) \
GitHub: [https://github.com/askn37/](https://github.com/askn37/) \
Product: [https://askn37.github.io/](https://askn37.github.io/)

Copyright (c) askn (K.Sato) multix.jp \
Released under the MIT license \
[https://opensource.org/licenses/mit-license.php](https://opensource.org/licenses/mit-license.php) \
[https://www.oshwa.org/](https://www.oshwa.org/)