问题来源:使用stm32f042时,本来设计的程序为USB端识别为键盘,但是每次插到电脑上都被枚举为DFU设备。
后来经过查找问题,因为stm32f042的boot0引脚被当做IO使用,并且外置了上拉电阻,根据启动选择,每次上电后会进入BootLoader(system memory)程序。
可以看出,对于STM32F04X和STM32F09X到底使用哪种配置方式取决于Boot_Sel选项位。对于非STM32F04X和STM32F09X的32F0系列芯片,配置方式只能使用第一种配置方式,此时Boot_Sel固定为1。
但是由于硬件设计原因,此处只能使用第二种方案:将Boot_Sel配置为0,nBoot0配置为1。
参考st官方应用笔记《STM32F09X不使用BOOT脚实现SYSTEMBOOTLOADER升级代码》,可以解决这个问题。但是st官方的程序是标准固件库版本的,我将其移植到了HAL库上。见以下代码:
参考笔记有:
《STM32F09X不使用BOOT脚实现SYSTEMBOOTLOADER升级代码》
《STM32F091从自举程序向应用程序跳转的问题与解决》
《STM32F091空片使用System Bootloader下载代码》
程序入口处调用:
/* 以下两行代码,是将向量表映射为 Main Flash memory,否则从 Bootloader 跳转到用户
码时,将无法正常工作。如有不清楚之处,请参考另外一份文档:
《STM32F091 从自举程序向应用程序跳转的问题与解决》 */
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
SYSCFG->CFGR1 = (uint32_t)0x00000000;
/* 此处调用子程序,用来判断 BOOT 的配置是否从 Main Flash memory 启动,如果不是,将
Option Bytes 中的BOOT 配置设置为从 Main Flash memory 启动 */
BOOTCONF_User();
在需要升级时调用:
BOOTCONF_System();
函数实现:
/**
* @brief Checks BOOT_SEL, nBOOT0, nBOOT1 and Reset.
* @param None
* @retval None
*/
void BOOTCONF_User(void)
{
HAL_StatusTypeDef status = HAL_OK;
uint16_t ob[5];
/* Get opiton bytes data */
ob[0] = *(uint16_t*)(0x1FFFF800); //RDP
ob[1] = *(uint16_t*)(0x1FFFF802); //USER
ob[2] = *(uint16_t*)(0x1FFFF804); //DATA0
ob[3] = *(uint16_t*)(0x1FFFF806); //DATA1
ob[4] = *(uint16_t*)(0x1FFFF808); //WRP0
/* Check boot configuration and correct */
if((ob[1] & 0x0098) != 0x0018)
{
/* Unlock */
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
/* Erase and update Option bytes*/
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* If the previous operation is completed, proceed to erase the option bytes */
FLASH->CR |= FLASH_CR_OPTER;
FLASH->CR |= FLASH_CR_STRT;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the OPTER Bit */
FLASH->CR &= ~FLASH_CR_OPTER;
/* Update option bytes */
ob[1] = (ob[1] & 0x6767) | 0x8018;
/* Enable the Option Bytes Programming operation */
FLASH->CR |= FLASH_CR_OPTPG;
/* Restore the last read protection Option Byte value */
OB->RDP = ob[0];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->USER = ob[1];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->DATA0 = ob[2];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->DATA1 = ob[3];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->WRP0 = ob[4];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
}
else
{
if (status != HAL_TIMEOUT)
{
/* Disable the OPTPG Bit */
FLASH->CR &= ~FLASH_CR_OPTPG;
}
}
/* Lock */
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
/* Verify */
if((*(uint16_t*)(0x1FFFF800)) != ob[0])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF802)) != ob[1])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF804)) != ob[2])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF806)) != ob[3])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF808)) != ob[4])
while(1) ; //ERROR
HAL_FLASH_OB_Launch();
}
}
/**
* @brief Checks BOOT_SEL, nBOOT0, nBOOT1 and Reset.
* @param None
* @retval None
*/
void BOOTCONF_System(void)
{
HAL_StatusTypeDef status = HAL_OK;
uint16_t ob[5];
/* Get opiton bytes data */
ob[0] = *(uint16_t*)(0x1FFFF800); //RDP
ob[1] = *(uint16_t*)(0x1FFFF802); //USER
ob[2] = *(uint16_t*)(0x1FFFF804); //DATA0
ob[3] = *(uint16_t*)(0x1FFFF806); //DATA1
ob[4] = *(uint16_t*)(0x1FFFF808); //WRP0
/* Unlock */
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
/* Erase and update Option bytes*/
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* If the previous operation is completed, proceed to erase the option bytes */
FLASH->CR |= FLASH_CR_OPTER;
FLASH->CR |= FLASH_CR_STRT;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the OPTER Bit */
FLASH->CR &= ~FLASH_CR_OPTER;
/* Update option bytes */
ob[1] = (ob[1] & 0xFFF7) | 0x0800;
/* Enable the Option Bytes Programming operation */
FLASH->CR |= FLASH_CR_OPTPG;
/* Restore the last read protection Option Byte value */
OB->RDP = ob[0];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->USER = ob[1];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->DATA0 = ob[2];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->DATA1 = ob[3];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
FLASH->CR |= FLASH_CR_OPTPG;
OB->WRP0 = ob[4];
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if(status == HAL_TIMEOUT)
while(1) ; //ERROR
FLASH->CR &= ~FLASH_CR_OPTPG;
}
else
{
if (status != HAL_TIMEOUT)
{
/* Disable the OPTPG Bit */
FLASH->CR &= ~FLASH_CR_OPTPG;
}
}
/* Lock */
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
/* Verify */
if((*(uint16_t*)(0x1FFFF800)) != ob[0])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF802)) != ob[1])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF804)) != ob[2])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF806)) != ob[3])
while(1) ; //ERROR
if((*(uint16_t*)(0x1FFFF808)) != ob[4])
while(1) ; //ERROR
}