文章目录
USBH HOST对接RTT
将USBH host注册到RTT中需要进行以下几步.
- 实现设备驱动
- 设备注册.
1.1 CDC设备实现
1.1.1 CDC类实现思路
官方驱动修改思路.
- 将CDC类中的状态机一直置为接收状态.
- 接收完成后,通过
USBH_CDC_ReceiveCallback
函数通知上层应用.
设备实现思路.
- 通过官方提供的接收回调函数将接收到的数据存放到ringbuf内,用户可通过
rt_device_read
接口调用usbh_cdc_class_read
函数读取缓冲区内容. - 发送时指定发送数据,直接发送指定数据(无缓冲区).如有需要,可将发送数据存入指定缓冲区,然后创建一个线程用于发送.
1.1.2 CDC类驱动文件修改
修改usbh_cdc.c
文件中的CDC_ProcessReception
函数为如下所示.
static void CDC_ProcessReception(USBH_HandleTypeDef *phost)
{
CDC_HandleTypeDef *CDC_Handle = (CDC_HandleTypeDef *) phost->pActiveClass->pData[USBH_CDC_INDEX];
USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
switch(CDC_Handle->data_rx_state)
{
case CDC_RECEIVE_DATA:
USBH_BulkReceiveData(phost,
CDC_Handle->pRxData,
CDC_Handle->DataItf.InEpSize,
CDC_Handle->DataItf.InPipe);
CDC_Handle->data_rx_state = CDC_RECEIVE_DATA_WAIT;
break;
case CDC_RECEIVE_DATA_WAIT:
URB_Status = USBH_LL_GetURBState(phost, CDC_Handle->DataItf.InPipe);
/*Check the status done for reception*/
if(URB_Status == USBH_URB_DONE)
{
USBH_CDC_ReceiveCallback(phost);
CDC_Handle->data_rx_state = CDC_RECEIVE_DATA;
}
break;
default:
break;
}
}
1.1.3 CDC类设备文件实现
实现usbh_cdc_device.h
.
#ifndef __USBH_CDC_DEVICE__H__
#define __USBH_CDC_DEVICE__H__
#include "usbh_core.h"
#define USBH_CDC_NAME "USBH_CDC"
#define CDC_RX_BUFSIZE 256
#define CDC_DEVICE_CMD_GET_SPCAE_LEN (0X0100)
#define CDC_DEVICE_CMD_GET_DATA_LEN (0X0200)
#define CDC_DEVICE_CMD_BUF_RESET (0X0400)
#define CDC_DEVICE_CMD_GET_DEV_STATE (0X0800)
#define CDC_DEVICE_CMD_START_RECV (0X1000)
#define CDC_DEVICE_CMD_MASK (CDC_DEVICE_CMD_START_RECV | CDC_DEVICE_CMD_GET_SPCAE_LEN | CDC_DEVICE_CMD_GET_DATA_LEN | CDC_DEVICE_CMD_BUF_RESET)
struct rt_cdc_device
{
struct rt_device device;
struct rt_ringbuffer rx_ringbuffer;
uint8_t *p_rx_buf;
};
typedef struct rt_cdc_device *rt_cdc_device_t;
rt_cdc_device_t cdc_device_creat(void);
#endif
实现usbh_cdc_device.c
.
#include "usbh_cdc_device.h"
#include "usbh_cdc.h"
extern USBH_HandleTypeDef hUsbHostHS;
static rt_err_t usbh_cdc_class_open(rt_device_t dev, rt_uint16_t oflag);
static rt_err_t usbh_cdc_class_close(rt_device_t dev);
static rt_size_t usbh_cdc_class_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
static rt_size_t usbh_cdc_class_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
static rt_err_t usbh_cdc_class_control(rt_device_t dev, int cmd, void *args);
static rt_cdc_device_t cdc_device_t = RT_NULL;
rt_cdc_device_t cdc_device_creat()
{
rt_err_t result = RT_EOK;
cdc_device_t = rt_malloc(sizeof(struct rt_cdc_device));
if(cdc_device_t == NULL)
{
USBH_ErrLog("cdc device init failed");
rt_free(cdc_device_t);
return RT_NULL;
}
rt_memset(cdc_device_t, 0, sizeof(struct rt_cdc_device));
cdc_device_t->device.parent.type = RT_Object_Class_Device;
cdc_device_t->device.type = RT_Device_Class_Char;
cdc_device_t->device.open = usbh_cdc_class_open;
cdc_device_t->device.close = usbh_cdc_class_close;
cdc_device_t->device.write = usbh_cdc_class_write;
cdc_device_t->device.read = usbh_cdc_class_read;
cdc_device_t->device.control = usbh_cdc_class_control;
result = rt_device_register(&(cdc_device_t->device), USBH_CDC_NAME, RT_DEVICE_FLAG_RDWR);
if(result != RT_EOK)
{
USBH_DbgLog("cdc device register failed");
rt_free(cdc_device_t);
return RT_NULL;
}
USBH_DbgLog("cdc device init ok");
return cdc_device_t;
}
static rt_err_t usbh_cdc_class_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_cdc_device_t cdc_handler = (rt_cdc_device_t)dev;
cdc_handler->p_rx_buf = rt_malloc(CDC_RX_BUFSIZE);
if(cdc_handler->p_rx_buf == NULL)
{
return RT_ENOMEM;
}
USBH_memset(cdc_handler->p_rx_buf, 0, CDC_RX_BUFSIZE);
rt_ringbuffer_init(&(cdc_handler->rx_ringbuffer), cdc_handler->p_rx_buf, CDC_RX_BUFSIZE);
USBH_CDC_Receive(&hUsbHostHS, NULL, 128);
return RT_EOK;
}
static rt_err_t usbh_cdc_class_close(rt_device_t dev)
{
rt_cdc_device_t cdc_handler = (rt_cdc_device_t)dev;
if(cdc_handler->p_rx_buf)
rt_free(cdc_handler->p_rx_buf);
cdc_handler->p_rx_buf = RT_NULL;
rt_ringbuffer_reset(&cdc_handler->rx_ringbuffer);
USBH_Stop(&hUsbHostHS);
return RT_EOK;
}
static rt_size_t usbh_cdc_class_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
extern USBH_StatusTypeDef USBH_CDC_Transmit(USBH_HandleTypeDef * phost, uint8_t * buf, uint32_t length);
USBH_CDC_Stop(&hUsbHostHS);
if(USBH_CDC_Transmit(&hUsbHostHS, (uint8_t *)buffer, size) == RT_EOK)
return size;
return 0;
}
void USBH_CDC_TransmitCallback(USBH_HandleTypeDef *phost)
{
if(cdc_device_t)
rt_device_control(&(cdc_device_t->device),CDC_DEVICE_CMD_START_RECV,NULL);
}
void USBH_CDC_ReceiveCallback(USBH_HandleTypeDef * phost)
{
extern CDC_HandleTypeDef usbh_cdc_handler;
uint32_t len = USBH_CDC_GetLastReceivedDataSize(phost);
if(len)
{
rt_ringbuffer_put(&(cdc_device_t->rx_ringbuffer), usbh_cdc_handler.pRxData, len);
cdc_device_t->device.rx_indicate((rt_device_t)cdc_device_t, len);
}
}
static rt_size_t usbh_cdc_class_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
rt_cdc_device_t cdc_handler = (rt_cdc_device_t)dev;
if(rt_ringbuffer_get(&(cdc_handler->rx_ringbuffer), buffer, size) == size)
return size;
else
return 0;
}
static rt_err_t usbh_cdc_class_control(rt_device_t dev, int cmd, void *args)
{
extern CDC_HandleTypeDef usbh_cdc_handler;
rt_cdc_device_t cdc_handler = (rt_cdc_device_t)dev;
uint32_t *len = (uint32_t *)args;
struct rt_ringbuffer *p_ringbuf = NULL;
rt_err_t status = RT_EOK;
p_ringbuf = &(cdc_handler->rx_ringbuffer);
switch(cmd & 0XFF00)
{
case CDC_DEVICE_CMD_BUF_RESET:
rt_ringbuffer_reset(p_ringbuf);
break;
case CDC_DEVICE_CMD_GET_SPCAE_LEN:
*len = rt_ringbuffer_space_len(p_ringbuf);
break;
case CDC_DEVICE_CMD_GET_DATA_LEN:
*len = rt_ringbuffer_data_len(p_ringbuf);
break;
case CDC_DEVICE_CMD_GET_DEV_STATE:
break;
case CDC_DEVICE_CMD_START_RECV:
USBH_CDC_Stop(&hUsbHostHS);
USBH_CDC_Receive(&hUsbHostHS, NULL, 64);
USBH_DbgLog("start recv");
default:
status = RT_EINVAL;
break;
}
return status;
}
2.1 MSC类设备驱动实现
2.1.1 MSC类设备实现思路
沿用ST官方例程,在此基础上模仿SPI_FLASH,SD卡的设备驱动即可.
2.1.2 MSC类设备实现
msc类不需要对底层驱动进行修改,专注于设备层功能实现即可.
添加usbh_msc_device.c
文件如下所示.
#include "usbh_msc_device.h"
#include "usbh_msc.h"
extern USBH_HandleTypeDef hUsbHostHS;
#define USB_DEFAULT_BLOCK_SIZE 512
static struct rt_msc_device msc_device_handler;
static rt_err_t usbh_msc_class_init(rt_device_t dev);
static rt_err_t usbh_msc_class_close(rt_device_t dev);
static rt_size_t usbh_msc_class_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
static rt_size_t usbh_msc_class_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
static rt_err_t usbh_msc_class_control(rt_device_t dev, int cmd, void *args);
rt_msc_device_t msc_device_init()
{
rt_err_t result = RT_EOK;
rt_memset(&msc_device_handler, 0, sizeof(struct rt_msc_device));
msc_device_handler.dev.init = usbh_msc_class_init;
msc_device_handler.dev.close = usbh_msc_class_close;
msc_device_handler.dev.write = usbh_msc_class_write;
msc_device_handler.dev.read = usbh_msc_class_read;
msc_device_handler.dev.control = usbh_msc_class_control;
if(result != RT_EOK)
{
USBH_ErrLog("msc device sem failed");
}
result = rt_device_register(&(msc_device_handler.dev), USBH_MSC_NAME, RT_DEVICE_FLAG_RDWR);
if(result != RT_EOK)
{
USBH_ErrLog("msc device register failed");
return NULL;
}
return &msc_device_handler;
}
static rt_err_t usbh_msc_class_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t usbh_msc_class_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_size_t usbh_msc_class_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
uint8_t lun;
MSC_LUNTypeDef info;
rt_err_t res = RT_ERROR;
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
lun = USBH_MSC_GetCurLUN(&hUsbHostHS);
// rt_enter_critical();
if(USBH_MSC_Write(&hUsbHostHS, lun, pos, (uint8_t *)buffer, size) == USBH_OK)
{
res = size;
}
else
{
USBH_MSC_GetLUNInfo(&hUsbHostHS, lun, &info);
switch(info.sense.asc)
{
case SCSI_ASC_WRITE_PROTECTED:
USBH_ErrLog("USB Disk is Write protected!");
res = -RT_EBUSY;
break;
case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
case SCSI_ASC_MEDIUM_NOT_PRESENT:
case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
USBH_ErrLog("USB Disk write is not ready!");
res = -RT_EBUSY;
break;
default:
res = -RT_ERROR;
break;
}
}
// rt_exit_critical();
return res;
}
static rt_size_t usbh_msc_class_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
uint8_t lun;
MSC_LUNTypeDef info;
rt_err_t res = RT_ERROR;
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
lun = USBH_MSC_GetCurLUN(&hUsbHostHS);
// rt_enter_critical();
if(USBH_MSC_Read(&hUsbHostHS, lun, pos, (uint8_t *)buffer, size) == USBH_OK)
{
res = size;
}
else
{
USBH_MSC_GetLUNInfo(&hUsbHostHS, lun, &info);
switch(info.sense.asc)
{
case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
case SCSI_ASC_MEDIUM_NOT_PRESENT:
case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
USBH_ErrLog("USB Disk read is not ready!");
res = -RT_EBUSY;
break;
default:
res = -RT_ERROR;
break;
}
}
// rt_exit_critical();
return res;
}
static rt_err_t usbh_msc_class_control(rt_device_t dev, int cmd, void *args)
{
uint8_t lun;
MSC_LUNTypeDef info;
rt_err_t res = RT_EOK;
struct rt_device_blk_geometry *geometry = NULL;
RT_ASSERT(dev != RT_NULL);
lun = USBH_MSC_GetCurLUN(&hUsbHostHS);
geometry = (struct rt_device_blk_geometry *) args;
switch(cmd)
{
/* GET_SECTOR_COUNT & GET_SECTOR_SIZE & GET_BLOCK_SIZE*/
case RT_DEVICE_CTRL_BLK_GETGEOME :
if(USBH_MSC_GetLUNInfo(&hUsbHostHS, lun, &info) == USBH_OK)
{
geometry->sector_count = info.capacity.block_nbr;
geometry->block_size = USB_DEFAULT_BLOCK_SIZE;
geometry->bytes_per_sector = info.capacity.block_size;
}
else
{
res = RT_ERROR;
}
break;
/* Get erase block size in unit of sector (DWORD) */
case RT_DEVICE_CTRL_BLK_SYNC :
break;
case RT_DEVICE_CTRL_BLK_ERASE:
break;
default:
res = RT_EINVAL;
}
return res;
}
添加usbh_msc_device.h
文件如下所示.
#ifndef __USBh_MSC_DEVICE__H__
#define __USBh_MSC_DEVICE__H__
#include "usbh_core.h"
#define USBH_MSC_NAME "USBH_MSC"
struct rt_msc_device
{
struct rt_device dev;
};
typedef struct rt_msc_device* rt_msc_device_t;
rt_msc_device_t msc_device_init(void);
#endif
至此,可通过RTT标准接口进行CDC通讯,及通过RTT文件系统标准接口对MSC从设备进行文件读写.