STM32/STM8技术william hill官网
直播中

zhou2sheng

10年用户 1849经验值
擅长:嵌入式技术 EDA/IC设计 处理器/DSP 接口/总线/驱动 控制/MCU
私信 关注
[经验]

基于STM32的USB程序开发笔记(三)

STM32 USB固件函数的一些介绍
接着上篇,详细情况可以查看u***_core(.c/.h)STM32 USB中断事件为以下几种:
void ISTR_CTR(void);
void ISTR_SOF(void);
void ISTR_ESOF(void);
void ISTR_DOVR(void);
void ISTR_ERROR(void);
void ISTR_RESET(void);
void ISTR_WAKEUP(void);
void ISTR_SUSPEND(void);

这些处理函数使能由定义CNTR_MASK决定:
// CNTR mask control
#define CNTR_MASK   CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM |      
                    CNTR_SOFM | CNTR_ESOFM | CNTR_RESETM | CNTR_DOVRM      

其中着重说明的是ISTR_RESET()ISTR_CTR()函数,ISTR_RESET()主要处理USB复位后进行一些初始化任务,ISTR_CTR()则是处理数据正确传输后控制,比如说响应主机。

// *****************************************************************************
// Function Name  : INT_ISTR_RESET
// Description    : ISTR Reset Interrupt service routines.
// Input          :
// Output         :
// Return         :
// *****************************************************************************
void INT_ISTR_RESET(void)
{
  // Set the buffer table address
  SetBTABLE(BASEADDR_BTABLE);

  // Set the endpoint type: ENDP0
  SetEPR_Type(ENDP0, EP_CONTROL);
  Clr_StateOut(ENDP0);

  // Set the endpoint data buffer address: ENDP0 RX
  SetBuffDescTable_RXCount(ENDP0, ENDP0_PACKETSIZE);
  SetBuffDescTable_RXAddr(ENDP0, ENDP0_RXADDR);

  // Set the endpoint data buffer address: ENDP0 TX
  SetBuffDescTable_TXCount(ENDP0, 0);
  SetBuffDescTable_TXAddr(ENDP0, ENDP0_TXADDR);
// Initialize the RX/TX status: ENDP0
  SetEPR_RXStatus(ENDP0, EP_RX_VALID);
  SetEPR_TXStatus(ENDP0, EP_TX_NAK);

  // Set the endpoint address: ENDP0
  SetEPR_Address(ENDP0, ENDP0);

  // ---------------------------------------------------------------------
  // TODO: Add you code here
  // ---------------------------------------------------------------------
  // Set the endpoint type: ENDP1
  SetEPR_Type(ENDP1, EP_INTERRUPT);
  Clr_StateOut(ENDP1);

  // Set the endpoint data buffer address: ENDP1 RX
  SetBuffDescTable_RXCount(ENDP1, ENDP1_PACKETSIZE);
  SetBuffDescTable_RXAddr(ENDP1, ENDP1_RXADDR);

  // Set the endpoint data buffer address: ENDP1 TX
  SetBuffDescTable_TXCount(ENDP1, 0);
  SetBuffDescTable_TXAddr(ENDP1, ENDP1_TXADDR);

  // Initialize the RX/TX status: ENDP1
  SetEPR_RXStatus(ENDP1, EP_RX_VALID);
  SetEPR_TXStatus(ENDP1, EP_TX_DIS);

  // Set the endpoint address: ENDP1
  SetEPR_Address(ENDP1, ENDP1);
  
  
  
  SetEPR_Type(ENDP2, EP_INTERRUPT);
  Clr_StateOut(ENDP2);

  // Set the endpoint data buffer address: ENDP2 RX
  SetBuffDescTable_RXCount(ENDP2, ENDP2_PACKETSIZE);
  SetBuffDescTable_RXAddr(ENDP2, ENDP2_RXADDR);

  // Set the endpoint data buffer address: ENDP2 TX
  SetBuffDescTable_TXCount(ENDP2, 0);
  SetBuffDescTable_TXAddr(ENDP2, ENDP2_TXADDR);

  // Initialize the RX/TX status: ENDP2
  SetEPR_RXStatus(ENDP2, EP_RX_DIS);
SetEPR_TXStatus(ENDP2, EP_TX_VALID);

  // Set the endpoint address: ENDP2
  SetEPR_Address(ENDP2, ENDP2);



  // ---------------------------------------------------------------------
  // End of you code
  // ---------------------------------------------------------------------
  
  SetDADDR(0x0080 | vsDeviceInfo.bDeviceAddress);
  vsDeviceInfo.eDeviceState = DS_DEFAULT;
  vsDeviceInfo.bCurrentFeature = 0x00;
  vsDeviceInfo.bCurrentConfiguration = 0x00;
  vsDeviceInfo.bCurrentInterface = 0x00;
  vsDeviceInfo.bCurrentAlternateSetting = 0x00;
  vsDeviceInfo.uStatusInfo.w = 0x0000;
}
在这个ISTR_CTR()函数中,定义了EP012的传输方式以及各自的缓冲描述符,其中EP0是默认端口,负责完成USB设备的枚举,一般情况是不需要更改的。其他端点配置则需根据实际应用而决定,如何设置请仔细理解STM32的参考手册。
值得说明的是STM32的端点RX/TX缓冲描述表是定义在PMA中的,他是基于分组缓冲区描述报表寄存器(BTABLE)而定位的,各端点RX/TX缓冲描述表说明是数据存储地址以及大小,这个概念需要了解,ST提供的固件很含糊,为此,我在u***_regs.h文件中进行了重新定义,如下:
// USB_IP Packet Memory Area base address  
#define PMAAddr  (0x40006000L)  

