STM32 Internal Flash DFU chip internal flash code upgrade

Publisher:大橙子5511Latest update time:2016-12-20 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

This time I want to talk about how to use USB to upgrade the microcontroller code. I have done serial port upgrades and network upgrades before. The basic principles of the upgrades are similar, except that the upgrade tools are different. Serial port upgrades use serial ports, network upgrades use TCP/IP, and USB upgrades use USB. Now let's talk about the implementation of USB upgrades.

The modified parts are all in the USB_User group:

STM32 Internal Flash DFU chip internal flash code upgrade - ziye334 - ziye334's blogLet’s go through each file one by one.

First, let's talk about hw_config.c. This file is similar to the previous project. Due to the needs of demonstration, we initialize a button pin in this file and define a button reading function. This button determines whether the code is upgraded. If the button is pressed at the beginning of the program, it will enter the upgrade mode, otherwise it will jump to the upgrade program code:



/****************************************************** ****************************

* Function Name: DFU_Button_Config.

* Description: Configure the DFU mode selection button.

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_Button_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DFU, ENABLE);


  /* Configure DFU button */

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

  GPIO_InitStructure.GPIO_Pin = DFU_ENTER_PIN;

  GPIO_Init(DFU_ENTER, &GPIO_InitStructure);

}


/****************************************************** ****************************

* Function Name: DFU_Button_Read.

* Description: Read whether the DFU button is pressed

* Input : None.

* Output : None.

* Return: Return 0: the button is pressed; 1: the button is not pressed

*************************************************** *******************************/

uint8_t DFU_Button_Read (void)

{

  return GPIO_ReadInputDataBit(DFU_ENTER, DFU_ENTER_PIN);

}


The usb_desc.c file must be modified. The USB function attributes are all defined here. First of all, we must pay attention to the device descriptor. One thing that needs to be emphasized here is that the value of the manufacturer ID field must be 0483, otherwise the computer will not recognize the USB. The product ID can be customized.

/* USB standard device descriptor */

uint8_t DFU_DeviceDescriptor[DFU_SIZ_DEVICE_DESC] =

{

    0x12, /*bLength: length, the length of the device descriptor is 18 bytes*/

    USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType: type, the device descriptor number is 0x01*/

    0x00, /*bcdUSB: The USB version used is 2.0*/

    0x02,

    0x00, /*bDeviceClass: class code used by the device*/

    0x00, /*bDeviceSubClass: subclass code used by the device*/

    0x00, /*bDeviceProtocol: protocol used by the device*/

    0x40, /*bMaxPacketSize: Maximum packet length is 64 bytes*/

    0x83, /*idVendor: vendor ID is 0x1234*/

    0x04,

    0x11, /*idProduct: product ID is 0x1010*/

    0xDF,

    0x00, /*bcdDevice: The device version number is 2.00*/

    0x02,

    1, /*iManufacturer: index of manufacturer string*/

    2, /*iProduct: index of product string*/

    3, /*iSerialNumber: device serial number string index*/

    0x01 /*bNumConfiguration: The device has 1 configuration*/

}; /* DFU device descriptor */


Next is the configuration descriptor set, which does not need to be modified. However, the bNumEndpoints field (the number of endpoints used by the interface) of the subsequent interface descriptor needs to be set to 0, because the USB DFU value requires endpoint 0 and does not need other endpoints; the value of the bInterfaceClass (the class used by the interface) field of the interface descriptor is 0xFE, indicating that the DFU class interface is used; the bInterfaceSubClass (the subclass used by the interface) of the interface descriptor is set to 0x01, indicating boot usage; the nInterfaceProtocol of the interface descriptor is set to 0x2, that is, DFU mode; and finally, the index value of the interface string descriptor needs to be set to 4. Next is the DFU function descriptor, where the USB attribute of the bmAttribute field is set to 0x0B (see the code below for the specific meaning); the DetachTimeOut (timeout) is set to 0XFF, indicating that the timeout is 255ms; next, set TransferSize: (transmission length) to 0x400, note that it is represented in two-byte little-endian mode.

/* USB configuration descriptor set (Configuration, Interface, Endpoint, Class, Vendor */

uint8_t DFU_ConfigDescriptor[DFU_SIZ_CONFIG_DESC] =

{

    0x09, /*bLength: length, the length of the device string is 9 bytes*/

    USB_CONFIGURATION_DESCRIPTOR_TYPE, /*bDescriptorType: type, the type number of the configuration descriptor is 0x2*/

    DFU_SIZ_CONFIG_DESC, /*wTotalLength: The total length of the configuration descriptor is 41 bytes*/    

    0x00,

    0x01, /*bNumInterfaces: Configure the number of interfaces supported by 1*/

    0x01, /*bConfigurationValue: the value of the configuration*/

    0x00, /*iConfiguration: The index value of the string of this configuration. The value 0 indicates that there is no string*/              

    0xC0, /* bmAttributes: some characteristics of the device, 0xc0 means self-powered, does not support remote wake-up

D7: Reserved must be 1, D6: Whether it is self-powered, D5: Whether it supports remote wake-up, D4~D0: Reserved set to 0*/

    0x32, /*The maximum current obtained from the bus is 100mA */

// 0x96, /*MaxPower: How much current the device needs to obtain from the bus, the unit is 2mA, 0x96 means 300mA*/



/****** Descriptor of DFU interface 0 Alternate setting 0************/

    0x09, /*bLength: length, the length of the interface descriptor is 9 bytes*/

    USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: The type of interface descriptor is 0x4 */

    0x00, /*bInterfaceNumber: the number of the interface*/

    0x00, /*bAlternateSetting: The alternate number of this interface*/

    0x00, /*bNumEndpoints: The number of endpoints used by this interface*/

    0xFE, /*bInterfaceClass The class used by this interface is DFU*/

    0x01, /*bInterfaceSubClass: The subclass used by this interface 1=BOOT, 0=no boot */

    0x02, /*nInterfaceProtocol :DFU mode*/


    4, /* iInterface: index of interface string descriptor*/


    /******************** DFU function descriptor********************/

    0x09, /*blength: The length of the DFU descriptor is 9 bytes*/

    0x21, /*The type of the function descriptor is 0x21*/

    0x0B, /*bmAttribute


                                             bitCanDnload = 1 (bit 0) Download capability

                                             bitCanUpload = 1 (bit 1) Upload capability

                                             bitManifestationTolerant = 0 (bit 2) Whether the device can communicate via USB after the waiting phase

                                             bitWillDetach = 1 (bit 3) When receiving the DFU_DETACH command, the bus will be detached-attached

                                             Reserved (bit4-6) Reserved

                                             bitAcceleratedST = 0 (bit 7) If this is set to 1, the device will increase the upload speed to 4096 bytes/command*/

    0xFF, /*DetachTimeOut: timeout 255 ms*/

    0x00,

    wTransferSizeB0,

    wTransferSizeB1, /* TransferSize: The transfer length is 1024 Byte*/

    0x1A, /* bcdDFUVersion: DFU protocol version*/

    0x01

}; 


