USB(Universal Serial BUS)通用串行总线,是一个外部总线规范,用于规范电脑与外部设备的衔接和通讯。是应用在 PC 领域的接口技能。USB 接口支撑设备的即插即用和热插拔功用。USB 是在 1994 年末由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。
USB 开展到现在现已有 USB1.0/1.1/2.0/3.0 等多个版别。现在用的最多的就是 USB1.1 和 USB2.0,USB3.0 现在现已开端普及。STM32F103 自带的 USB 契合 USB2.0 规范,不过 STM32F103 的 USB 都只能用来做设备,而不能用作主机。
规范 USB 共四根线组成,除 VCC/GND 外,别的为 D+,D-; 这两根数据线选用的是差分电压的方法进行数据传输的。在 USB 主机上,D-和 D+都是接了 15K 的电阻到低的,所以在没有设备接入的时分,D+、D-均是低电平。而在 USB 设备中,假如是高速设备,则会在 D+上接一个 1.5K 的电阻到 VCC,而假如是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样当设备接入主机的时分,主机就能够判别是否有设备接入,并能判别设备是高速设备仍是低速设备。
STM32F103 的 MCU 自带 USB 从操控器,契合 USB 规范的通讯衔接;PC 主机和微操控器之间的数据传输是经过共享一专用的数据缓冲区来完结的,该数据缓冲区能被 USB 外设直接拜访。这块专用数据缓冲区的巨细由所运用的端点数目和每个端点最大的数据分组巨细所决议,每个端点最大可运用 512 字节缓冲区(专用的 512 字节,和 CAN 共用),最多可用于 16 个单向或 8 个双向端点。USB 模块同 PC 主机通讯,依据 USB 规范完结令牌分组的检测,数据发送/接纳的处理,和握手分组的处理。整个传输的格式由硬件完结,其间包含 CRC 的生成和校验。
/**
* @brief De-Initializes Memory
* @retval USBD_OK if operation is successful, MAL_FAIL else
*/uint16_tMEM_If_DeInit_FS(void){
/* USER CODE BEGIN 1 */HAL_FLASH_Lock();
return (USBD_OK);
/* USER CODE END 1 */
}
MEM_If_Erase_FS
Flash擦除
/**
* @brief Erase sector.
* @param Add: Address of sector to be erased.
* @retval 0 if operation is successful, MAL_FAIL else.
*/uint16_tMEM_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 */
}
MEM_If_Write_FS
Flash写入,将USB接纳到的Flash数据写入到Flash中
/**
* @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_tMEM_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 */
}
MEM_If_Read_FS
Flash读取,读取指定地址的数据到目标数组中,并返回数组地址
/**
* @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[i] = *psrc++;
}
/* Return a valid address to avoid HardFault */return (uint8_t *)(dest);
/* USER CODE END 4 */
}
MEM_If_GetStatus_FS
获取Flash状况
/**
* @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_tMEM_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 */
}
6.2 修正main.c
增加APP程序进口函数指针。
/* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD */typedefvoid(*pFunction)(void);
/* USER CODE END PTD */
/**
* @brief The application entry point.
* @retval int
*/intmain(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_USB_DEVICE_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */printf("\r\n****** USB-DFU Example ******\r\n\r\n");
//读取PA0引脚电平决议是否进入APP以及判别APP程序进口地址是否存在或正确//按下按键进入DFU,不按按键进入Application程序if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_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)
{
/* 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");
MX_USB_DEVICE_Init();
/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1)
{
/* USER CODE END WHILE *//* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}