近几日在帮客户移植USB MSD host的协议栈。发现一下子将100+K的代码从一颗M3移植到另外一颗M3,其实还真的不简单,主要是不同厂家的M3,外设区别太大了。辛苦将底层的硬件层描述完成之后,发现USB协议的写法相差过大。不得不对其进行了一些修改。言归正传,我们还是看一下EFM32的 MSD host的协议栈的框架吧。
1. 硬件原理图设计
参照reference manual中的USB章节内的HOST部分的原理框图即可。如下图所示:
只是这张图里面是用了一颗带电源管理的3V转5V的升压芯片,来作为管理VBUS的电源。如果板子上有5V,可以直接输入到电源管理芯片。
另外,就是要选择一颗基频为48MHz的晶振,用来给USB提供基准时钟源。
2.软件框架:
/* USB related data */
STATIC_UBUF(tmpBuf, 1024); // 定义一个给usb使用的缓冲区。 #define STATIC_UBUF( x, y ) EFM32_ALIGN( 4 ) static uint8_t x[((y)+3)&~3];
USBH_Init_TypeDef is = USBH_INIT_DEFAULT;
USBH_Init( &is ); //初始化USB协议栈
for (;;)
{
// Wait for ever on device attachment, 等待U盘插入
// The second parameter is timeout in seconds, 0 means for ever
if ( USBH_WaitForDeviceConnectionB( tmpBuf, 0 ) == USB_STATUS_OK )
{
// Device is now connected and ready for enumeration ! //检测到U盘存在了
if (MSDH_Init(tmpBuf, sizeof(tmpBuf)))
{
/* Initialize filesystem */
FileResult = f_mount( 0, &Fatfs );
if (FileResult == FR_OK)
{
//进行Fat文件操作
//FileResult = f_open();
//FileResult = f_read();
}
}
}
// Wait for disconnection
while ( USBH_DeviceConnected() ){}
// Disable USB peripheral, power down USB port.
USBH_Stop();
}
单看如上的框架其实是比较简单的,但是还需要注意如下几点:
1.可以配置宏定义DEBUG_USB_API和USB_USE_PRINTF 来决定是否打开USB调试开关。一般调试时是不需要打开的。而默认提供的usbconfig.h头文件中会有如下的定义:
#ifndef NDEBUG
/* Debug USB API functions (illegal input parameters etc.) */
#define DEBUG_USB_API /* Uncomment to turn on */
#define USB_USE_PRINTF /* Uncomment to enable */
#endif
因此在IAR中预先定义NDEBUG,来关闭USB调试输出。
2. USB协议栈中,默认使用了Timer0来作为基准时钟。如果要改动的话,需要修改em_usbtimer.c。就在这个文件的开头部分。在这个文件中,也实现了相应的中断响应函数。
3.如果需要过流保护的话,还需要在usbconfig.h里面,而外定义过流侦测的GPIO口。
#define USB_VBUSOVRCUR_PORT gpioPortA
#define USB_VBUSOVRCUR_PIN 14
#define USB_VBUSOVRCUR_POLARITY USB_VBUSOVRCUR_POLARITY_LOW
如果没有过流保护功能,则需要将USB_VBUSOVRCUR_PORT定义成USB_VBUSOVRCUR_PORT_NONE。
4.中断处理
在USB协议栈中,普遍使用了EMlib中的关中断函数和开中断函数,INT_Disable() 和 INT_Enable()。而不是直接使用__disable_irq()和__enable_irq()。
所以在主函数中,也请注意。
以上是目前的心得,可能还存在理解上的错误。也欢迎大家指出。