关于stm32的USB学习笔记之USB_HW.c
扫描二维码
随时随地手机看文章
[cpp] view plaincopyprint?
#include
#include
#include "usbreg.h"
#include "usbuser.h"
#include "usbcore.h"
#include "usb_hw.h"
#define _DEBUG_
#include "debug.h"
#define USB_EP_NUM 4
/*端点缓冲区的开始地址
*因为每个缓冲块都需要一个端点描术表
*而所有的端点描述表放在,USB缓冲区的首部
*此地址是相对于USB缓冲区的地址,我认为加上Offset更好些
*这里使用2个端点
*端点0与端点1
*此时EP_BUF_ADDR指向缓冲区的内容
*/
#define EP_BUF_ADDR (sizeof(EP_BUF_DSCR)*USB_EP_NUM)
/*USB缓冲区首地址包括缓冲区描述表,绝对地址*/
EP_BUF_DSCR * pBUF_DSCR = (EP_BUF_DSCR *) USB_PMA_ADDR;
/*端点空闲缓冲区地址
*用于指示目前为止USB缓冲区中还没有分配的空闲地址的首地址*/
WORD FreeBufAddr;
/*功能:用于初始化USB的时钟等部分
*参数:无
*返回值:无
*/
void USB_Init(void)
{
printf("进入USB_Init,进行初始化rn");
//使能USB时钟
RCC->APB1ENR |= (1<<23);
//使能USB中断
/*因为USB低优先级中断的中断号为20,而NVIC——IPRX
*寄存器用四位来存储中断优先级,所以20/4=5 ,
*然后使能第20位中断*/
NVIC->IPR[5] |=0x10;
NVIC->ISER[0]|=(1<<20);
}
/*功能:用于复位USB模块
*参数:无
*返回值:无
*/
/*现在以我的水平还搞不懂双缓冲为何物,所以先不搞^-^*/
/*一些资料:
*USB低优先级中断(通道20):可由所有USB事件触发(正确传输,USB复位等).
*USB高优先级中断(通道19):仅能由同步和双缓冲批量传输事件触发,目的是保证最大的传输速率.
*USB唤醒中断(通道42):由USB挂起模式的唤醒事件触发. OTG_FS_WKUP唤醒
*
*复位要执行的内容可以参见rm0008 21.4.2节
*/
void USB_Reset(void)
{
PrintS("USB_Resetrn");
/*复位了嘛,那所有以前产生的中断都没有用了,清了完事!*/
ISTR=0;
/*通过设置CNTR来控制stm32的USB模块的工作方式
*所有的USB事件中断都是在低优先级中断(通道20)上处理的
*好吧就先使能这么多吧,先跑起来再说!
*/
CNTR= CNTR_CTRM | // 使能正确传输中断
CNTR_RESETM | //使能复位中断
CNTR_SUSPM | //使能挂起中断
CNTR_WKUPM ; //使能唤醒中断
FreeBufAddr = EP_BUF_ADDR; //此时FreeBuff指向第一个缓冲区首地址(不包括描述符表),相对地址
BTABLE = 0x00; //设置缓冲区描述表的位置仍是相对地址
/*为端点0设置缓冲区及各种控制位*/
pBUF_DSCR->ADDR_TX = FreeBufAddr;
FreeBufAddr+=8; //端点0设置为8个字节,一般控制数据为8个字节
pBUF_DSCR->ADDR_RX = FreeBufAddr;
FreeBufAddr+=8;
/*在count_Rx字段中10~14bit用来表示缓冲区字节的快数
*而15bit用来表示块的大小
*0---2byte
*1---1byte
*我们这里使用了8个字节,bit15为0,所以应该((8<<10)>>1)即8<<9;
*至于count_Rx我们在发送时再来赋值
*/
pBUF_DSCR->COUNT_RX= 8 << 9;
/*设置端点0为控制端点,接收缓冲区有效
*低四位代表端点地址
*/
EPxREG(0) = EP_CONTROL | EP_RX_VALID;
/*使能USB模块,并设置USB地址为0,以响应枚举*/
DADDR = DADDR_EF | 0;
}
/*功能:复位一个端点
*参数: 端点号
* EPNum:bit3~bit0 ----> 端点号
* EPNum:bit7 ----> 端点方向
*
*返回值:无
*/
/*其实就是将下一个要发送的数据包变成DATA0*/
void EP_Reset(DWORD EPNum)
{
DWORD num,var;
PrintS("EP_Resetrn");
/*获得端点号,低四位为端点号*/
num = EPNum & 0x0F;
var = EPxREG(num);
/*如果bit7为1则将此端点的发送toggle置为0,
*否则将此端点的接收toggle置为0
*因为数据总是从data0数据包开始发送的
*/
if(EPNum & 0x80)
EPxREG(num) = var & (EP_MASK | EP_DTOG_TX);/*输入端点*/
else
EPxREG(num) = var & (EP_MASK | EP_DTOG_RX);/*输出端点*/
}
/*功能:连接或断开USB功能
*参数:true -->连接USB
* false-->关闭USB
*返回值:无
*/
void USB_Connect(BOOL turnon)
{
/*需要注意一点的事,所有的USB寄存器尽量用=而不要用与或非
*在编程手册上有明确表明,这样可能会导至出一些问题*/
printf("进入连接USB程序rn");
/*将USB强制复位*/
CNTR = CNTR_FRES;
// printf("test1rn");
/*因为刚连接所以应该跟才启动一样,将所有没有处理的中断给清理掉*/
ISTR=0;
// printf("test2rn");
if(turnon)
{
// printf("test3rn");
/*使能GPIOA,然后将PA.8置低,使USB
*的D+加1.5K上接电阻,使USB集线器识别了高速设备
*这样才能让USB识别
*/
RCC->APB2ENR |= (1 << 2); /* enable clock for GPIOA */
GPIOA->CRH &= ~(0x0f << 0 * 4); /* clear port PA8 */
GPIOA->CRH |= (0x03 << 0 * 4); /* PA6 General purpose output open-drain, max speed 50 MHz */
GPIOA->BRR = ( 1 << 8 ); /* reset PA8 (set to low) */
/*经过调试发现,这个语句的本意是:复位USB模块
*然后在此使能CNTR_RESETM即复位中断标志
*至于端点0的初始化留在USB低优先级中进行处理
*当然,我们也只开了低优先级中断^_^!*/
CNTR = CNTR_RESETM; /*此处只使能了复位中断,*/
}
else
CNTR = CNTR_FRES | CNTR_PDWN ;/*复位并关闭*/
}
/*功能:设置端点状态
*参数:EPnum --->端点号
* stat --->要设置的状态值
*返回值:无
*/
void USB_ConfigEP (USB_ENDPOINT_DESCRIPTOR * pEPD)
{
DWORD num,val;
//取得端点号
num = pEPD->bEndpointAddress & 0xf;
val = pEPD->wMaxPacketSize;
//如果是IN端点
if(pEPD->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK)
{
//此处我只想说pBUF_DSCR是指针,剩下的就是语法问题了
(pBUF_DSCR + num)->ADDR_TX = FreeBufAddr;
/*取2的倍数,因为缓冲区都是字对齐的,注意此处如果大于1023会出现浪费现象
*因为USB_COUNTn