14、USBH HOST对接RTT系统(CDC+MSC)

本文档详细介绍了如何将USBHHOST与RTT系统进行对接,以实现CDC(通用串行总线通信设备类)和MSC(存储设备类)设备的驱动。首先,介绍了CDC设备的驱动实现,包括接收和发送数据的流程,以及驱动文件的修改。接着,阐述了MSC设备驱动的实现思路,主要涉及设备的打开、关闭、读写和控制操作。通过这些步骤,开发者可以利用RTT标准接口进行CDC通信和对MSC设备进行文件读写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

USBH HOST对接RTT

将USBH host注册到RTT中需要进行以下几步.

  1. 实现设备驱动
  2. 设备注册.

1.1 CDC设备实现

1.1.1 CDC类实现思路

官方驱动修改思路.

  1. 将CDC类中的状态机一直置为接收状态.
  2. 接收完成后,通过USBH_CDC_ReceiveCallback函数通知上层应用.

设备实现思路.

  1. 通过官方提供的接收回调函数将接收到的数据存放到ringbuf内,用户可通过rt_device_read接口调用usbh_cdc_class_read函数读取缓冲区内容.
  2. 发送时指定发送数据,直接发送指定数据(无缓冲区).如有需要,可将发送数据存入指定缓冲区,然后创建一个线程用于发送.

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从设备进行文件读写.

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值