⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb.c

📁 USB 通信,使用的是Freescale公司的CMX协议栈
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
 *
 *            Copyright (c) 2006 by CMX Systems, Inc.
 *
 * This software is copyrighted by and is the sole property of
 * CMX.  All rights, title, ownership, or other interests
 * in the software remain the property of CMX.  This
 * software may only be used in accordance with the corresponding
 * license agreement.  Any unauthorized use, duplication, transmission,
 * distribution, or disclosure of this software is expressly forbidden.
 *
 * This Copyright notice may not be removed or modified without prior
 * written consent of CMX.
 *
 * CMX reserves the right to modify this software without notice.
 *
 * CMX Systems, Inc.
 * 12276 San Jose Blvd. #511
 * Jacksonville, FL 32223
 * USA
 *
 * Tel:  (904) 880-1840
 * Fax:  (904) 880-1632
 * http: www.cmx.com
 * email: cmx@cmx.com
 *
 ***************************************************************************/
#include "hcc_types.h"
#include "mcf5222x_reg.h"
#include "usb.h"
#include "target.h"
#include "uart.h"
/*****************************************************************************
 * Local types.
 *****************************************************************************/
typedef struct {
  volatile hcc_u32 tlength;           //需要传输的字节数
  volatile hcc_u32 maxlength;         //最大传输字节数
  void * volatile address;            //数据缓冲区地址
  volatile usb_callback_t data_func;  //
  hcc_u16 psize;                      //端点允许的最大包长度
  hcc_u32 data0_tx;                   //tx触发位
  hcc_u32 data0_rx;                   //rx触发位
  volatile hcc_u8 state;              //控制端点状态机的状态值
  volatile hcc_u8 flags;              //端点标识位
                                      //EPFL_ERROR   :传输过程中有错误
                                      //EPFL_ZPACKET :最后一个数据包结束后发送0长度的包结束数据阶段
  volatile hcc_u8 error;              //错误标志
  hcc_u8 next_rx;                     //下一个rx缓冲区
  hcc_u8 next_tx;                     //下一个tx缓冲区
  hcc_u8 pad1;                        //
} ep_info_t;

/*****************************************************************************
 * Macro definitions.
 *****************************************************************************/
#define DIR_TX             BIT7

#define SOF_PID_VALUE		0xd
/* Note: BIT3 shows if the data packet is data0 or data1. */
#define DATA_PID_VALUE      0x3
#define DATA0_PID_VALUE     0x3
#define DATA1_PID_VALUE     0xb
 
#define MCF_USB_ENDPT(ep)  (((hcc_u8*)&MCF_USB_ENDPT0)[ep<<2])
#define MCF_USB_ENDPT_EP_HSHK      BIT0
#define MCF_USB_ENDPT_EP_STALL     BIT1
#define MCF_USB_ENDPT_EP_TX_EN     BIT2
#define MCF_USB_ENDPT_EP_RX_EN     BIT3
#define MCF_USB_ENDPT_EP_CTL_DIS   BIT4
#define MCF_USB_ENDPT_RETRY_DIS    BIT6
#define MCF_USB_ENDPT_HOST_WO_HUB  BIT7

#define MIN(a,b)     ((a) < (b) ? (a) : (b))

/* Control endpoint state machine state values. */
#define EPST_IDLE             0x0
#define EPST_DATA_TX          0x1
#define EPST_DATA_TX_LAST     0x2
#define EPST_DATA_RX          0x3
#define EPST_STATUS_TX        0x4
#define EPST_STATUS_RX        0x5
#define EPST_TX_STOP          0x6
#define EPST_ABORT_TX         0x7
#define EPST_DATA_TX_WAIT_DB  0x8
#define EPST_DATA_TX_EMPTY_DB 0x9

/* Standard USB feature selector values. */
#define FEAT_ENDPOINT_HALT        0u
#define FEAT_DEVICE_REMOTE_WAKEUP 1u

/* Endpoint flag bits. */
#define EPFL_ERROR    (hcc_u8)BIT0  /* There was an error during the ongoing
                               transfer. */
#define EPFL_ZPACKET  (hcc_u8)BIT1  /* After the last data packet an additional zero
                               length packet needs to be transmitted to close
                               the transfer. */

/* This macro shall evaluate to a uint32 pointer to the start address of the
   buffer descriptor table (BDT). The BDT has 32 bytes for each endpoint. 
   The BDT shall be alignet to 512 byte boundary! */