The following language string descriptor, manufacturer string descriptor, product string descriptor, and serial number string descriptor will not be introduced in detail.

/* Language ID descriptor */

uint8_t DFU_StringLangId[DFU_SIZ_STRING_LANGID] =

{

    DFU_SIZ_STRING_LANGID, /*bLength: The length of this descriptor is 4 bytes*/

    USB_STRING_DESCRIPTOR_TYPE, /*bDescriptorType: string descriptor type is 0x03*/

    0x09, /*bString: Language ID is 0x0409, indicating American English*/

    0x04

}; /* LangID = 0x0409: US English*/


/*Manufacturer string descriptor*/

uint8_t DFU_StringVendor[DFU_SIZ_STRING_VENDOR] =

{

    DFU_SIZ_STRING_VENDOR, /*bLength: length of the vendor string descriptor*/

    USB_STRING_DESCRIPTOR_TYPE, /*bDescriptorType: string descriptor type is 0x03*/

    'B' , 0, 'y', 0, ':' , 0, 'z' , 0, 'i', 0, 'y', 0,'e', 0,'3', 0, '3', 0, '4', 0 /*Custom*/

};


/*String descriptor of the product*/

uint8_t DFU_StringProduct[DFU_SIZ_STRING_PRODUCT] =

{

    DFU_SIZ_STRING_PRODUCT, /* bLength: string descriptor of the product */

    USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType: string descriptor type is 0x03*/

    'z', 0, 'i', 0, 'y', 0, 'e', ​​0, '3', 0, '3', 0 ,'4',0/*Custom*/

};


/* Product serial number string descriptor */

uint8_t DFU_StringSerial[DFU_SIZ_STRING_SERIAL] =

{

    DFU_SIZ_STRING_SERIAL, /* bLength: product serial number*/

    USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType: string descriptor type is 0x03*/

    '1', 0, '2', 0, '3', 0,'4', 0,'5', 0, '6', 0, '7', 0 /*Custom*/

};


The focus is on the interface string descriptor, which defines the upgraded hardware information. The following is our interface descriptor:

/*Interface string descriptor*/

uint8_t DFU_StringInterface0[DFU_SIZ_STRING_INTERFACE0] =

  {

    DFU_SIZ_STRING_INTERFACE0,

    0x03,

    // Interface 0: "@Internal Flash /0x08000000/12*001Ka,500*001Kg"

    '@', 0, 'I', 0, 'n', 0, 't', 0, 'e', ​​0, 'r', 0, 'n', 0, 'a', 0, 'l ', 0, /* 18 */

    ' ', 0, 'F', 0, 'l', 0, 'a', 0, 's', 0, 'h', 0, ' ', 0, ' ', 0, /* 16 */


    '/', 0, '0', 0, 'x', 0, '0', 0, '8', 0, '0', 0, '0', 0, '0', 0, '0 ', 0, '0', 0, '0', 0, /* 22 */


    '/', 0, '1', 0, '2', 0, '*', 0, '0', 0, '0', 0, '1', 0, 'K', 0, 'a ', 0, /* 18 */

    ',', 0, '5', 0, '0', 0, '0', 0, '*', 0, '0', 0, '0', 0, '1', 0, 'K ', 0, 'g', 0, /* 20 */

  };


You can see the comment above: // Interface 0: "@Internal Flash /0x08000000/12*001Ka,500*001Kg", which is the information expressed by this interface descriptor. Next, we will introduce the information of the array content of the interface descriptor in detail:

—— @: Indicates that this is a special mapping descriptor (avoid decoding according to the standard descriptor)

—— /: indicates the separator between different areas

—— Maximum address is 8 bits, starting with "0X"

—— The sector number with two digits at most

—— *: separator between the number of sectors and the sector size

—— Maximum 3-digit sector size (0~999)

—— 1-bit sector size unit: valid input is: B (byte), K (kilo), M (mega)

—— 1-bit sector type:

a(0x41): readable

b(0x42): erasable

c(0x43): readable and writable

d(0x44): writable

e(0x45): readable and writable

f (0x46): writable and erasable

g(0x47): readable, writable and erasable

For example, "@Internal Flash /0x08000000/12*001Ka,500*001Kg" means: the name of the memory is "Internal Flash", the starting address is 0x08000000, the 12*1K space is readable, and the 500*1K space is readable, writable and erasable. By the way, the chip I use is STM32F103ZET6, and the flash space is 512K.



