RT-Thread:GD32E103移植USB-Host优化


前言

在之前《GD32E103移植USB-Host》的文章基础上做优化,之前的移植只是把裸机程序移植到RTT,实质上存在BUG和内存分配不合理的地方,需要进一步修改。


一、优化USB-Host内存分配

1、修改usb_host.c中usb_host_init函数,注意对应.h文件也要改一下函数声明,你懂的,该函数主要修改有:

  • 将USB相关的结构体、数组的全局定义改成使用动态内存去分配,有利于内存管理。
  • 添加一个事件的初始化,为了后续修复BUG。
  • 将初始化顺序做了调整,内存申请、事件初始化、设备注册和线程创建成功后才能进行usb初始化,最后再启动USB线程。
int usb_host_init(void)
{
	rt_err_t res = -RT_ERROR;
	rt_device_t dev = RT_NULL;
	rt_thread_t thread = RT_NULL;

	if((local_buffer = (uint8_t *)rt_malloc(LOCAL_BUFFER_SIZE)) == RT_NULL)
	{
		rt_kprintf("local_buffer malloc failed\r\n");
		return -1;
	}
	rt_memset(local_buffer, 0, LOCAL_BUFFER_SIZE);
	
	if((usbh_cfg_desc = (uint8_t *)rt_malloc(USBH_CFG_DESC_SIZE)) == RT_NULL)
	{
		rt_kprintf("usbh_cfg_desc malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_cfg_desc, 0, USBH_CFG_DESC_SIZE);
	
	if((usbh_msc_param = (msc_param_struct *)rt_malloc(sizeof(msc_param_struct))) == RT_NULL)
	{
		rt_kprintf("usbh_msc_param malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_msc_param, 0, sizeof(msc_param_struct));
	
	if((msc_machine = (msc_machine_struct *)rt_malloc(sizeof(msc_machine_struct))) == RT_NULL)
	{
		rt_kprintf("msc_machine malloc failed\r\n");
		return -1;
	}
	rt_memset(msc_machine, 0, sizeof(msc_machine_struct));
	
	if((usbh_state_core = (usbh_state_handle_struct *)rt_malloc(sizeof(usbh_state_handle_struct))) == RT_NULL)
	{
		rt_kprintf("usbh_state_core malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_state_core, 0, sizeof(usbh_state_handle_struct));
	
	if((usbh_msc_cbw_data = (host_cbwpkt_union *)rt_malloc(sizeof(host_cbwpkt_union))) == RT_NULL)
	{
		rt_kprintf("usbh_msc_cbw_data malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_msc_cbw_data, 0, sizeof(host_cbwpkt_union));
	
	if((usbh_msc_csw_data = (host_cswpkt_union *)rt_malloc(sizeof(host_cswpkt_union))) == RT_NULL)
	{
		rt_kprintf("usbh_msc_csw_data malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_msc_csw_data, 0, sizeof(host_cswpkt_union));
	
	if((usbh_msc_botxfer_param = (usbh_botxfer_struct *)rt_malloc(sizeof(usbh_botxfer_struct))) == RT_NULL)
	{
		rt_kprintf("usbh_msc_botxfer_param malloc failed\r\n");
		return -1;
	}
	rt_memset(usbh_msc_botxfer_param, 0, sizeof(usbh_botxfer_struct));
	
	/* allocate memory for the usbh_usr_struct */
    if((usbh_usr = (usbh_usr_struct *)rt_malloc(sizeof(usbh_usr_struct))) == RT_NULL)
    {
        rt_kprintf("malloc memory for usbh_usr_struct failed!\r\n");
		return -1;
    }
    rt_memset(usbh_usr, 0, sizeof(usbh_usr_struct));
	
	/* allocate memory for the usbh_data_in_buffer */
    if((usbh_data_in_buffer = (uint8_t *)rt_malloc(USBH_DATA_BUFFER_SIZE)) == RT_NULL)
    {
        rt_kprintf("malloc memory for usbh_data_in_buffer failed!\r\n");
		return -1;
    }
    rt_memset(usbh_data_in_buffer, 0, USBH_DATA_BUFFER_SIZE);
	
	/* allocate memory for the usbh_data_in_buffer */
    if((usbh_data_out_buffer = (uint8_t *)rt_malloc(USBH_DATA_BUFFER_SIZE)) == RT_NULL)
    {
        rt_kprintf("malloc memory for usbh_data_out_buffer failed!\r\n");
		return -1;
    }
    rt_memset(usbh_data_out_buffer, 0, USBH_DATA_BUFFER_SIZE);

	if((dev = (rt_device_t)rt_malloc(sizeof(struct rt_device))) == RT_NULL)
	{
		rt_kprintf("dev malloc failed\r\n");
		return -1;
	}
	rt_memset(dev, 0, sizeof(struct rt_device));
	
    if((res = rt_device_register(dev, UDISK_DEVIVE_NAME, RT_DEVICE_FLAG_DEACTIVATE)) != RT_EOK)
    {
        rt_kprintf("register usb host failed res = %d\r\n", res);
		return -2;
    }
	
	dev->init = rt_udisk_init;
	dev->read = rt_udisk_read;
	dev->write = rt_udisk_write;
	dev->control = rt_udisk_control;
	
	/* 初始化事件对象 */
    if(rt_event_init(&udisk_event, "udisk event", RT_IPC_FLAG_FIFO) != RT_EOK)
    {
        rt_kprintf("udisk event init failed.\n");
        return -3;
    }
	
	if((thread = rt_thread_create("usbh", rt_usbh_thread_entry, RT_NULL,USB_THREAD_STACK_SIZE, 8, 20)) == RT_NULL)
	{
		rt_kprintf("create usb host thread failed.\n");
        return -4;
	}
	
	/* usb rcu init */
    usb_rcu_init();

    /* timer nvic initialization */
    timer_nvic_init();

    /* configure GPIO pin used for switching VBUS power */
    usb_hwp_vbus_config(&usb_core_dev);
	
    /* host de-initializations */
    usbh_deinit(&usb_core_dev, &usb_host, usbh_state_core);

    /* start the USB core */
    hcd_init(&usb_core_dev, USB_FS_CORE_ID);
	
    /* init usr call back */
    usb_host.usr_cb->init();

    /* enable interrupts */
    usb_hwp_interrupt_enable(&usb_core_dev);

	/* startup usb host thread */
	rt_thread_startup(thread);
	
	return RT_EOK;
}

2、以下变量均可以在工程中找到,我们将其修改成指针即可,注意对应的.h文件的外部声明也要修改成指针,并对其赋RT_NULL初值,原本没有外部声明的变量就需要自己添加一个外部声明,修改后原代码使用的是“.”去引用结构体成员变量,我们需要将其改成“->”,原码使用“&”获取结构体地址,我们就需要删掉,不需要“&”了,修改的地方有特别多这边篇幅有限就不一一讲了,可以使用MDK自带的全局替换功能区快速搞定。
local_buffer、local_buffer
在这里插入图片描述
在这里插入图片描述
usbh_msc_param
在这里插入图片描述
在这里插入图片描述
msc_machine
在这里插入图片描述
在这里插入图片描述
usbh_state_core
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

usbh_msc_cbw_data、usbh_msc_csw_data、usbh_msc_botxfer_param
在这里插入图片描述在这里插入图片描述
3、在usb_host.h中添加以下宏定义。

#define UDISK_MOUNTPOINT	"/udisk"
#define UDISK_DEVIVE_NAME	"usbh"

二、修复USB-Host移植后BUG

1、之前移植过后的工程,时而会发现操作一段时间或者快速连续操作几次后USB就挂了,需要重新挂载或者重启整个系统,这是因为原USB框架下只允许在其提供的用户函数usbh_usr_msc_application中进行USB操作,在其他地方操作USB可能会出现意向不到的错误,我们使用事件就是为了线程之间的同步,让我们在作其他任何线程中操作USB时都会等待到USB用户线程usbh_usr_msc_application和其同步后再进行操作。
2、定义和声明事件
在这里插入图片描述
在这里插入图片描述
3、修改rt_udisk_read、rt_udisk_write函数,这两个函数提供给文件系统使用的,顶层的文件系统操作函数最终都要调用这个函数来对U盘读写操作。

  • 读、写函数和下面的流程都一样
    在这里插入图片描述
/**
 * This function will read some data from a device.
 *
 * @param dev the pointer of device driver structure
 * @param pos the position of reading
 * @param buffer the data buffer to save read data
 * @param size the size of buffer
 *
 * @return the actually read size on successful, otherwise negative returned.
 */
rt_size_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void* buffer,
    rt_size_t size)
{
	rt_uint32_t res;
    BYTE status = USBH_MSC_OK;

    if (!size)
		return 0;

	rt_event_send(&udisk_event, WR_EVENT);
	if (rt_event_recv(&udisk_event, ALLOW_EVENT, RT_EVENT_FLAG_OR  | RT_EVENT_FLAG_CLEAR, 1000, &res) != RT_EOK)
	{
		rt_kprintf("Recv ALLOW_EVENT timeout!\n");
		goto err;
	}
	
	do
	{
		status = usbh_msc_read10(&usb_core_dev, buffer, pos, 512 * size);
		usbh_msc_handle_botxfer(&usb_core_dev, &usb_host, usbh_state_core);

		if(!hcd_is_device_connected(&usb_core_dev))
			goto err;
	}while(USBH_MSC_BUSY == status);
	
err:
	rt_event_send(&udisk_event, END_EVENT);
	
	if(USBH_MSC_OK == status)
		return size;
	
    return 0;
}

/**
 * This function will write some data to a device.
 *
 * @param dev the pointer of device driver structure
 * @param pos the position of written
 * @param buffer the data buffer to be written to device
 * @param size the size of buffer
 *
 * @return the actually written size on successful, otherwise negative returned.
 */
rt_size_t rt_udisk_write (rt_device_t dev, rt_off_t pos, const void* buffer,
    rt_size_t size)
{
	rt_uint32_t res;
    BYTE status = USBH_MSC_OK;
	
    if (!size) 
		return 0;
	
    if (stat & USBH_MSC_STA_PROTECT) 
		return 0;
	
	rt_event_send(&udisk_event, WR_EVENT);
	if (rt_event_recv(&udisk_event, ALLOW_EVENT, RT_EVENT_FLAG_OR  | RT_EVENT_FLAG_CLEAR, 1000, &res) != RT_EOK)
	{
		rt_kprintf("Recv WR_EVENT timeout!\n");
		goto err;
	}
	
	do
	{
		status = usbh_msc_write10(&usb_core_dev, (BYTE*)buffer, pos, 512 * size);
		usbh_msc_handle_botxfer(&usb_core_dev, &usb_host, usbh_state_core);

		if (!hcd_is_device_connected(&usb_core_dev))
			goto err;
	} while(USBH_MSC_BUSY == status);
	
err:
	rt_event_send(&udisk_event, END_EVENT);
	
	if(USBH_MSC_OK == status)
		return size;
	
    return 0;
}

4、添加头文件
在这里插入图片描述
5、添加宏定义
在这里插入图片描述
6、修改usbh_usr.c函数
在这里插入图片描述

int usbh_usr_msc_application(usb_core_handle_struct *pudev, uint8_t id)
{
	rt_uint32_t res;
	
	if(usbh_usr->init_status == USBH_USR_NOT_READY)
	{
		rt_kprintf("usbh msc init successfully.\r\n");
		usbh_usr->init_status = USBH_USR_READY;
	}
	
	if (rt_event_recv(&udisk_event, WR_EVENT, RT_EVENT_FLAG_OR  | RT_EVENT_FLAG_CLEAR, 1, &res) == RT_EOK)
	{
		rt_event_send(&udisk_event, ALLOW_EVENT);
		if (rt_event_recv(&udisk_event, END_EVENT, RT_EVENT_FLAG_OR  | RT_EVENT_FLAG_CLEAR, 2000, &res) == RT_EOK)
		{
			
		}
	}
	
    return 0;
}

7、编译、下载测试,快速使用ls命令列出USB根目录下文件,看看会不会挂,不会挂,那就ok了。

三、添加应用层代码

1、实现系统启动后自动挂载GD25QXX和USB初始化,插入U盘后自动挂载U盘,拔出U盘后自动卸载U盘,具体代码自己看,对于移植这个顶层的代码是很简单的了,不懂的再留言吧。
2、修改usb_host.c中的udisk_mount和udisk_unmount函数,并在.h文件中进行声明。

int udisk_mount(void)
{
	/*查找Flash设备*/
	if(rt_device_find(UDISK_DEVIVE_NAME) != RT_NULL) 
	{
		/*挂载Flash*/
		if(dfs_mount(UDISK_DEVIVE_NAME, UDISK_MOUNTPOINT, "elm", 0, 0) == 0)
		{
			rt_kprintf("flash mount success!\n");
			usbh_usr->mount_status = UDISK_MOUNT;
		} 
		else 
		{
			rt_kprintf("flash mount failed!\n");
			return -1;
		}
	}
	
	return RT_EOK;
}
MSH_CMD_EXPORT(udisk_mount,udisk mount);

int udisk_unmount(void)
{
	if(dfs_unmount(UDISK_MOUNTPOINT) == 0)
	{
		usbh_usr->mount_status = UDISK_UNMOUNT;
		rt_kprintf("unmount %s success!\n",UDISK_MOUNTPOINT);
	} 
	else 
	{
		rt_kprintf("unmount %s failed!\n",UDISK_MOUNTPOINT);
		return -1;
	}
	
	return RT_EOK;
}
MSH_CMD_EXPORT(udisk_unmount,udisk unmount);

3、在usbh_usr.h中添加宏,和挂载先关的结构体变量
在这里插入图片描述
4、修改gd25qxx.c和gd25qxx.h文件
gd25qxx.c

#include "gd25qxx.h"

gd25qxx_struct *gd25qxx_sta = RT_NULL;

int gd25qxx_init(void)
{
	if((gd25qxx_sta = (gd25qxx_struct *)rt_malloc(sizeof(gd25qxx_struct))) == RT_NULL)
	{
		rt_kprintf("gd25qxx_sta malloc failed\r\n");
		return -1;
	}
	rt_memset(gd25qxx_sta, 0, sizeof(gd25qxx_struct));
	
	if(gd25qxx_mount() != RT_EOK)
		return -1;
	
	return RT_EOK;
}

/*******************************************************************************
* 函 数 名         : gd25qxx_create_fatfs
* 输    入         : 空
* 输    出         : 空
* 函数功能		   : 创建文件系统
* 详细描述		   : 空
*******************************************************************************/
int gd25qxx_create_fatfs(void)
{
	/*格式化指定存储设备,并创建文件系统*/
	if(dfs_mkfs("elm", "gd25q") == RT_EOK)
	{
		rt_kprintf("create file system succeed!\n");
	}
	else
	{
		rt_kprintf("create file system failed!\n");
		return -1;
	}
	
	return RT_EOK;
}
MSH_CMD_EXPORT(gd25qxx_create_fatfs,gd25qxx create fatfs);

/*******************************************************************************
* 函 数 名         : w25qxx_mount
* 输    入         : 空
* 输    出         : 空
* 函数功能		   : 挂载Flash文件系统
* 详细描述		   : 空
*******************************************************************************/
int gd25qxx_mount(void)
{
	/*查找Flash设备*/
	if(rt_device_find("gd25q") != RT_NULL) 
	{
		/*挂载Flash*/
		if(dfs_mount("gd25q", FLASH_MOUNTPOINT, "elm", 0, 0) == 0)
		{
			gd25qxx_sta->fatfs_status = FATFS_NORMAL;
			gd25qxx_sta->mount_status = GD25QXX_MOUNT;
			rt_kprintf("mount %s success!\n",FLASH_MOUNTPOINT);
		} 
		else 
		{
			gd25qxx_sta->fatfs_status = FATFS_FAILURE;
			gd25qxx_sta->mount_status = GD25QXX_UNMOUNT;
			rt_kprintf("mount %s failed!\n",FLASH_MOUNTPOINT);
			return -1;
		}
	}
	
	return 0;
}
MSH_CMD_EXPORT(gd25qxx_mount,gd25qxx mount);

/*******************************************************************************
* 函 数 名         : w25qxx_unmount
* 输    入         : 空
* 输    出         : 空
* 函数功能		   : 卸载Flash文件系统
* 详细描述		   : 空
*******************************************************************************/
int gd25qxx_unmount(void)
{
	if(dfs_unmount(FLASH_MOUNTPOINT) == 0)
	{
		rt_kprintf("unmount %s success!\n",FLASH_MOUNTPOINT);
	} 
	else 
	{
		rt_kprintf("unmount %s failed!\n",FLASH_MOUNTPOINT);
		return -1;
	}
	
	return RT_EOK;
}
MSH_CMD_EXPORT(gd25qxx_unmount,gd25qxx unmount);

gd25qxx.h

#ifndef __GD25QXX_H
#define __GD25QXX_H

#include <rtthread.h>
#include "spi_flash.h"
#include "spi_flash_sfud.h"
#include "drv_spi.h"
#include <dfs_elm.h>
#include <dfs_fs.h>

#define FLASH_MOUNTPOINT 	"/"

#define FATFS_FAILURE		0
#define FATFS_NORMAL		1

#define GD25QXX_MOUNT		0
#define GD25QXX_UNMOUNT		1

typedef struct
{
	uint8_t fatfs_status:1;			//文件系统状态
	uint8_t mount_status:1;			//挂载状态
}gd25qxx_struct;

extern gd25qxx_struct *gd25qxx_sta;

int gd25qxx_init(void);
int gd25qxx_create_fatfs(void);
int gd25qxx_mount(void);
int gd25qxx_unmount(void);

#endif

5、在applications文件夹下新建disk.h、disk.c文件,并添加以下代码。
disk.c

#include "disk_app.h"

#define DISK_THREAD_STACK_SIZE	1024

static void rt_disk_thread_entry(void* parameter)
{
    while(1)
    {
		if((usbh_usr->init_status == USBH_USR_READY) && (usbh_usr->mount_status == UDISK_UNMOUNT))
		{
			usbh_usr->mount_status = UDISK_MOUNT;
			udisk_mount();
		}
		
		if((usbh_usr->connected_status == USBH_USR_DISCONNECTED) && (usbh_usr->mount_status == UDISK_MOUNT))
		{
			usbh_usr->mount_status = UDISK_UNMOUNT;
			udisk_unmount();
		}
		
		rt_thread_mdelay(100);
    }
}

int disk_init(void)
{
	rt_thread_t thread = RT_NULL;
	
	rt_thread_mdelay(100);
	gd25qxx_init();
	usb_host_init();
	
	if((thread = rt_thread_create("disk", rt_disk_thread_entry, RT_NULL,DISK_THREAD_STACK_SIZE, 10, 20)) != RT_NULL)
		rt_thread_startup(thread);
	else
		rt_kprintf("create disk thread failed.\n");
	
	return RT_EOK;
}
MSH_CMD_EXPORT(disk_init,disk init);
INIT_APP_EXPORT(disk_init);


disk.h

#ifndef __DISK_APP_H
#define __DISK_APP_H

#include "gd25qxx.h"
#include "usb_host.h"

#endif

6、修改usb_host.c中rt_usbh_thread_entry函数。

static void rt_usbh_thread_entry(void* parameter)
{
    while(1)
    {    
		host_state_polling_fun(&usb_core_dev, &usb_host, usbh_state_core);
		rt_thread_mdelay(10);
    }
}

7、编译下载运行后发现初始化就会死机。
在这里插入图片描述
加大man线程的堆内存即可。
在这里插入图片描述
8、编译下载运行。
在这里插入图片描述

四、源码下载

代码下载—


总结

搞定!躺尸...
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小破孩 != ERR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值