下面是USB的数据状态与信号的说明:
数据 J 和 K 状态Data J and K states
对于全速总线段,J 状态与差分 1 相同,即 D+ 为逻辑高电平时和 D- 为逻辑低电平,而 K 状态与差分 0 相同,即当 D+ 为逻辑低电平且D- 是逻辑高电平。
空闲状态Idle state
在空闲状态下,对于全速总线段,D+ 比 D- 的电平高。
挂起状态Suspend signal
由于当USB总线处于空闲状态超过3 ms时进入挂起状态,因此挂起状态与空闲状态相同或与全速总线段中的J状态相同。
恢复信号Resume signal
当设备处于挂起状态时,设备端口上的数据K状态表示从挂起状态恢复。这意味着恢复信号是全速段中从数据J状态到数据K状态的变化。
2.3
MM32F0270 USB支持从Suspend模式下唤醒
MM32F0270 可通过EX
ti线 18连接到 USB总线挂起中断实现USB从挂起状态唤醒。
需要使用唤醒时,需要使能相应的USB中断外,还需配置EXTI 18以使能相关的功能。
相关的寄存器与控制状态位的控制与查询,可以参考MM32F0270的用户手册。
3
USB进入Suspend与Res ume的软硬件设计
3.1
在库函数版本的样例中可以通过如下顺序初始化USB
a.
配置系统时钟为48MHz或96Mhz,使能GPIOA时钟,使能USB时钟
void USB_ClockConfig(void)
{
USB_HSI48M_Config();
Set_CRS(); // The calibration of vibration
// Select USBCLK source
// RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2); //if SYSCLK is 96MHz
// Enable USB clock
RCC_APB1PeriphClockCmd(RCC_APB1ENR_USB, ENABLE);
}
b.
配置USB D+和D-所需用到的GPIO引脚,使用GPIO_Configuration函数
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_StructInit(&GPIO_InitStruct);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
// USB_DISCONNECT used as USB pull-up
GPIO_InitStruct.GPIO_Pin = USB_DISCONNECT_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;
GPIO_Init(USB_DISCONNECT, &GPIO_InitStruct);
}
c.
配置USB的中断,调用USB_NVIC_Config函数
void USB_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USB_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
d.
设置USB的时钟,调用USB_ClockConfig
void USB_ClockConfig(void)
{
USB_HSI48M_Config();
Set_CRS(); // The calibration of vibration
// Select USBCLK source
// RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2);
// Enable USB clock
RCC_APB1PeriphClockCmd(RCC_APB1ENR_USB, ENABLE);
}
e.
设置USB 初始化
void USB_Init(void)
{
pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
// Initialize devices one by one
pProperty->Init();
}
f.
设定USB对应唤醒的EXTI参数
void USB1_WKUP_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line18;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
g.
中断相应处理函数
void USB_Istr(void)
{
__IO u16 wIstr;
wIstr = _GetUSB_INT_STA();
//USB->INT_STATE = wIstr;
// fSuspendEnabled = 0;
if(wIstr & USB_INT_STATE_RSTF) {
_ClrUSB_INT_STA(USB_INT_STATE_RSTF) ;
Device_Property.Reset();
}
//…
EXTI_ClearITPendingBit(EXTI_Line22);
}
3.2
实现main Demo功能的主要函数代码
s32 main(void)
{
GPIO_Configuration();
USB_NVIC_Config();
USB_ClockConfig();
USB_Init();
while(1) {
if(bDeviceState == CONFIGURED) {
if(!(_GetUSB_CTRL1()&EP1_CTRL_TRANEN)) {
UserToPMABufferCopy(gTableData, ENDP1, BUFF_SIZE);
_SetUSB_CTRL1(EP1_CTRL_TRANEN | BUFF_SIZE) ; //Loop IN transmission
}
}
}
}
配置好初始化USB收发的初始化操作后,PC端会发现USB HID枚举成功;此时PC端进入待机模式,
MCU的USB收到Suspend的命令后,执行:void Suspend(void)
{
if(bDeviceState == CONFIGURED) {
//Frequency the bus clock 512
USB->POWER &= ~USB_POWER_SUSP;
bDeviceState = SUSPENDED;
fSuspendEnabled = true;
RCC->CFGR &= ~RCC_CFGR_HPRE;
RCC->CFGR |= RCC_CFGR_HPRE_DIV512;
RCC->CR &= ~(0x1f << 26);
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div4);
UART_DeInit(UART1);
}
}
USB唤醒机制
USB设备进入挂起状态之后,将由Resume信号进行唤醒。Resume信号可以由USB主机发起,也可以由USB设备本身触发,但是只有USB主机可以结束Resume信号。
主机在挂起设备后可通过翻转数据线上的极性并保持20ms来唤醒设备,并以低速EOP信号结尾。
如果设备支持远程唤醒,设备可向主机发起远程唤醒请求,前提是设备已进入idle状态至少5ms,设备会驱动总线进入K状态,如下图,K状态必须维持1ms-15ms之内,此信号会在1ms内被主机接管,主机会继续驱动唤醒信号直到20ms,并以低速EOP信号结尾。
主机复位设备或者设备对自己强行复位,设备也会从挂起状态切换到默认状态。
MM32F0270 设备被唤醒后,如果唤醒中断使能(比如使用PA0的EXTI0),则会进入唤醒中断,退出低功耗模式,然后清除USB_POWER寄存器的SUSPEND位,退出强制挂起操作。
操作上体现为PC Host主机同按主机KeyBoard或鼠标按键实现退出睡眠状态,从而唤醒MM32F0270的挂起状态。
通过上述的步骤,简单的演示了MM32F0270的USB 接收数据,通过数据帧中的Start Bit唤醒MCU的功能。
Demo程序可登录MindMotion的官网下载MM32F0270 lib_Samples
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/MM32F0270/
工程路径如下:
~ MM32F0270_Samples\LibSamples\USB\
0