The files usb_istr.c and usb_pwr.c do not need to be modified.

The modification of the usb_prop.c file is relatively large. This file describes the changes between the various states of DFU. The code is still a bit vague and I am not going to explain it in detail. I will just paste the code directly. Some of it has been annotated:


#include "usb_lib.h"

#include "hw_config.h"

#include "usb_conf.h"

#include "usb_prop.h"

#include "usb_desc.h"

#include "usb_pwr.h"

#include "dfu_mal.h"


uint32_t wBlockNum = 0, wlength = 0;

uint32_t Manifest_State = Manifest_complete;

uint32_t Pointer = ApplicationAddress; //Base address for program erase, read and write


DEVICE Device_Table = //Endpoint information

  {

    EP_NUM, //Number of endpoints used

    1 //Number of endpoints that can be used

  };


DEVICE_PROP Device_Property = //Register some DFU related processing functions

  {

    DFU_init, //initialization

    DFU_Reset, //Reset

    DFU_Status_In, //status input

    DFU_Status_Out, //status output

    DFU_Data_Setup, //Establishment with data stage

    DFU_NoData_Setup, //Setup without data stage

    DFU_Get_Interface_Setting, //Get interface value

    DFU_GetDeviceDescriptor, //Get device descriptor

    DFU_GetConfigDescriptor, //Get configuration descriptor

    DFU_GetStringDescriptor, //Get string descriptor

    0, //DFU_EP0Buffer

    bMaxPacketSize0 //Maximum packet size*/

  };


USER_STANDARD_REQUESTS User_Standard_Requests = //Standard requests

  {

    DFU_GetConfiguration, //Get configuration value request

    DFU_SetConfiguration, //Set configuration value request

    DFU_GetInterface, //Get interface value request

    DFU_SetInterface, //Set interface value request

    DFU_GetStatus, //Get status request

    DFU_ClearFeature, // Clear feature request

    DFU_SetEndPointFeature, //Set breakpoint feature request

    DFU_SetDeviceFeature, //Set device feature request

    DFU_SetDeviceAddress //Set device address request

  };


ONE_DESCRIPTOR Device_Descriptor = //Register device descriptor information

  {

    (uint8_t*)DFU_DeviceDescriptor, //Device descriptor address

    DFU_SIZ_DEVICE_DESC

  };


ONE_DESCRIPTOR Config_Descriptor = //Register configuration descriptor information

  {

    (uint8_t*)DFU_ConfigDescriptor, //Configuration descriptor address

    DFU_SIZ_CONFIG_DESC

  };



ONE_DESCRIPTOR DFU_String_Descriptor[5] = //Register string descriptor

  {

    { (uint8_t*)DFU_StringLangId, DFU_SIZ_STRING_LANGID }, //language string

    { (uint8_t*)DFU_StringVendor, DFU_SIZ_STRING_VENDOR }, //Vendor string

    { (uint8_t*)DFU_StringProduct, DFU_SIZ_STRING_PRODUCT }, //Product string

    { (uint8_t*)DFU_StringSerial, DFU_SIZ_STRING_SERIAL }, //Serial number string

    { (uint8_t*)DFU_StringInterface0, DFU_SIZ_STRING_INTERFACE0 } //Interface descriptor

  };


/* Extern variables ----------------------------------------------- ----------*/

extern uint8_t DeviceState;

extern uint8_t DeviceStatus[6];


/* Private function prototypes --------------------------------------------- --*/

/* Private functions -------------------------------------------------- -----------*/


/****************************************************** ****************************

* Function Name : DFU_init.

* Description : DFU initialization.

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_init(void)

{

  DEVICE_INFO *pInfo = &Device_Info;


  Get_SerialNum(); //Get the serial number


  pInfo->Current_Configuration = 0; //Initialize the current configuration value


  PowerOn(); //Connect device


  USB_SIL_Init(); //Perform basic device initialization operations


  USB_Interrupts_Config(); //Enable USB interrupts


  bDeviceState = UNCONNECTED;

}


/****************************************************** ****************************

* Function Name : DFU_Reset.

* Description : DFU reset

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_Reset(void)

{

  Device_Info.Current_Configuration = 0;


  /* Current Feature initialization */

  pInformation->Current_Feature = DFU_ConfigDescriptor[7]; //Get the current feature


  _SetBTABLE(BTABLE_ADDRESS);


  /* Initialize Endpoint 0 */   

  _SetEPType(ENDP0, EP_CONTROL); //Set endpoint 0 as the control endpoint

  _SetEPTxStatus(ENDP0, EP_TX_NAK); //Set endpoint 0 to EP_TX_NAK

  _SetEPRxAddr(ENDP0, ENDP0_RXADDR); //Set the receiving address of endpoint 0

  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); //Set the maximum receive packet length of endpoint 0

  _SetEPTxAddr(ENDP0, ENDP0_TXADDR); //Set the send address of endpoint 0

  SetEPTxCount(ENDP0, Device_Property.MaxPacketSize); //Set the maximum send packet length of endpoint 0

  Clear_Status_Out(ENDP0); //Clear endpoint 0 status

  SetEPRxValid(ENDP0); //Set endpoint reception valid


  /* Set this device to respond on default address */

  SetDeviceAddress(0); //Set the device default address


  /* Set the new control state of the device to Attached */

  bDeviceState = ATTACHED;

}

/****************************************************** ****************************

* Function Name: DFU_SetConfiguration.

* Description: Update device configuration status

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_SetConfiguration(void)

{

  DEVICE_INFO *pInfo = &Device_Info;


  if (pInfo->Current_Configuration != 0)

  {

    /* Device configured */

    bDeviceState = CONFIGURED;

  }

}

