zoukankan      html  css  js  c++  java
  • 【演示实例】在EKSTM32F学习套件上实现了USBDFU设备功能转载

    首先在ST官网上下载了STM32的USB开发套件地址:http://www.st.com/stonline/products/support/micro/files/um0424.zip

    由于此开发套件基于ST的官方开发板,与EK-STM32F的电路有所不同。

    比较了一下,不同之处在于
    1, 官方的开发套件使用PD.09作为USB识别使能线,而EK-STM32F使用PD.08。
    2, 官方的开发套件通过PB.09来判断是否进入DFU模式, 而EK-STM32F的按键使用了PD.03和PD.04。
    3,  EK-STM32F没有接外部SPI Flash, 所以只能更新内部flash。

    因此修改代码如下:

    void DFU_Button_Config(void)
    {
      GPIO_InitTypeDef GPIO_InitStructure;
     
      /* Enable GPIOD clock */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
     
      /* Configure PD.04 as input floating (Key push-button on EK-STM32F) */
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      GPIO_Init(GPIOD, &GPIO_InitStructure);
    }

    u8 DFU_Button_Read (void)
    {
      /* Return the value of PD.04 */
      return GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_4);
    }

    void Set_System(void)
    {
      GPIO_InitTypeDef GPIO_InitStructure;
     
      FLASH_Unlock();

      /* RCC system reset(for debug purpose) */
      RCC_DeInit();

      /* Enable HSE */
      RCC_HSEConfig(RCC_HSE_ON);

      /* Wait till HSE is ready */
      HSEStartUpStatus = RCC_WaitForHSEStartUp();

      if(HSEStartUpStatus == SUCCESS)
      {
        /* Enable Prefetch Buffer */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

        /* Flash 2 wait state */
        FLASH_SetLatency(FLASH_Latency_2);

        /* HCLK = SYSCLK */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
     
        /* PCLK2 = HCLK */
        RCC_PCLK2Config(RCC_HCLK_Div1);

        /* PCLK1 = HCLK/2 */
        RCC_PCLK1Config(RCC_HCLK_Div2);

        /* PLLCLK = 8MHz * 9 = 72 MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

        /* Enable PLL */
        RCC_PLLCmd(ENABLE);

        /* Wait till PLL is ready */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
        {
        }

        /* Select PLL as system clock source */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

        /* Wait till PLL is used as system clock source */
        while(RCC_GetSYSCLKSource() != 0x08)
        {
        }
      }

      /* Enable GPIOD clock */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
     
      /* PD.08 used as USB pull-up --> EK-STM32F */
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_Init(GPIOD, &GPIO_InitStructure);
     
      USB_Cable_Config (DISABLE);
    // SPI_FLASH_Init();
      USB_Cable_Config (ENABLE);
    }

    void USB_Cable_Config (FunctionalState NewState)
    {
      if (NewState != DISABLE)
      {
        GPIO_ResetBits(GPIOD, GPIO_Pin_8);
      }
      else
      {
        GPIO_SetBits(GPIOD, GPIO_Pin_8);
      }   
    }

    修改后烧入EK-STM32F学习板,果然能识别出一个DFU设备。



    --------------------------------------------------------------------------------


    请下载移植到EKSTM32F的USB开发套件后把他们放到同一个目录下(STM32F10xUSBLib),方法如下:

    1)自建一个STM32F10xUSBLib目录

    2)下载这个文件并解压到STM32F10xUSBLib目录

    3)下载这个文件并解压到STM32F10xUSBLib目录


    最终目录结构应为:
    STM32F10xUSBLib
      FWLib
        library
          inc
          src
      USBLib
        demos
          Device_Firmware_Upgrade  本帖介绍的DFU演示软件
          JoyStickMouse
          Mass_Storage
          Virtual_COM_Port
        library
          inc
          src


    --------------------------------------------------------------------------------


    在ST官网下载PC端驱动和应用程序地址:http://www.st.com/stonline/products/support/micro/files/um0412.zip

    安装后运行DfuSeDemo(V2.1),在DFU Device中识别到一个STM Device in DFU Mode设备。

    选择Internal Flash,选择STM32 USB开发套件的DFU DEMO中的任意image, 按下Upgrade按键。

    出现一个对话框:擦除操作失败

    。。。。。。

    DFU的代码我曾经在ST的官方开发板上测试过,没有出过错,那么现在的错误在哪里呢?

    拿了USB分析仪,看USB线上数据,发现设备总在某次的DFU_GETSTATUS请求后响应一个STALL信号,导致出错。

    根据USB DFU协议(下载地址: http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf), 对DFU_GETSTATUS的响应应该由:bStatus(1byte) + bwPollTimeout(3Bytes,以ms为单位) + bState(1byte) + iString(1byte)组成,但看USB线上数据,设备的响应为:00 00 00 00 04 00,显然是要求的Poll Time时间太短,导致设备在擦除flash的等待时间内无法响应PC端的又一个请求。

    仔细看u8 *GETSTATUS(u16 Length)的代码:
        case   STATE_dfuDNLOAD_SYNC:
          if (wlength != 0)
          {
            DeviceState = STATE_dfuDNBUSY;
            DeviceStatus[4] = DeviceState;
            if ((wBlockNum == 0) && (Load_Buffer[0] == CMD_ERASE))
            {
              if  (Pointer < 0x800000) /* 64K sectors of SPI Flash */
              {
                DeviceStatus[1] = 0xDC;  /* 1.5 seconds */
                DeviceStatus[2] = 0x05;
                DeviceStatus[3] = 0x00;
              }
                      <=====================此处值得商榷
            }
            else
            {
              DeviceStatus[1] = (wlength >> 8) * 2  ; /* Nb of Pages(of 256 )* 2ms */
              DeviceStatus[2] = 0;
              DeviceStatus[3] = 0;
            }
        
          }
          else  /* (wlength==0)*/
          {
            DeviceState = STATE_dfuDNLOAD_IDLE;
            DeviceStatus[4] = DeviceState;
            DeviceStatus[1] = 0;
            DeviceStatus[2] = 0;
            DeviceStatus[3] = 0;
           
          }
       break;

    代码在分析到当前操作为CMD_ERASE命令时,仅仅对SPI FLASH的操作定义了Poll的时间,而对内部flash的操作没有定义,因此设备直接返回了0。

    察看STM32F103的Datasheet:
    Page(1KB)erase time 为 Min20ms,  Max40ms
    Word programming time 为 Min20us, Max40us


    修改代码如下:
       case   STATE_dfuDNLOAD_SYNC:
          if (wlength != 0)
          {
            DeviceState = STATE_dfuDNBUSY;
            DeviceStatus[4] = DeviceState;
            if ((wBlockNum == 0) && (Load_Buffer[0] == CMD_ERASE))
            {
              if  (Pointer < 0x800000) /* 64K sectors of SPI Flash */
              {
                DeviceStatus[1] = 0xDC;  /* 1.5 seconds */
                DeviceStatus[2] = 0x05;
                DeviceStatus[3] = 0x00;
              }
              else {
                DeviceStatus[1] = 0x28;
                DeviceStatus[2] = 0x00;
                DeviceStatus[3] = 0x00;
              }
            }
            else
            {
    //          DeviceStatus[1] = (wlength >> 8) * 2  ; /* Nb of Pages(of 256 )* 2ms */
              DeviceStatus[1] = (wlength >> 8) * 10  ; /* Nb of Pages(of 256 )* 10ms */
              DeviceStatus[2] = 0;
              DeviceStatus[3] = 0;
            }
        
          }
          else  /* (wlength==0)*/
          {
            DeviceState = STATE_dfuDNLOAD_IDLE;
            DeviceStatus[4] = DeviceState;
            DeviceStatus[1] = 0;
            DeviceStatus[2] = 0;
            DeviceStatus[3] = 0;
           
          }
          break;


    修改后重新烧录代码,重新执行Upgrade操作,OK。



    --------------------------------------------------------------------------------


    至于原先在测试DFU代码时为何没有出错,我认为是因为我刚新换了电脑的缘故,PC跑的快了,愿意等待的时间短了。。。。。

    DUF搞完,开始考虑image的生成。

    PC端的应用程序除了DfuSeDemo,还有个DfuFileManage(V2.1),能将S19,HEX和BIN文件生成DFU文件。


    随便找了个LCD的demo,修改lnkarm_flash.xcl文件如下:
    // Code memory in FLASH
    -DROMSTART=0x8003000
    -DROMEND=0x801FFFF

    修改stm32f10x_nvic.h文件对于Vector Table地址的定义如下:
    #define NVIC_VectTab_RAM             ((u32)0x20000000)
    #define NVIC_VectTab_FLASH           ((u32)0x08003000)

    使用IAR生成raw-binary文件。

    运行DFU File Manager Generation程序, 选择Mullti Bin injection,输入刚才生成的bin文件,选择地址为0x08003000, 生成OK。

    运行DfuSeDemo程序,将刚才生成的DFU文件烧录到内部flash中。

    按下Reset按键,LCD DEMO程序如愿跑了起来,再次按下Reset按键,同时按下KEY3,PC识别到一个DFU设备。

    至此,DFU设备在EK-STM32F学习板上移植成功。

  • 相关阅读:
    sql server mdx
    mysql 按照 汉字的第一个拼音排序
    转,mysql的select * into
    mysql 日期的操作
    google 地图api
    ip_test
    AJAX (转w3cschool)
    jquery ajax 失败
    安装AdventureWorks2008R2示例数据库
    弹出新的网页窗口 js
  • 原文地址:https://www.cnblogs.com/glguan/p/2260473.html
Copyright © 2011-2022 走看看