- #include <usb/hal/numicro> // USB HAL(Hardware Abstract Layer),新唐 Numicro
- #include <usb/adc> // USB Audio Device Class
- #include <numicro/nuc/sfr/i2s> // I2S Register
- void i2s_start();
- using namespace usb; // 使用 usb 名空间
- using namespace adc; // 使用 usb adc(audio device class)名空间
- template<typename PARENT, uint8_t ID> // 定式
- struct it_t : it_impl_t< // 定义 Input Terminal 类模板
- it_t, PARENT, ID, // 定式
- 0 // 指定 String ID,为 0 表示不定义
- > {
- using input_t = typename it_t::it_impl_t; // 为本类指定一个“别名”,方便在定义 Entities 集合时标识
- };
- template<typename PARENT, uint8_t ID>
- struct ot_t : ot_impl_t< // 定义 Output Terminal 类模板
- ot_t, PARENT, ID,
- 0
- > {
- using output_t = typename ot_t::ot_impl_t;
- };
- template<typename PARENT> // 定式
- struct tuple_t : entity_tuple_t< // 定义 Entities 集合类,其中可以加入以上定义的各个 Entity 类模板
- PARENT, // 定式
- it_t, // 已定义的类模板
- ot_t // 已定义的类模板
- > {
- using typename tuple_t::entity_tuple_t::input_t; // 导入各个 Terminal 的别名
- using typename tuple_t::entity_tuple_t::output_t; // ...
- struct __attribute__((packed)) entities_descriptor_t // 定义 Entities 集合的描述符
- : td_t< // 定义 Terminal 描述符
- input_t, // 使用已导入的别名,用于确定本 Entity ID,
- USB_STREAMING, // 指定 Terminal 类型
- cluster_t< // 定义 Channel(声道) Cluster,其中可以加入任意声道
- 0, // 指定 String ID
- cluster_channel_t::LEFT_FRONT, // 指定 Left Front
- cluster_channel_t::RIGHT_FRONT // 指定 Right Front
- >
- >,
- td_t< // 定义 Terminal 描述符
- output_t, // 使用已导入的别名,用于确定本 Entity ID,
- SPEAKER, // 指定 Terminal 类型
- input_t // 指定本输出 Terminal 的数据来源
- > { };
- };
- template<typename PARENT, uint32_t PARAM> // 定式
- class ep_t : public streaming::data::out::ep_impl_t< // 定义 Audio Data Endpoint(数据端点)类
- ep_t, PARENT, PARAM, // 定式
- core::transfer::iso::sync_t::SYNC, // 指定端点的 sync 类型
- false, // 指定 bmAttributes 的 sampling frequency,参见 USB Audio 规范
- false, // 指定 bmAttributes 的 pitch,参见 USB Audio 规范
- false, // 指定 bmAttributes 的 MaxPacketsOnly, 参见 USB Audio 规范
- streaming::UNDEFINED, // 指定 bLockDelayUnits, 参见 USB Audio 规范
- 0 // 指定 wLockDelay, 参见 USB Audio 规范
- > { };
- #define SAMPLE_RATE 16000
- struct { // 定义 Audio Data 缓冲区
- union {
- struct {
- uint8_t wrpos; // 写缓冲指针
- uint8_t rdpos; // 读缓冲指针
- };
- uint16_t pos;
- };
- uint32_t data[64 * 2 / sizeof(uint32_t)]; // 缓冲数据区,包含两个 packet
- } buffer;
- template<typename PARENT, uint32_t PARAM> // 定式
- class ifc_t : public control::if_impl_t< // 定义 AudioControl Interface(控制接口)类
- ifc_t, PARENT, PARAM, // 定式
- 0 // 指定 String ID
- > { };
- template<typename PARENT, uint32_t PARAM> // 定式
- class ifs_t : public streaming::if_impl_t< // 定义 AudioStream Interface(流接口)类
- ifs_t, PARENT, PARAM, // 定式
- 0, // 指定 String ID
- typename tuple_t<PARENT>::input_t, // 指定连接到的 terminal
- ep_t // 指定本接口包含的数据端点(暂不支持同步端点)
- > {
- public:
- template<uint8_t N> using ep_t = typename core::elem_t<N, typename ifs_t::tuple_t>::type;
- struct __attribute__((packed)) descriptor_t // 定义流接口描述符
- : core::descriptor_t<core::descriptor::std_if_t<ifs_t, 0, 0, 0>>, // Alternative 0
- core::descriptor_t<core::descriptor::std_if_t<ifs_t, 1, 0, 0>, // Alternative 1
- streaming::pcm_descriptor_t< // 定义 PCM 描述符
- ifs_t, // 定式
- 1, // bDelay
- 2, // bNrChannels
- 2, // bSubframeSize
- 16, // bBitResolution
- true, // 指定固定采样
- SAMPLE_RATE // 采样率
- >,
- ep_t<0> // 指定 Alternative 1 所包含的 Endpoint
- > { };
- __INLINE bool set_interface(uint_fast8_t alternative) // Set Interface 处理
- {
- if (alternative) {
- first = true;
- this->read(buffer.data, 64); // 读 packet
- buffer.pos = 0;
- }
- return true;
- }
- __INLINE void read_complete(uint_fast16_t length) // 读 packet 完成
- {
- uint_fast8_t pos = buffer.wrpos;
- pos ^= 64 / sizeof(uint32_t);
- buffer.wrpos = pos;
- this->read(&buffer.data[pos], 64); // 读 packet
- if (first) {
- first = 0;
- i2s_start(); // 启动 I2S
- }
- }
- private:
- uint8_t first;
- };
- template<typename PARENT, uint32_t PARAM> // 定式
- class fn_t : public adc::fn_impl_t< // 定义 Function
- fn_t, PARENT, PARAM, // 定式
- 0, // 指定 String ID
- 0x100, // 指定 bcdADC,Release Number
- ifc_t, // 已定义的 AudioControl Interface
- tuple_t<fn_t<PARENT, PARAM>>, // 已定义的 Entiies 集合
- ifs_t // 已定义的 AudioStream Interface,可连续加入多个
- > { };
- class usbd_t : public core::usbd_impl_t< // 定义 USB 类
- usbd_t, // 定式
- 0x110, // bcdUSB
- 0, // bDeviceClass
- 0, // bDeviceSubClass
- 0, // bDeviceProtocol
- 0x0416, // idVendor
- 0x5011, // idProduct
- 0x100, // bcdDevice
- 1, // iManufacture
- 2, // iProduct
- 3, // iSerialNumber
- true, // bmAttributes, Bus Powered
- false, // bmAttributes, Self Powered
- false, // bmAttributes, Remote Wakeup
- 50_mA, // bMaxPower
- 0, // iConfiguration
- fn_t> { // 已定义的 Function,可连续加入多个 Function 和 Interface
- public:
- __INLINE usbd_t() { }
- #if 1
- __INLINE bool data_out(uint_fast8_t type, uint_fast8_t request, uint_fast16_t value, uint_fast16_t index, uint_fast16_t length)
- {
- out();
- return true;
- }
- __INLINE bool data_in(uint_fast8_t type, uint_fast8_t request, uint_fast16_t value, uint_fast16_t index, uint_fast16_t length)
- {
- in();
- return true;
- }
- #endif
- __INLINE const uint8_t* get_string_descriptor(uint_fast8_t index, uint_fast16_t lang_id) // GetDescriptor(String) 处理
- {
- static const string_langid_t<langid_t::English_UnitedStates> desc0;
- static const string_t<u'j', u'.', u'y', u'.', u'l', u'e', u'e', u'@', u'y', u'e', u'a', u'h', u'.', u'n', u'e', u't'> desc1;
- static const string_t<u'U', u'S', u'B', u' ', u'A', u'u', u'd', u'i', u'o'> desc2;
- static const string_t<u'0', u'0', u'0', u'0'> desc3;
- static const uint8_t* const descriptor[] {
- reinterpret_cast<const uint8_t*>(&desc0),
- reinterpret_cast<const uint8_t*>(&desc1),
- reinterpret_cast<const uint8_t*>(&desc2),
- reinterpret_cast<const uint8_t*>(&desc3)
- };
- return index < sizeof(descriptor) / sizeof(descriptor[0]) ? descriptor[index] : nullptr;
- }
- };
- usbd_t usbd; // 定义 USB 类对象
- void usbd_isr() // USBD_IRQn 中断向量 handler
- {
- usbd.isr(); // 调用 USB 类的中断处理
- }
- void i2s_isr() // I2S_IRQn 中断向量 handler
- {
- using namespace sfr::i2s;
- if (I2S.STATUS().TXUDF) {
- I2S.STATUS(0).TXUDF(1);
- I2S.CON(0);
- I2S.IE(0);
- return;
- }
- if (buffer.pos == 0x400 || buffer.pos == 0x1014) {
- I2S.IE(0).TXUDFIE(1);
- return;
- }
- // 从 Audio Data 缓冲填充数据到 I2S 发送 FIFO
- uint_fast8_t rdpos{ buffer.rdpos };
- do {
- I2S.TXFIFO = buffer.data[rdpos++];
- if (rdpos == sizeof(buffer.data) / 4)
- rdpos = 0;
- } while (I2S.STATUS().TXFULL == 0);
- buffer.rdpos = rdpos;
- // 调整 I2S 速率
- uint_fast16_t pos{ buffer.pos };
- if (pos == 0xc00 || pos == 0x1c10) { // 加快
- I2S.CLKDIV(0).BCLK_DIV(45);
- } else if (pos == 0 || pos == 0x1010) { // 减慢
- I2S.CLKDIV(0).BCLK_DIV(47);
- } else
- I2S.CLKDIV(0).BCLK_DIV(46); // 恢复正常
- }
- void i2s_start() // I2S 启动
- {
- using namespace sfr::i2s;
- do {
- I2S.TXFIFO = 0;
- } while (I2S.STATUS().TXFULL == 0);
- I2S.CON(0)
- .I2SEN(1)
- .TXEN(1)
- .WORDWIDTH(1)
- .FORMAT(1)
- .TXTH(4);
- I2S.IE(0).TXTHIE(1);
- }
- int main()
- {
- using namespace sfr::i2s;
- I2S.CLKDIV(0).BCLK_DIV(46); // 设置 I2S 默认速率
- *reinterpret_cast<volatile uint32_t*>(0xe000e100) = 1 << I2S_IRQn; // NVIC:允许 I2S 中断
- usbd.open(true); // 初始化 usb 对象
- while (true);
- }
程序中所有的类和模板的层次结构:- usbd_t USB device 的封装
- |
- +--fn_t<...> Interface 的容器
- |
- +--ifc_t<...> Audio Control Interface 的模板封装
- |
- +--tuple_t<...> Terminal 和 Unit 的容器
- | |
- | +--it_t<...> Input Terminal 的模板封装
- | |
- | +--ot_t<...> Output Terminal 的模板封装
- |
- +--ifs_t<...> Audio Stream Interface 的模板封装
- |
- +--ep_t<...> Audio Data Endpoint 的模板封装