/****************************************************** ****************************

* Function Name: DFU_SetConfiguration.

* Description: Update the addressing status of the device

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_SetDeviceAddress (void)

{

  bDeviceState = ADDRESSED;

}

/****************************************************** ****************************

* Function Name: DFU_Status_In.

* Description: DFU status input function

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_Status_In(void)

{}


/****************************************************** ****************************

* Function Name: DFU_Status_Out.

* Description: DFU status output function

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_Status_Out (void)

{

  DEVICE_INFO *pInfo = &Device_Info;

  uint32_t Addr;


  if (pInfo->USBbRequest == DFU_GETSTATUS)

  {

    if (DeviceState == STATE_dfuDNBUSY) //Current state is in progress

    {

      if (wBlockNum == 0) //The number of blocks is 0

      {

        if ((MAL_Buffer[0] == CMD_GETCOMMANDS) && (wlength == 1)) //Get more device performance and which devices DFU supports

        {}

        else if (( MAL_Buffer[0] == CMD_SETADDRESSPOINTER ) && (wlength == 5)) //Set address pointer

        {

          Pointer = MAL_Buffer[1];

          Pointer += MAL_Buffer[2] << 8;

          Pointer += MAL_Buffer[3] << 16;

          Pointer += MAL_Buffer[4] << 24;

        }

        else if (( MAL_Buffer[0] == CMD_ERASE ) && (wlength == 5)) //Send erase address sector command

        {

          Pointer = MAL_Buffer[1]; //Get the download address

          Pointer += MAL_Buffer[2] << 8;

          Pointer += MAL_Buffer[3] << 16;

          Pointer += MAL_Buffer[4] << 24;

          MAL_Erase(Pointer); //Erase the address

        }

      }


      else if (wBlockNum > 1) //The number of blocks is greater than 1

      {

        Addr = ((wBlockNum - 2) * wTransferSize) + Pointer; //Get the address of the data written into the memory

        MAL_Write(Addr, wlength); //Write data

      }

      wlength = 0;

      wBlockNum = 0;


      DeviceState = STATE_dfuDNLOAD_SYNC; //Set the state to download synchronization

      DeviceStatus[4] = DeviceState;

      DeviceStatus[1] = 0;

      DeviceStatus[2] = 0;

      DeviceStatus[3] = 0;

      return;

    }

    else if (DeviceState == STATE_dfuMANIFEST) //Display process

    {

      DFU_write_crc(); //Write CRC check

      return;

    }

  }

  return;

}


/****************************************************** ****************************

* Function Name: DFU_Data_Setup.

* Description: Process special class requests with data

* Input : RequestNb.

* Output : None.

* Return: USB_SUCCESS or USB_UNSUPPORT.

*************************************************** *******************************/

RESULT DFU_Data_Setup(uint8_t RequestNo)

{

  uint8_t *(*CopyRoutine)(uint16_t);

  CopyRoutine = NULL;


  if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) //Class request, the recipient of the request is the interface

  {

    if (RequestNo == DFU_UPLOAD && (DeviceState == STATE_dfuIDLE

                                    || DeviceState == STATE_dfuUPLOAD_IDLE ))//Device is idle, upload is idle

    {

      CopyRoutine = UPLOAD; //The function pointer points to the UPLOAD function

    }

    else if (RequestNo == DFU_DNLOAD && (DeviceState == STATE_dfuIDLE

                                         || DeviceState == STATE_dfuDNLOAD_IDLE))//Device is idle, download is idle

    {

      DeviceState = STATE_dfuDNLOAD_SYNC; //Set the device state to download synchronization

      CopyRoutine = DNLOAD; //Function pointer points to DNDOWN function

    }

    else if (RequestNo == DFU_GETSTATE) //DFU_GETSTATE request

    {

      CopyRoutine = GETSTATE; //Function pointer points to GETSTATE function

    }

    else if (RequestNo == DFU_GETSTATUS) //DFU_GETSTATUS request

    {

      CopyRoutine = GETSTATUS; //Function pointer points to GETSTATUS function

    }

    else

    {

      return USB_UNSUPPORT;

    }

  }

  else

  {

    return USB_UNSUPPORT;

  }


  if (CopyRoutine == NULL)

  {

    return USB_UNSUPPORT;

  }


  pInformation->Ctrl_Info.CopyData = CopyRoutine; //Register this function pointer

  pInformation->Ctrl_Info.Usb_wOffset = 0;

  (*CopyRoutine)(0); //Point to the function pointed to by the overview pointer


  return USB_SUCCESS;

}


/****************************************************** ****************************

* Function Name: DFU_NoData_Setup.

* Description: Handle the No data class specific requests.

* Input : Request Nb.

* Output : None.

* Return: USB_SUCCESS or USB_UNSUPPORT.

*************************************************** *******************************/

RESULT DFU_NoData_Setup(uint8_t RequestNo)