extern hcc_u32 _BDT_BASE[];
#define BDT_BASE              ((hcc_u32*)(_BDT_BASE))
#define BDT_CTL_RX(ep, b)     (BDT_BASE[((ep)<<3)+((b)<<1)+0])
#define BDT_ADR_RX(ep, b)     (BDT_BASE[((ep)<<3)+((b)<<1)+1])
#define BDT_CTL_TX(ep, b)     (BDT_BASE[((ep)<<3)+((b)<<1)+4])
#define BDT_ADR_TX(ep, b)     (BDT_BASE[((ep)<<3)+((b)<<1)+5])

#define BDT_CTL_STALL BIT2 
#define BDT_CTL_DTS   BIT3
#define BDT_CTL_DATA  BIT6
#define BDT_CTL_OWN   BIT7

/*****************************************************************************
 * Global variables.
 *****************************************************************************/
/* N/A */

/*****************************************************************************
 * Module variables.
 *****************************************************************************/
static volatile hcc_u8 usb_current_config;
static volatile hcc_u8 usb_state;
static volatile hcc_u8 new_address;
static ep_info_t ep_info[16];

/*****************************************************************************
 * Function predefinitions.
 *****************************************************************************/
static void enter_default_state(void);
static void disable_ep_rx(hcc_u8);
static void disable_ep_tx(hcc_u8);
static void ready_ep_rx(hcc_u8, hcc_u8);
static void ready_ep_tx(hcc_u8, hcc_u8);
static hcc_u8 select_tx_buf(hcc_u8 ep);
static void send_zero_packet(hcc_u8 ep);
static void _usb_send(hcc_u8 ep);
static void _usb_receive(hcc_u8 ep);
static callback_state_t cb_set_address(void);
static callback_state_t usb_stm_ctrl0(void);

//usb_get_rx_pptr:取得端点刚接收到数据的缓冲区地址-------------------------*
//功  能:                                                                  *
//    取得端点刚接收到数据的缓冲区地址,即该端点的BD.ADR_RX                 *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 端点接收缓冲区的地址                                             *
//说  明:                                                                  *
//       由于端点有两个接收缓冲区EVEN和ODD,所以还要根据MCF_USB_STAT.ODD位 *
//       判断上一个接收到的数据是存放在ODD还是EVEN中                       *
//-------------------------------------------------------------------------*
hcc_u8* usb_get_rx_pptr(hcc_u8 ep)
{
  hcc_u8 cur_buf=(hcc_u8)(MCF_USB_STAT & MCF_USB_STAT_ODD ? 1 : 0);
  return((hcc_u8 *)(RD_LE32(&BDT_ADR_RX(ep, cur_buf))));	
}
 
//select_tx_buf:取得端点下一个发送缓冲区的索引-----------------------------*
//功  能:                                                                  *
//    取得下一个发送缓冲区的索引                                           *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 下一个tx缓冲区的索引,有效值为0或1                               *
//说  明:                                                                  *
//       由于端点有两个发送缓冲区EVEN和ODD,所以还要判断是选EVEN还是ODD    *
//-------------------------------------------------------------------------*
static hcc_u8 select_tx_buf(hcc_u8 ep)
{
/* SHALL ONLY BE CALLED WITH USB INTERRUPTS DISABLED. */
  hcc_u8 buf;
  hcc_u32 ctl;
  //查找BDT中该端点的EVEN或ODD BD是否已经被使用
  ctl=(RD_LE32(&BDT_CTL_TX(ep, 0)) & BDT_CTL_OWN)
      | (RD_LE32(&BDT_CTL_TX(ep, 1)) & BDT_CTL_OWN) << 1;  
      
  switch(ctl)
  {
	  case 0:               //两个BD均未被使用
	    buf=ep_info[ep].next_tx;
	    ep_info[ep].next_tx ^= 0x1;    
	    break;
	  case BDT_CTL_OWN:     //EVEN BD已经被USB使用
	    buf=1;
	    ep_info[ep].next_tx=0;
	    break;
	  case BDT_CTL_OWN<<1:  //ODD BD已经被USB使用
	    buf=0;
	    ep_info[ep].next_tx=1;
	    break;
	  default:              //两个BD均被使用则报告错误
	    CMX_ASSERT(0);
  }
  return(buf);   
}

//usb_get_done:返回发送完成的字节数----------------------------------------*
//功  能:                                                                  *
//    返回发送完成的字节数                                                 *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 发送完成的字节数                                                 *
//-------------------------------------------------------------------------*
hcc_u32 usb_get_done(hcc_u8 ep)
{
  return(ep_info[ep].maxlength-ep_info[ep].tlength);
}

//usb_ep_is_busy:判断USB模块是否忙-----------------------------------------*
//功  能:                                                                  *
//    判断USB模块是否忙                                                    *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 0:空闲,1:忙                                                      *
//-------------------------------------------------------------------------*
hcc_u8 usb_ep_is_busy(hcc_u8 ep)
{
  return(ep_info[ep].state != EPST_IDLE ? (hcc_u8)1 : (hcc_u8)0);
}