// Buffer Table address register
#define BTABLE  ((volatile unsigned *)(RegBase + 0x50))

// *****************************************************************************
// Packet memory area: Total 512Bytes
// *****************************************************************************
#define BASEADDR_BTABLE        0x0000
// *****************************************************************************
// PMAAddr + BASEADDR_BTABLE + 0x00000000 : EP0_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000002 : EP0_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x00000004 : EP0_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000006 : EP0_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000008 : EP1_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000000A : EP1_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x0000000C : EP1_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000000E : EP1_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000010 : EP2_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000012 : EP2_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x00000014 : EP2_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000016 : EP2_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000018 : EP3_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000001A : EP3_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x0000001C : EP3_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000001E : EP3_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000020 : EP4_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000022 : EP4_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x00000024 : EP4_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000026 : EP4_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000028 : EP5_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000002A : EP5_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x0000002C : EP5_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000002E : EP5_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000030 : EP6_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000032 : EP6_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x00000034 : EP6_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x00000036 : EP6_RX_COUNT
//
// PMAAddr + BASEADDR_BTABLE + 0x00000038 : EP7_TX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000003A : EP7_TX_COUNT
// PMAAddr + BASEADDR_BTABLE + 0x0000003C : EP7_RX_ADDR
// PMAAddr + BASEADDR_BTABLE + 0x0000003E : EP7_RX_COUNT
// *****************************************************************************
//
// PMAAddr + BASEADDR_BTABLE + (0x00000040 - 0x000001FF) : assigned to data buffer
//
// *****************************************************************************
#define BASEADDR_DATA   (BASEADDR_BTABLE + 0x00000040)

// ENP0
#define ENDP0_PACKETSIZE      0x40
#define ENDP0_RXADDR          BASEADDR_DATA
#define ENDP0_TXADDR          (ENDP0_RXADDR + ENDP0_PACKETSIZE)

// ENP1
#define ENDP1_PACKETSIZE      0x40
#define ENDP1_RXADDR          (ENDP0_TXADDR + ENDP0_PACKETSIZE)
#define ENDP1_TXADDR          (ENDP1_RXADDR + ENDP1_PACKETSIZE)

// ENP2
#define ENDP2_PACKETSIZE      0x40
#define ENDP2_RXADDR          (ENDP1_TXADDR + ENDP1_PACKETSIZE)
#define ENDP2_TXADDR          (ENDP2_RXADDR + ENDP2_PACKETSIZE)

// ENP3
#define ENDP3_PACKETSIZE      0x40
#define ENDP3_RXADDR          (ENDP2_TXADDR + ENDP2_PACKETSIZE)
#define ENDP3_TXADDR          (ENDP3_RXADDR + ENDP3_PACKETSIZE)

// ENP4
#define ENDP4_PACKETSIZE      0x40
#define ENDP4_RXADDR          (ENDP3_TXADDR + ENDP3_PACKETSIZE)
#define ENDP4_TXADDR          (ENDP4_RXADDR + ENDP4_PACKETSIZE)

// ENP5
#define ENDP5_PACKETSIZE      0x40
#define ENDP5_RXADDR          (ENDP4_TXADDR + ENDP4_PACKETSIZE)
#define ENDP5_TXADDR          (ENDP5_RXADDR + ENDP5_PACKETSIZE)