{


  if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) //Class request

  {

    /*DFU_NDLOAD*/

    if (RequestNo == DFU_DNLOAD) //DFU_DNLOAD request

    {

      /* End of DNLOAD operation*/

      if (DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuIDLE ) //Download idle or device idle

      {

        Manifest_State = Manifest_In_Progress; //Set the display state to display progress

        DeviceState = STATE_dfuMANIFEST_SYNC; //Set display synchronization

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0;

        DeviceStatus[4] = DeviceState;

        return USB_SUCCESS;

      }

    }

    /*DFU_UPLOAD*/

    else if (RequestNo == DFU_UPLOAD) //DFU_UPLOAD command

    {

      DeviceState = STATE_dfuIDLE; //Set device to idle

      DeviceStatus[1] = 0;

      DeviceStatus[2] = 0;

      DeviceStatus[3] = 0;

      DeviceStatus[4] = DeviceState;

      return USB_SUCCESS;

    }


    /*DFU_CLRSTATUS*/

    else if (RequestNo == DFU_CLRSTATUS) //DFU_CLRSTATUS command

    {


      if (DeviceState == STATE_dfuERROR) //dfu error

      {

        DeviceState = STATE_dfuIDLE; // Clear error status

        DeviceStatus[0] = STATUS_OK;/*bStatus*/

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/

        DeviceStatus[4] = DeviceState;/*bState*/

        DeviceStatus[5] = 0;/*iString*/

      }

      else

      { /*State Error*/

        DeviceState = STATE_dfuERROR; //Set the device status to upgrade error

        DeviceStatus[0] = STATUS_ERRUNKNOWN;/*bStatus*/

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/

        DeviceStatus[4] = DeviceState;/*bState*/

        DeviceStatus[5] = 0;/*iString*/

      }

      return USB_SUCCESS;

    }

    /*DFU_ABORT*/

    else if (RequestNo == DFU_ABORT) //DFU_ABORT terminates the command

    {

      if (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuDNLOAD_SYNC

          || DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuMANIFEST_SYNC

          || DeviceState == STATE_dfuUPLOAD_IDLE ) //Device idle or upload synchronization or download idle or display synchronization or upload idle

      {

        DeviceState = STATE_dfuIDLE; //Set device to idle

        DeviceStatus[0] = STATUS_OK;

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/

        DeviceStatus[4] = DeviceState;

        DeviceStatus[5] = 0; /*iString*/

        wBlockNum = 0;

        wlength = 0;

      }

      return USB_SUCCESS;

    }

  }



  return USB_UNSUPPORT;


} /* End of DFU_NoData_Setup */


/****************************************************** ****************************

* Function Name: DFU_GetDeviceDescriptor.

* Description: Get device descriptor

* Input : Length.

* Output : None.

* Return: Return the address of the device descriptor

*************************************************** *******************************/

uint8_t *DFU_GetDeviceDescriptor(uint16_t Length)

{

  return Standard_GetDescriptorData(Length, &Device_Descriptor);

}


/****************************************************** ****************************

* Function Name: DFU_GetConfigDescriptor.

* Description: Get configuration descriptor

* Input : Length.

* Output : None.

* Return: Returns the address of the configuration descriptor

*************************************************** *******************************/

uint8_t *DFU_GetConfigDescriptor(uint16_t Length)

{

  return Standard_GetDescriptorData (Length, &Config_Descriptor);

}


/****************************************************** ****************************

* Function Name: DFU_GetStringDescriptor.

* Description: Get string description according to index

* Input : Length.

* Output : None.

* Return: Return the address of the string descriptor

*************************************************** *******************************/

uint8_t *DFU_GetStringDescriptor(uint16_t Length)

{

  uint8_t wValue0 = pInformation->USBwValue0;


  if (wValue0 > 8)

  {

    return NULL;

  }

  else

  {

    return Standard_GetDescriptorData(Length, &DFU_String_Descriptor[wValue0]);

  }

}


/****************************************************** ****************************

* Function Name: DFU_Get_Interface_Setting.

* Description: Tests whether the interface and backup interface are supported

* Input : - Interface : Interface number

* - AlternateSetting: Alternate interface number

* Output : None.

* Return: USB_SUCCESS or USB_UNSUPPORT.

*************************************************** *******************************/

RESULT DFU_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting)

{

  if (AlternateSetting > 3)

  {

    return USB_UNSUPPORT; /* In this application we don't have more than 3 AlternateSettings */

  }

  else if (Interface > 2)

  {

    return USB_UNSUPPORT; /* In this application we have only 1 interfaces */

  }


  return USB_SUCCESS;

}


/****************************************************** ****************************

* Function Name : UPLOAD

* Description : Upload

* Input : Length.

* Output : None.

* Return: Pointer to data.

*************************************************** *******************************/

uint8_t *UPLOAD(uint16_t Length)

{

  DEVICE_INFO *pInfo = &Device_Info; //Get device information

  uint8_t B1, B0; //16bit high 8 bits and low 8 bits

  uint16_t offset, returned;  

  uint8_t *Phy_Addr = NULL;  

  uint32_t Addr = 0;


  B0 = pInfo->USBwValues.bw.bb0; //Get the lower 8 bits of the requested wValue

  B1 = pInfo->USBwValues.bw.bb1; //Get the high 8 bits of the requested wValue

  wBlockNum = (uint16_t)B1;

  wBlockNum = wBlockNum * 0x100;

  wBlockNum += (uint16_t)B0; //Update wBlockNum


  B0 = pInfo->USBwLengths.bw.bb0; //Get the lower 8 bits of the requested wLength

  B1 = pInfo->USBwLengths.bw.bb1; //Get the high 8 bits of the requested wLength

  wlength = (uint16_t)B0;

  wlength = wlength * 0x100;

  wlength += (uint16_t)B1; //Update wLength


  offset = pInformation->Ctrl_Info.Usb_wOffset; //Get data offset


  if (wBlockNum == 0) //wBlockNum is equal to 0, indicating no data transmission

  {

    if (wlength > 3)

    {

      DeviceState = STATE_dfuIDLE;

    }

    else

    {

      DeviceState = STATE_dfuUPLOAD_IDLE;

    }


    DeviceStatus[4] = DeviceState;

    DeviceStatus[1] = 0;

    DeviceStatus[2] = 0;

    DeviceStatus[3] = 0;

  

    MAL_Buffer[0] = CMD_GETCOMMANDS; //Get commands

    MAL_Buffer[1] = CMD_SETADDRESSPOINTER; //Set address pointer

    MAL_Buffer[2] = CMD_ERASE; // Erase the sector containing the address


    if (Length == 0)

    {

      pInformation->Ctrl_Info.Usb_wLength = 3;

      return NULL;

    }


    return(&MAL_Buffer[0]);

  }

  else if (wBlockNum > 1) //wBlockNum is greater than 1

  {

    DeviceState = STATE_dfuUPLOAD_IDLE;

    DeviceStatus[4] = DeviceState;

    DeviceStatus[1] = 0;

    DeviceStatus[2] = 0;

    DeviceStatus[3] = 0;

    Addr = ((wBlockNum - 2) * wTransferSize) + Pointer; //Calculate the address of the data to be uploaded in the memory


    Phy_Addr = MAL_Read(Addr, wlength); //Read data

    returned = wlength - offset; //Get the starting address of the uploaded data


    if (Length == 0) //The length to upload is 0

    {

      pInformation->Ctrl_Info.Usb_wLength = returned;

      return NULL;

    }

    return(Phy_Addr + offset);

  }

  else //That is, wBlockNum=1, unsupported wBlockNum

  {

    DeviceState = STATUS_ERRSTALLEDPKT;

    DeviceStatus[4] = DeviceState;

    DeviceStatus[1] = 0;

    DeviceStatus[2] = 0;

    DeviceStatus[3] = 0;


    return NULL;

  }

}


