text data bss dec hex filename 1580 244 168 1992 7c8 .\default\adc.elf
#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 的模板封装
使用特权
dong_abc 发表于 2013-5-23 01:12 码功 太薄弱,看不懂。
john_lee 发表于 2013-5-23 02:10 在不在九哥的群 18748628 里?不在可以加进来聊聊。
缥缈九哥 发表于 2013-5-19 03:31 可是功力不够 。一看就有走火入魔的感觉 ,赶紧退出了。
dong_abc 发表于 2013-5-24 22:01 9G,你这个群,我怎么加了3天都没加上啊,18748628 。
发表回复 本版积分规则 回帖后跳转到最后一页
时间类勋章
等级类勋章
发帖类勋章
人才类勋章
33
1466
21
扫码关注 21ic 官方微信
扫码关注嵌入式微处理器
扫码关注电源系统设计
扫码关注21ic项目外包
扫码浏览21ic手机版
本站介绍 | 申请友情链接 | 欢迎投稿 | 隐私声明 | 广告业务 | 网站地图 | 联系我们 | 诚聘英才
京公网安备 11010802024343号