// ENP6
#define ENDP6_PACKETSIZE      0x40
#define ENDP6_RXADDR          (ENDP5_TXADDR + ENDP5_PACKETSIZE)
#define ENDP6_TXADDR          (ENDP6_RXADDR + ENDP6_PACKETSIZE)

// ENP7
#define ENDP7_PACKETSIZE      0x40
#define ENDP7_RXADDR          (ENDP6_TXADDR + ENDP6_PACKETSIZE)
#define ENDP7_TXADDR          (ENDP7_RXADDR + ENDP7_PACKETSIZE)

这样,一般只要在PMA的大小区域内(512Bytes),修改端点EPnR的数据包大小就可以了,当然,实际情况可以根据需要进行更改。


// *****************************************************************************
// Function Name  : INT_ISTR_CTR
// Description    : ISTR Correct Transfer Interrupt service routine.
// Input          :
// Output         :
// Return         :
// *****************************************************************************
void INT_ISTR_CTR(void)
{
  unsigned short wEPIndex;
  unsigned short wValISTR;
  unsigned short wValENDP;

  while( ((wValISTR=GetISTR()) & ISTR_CTR) != 0 )
  {
    // Get the index number of the endpoints
    wEPIndex =  wValISTR & ISTR_EP_ID;

    if(wEPIndex == 0)
    {
      // Set endpoint0 RX/TX status: NAK (Negative-Acknowlegment)
      SetEPR_RXStatus(ENDP0, EP_RX_NAK);
      SetEPR_TXStatus(ENDP0, EP_TX_NAK);

       // Transfer direction
      if((wValISTR & ISTR_DIR) == 0)
      {
        // DIR=0: IN
        // DIR=0 implies that EP_CTR_TX always 1
        ClrEPR_CTR_TX(ENDP0);
        CTR_IN0();
        return;
      }
      else
      {
        // DIR=1: SETUP or OUT
        // DIR=1 implies that CTR_TX or CTR_RX always 1
        wValENDP = GetEPR(ENDP0);
        if((wValENDP & EP_CTR_TX) != 0)
        {
          ClrEPR_CTR_TX(ENDP0);
          CTR_IN0();
          return;
        }
        else if((wValENDP & EP_SETUP) != 0)
        {
          ClrEPR_CTR_RX(ENDP0);
          CTR_SETUP0();
          return;
        }
else if((wValENDP & EP_CTR_RX) != 0)
        {
          ClrEPR_CTR_RX(ENDP0);
          CTR_OUT0();
          return;
        }
      }      
    }
    // Other endpoints
    else
    {
      wValENDP = GetEPR(wEPIndex);
      
      SetEPR_RXStatus(wEPIndex, EP_RX_NAK);
      SetEPR_TXStatus(wEPIndex, EP_TX_NAK);
            
      if((wValENDP & EP_CTR_TX) != 0)
      {
        ClrEPR_CTR_TX(wEPIndex);
        switch(wEPIndex)
        {
        case ENDP1: CTR_IN1(); break;
        case ENDP2: CTR_IN2(); break;
        case ENDP3: CTR_IN3(); break;
        case ENDP4: CTR_IN4(); break;
        case ENDP5: CTR_IN5(); break;
        case ENDP6: CTR_IN6(); break;
        case ENDP7: CTR_IN7(); break;
        default: break;
        }
      }

      if((wValENDP & EP_CTR_RX) != 0)
      {
        ClrEPR_CTR_RX(wEPIndex);
        switch(wEPIndex)
        {
        case ENDP1: CTR_OUT1(); break;
        case ENDP2: CTR_OUT2(); break;
        case ENDP3: CTR_OUT3(); break;
        case ENDP4: CTR_OUT4(); break;
        case ENDP5: CTR_OUT5(); break;
        case ENDP6: CTR_OUT6(); break;
        case ENDP7: CTR_OUT7(); break;
default: break;
        }
      }
    }
  }
}

INT_ISTR_CTR()函数将各自响应事件提取出来,默认端点EP0也是最为复杂的,这个需要查看STM32的参考手册以及USB协议才能更好了解为何如此。到这里STM32 USB里数据传输事件就指向了各个对应的端点。下篇着重说明USB设备的枚举。

回帖(3)

184747694

2014-7-6 14:58:28
管理员 头像是你的本人吗?
举报

Shah

2015-3-20 14:46:35
可以参考,感谢分享
举报

黄友霖

2015-9-7 00:19:30
参考下,谢谢大神
举报

更多回帖

发帖
×
20
完善资料,
赚取积分