/****************************************************** ****************************

* Function Name : DNLOAD

* Description : Download

* Input : Length.

* Output : None.

* Return: Returns a pointer to the data

*************************************************** *******************************/

uint8_t *DNLOAD (uint16_t Length)

{

  DEVICE_INFO *pInfo = &Device_Info; //Get device information

  uint8_t B1, B0; //16bit high 8 bits and low 8 bits

  uint16_t offset, returned;


  B0 = pInfo->USBwValues.bw.bb0; //Get the lower 8 bits of the requested wValue

  B1 = pInfo->USBwValues.bw.bb1; //Get the high 8 bits of the requested wValue

  wBlockNum = (uint16_t)B1;

  wBlockNum = wBlockNum * 0x100;

  wBlockNum += (uint16_t)B0; //Update wBlockNum


  B0 = pInfo->USBwLengths.bw.bb0; //Get the lower 8 bits of the requested wLength

  B1 = pInfo->USBwLengths.bw.bb1; //Get the high 8 bits of the requested wLength

  wlength = (uint16_t)B0;

  wlength = wlength * 0x100;

  wlength += (uint16_t)B1; //Update wLength


  offset = pInfo->Ctrl_Info.Usb_wOffset;


  DeviceState = STATE_dfuDNLOAD_SYNC;

  DeviceStatus[4] = DeviceState;


  returned = wlength - offset; //point to the starting address of the data


  if (Length == 0)

  {

    pInformation->Ctrl_Info.Usb_wLength = returned;

    return NULL;

  }


  return((uint8_t*)MAL_Buffer + offset);

}


/****************************************************** ****************************

* Function Name : GETSTATE.

* Description : Get STATE request function.

* Input : Length.

* Output : None.

* Return: Pointer to data.

*************************************************** *******************************/

uint8_t *GETSTATE(uint16_t Length)

{

  if (Length == 0)

  {

    pInformation->Ctrl_Info.Usb_wLength = 1;

    return NULL;

  }

  else

    return(&DeviceState);

}


/****************************************************** ****************************

* Function Name : GETSTATUS.

* Description: Get Status request function

* Input : Length.

* Output : None.

* Return: Pointer to data.

*************************************************** *******************************/

uint8_t *GETSTATUS(uint16_t Length)

{

  switch (DeviceState)

  {

    case STATE_dfuDNLOAD_SYNC:

      if (wlength != 0)

      {

        DeviceState = STATE_dfuDNBUSY;

        DeviceStatus[4] = DeviceState;

        if ((wBlockNum == 0) && (MAL_Buffer[0] == CMD_ERASE))

        {

          MAL_GetStatus(Pointer, 0, DeviceStatus);

        }

        else

        {

          MAL_GetStatus(Pointer, 1, DeviceStatus);

        }

      }

      else /* (wlength==0)*/

      {

        DeviceState = STATE_dfuDNLOAD_IDLE;

        DeviceStatus[4] = DeviceState;

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0;


      }

      break;

    case STATE_dfuMANIFEST_SYNC :

      if (Manifest_State == Manifest_In_Progress)

      {

        DeviceState = STATE_dfuMANIFEST;

        DeviceStatus[4] = DeviceState;

        DeviceStatus[1] = 1; /*bwPollTimeout = 1ms*/

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0;

        //break;

      }

      else if (Manifest_State == Manifest_complete && Config_Descriptor.Descriptor[20]

               & 0x04)

      {

        DeviceState = STATE_dfuIDLE;

        DeviceStatus[4] = DeviceState;

        DeviceStatus[1] = 0;

        DeviceStatus[2] = 0;

        DeviceStatus[3] = 0;

        //break;

      }

      break;

    default :

      break;

  }


  if (Length == 0)

  {

    pInformation->Ctrl_Info.Usb_wLength = 6;

    return NULL;

  }

  else

    return(&(DeviceStatus[0]));

}


/****************************************************** ****************************

* Function Name: DFU_write_crc.

* Description: DFU write CRC

* Input : None.

* Output : None.

* Return : None.

*************************************************** *******************************/

void DFU_write_crc(void)

{

  Manifest_State = Manifest_complete;


  if (Config_Descriptor.Descriptor[20] & 0x04)

  {

    DeviceState = STATE_dfuMANIFEST_SYNC;

    DeviceStatus[4] = DeviceState;

    DeviceStatus[1] = 0;

    DeviceStatus[2] = 0;

    DeviceStatus[3] = 0;

    return;

  }

  else

  {

    DeviceState = STATE_dfuMANIFEST_WAIT_RESET;

    DeviceStatus[4] = DeviceState;

    DeviceStatus[1] = 0;

    DeviceStatus[2] = 0;

    DeviceStatus[3] = 0;


    Reset_Device();


    return;

  }

}



