打印
[应用相关]

STM32 USB的DFU模式升级

[复制链接]
433|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2025-2-19 09:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1.BootLoader端
配置串口,按键,选择USB为DFU模式,配置地址,生成项目。



打开usbd_dfu_if.c文件,编写函数

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

/**
  * @brief  Memory initialization routine.
  * @retval USBD_OK if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Init_FS(void)
{
  /* USER CODE BEGIN 0 */
    HAL_FLASH_Unlock();
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);
  return (USBD_OK);
  /* USER CODE END 0 */
}


/**
  * @brief  De-Initializes Memory
  * @retval USBD_OK if operation is successful, MAL_FAIL else
  */
uint16_t MEM_If_DeInit_FS(void)
{
  /* USER CODE BEGIN 1 */
    HAL_FLASH_Lock();
  return (USBD_OK);
  /* USER CODE END 1 */
}


/**
  * @brief  Erase sector.
  * @param  Add: Address of sector to be erased.
  * @retval 0 if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Erase_FS(uint32_t Add)
{
  /* USER CODE BEGIN 2 */
    uint32_t PageError;
    /* Variable contains Flash operation status */
    HAL_StatusTypeDef status;
    FLASH_EraseInitTypeDef eraseinitstruct;

    eraseinitstruct.TypeErase = FLASH_TYPEERASE_PAGES;
    eraseinitstruct.PageAddress = Add;
    eraseinitstruct.NbPages = 1U;
    status = HAL_FLASHEx_Erase(&eraseinitstruct, &PageError);

    if(status != HAL_OK)
    {
        return (USBD_FAIL);
    }
  return (USBD_OK);
  /* USER CODE END 2 */
}


/**
  * @brief  Memory write routine.
  * @param  src: Pointer to the source buffer. Address to be written to.
  * @param  dest: Pointer to the destination buffer.
  * @param  Len: Number of data to be written (in bytes).
  * @retval USBD_OK if operation is successful, MAL_FAIL else.
  */
uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
  /* USER CODE BEGIN 3 */
    uint32_t i = 0;

    for(i = 0; i < Len; i += 4)
    {
        /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
        * be done by byte */
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest + i), *(uint32_t *)(src + i)) == HAL_OK)
        {
            /* Check the written value */
            if(*(uint32_t *)(src + i) != *(uint32_t *)(dest + i))
            {
                /* Flash content doesn't match SRAM content */
                return (USBD_FAIL);
            }
        }
        else
        {
            /* Error occurred while writing data in Flash memory */
            return (USBD_FAIL);
        }
    }
  return (USBD_OK);
  /* USER CODE END 3 */
}


/**
  * @brief  Memory read routine.
  * @param  src: Pointer to the source buffer. Address to be written to.
  * @param  dest: Pointer to the destination buffer.
  * @param  Len: Number of data to be read (in bytes).
  * @retval Pointer to the physical address where data should be read.
  */
uint8_t *MEM_If_Read_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
  /* Return a valid address to avoid HardFault */
  /* USER CODE BEGIN 4 */
    uint32_t i = 0;
    uint8_t *psrc = src;

    for(i = 0; i < Len; i++)
    {
        dest = *psrc++;
    }
    /* Return a valid address to avoid HardFault */
    return (uint8_t *)(dest);
  /* USER CODE END 4 */
}


/**
  * @brief  Get status routine
  * @param  Add: Address to be read from
  * @param  Cmd: Number of data to be read (in bytes)
  * @param  buffer: used for returning the time necessary for a program or an erase operation
  * @retval USBD_OK if operation is successful
  */
uint16_t MEM_If_GetStatus_FS(uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{
  /* USER CODE BEGIN 5 */
    //擦除及写入时间应该按文档改写
    uint16_t FLASH_PROGRAM_TIME = 50;
    uint16_t FLASH_ERASE_TIME = 50;

    switch(Cmd)
    {
    case DFU_MEDIA_PROGRAM:
        buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
        buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
        buffer[3] = 0;
        break;
    case DFU_MEDIA_ERASE:
    default:
        buffer[1] = (uint8_t)FLASH_ERASE_TIME;
        buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
        buffer[3] = 0;
        break;
    }
    return (USBD_OK);
  /* USER CODE END 5 */
}

打开mian.c文件,编写测试代码

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch,1, 0xFFFF);
    return ch;
}
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef void (*pFunction)(void);
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
        pFunction JumpToApplication;
        uint32_t JumpAddress;

  /* 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 */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */
       
        printf("\r\n*****usb-DFU2222 *****\r\n");
        //printf("\r\n*****usb Applocation123456*****\r\n");
       
          //读取PA0引脚电平决定是否进入APP以及判断APP程序入口地址是否存在或正确
  //按下按键进入DFU,不按按键进入Application程序
       
  if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
  {
    printf("Enter Application\r\n");
    /* Test if user code is programmed starting from USBD_DFU_APP_DEFAULT_ADD address */
    if(((*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000) == 0x20000000)
    {
                        printf("Jump to user application\n");
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t *)(USBD_DFU_APP_DEFAULT_ADD + 4);
      JumpToApplication = (pFunction)JumpAddress;

      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD);
      __disable_irq(); //此处官方代码未放置关闭中断,在跳转app的时候会出问题!!!!!!
      JumpToApplication();
    }
  }
  printf("Key Down Enter DFU\r\n");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

2.APP端
需要修改下载代码地址与上述BootLoader端所设置的一致。



正常运行代码时,USB为虚拟通信串口,建立项目在上篇文章中,在此基础上需加入几行代码。

int main(void)
{
  /* USER CODE BEGIN 1 */
       
        __set_FAULTMASK(1);
       
        //地址偏移量
        SCB->VTOR=FLASH_BASE | 0x5800;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
       
        __ASM("CPSIE  I");
  __set_FAULTMASK(0);

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */
       
        printf("hello");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
        uint8_t i;
        uint8_t USB_RX_BUF_Change[USB_REC_LEN];
  while (1)
  {
                printf("\r\n*****usb Applocation333*****\r\n");
                HAL_Delay(1000);
                if(USB_RX_STA!=0)
                        {
                        //USB_printf("USB_RX:");
                        //CDC_Transmit_FS(USB_RX_BUF,USB_RX_STA);
                        for(i=0;i<12;i++)
                        {
                               
                                USB_RX_BUF_Change=USB_RX_BUF;
                                //USB_printf("USB_RX_BUF[%d]=%X\n",i,USB_RX_BUF_Change);
                                USB_printf("%X ",USB_RX_BUF_Change);
                        }
                        //USB_printf("\r\n");
                        USB_RX_STA=0;
                        memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));
                        }
               
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

当上电时,若按键按下,进入APP代码运行模式。若按键未按下,则进入DFU下载模式。

按下按键时





未按下按键





3.使用USB的DFU模式更新代码
上电不要按下按键,进入DFU模式,打开STM32CubeProgrammer

修改APP端代码,重新编译。用于测试是否更新成功。



选择USB,点击连接,显示连接成功。



点击下载,显示下载成功。



重新上电,按下按键。可知代码更新成功。



进入APP模式可进行虚拟串口通信



————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_53197842/article/details/145617770

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2180

主题

16468

帖子

17

粉丝