您的位置:控制工程论坛网论坛 » 教程与手册 » 基于STM32的USB程序开发笔记 1

xilinxue

xilinxue   |   当前状态:在线

总积分:16186  2024年可用积分:0

注册时间: 2008-06-26

最后登录时间: 2020-03-22

空间 发短消息加为好友

基于STM32的USB程序开发笔记 1

xilinxue  发表于 2008/11/22 13:29:25      1137 查看 2 回复  [上一主题]  [下一主题]

手机阅读

STM32 USB固件函数的一些介绍
接着上篇,详细情况可以查看usb_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;
}
1楼 0 0 回复
  • xilinxue

    xilinxue   |   当前状态:在线

    总积分:16186  2024年可用积分:0

    注册时间: 2008-06-26

    最后登录时间: 2020-03-22

    空间 发短消息加为好友

    xilinxue   发表于 2008/11/22 13:29:03

    在这个ISTR_CTR()函数中,定义了EP0、1、2的传输方式以及各自的缓冲描述符,其中EP0是默认端口,负责完成USB设备的枚举,一般情况是不需要更改的。其他端点配置则需根据实际应用而决定,如何设置请仔细理解STM32的参考手册。
    值得说明的是STM32的端点RX/TX缓冲描述表是定义在PMA中的,他是基于分组缓冲区描述报表寄存器(BTABLE)而定位的,各端点RX/TX缓冲描述表说明是数据存储地址以及大小,这个概念需要了解,ST提供的固件很含糊,为此,我在usb_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的数据包大小就可以了,当然,实际情况可以根据需要进行更改。

    2楼 回复本楼

    引用 xilinxue 2008/11/22 13:29:03 发表于2楼的内容

  • xilinxue

    xilinxue   |   当前状态:在线

    总积分:16186  2024年可用积分:0

    注册时间: 2008-06-26

    最后登录时间: 2020-03-22

    空间 发短消息加为好友

    xilinxue   发表于 2008/11/22 13:29:25

    // *****************************************************************************
    // 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楼 回复本楼

    引用 xilinxue 2008/11/22 13:29:25 发表于3楼的内容

总共 , 当前 /