Next, we will talk about the file flash_if.c. The premise for implementing this file is that the stm32f10x_flash.c library file has been added to the project. This file has only four files: FLASH_If_Init(), FLASH_If_Erase(), FLASH_If_Write(), and FLASH_If_Read(). First, let's talk about FLASH_If_Init(). Because flash is where the program is stored and can be used as soon as it is powered on, there is no need to initialize it. This function can be an empty function:

uint16_t FLASH_If_Init(void)

{

  return MAL_OK;

}


Then comes FLASH_If_Erase(uint32_t SectorAddress), this function calls the flash erase page function FLASH_ErasePage():

uint16_t FLASH_If_Erase(uint32_t SectorAddress)

{

  FLASH_ErasePage(SectorAddress);

  return MAL_OK;

}


As for the FLASH_If_Write() function, it is a little more complicated. This function needs to determine whether the length to be written is sub-aligned. If it is not word-aligned, it needs to be filled to be word-aligned and then written to the flash. It should be noted here that our STM32 is 32-bit, and word alignment is required for both writing and reading.

uint16_t FLASH_If_Write(uint32_t SectorAddress, uint32_t DataLength)

{

  uint32_t idx = 0;

  

  if (DataLength & 0x3) /* Not an aligned data */

  {

    for (idx = DataLength; idx < ((DataLength & 0xFFFC) + 4); idx++)

    {

      MAL_Buffer[idx] = 0xFF;

    }

  }

  /* Data received are Word multiple */


  for (idx = 0; idx < DataLength; idx = idx + 4)

  {

    FLASH_ProgramWord(SectorAddress, *(uint32_t *)(MAL_Buffer + idx));

    SectorAddress += 4;

  }

  return MAL_OK;

}


Then comes the read function uint8_t *FLASH_If_Read (uint32_t SectorAddress, uint32_t DataLength). Here we directly return the address to be read. This function will only be called during verification.

uint8_t *FLASH_If_Read (uint32_t SectorAddress, uint32_t DataLength)

{

  return (uint8_t*)(SectorAddress);

}


Next is dfu_mal.c. This file includes MAL_Init(), MAL_Erase(), MAL_Write(), MAL_Read(), MAL_GetStatus():

uint16_t MAL_Init(void)

{


  FLASH_If_Init(); //Internal Flash initialization

  return MAL_OK;

}


/****************************************************** ****************************

* Function Name : MAL_Erase

* Description : Erase sector

* Input : None

* Output : None

* Return : None

*************************************************** *******************************/

uint16_t MAL_Erase(uint32_t SectorAddress)

{


  switch (SectorAddress & MAL_MASK) //See address

  {

    case INTERNAL_FLASH_BASE: //If it is in the INTERNAL FLASH address pool

      pMAL_Erase = FLASH_If_Erase; //Erase function pointer points to FLASH_If_Erase

      break;      

    default:

      return MAL_FAIL;

  }

  return pMAL_Erase(SectorAddress); //Point to erase function

}


/****************************************************** ****************************

* Function Name : MAL_Write

* Description : Write sector

* Input : None

* Output : None

* Return : None

*************************************************** *******************************/

uint16_t MAL_Write (uint32_t SectorAddress, uint32_t DataLength)

{


  switch (SectorAddress & MAL_MASK) //View address

  {

    case INTERNAL_FLASH_BASE: //If it is in the INTERNAL FLASH address pool

      pMAL_Write = FLASH_If_Write; //Write function pointer points to FLASH_If_Write

      break;

    default:

      return MAL_FAIL;

  }

  return pMAL_Write(SectorAddress, DataLength); //Call the write sector function

}


/****************************************************** ****************************

* Function Name : MAL_Read

* Description : Degree sector

* Input : None

* Output : None

* Return : Buffer pointer

*************************************************** *******************************/

uint8_t *MAL_Read (uint32_t SectorAddress, uint32_t DataLength)

{


  switch (SectorAddress & MAL_MASK) //View address

  {

    case INTERNAL_FLASH_BASE: //If it is in the INTERNAL FLASH address pool

      pMAL_Read = FLASH_If_Read; //Read function pointer points to FLASH_If_Read

      break;

    default:

      return 0;

  }

  return pMAL_Read (SectorAddress, DataLength); //Call sector function

}


/****************************************************** ****************************

* Function Name: MAL_GetStatus

* Description: Get status

* Input : None

* Output : None

* Return : MAL_OK

*************************************************** *******************************/

uint16_t MAL_GetStatus(uint32_t SectorAddress, uint8_t Cmd, uint8_t *buffer)

{ //Corresponding options for address lookup timing table

  uint8_t x = (SectorAddress >> 26) & 0x03 ; /* 0x000000000 --> 0 */

  /* 0x640000000 --> 1 */

  /* 0x080000000 --> 2 */


  uint8_t y = Cmd & 0x01;  


  SET_POLLING_TIMING(TimingTable[x][y]); /* x: erase/write timing*/

  /* y: Media */

  return MAL_OK;

}


Finally, let’s talk about the main function:

typedef void (*pFunction)(void);

uint8_t DeviceState;

uint8_t DeviceStatus[6];

pFunction Jump_To_Application;

uint32_t JumpAddress;




int main(void)

{  

BSP_Init();

printf(" |============================================== =|\r\n");

printf(" STM32 DFU program starts \r\n");

printf("|============================================== =|\r\n");


if (DFU_Button_Read() != 0x00)

if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) // Check if the jump address area is correct