//usb_get_state:取得USB模块的当前状态--------------------------------------*
//功  能:                                                                  *
//    取得USB模块的当前状态                                                *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: USB模块的当前状态                                                *
//-------------------------------------------------------------------------*
hcc_u8 usb_get_state(void)
{
  return(usb_state);
}

//usb_ep_error:取得USB模块的错误标识---------------------------------------*
//功  能:                                                                  *
//    取得USB模块的错误标识                                                *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 取得USB模块的错误标识                                            *
//-------------------------------------------------------------------------*
hcc_u8 usb_ep_error(hcc_u8 ep)
{
  hcc_u8 tmp=ep_info[ep].error;
  ep_info[ep].error=USBEPERR_NONE;
  return(tmp);
}
 
//send_zero_packet:发送0长度的包-------------------------------------------*
//功  能:                                                                  *
//    控制OUT传输状态阶段的响应                                            *                                                          *
//参  数: ep: 端点号                                                       *
//返  回: 无                                                               *
//说  明: 发送0长度的数据包说明设备的状态是OK的                            *
//-------------------------------------------------------------------------*
static void send_zero_packet(hcc_u8 ep)
{
  hcc_u8 buf;
  
  buf=select_tx_buf(ep);
  WR_LE32(&BDT_CTL_TX(ep, buf), 0);  
  ready_ep_tx(ep, buf);
}

//USB_Init:USB模块初始化函数-----------------------------------------------*
//功  能:                                                                  *
//    USB模块初始                                                          *
//参  数: ip: 中断优先级                                                   *
//        use_alt_clk: 使用的时钟源                                        *
//返  回:成功返回0,不成功返回非0                                          *
//说  明:                                                                  *
//    (1)必须在模块初始化完成后才能全能上拉,以供主机识别                  *
//    (2)调用该函数之前必须确保设置了稳定的USB模块的时钟源                 *
//-------------------------------------------------------------------------*
hcc_u8 usb_init(hcc_u8 ip, hcc_u8 use_alt_clk)
{
  //退出suspend状态并设定时钟源
  MCF_USB_USB_CTRL = (hcc_u8)(use_alt_clk ? 0u : 1u);

  //禁止所有USB中断
  MCF_USB_INT_ENB = 0x0;
  //禁止所有OTG中断
  MCF_USB_OTG_INT_EN = 0x0;
  //禁止所有USB错误中断
  MCF_USB_ERR_ENB = 0x0;

  MCF_USB_OTG_CTRL &= ~MCF_USB_OTG_CTRL_DP_HIGH;
  //配置USB为默认状态
  enter_default_state();

  //清除OTG中断标志
  MCF_USB_OTG_INT_STAT = 0xff;
  //清除USB中断标志
  MCF_USB_INT_STAT = 0xff;
  //清除USB Error中断标志
  MCF_USB_ERR_STAT = 0xff;

  //设置中断优先级
  MCF_INTC0_ICR53 = ip;
  //使能中断控制器中的USB中断
  MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_MASK53;
  MCF_INTC0_IMRL &= ~ MCF_INTC_IMRL_MASKALL;

  //使能USB中断
  MCF_USB_INT_ENB = MCF_USB_INT_ENB_SLEEP | MCF_USB_INT_ENB_TOK_DNE
                    | MCF_USB_INT_ENB_ERROR | MCF_USB_INT_ENB_USB_RST
                    | MCF_USB_INT_ENB_STALL;

  //设定缓冲区描述符表BDT的地址 
  MCF_USB_BDT_PAGE_01 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 8);
  MCF_USB_BDT_PAGE_02 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 16);
  MCF_USB_BDT_PAGE_03 = (hcc_u8)(((hcc_u32)BDT_BASE) >> 24);

  //使能USB模块
  MCF_USB_CTL = MCF_USB_CTL_USB_EN_SOF_EN;

  //使能D+和D-上的上拉电阻
  //MCF_USB_OTG_CTRL = MCF_USB_OTG_CTRL_DP_HIGH | MCF_USB_OTG_CTRL_DM_HIGH;
  MCF_USB_OTG_CTRL = MCF_USB_OTG_CTRL_DP_HIGH|MCF_USB_OTG_CTRL_OTG_EN;

  I2CsendByte(0x00, 0x11, 0x58);	/*just turn on*/
  iic_delay();
  I2CsendByte(0x14, 0x10, 0x58);  /*FS device   */
  iic_delay();
  return(0);
}
 
//usb_setup_ep:设置端点函数_-----------------------------------------------*
//功  能:                                                                  *
//    设置端点                                                             *
//参  数: addr: 端点地址                                                   *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -