基于Ch554 制作的USB喇叭

很早之前使用 Arduino Pro Micro 实现过USB耳机转接器,这次尝试使用 WCH 的 Ch554 来实现(实际上可以使用 更见偏移的 Ch552 来实现,但是因为 Ch552 有烧写次数限制,所以最终是在 Ch554上进行开发)。

无需过多了解 USB Audio的相关知识,所作的工作基本上只有:通过描述符报告自己是一个USB Audio 设备。之后 Windows 就会发送 48Khz 16位双声道的采样数据给设备(如果想了解更多,推荐去USB中文网阅读相关内容)。我们在设备响应的 OUTPUT 端点上即可收到数据。

需要特别注意的是,代码中有一个向HOST 汇报当前支持采样率的描述符。这里申明了2个采样率:22,050Hz和48000Hz。

  0x0E,  	//Size of the descriptor, in bytes  
  0x24,  	//CS_INTERFACE Descriptor Type  
  0x02,  	//FORMAT_TYPE descriptor subtype  
  0x01,  	//FORMAT_TYPE_I  
  0x02,  	//Indicates the number of physical channels in the audio data stream.  
  0x02,  	//The number of bytes occupied by one audio subframe. Can be 1, 2, 3 or 4.  
  0x10,  	//The number of effectively used bits from the available bits in an audio subframe.  
  0x02,  	//Indicates how the sampling frequency can be programmed:  
  0x22,0x56,0x00, //	  Sampling frequency 1 in Hz for this isochronous data endpoint.  
  0x80,0xBB,0x00, //	  Sampling frequency 2 in Hz for this isochronous data endpoint.  

在工作过程中,Windows会通知当前使用的采样率。

需要注意的是:

  1. 如果你只报告支持 48000的采样率,那么Windows就不会发送 SET_CUR
  2. Windows不支持所有的采样率,我这边实验只支持48000Hz的采样率,换句话,你申明支持 24000或者22050,实际上并不会使用。

具体的数据是下面这样的,可以看到这种同步传输/等时传输的数据和通常的最大区别在于不会有 ACK 信号,相当于HOST 直接丢出来不管对错。

从上面可以看到每个数据之间间隔是1ms,每笔数据 192字节。

对应在代码中会在USBAudioSpeaker.c文件中的Mass_Storage_Out函数进行处理:

void Mass_Storage_Out (void) {
    PWM_CTRL |= bPWM2_OUT_EN;
	for (uint8_t i = 0; i < BOT_EP_Rx_Length; i=i+4){		
		PWM_DATA2 = BOT_Rx_Buf[i+1];
		// Delay for 20833ns
		for (uint16_t j=0;j<51;j++) {
		   __asm__ ("nop\n");
		}
    }
	PWM_CTRL &= (~bPWM2_OUT_EN);
    //Serial0_println("Ending");
	BOT_EP_Tx_ISO_Valid();
}

经过前面的工作,现在能够拿到PC输出的音频数据,接下来的问题就是如何将收到的数据通过喇叭播放出去。这个过程相当于一个 DAC (数字到模拟)的过程。这次选择的方法是:通过 PWM 进行模拟。这是使用的是CH554 芯片,它支持PWM:2 组 PWM 输出,PWM1/PWM2 为 2 路 8 位 。在下图可以看到 P1.5/P3.1/P3.0/P3.4都是可以选择的引脚。代码使用了 P3.4这个引脚。

PWM初始化代码如下,特别注意使用了1分频产生 PWM 信号,我们使用的主频为 24Mhz 5V,因此频率是 24000000/256=93750Hz

  // 打开 PWM2 功能
  PIN_FUNC &= ~(bPWM2_PIN_X);
  // PWM 分频设置
  // 1 分频,这样 PWM 频率为 Fsys/256
  PWM_CK_SE=1;

上述设置之后,直接在 PWM_DATA2 寄存器中填写你要生成的高电平比例即可产生对应的 PWM 信号。对应的代码就在前面提到的void Mass_Storage_Out (void) {} 函数中。此外,使用NOP 指令制作了一个简单的延时,延时 1/48000=20833ns:

// Delay for 20833ns
		for (uint16_t j=0;j<51;j++) {
		   __asm__ ("nop\n");
		}

在编译时,还需要对项目进行如下设置:

  1. 选择 Ch552 Board,前面提到了Ch552和 Ch554 在代码方面是完全兼容的;
  2. 设置USB 为“U148B USB Ram”
  3. Clock Source 为 “24Mhz(internal),5V”

硬件方面非常简单,Ch554最小系统,喇叭接到对应引脚即可:

这是我设计的用于测试 Ch554 和 Ch559 最小开发板。Ch554和Ch559 最小系统外围只需要2个电容即可,两颗芯片相互独立:

完整代码:

电路图:

从上面可以看到,Ch55xduino提供的 USB 框架扩展性不错。Ch554 可以方便的通过 Ch55xduino 实现一个USB Speaker 的功能。目前美中不足的只是音频质量较差(所有看到的人都怀疑这个是一个收音机),后续会持续进行改进。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注