{

JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); //Get the RESET interrupt vector address of the jump program

Jump_To_Application = (pFunction) JumpAddress; //Force conversion into function pointer

__set_MSP(*(__IO uint32_t*) ApplicationAddress); //Write the address to R14

Jump_To_Application(); //Call the function. When the function call ends, PC points to the address of R14.

}

}


FLASH_Unlock();

/* Enter DFU mode */

DeviceState = STATE_dfuERROR; //The program points to this sentence, indicating that the DFU jump is unsuccessful

DeviceStatus[0] = STATUS_ERRFIRMWARE;

DeviceStatus[4] = DeviceState;

USB_Configuration(); //Initialize USB

while(1)

{ //LED1 flashes

LED1_Toggle();

Delay_ms(1000);

}

}


There are three places that need special explanation:

1. Implementation of program jump. We define the upgrade address in hw_config.h: #define ApplicationAddress 0x08005000. In the main function, the first press will check whether the upgrade address is valid if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000). This sentence actually checks whether the upgrade address is within the address range of BANK1, because the flash is in BANK1. You can see that a function pointer type function structure is defined above: typedef

 void (*pFunction)(void); A jump address variable uint32_t JumpAddress is also defined; You can see JumpAddress =

 *(__IO uint32_t*) (ApplicationAddress + 4); In this sentence, JumpAddress is assigned the address of the upgrade address + 4. It can be known that this address points to the main stack of the upgrade code. As for why someone asked: why not use ApplicationAddress directly? The reason is very simple, because ApplicationAddresss is a constant and cannot be used directly, so the JumpAddress variable is defined here. Then a function pFunction is defined using this function structure

 Jump_To_Application;, the function pointer Jump_To_Application in the code Jump_To_Application = (pFunction) JumpAddress; points to the JumpAddress address. Then the code calls __set_MSP(*(__IO

 uint32_t*) ApplicationAddress); This sentence means writing the address of ApplicationAddress into R14 register. Finally, call Jump_To_Application() function. When the function call returns, the PC pointer will return to the address saved in R14, and then the program will jump to this address to execute. This is the implementation of program jump.



2. The flash must be unlocked, otherwise the upgrade program cannot be burned into the flash, so the FLASH_Unlock() function must be called.



3. The device state must be given. Initially, DeviceState must be set to STATE_dfuERROR and DeviceStatus[0] must be set to STATUS_ERRFIRMWARE.


Keywords:STM32 Reference address:STM32 Internal Flash DFU chip internal flash code upgrade

Previous article:STM32 USB DFU firmware upgrade must read
Next article:STM32 SPI Flash DFU

Recommended ReadingLatest update time:2024-11-16 23:40

STM32:keil software logic analyzer (logic analyzer) usage
The software logic analyzer in Keil MDK has powerful functions, which can analyze digital signals, analog signals, CPU bus (UART, IIC and other output pins), provide debugging function mechanism, and generate custom signals, such as Sin, triangle wave, bath sound signal, etc., which can be defined.   Take the built-i
[Microcontroller]
STM32:keil software logic analyzer (logic analyzer) usage
STM32 I2C Hardware
1. The module works in slave mode by default. The interface automatically switches from slave mode to master mode after generating a start condition; when arbitration is lost or a stop signal is generated, it switches from master mode to slave mode. 2. Data and address are transmitted as 8 bits/byte, with the high bit
[Microcontroller]
A preliminary study on STM32 general timer
STM32F103ZET6 has two advanced timers, TIM1 and TIM8, four general timers, TIM2-TIM5, and two basic timers, TIM6-TIM7. This article uses TIM3 to introduce the general timer of STM32. The timer of STM32 is powerful. This article takes a preliminary look at the general timer.   Paste the code below: void TIM3_In
[Microcontroller]
stm32 PUSH button controls LED flashing
int main(void) {   /* USER CODE BEGIN 1 */     /* USER CODE END 1 */     /* MCU Configuration----------------------------------------------------------*/     /* Reset of all peripherals, Initializes the Flash interface and the Systick. */   HAL_Init();     /* USER CODE BEGIN Init */     /* USER CODE END Init */     /*
[Microcontroller]
Implementing the comprehensive design of stm32 in FSK modem
       General requirements: Design an FSK modem with a baseband signal code rate of 2000B/s, a carrier rate of 4khz and 8khz, and the demodulated signal must be able to completely restore the baseband signal. There are many ways to implement it. Most modem designs in the communication field use hardware circuits. Sinc
[Microcontroller]
Implementing the comprehensive design of stm32 in FSK modem
About the HardFault_Handler error cause of STM32 processor
The STM32xx processor is a processor implemented by ST using the Cortex-M IP core. It has compact code and very high cost performance, and occupies a very strong position in the field of single-chip microcomputers. My company even directly replaced some scenes using the S3C4510B processor with the STM32F207, because t
[Microcontroller]
About the HardFault_Handler error cause of STM32 processor
STM32 system learning - DMA (direct memory access)
The main function of DMA is to transfer data, but it does not need to occupy the CPU, that is, when transferring data, the CPU can do other things, such as multithreading. Data is transferred from peripherals to memory or from memory to memory. The DMA controller includes DMA1 and DMA2, of which DMA1 has 7 channels an
[Microcontroller]
STM32 system learning - DMA (direct memory access)
The problem that some channels of stm32 TIM output pwm cannot be output
I was playing with the servo tonight and looked at the code of the example program. I wanted to change the channel to practice, so I wanted to change the channel of TIM1 from ch1 to ch2, so I changed PA8 to PA9 (it is on the data sheet), and changed TIM_OC1PreloadConfig to TIM_OC2PreloadConfig. I tried it but it didn’
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号