一:单片机的BootLoader
Bootloader部分移植ST官网的例程,官网例程的IAP有多个文件,为了移植方便我把多个文件合成了一个ymodem.c文件和ymodem.h文件
/* * ymodem.c * * Created on: Jun 6, 2023 * Author: MingYi-LZQ */ #include "main.h" #include "ymodem.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /** * @brief Convert an Integer to a string 将整数转换为字符串 * @param p_str: The string output pointer 字符串输出指针 * @param intnum: The integer to be converted 要转换的整数 * @retval None */ void Int2Str(uint8_t *p_str, uint32_t intnum) { uint32_t i, divider = 1000000000, pos = 0, status = 0; for (i = 0; i < 10; i++) { p_str[pos++] = (intnum / divider) + 48; intnum = intnum % divider; divider /= 10; if ((p_str[pos-1] == '0') & (status == 0)) { pos = 0; } else { status++; } } } /** * @brief Convert a string to an integer 将字符串转换为整数 * @param p_inputstr: The string to be converted 要转换的字符串 * @param p_intnum: The integer value 整数值 * @retval 1: Correct * 0: Error */ uint32_t Str2Int(uint8_t *p_inputstr, uint32_t *p_intnum) { uint32_t i = 0, res = 0; uint32_t val = 0; if ((p_inputstr[0] == '0') && ((p_inputstr[1] == 'x') || (p_inputstr[1] == 'X'))) { i = 2; while ( ( i < 11 ) && ( p_inputstr[i] != '\0' ) ) { if (ISVALIDHEX(p_inputstr[i])) { val = (val << 4) + CONVERTHEX(p_inputstr[i]); } else { /* Return 0, Invalid input 返回0,无效输入 */ res = 0; break; } i++; } /* valid result 有效的结果 */ if (p_inputstr[i] == '\0') { *p_intnum = val; res = 1; } } else /* max 10-digit decimal input 最大10位十进制输入 */ { while ( ( i < 11 ) && ( res != 1 ) ) { if (p_inputstr[i] == '\0') { *p_intnum = val; /* return 1 */ res = 1; } else if (((p_inputstr[i] == 'k') || (p_inputstr[i] == 'K')) && (i > 0)) { val = val << 10; *p_intnum = val; res = 1; } else if (((p_inputstr[i] == 'm') || (p_inputstr[i] == 'M')) && (i > 0)) { val = val << 20; *p_intnum = val; res = 1; } else if (ISVALIDDEC(p_inputstr[i])) { val = val * 10 + CONVERTDEC(p_inputstr[i]); } else { /* return 0, Invalid input */ res = 0; break; } i++; } } return res; } /** * @brief Print a string on the HyperTerminal 在超级终端上打印一个字符串 * @param p_string: The string to be printed 要打印的字符串 * @retval None */ void Serial_PutString(uint8_t *p_string) { uint16_t length = 0; while (p_string[length] != '\0') { length++; } HAL_UART_Transmit(&huart1, p_string, length, TX_TIMEOUT); } /** * @brief Transmit a byte to the HyperTerminal 向超终端发送一个字节 * @param param The byte to be sent * @retval HAL_StatusTypeDef HAL_OK if OK */ HAL_StatusTypeDef Serial_PutByte( uint8_t param ) { return HAL_UART_Transmit(&huart1, ¶m, 1, TX_TIMEOUT); } /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ pFunction JumpToApplication; uint32_t JumpAddress; uint32_t FlashProtection = 0; uint8_t aFileName[FILE_NAME_LENGTH]; /* Private function prototypes -----------------------------------------------*/ void SerialDownload(void); void SerialUpload(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Download a file via serial port * @param None * @retval None */ void SerialDownload(void) { uint8_t number[11] = {0}; uint32_t size = 0; COM_StatusTypeDef result; Serial_PutString((uint8_t *)"Waiting for the file to be sent ... (press 'a' to abort)\n\r"); result = Ymodem_Receive( &size ); if (result == COM_OK) { Serial_PutString((uint8_t *)"\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: "); Serial_PutString(aFileName); Int2Str(number, size); Serial_PutString((uint8_t *)"\n\r Size: "); Serial_PutString(number); Serial_PutString((uint8_t *)" Bytes\r\n"); Serial_PutString((uint8_t *)"-------------------\n"); } else if (result == COM_LIMIT) { Serial_PutString((uint8_t *)"\n\n\rThe image size is higher than the allowed space memory!\n\r"); } else if (result == COM_DATA) { Serial_PutString((uint8_t *)"\n\n\rVerification failed!\n\r"); } else if (result == COM_ABORT) { Serial_PutString((uint8_t *)"\r\n\nAborted by user.\n\r"); } else { Serial_PutString((uint8_t *)"\n\rFailed to receive the file!\n\r"); } } /** * @brief Upload a file via serial port. * @param None * @retval None */ void SerialUpload(void) { uint8_t status = 0; Serial_PutString((uint8_t *)"\n\n\rSelect Receive File\n\r"); HAL_UART_Receive(&huart1, &status, 1, RX_TIMEOUT); if ( status == CRC16) { /* Transmit the flash image through ymodem protocol */ status = Ymodem_Transmit((uint8_t*)APPLICATION_ADDRESS, (const uint8_t*)"UploadedFlashImage.bin", USER_FLASH_SIZE); if (status != 0) { Serial_PutString((uint8_t *)"\n\rError Occurred while Transmitting File\n\r"); } else { Serial_PutString((uint8_t *)"\n\rFile uploaded successfully \n\r"); } } } /** * @brief Display the Main Menu on HyperTerminal * @param None * @retval None */ void Main_Menu(void) { uint8_t key = 0; Serial_PutString((uint8_t *)"\r\n======================================================================"); Serial_PutString((uint8_t *)"\r\n= (C) COPYRIGHT 2016 STMicroelectronics ="); Serial_PutString((uint8_t *)"\r\n= ="); Serial_PutString((uint8_t *)"\r\n= STM32F1xx In-Application Programming Application (Version 1.0.0) ="); Serial_PutString((uint8_t *)"\r\n= ="); Serial_PutString((uint8_t *)"\r\n= By MCD Application Team ="); Serial_PutString((uint8_t *)"\r\n======================================================================"); Serial_PutString((uint8_t *)"\r\n\r\n"); /* Test if any sector of Flash memory where user application will be loaded is write protected */ FlashProtection = FLASH_If_GetWriteProtectionStatus(); while (1) { Serial_PutString((uint8_t *)"\r\n=================== Main Menu ============================\r\n\n"); Serial_PutString((uint8_t *)" Download image to the internal Flash ----------------- 1\r\n\n"); Serial_PutString((uint8_t *)" Upload image from the internal Flash ----------------- 2\r\n\n"); Serial_PutString((uint8_t *)" Execute the loaded application ----------------------- 3\r\n\n"); if(FlashProtection != FLASHIF_PROTECTION_NONE) { Serial_PutString((uint8_t *)" Disable the write protection ------------------------- 4\r\n\n"); } else { Serial_PutString((uint8_t *)" Enable the write protection -------------------------- 4\r\n\n"); } Serial_PutString((uint8_t *)"==========================================================\r\n\n"); /* Clean the input path */ __HAL_UART_FLUSH_DRREGISTER(&huart1); /* Receive key */ HAL_UART_Receive(&huart1, &key, 1, RX_TIMEOUT); switch (key) { case '1' : /* Download user application in the Flash */ SerialDownload(); break; case '2' : /* Upload user application from the Flash */ SerialUpload(); break; case '3' : Serial_PutString((uint8_t *)"Start program execution......\r\n\n"); /* execute the new program */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); /* Jump to user application */ JumpToApplication = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); JumpToApplication(); break; case '4' : if (FlashProtection != FLASHIF_PROTECTION_NONE) { /* Disable the write protection */ if (FLASH_If_WriteProtectionConfig(FLASHIF_WRP_DISABLE) == FLASHIF_OK) { Serial_PutString((uint8_t *)"Write Protection disabled...\r\n"); Serial_PutString((uint8_t *)"System will now restart...\r\n"); /* Launch the option byte loading */ HAL_FLASH_OB_Launch(); } else { Serial_PutString((uint8_t *)"Error: Flash write un-protection failed...\r\n"); } } else { if (FLASH_If_WriteProtectionConfig(FLASHIF_WRP_ENABLE) == FLASHIF_OK) { Serial_PutString((uint8_t *)"Write Protection enabled...\r\n"); Serial_PutString((uint8_t *)"System will now restart...\r\n"); /* Launch the option byte loading */ HAL_FLASH_OB_Launch(); } else { Serial_PutString((uint8_t *)"Error: Flash write protection failed...\r\n"); } } break; default: Serial_PutString((uint8_t *)"Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r"); break; } } } /** * @brief 解锁闪存进行写入访问 * @param None * @retval None */ void FLASH_If_Init(void) { /* 解锁程序内存 */ HAL_FLASH_Unlock(); /* 清除所有闪存标志 */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR); /* 锁定程序内存 */ HAL_FLASH_Lock(); } /** * @brief 此函数对所有用户闪存区域进行擦除a * @param start: 用户闪存区域的开始 * @retval FLASHIF_OK : 用户闪存区域成功擦除 * FLASHIF_ERASEKO : 发生了错误 */ uint32_t FLASH_If_Erase(uint32_t start) { uint32_t NbrOfPages = 0; uint32_t PageError = 0; FLASH_EraseInitTypeDef pEraseInit; HAL_StatusTypeDef status = HAL_OK; /* 解锁闪存以启用闪存控制寄存器访问 *************/ HAL_FLASH_Unlock(); /* 获取启动用户闪存区域的扇区 */ NbrOfPages = (USER_FLASH_END_ADDRESS - start)/FLASH_PAGE_SIZE; pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES; pEraseInit.PageAddress = start; pEraseInit.NbPages = NbrOfPages; status = HAL_FLASHEx_Erase(&pEraseInit, &PageError); /* 锁定闪存以禁用闪存控制寄存器访问(建议保护闪存免受可能不必要的操作)*********/ HAL_FLASH_Lock(); if (status != HAL_OK) { /* 页面擦除时发生错误 */ return FLASHIF_ERASEKO; } return FLASHIF_OK; } /* Public functions ---------------------------------------------------------*/ /** * @brief 此函数在闪存中写入数据缓冲区 (数据是32位对齐的). * @note 写入数据缓冲区后,检查闪存内容 * @param destination: 目标位置的起始地址 * @param p_source: 指向要写入数据的缓冲区的指针 * @param length: 数据缓冲区的长度(单位是32位字) * @retval uint32_t 0: 数据成功地写入闪存 * 1: 在闪存中写入数据时发生错误 * 2: 闪存中的写入数据不同于预期的数据 */ uint32_t FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length) { uint32_t i = 0; /* 解锁闪存以启用闪存控制寄存器访问 *************/ HAL_FLASH_Unlock(); for (i = 0; (i < length) && (destination <= (USER_FLASH_END_ADDRESS-4)); i++) { /* 设备电压范围应为[2.7V至3.6V],操作将通过Word完成*/ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, destination, *(uint32_t*)(p_source+i)) == HAL_OK) { /* 检查写入的值 */ if (*(uint32_t*)destination != *(uint32_t*)(p_source+i)) { /* 闪存内容与SRAM内容不匹配 */ return(FLASHIF_WRITINGCTRL_ERROR); } /* 增量Flash目的地地址 */ destination += 4; } else { /* 在闪存中写入数据时发生错误 */ return (FLASHIF_WRITING_ERROR); } } /* 锁定闪存以禁用闪存控制寄存器访问(建议保护闪存免受可能不必要的操作 *********/ HAL_FLASH_Lock(); return (FLASHIF_OK); } /** * @brief 返回应用程序闪存区域的写保护状态 * @param None * @retval 如果应用程序区域中的扇区是写保护的,则返回值是一个组合 可能的值 : FLASHIF_PROTECTION_WRPENABLED, FLASHIF_PROTECTION_PCROPENABLED, ... * 如果没有扇区是写保护的 FLASHIF_PROTECTION_NONE 被退回. */ uint32_t FLASH_If_GetWriteProtectionStatus(void) { uint32_t ProtectedPAGE = FLASHIF_PROTECTION_NONE; FLASH_OBProgramInitTypeDef OptionsBytesStruct; /* 解锁闪存以启用闪存控制寄存器访问*************/ HAL_FLASH_Unlock(); /* 检查用户闪存区域内是否有写保护扇区 ****/ HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct); /* 锁定闪存以禁用闪存控制寄存器访问(建议保护闪存免受可能不必要的操作) *********/ HAL_FLASH_Lock(); /* 获取已写入保护的页面 ****************************************/ ProtectedPAGE = ~(OptionsBytesStruct.WRPPage) & FLASH_PAGE_TO_BE_PROTECTED; /* 检查所需页面是否已经写入保护 ***********************/ if(ProtectedPAGE != 0) { /* 用户闪存区域内的一些扇区被写入保护 */ return FLASHIF_PROTECTION_WRPENABLED; } else { /* 用户闪存区域内没有写保护扇区 */ return FLASHIF_PROTECTION_NONE; } } /** * @brief 配置用户闪存区域的写保护状态. * @param protectionstate : FLASHIF_WRP_DISABLE or FLASHIF_WRP_ENABLE the protection * @retval uint32_t FLASHIF_OK if change is applied. */ uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate) { uint32_t ProtectedPAGE = 0x0; FLASH_OBProgramInitTypeDef config_new, config_old; HAL_StatusTypeDef result = HAL_OK; /* 获取页面写入保护状态 ****************************************/ HAL_FLASHEx_OBGetConfig(&config_old); /* 参数表示我们是否打开或关闭保护 */ config_new.WRPState = (protectionstate == FLASHIF_WRP_ENABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE); /* 我们只想修改写保护 */ config_new.OptionType = OPTIONBYTE_WRP; /* 没有读取保护,保持BOR和重置设置*/ config_new.RDPLevel = OB_RDP_LEVEL_0; config_new.USERConfig = config_old.USERConfig; /* 获取已写入保护的页面 ****************************************/ ProtectedPAGE = config_old.WRPPage | FLASH_PAGE_TO_BE_PROTECTED; /* 解锁闪存以启用闪存控制寄存器访问 *************/ HAL_FLASH_Unlock(); /* 解锁选项字节*************************************************/ HAL_FLASH_OB_Unlock(); /* 删除所有选项字节 ***********************************************/ result = HAL_FLASHEx_OBErase(); if (result == HAL_OK) { config_new.WRPPage = ProtectedPAGE; result = HAL_FLASHEx_OBProgram(&config_new); } return (result == HAL_OK ? FLASHIF_OK: FLASHIF_PROTECTION_ERRROR); } /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ #define CRC16_F /* activate the CRC16 integrity 激活CRC16 */ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* @note ATTENTION - please keep this variable 32bit alligned 请保持此变量32位对齐*/ uint8_t aPacketData[PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE]; /* Private function prototypes -----------------------------------------------*/ static void PrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_t length); static void PreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_t size_blk); static HAL_StatusTypeDef ReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout); uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte); uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size); uint8_t CalcChecksum(const uint8_t *p_data, uint32_t size); /* Private functions ---------------------------------------------------------*/ /** * @brief Receive a packet from sender * @param data * @param length * 0: end of transmission * 2: abort by sender * >0: packet length * @param timeout * @retval HAL_OK: normally return * HAL_BUSY: abort by user */ static HAL_StatusTypeDef ReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout) { uint32_t crc; uint32_t packet_size = 0; HAL_StatusTypeDef status; uint8_t char1; *p_length = 0; status = HAL_UART_Receive(&huart1, &char1, 1, timeout); if (status == HAL_OK) { switch (char1) { case SOH: packet_size = PACKET_SIZE; break; case STX: packet_size = PACKET_1K_SIZE; break; case EOT: break; case CA: if ((HAL_UART_Receive(&huart1, &char1, 1, timeout) == HAL_OK) && (char1 == CA)) { packet_size = 2; } else { status = HAL_ERROR; } break; case ABORT1: case ABORT2: status = HAL_BUSY; break; default: status = HAL_ERROR; break; } *p_data = char1; if (packet_size >= PACKET_SIZE ) { status = HAL_UART_Receive(&huart1, &p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE, timeout); /* Simple packet sanity check 简单的数据包健全检查 */ if (status == HAL_OK ) { if (p_data[PACKET_NUMBER_INDEX] != ((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE)) { packet_size = 0; status = HAL_ERROR; } else { /* Check packet CRC 检查分组CRC */ crc = p_data[ packet_size + PACKET_DATA_INDEX ] << 8; crc += p_data[ packet_size + PACKET_DATA_INDEX + 1 ]; if (Cal_CRC16(&p_data[PACKET_DATA_INDEX], packet_size) != crc ) { packet_size = 0; status = HAL_ERROR; } } } else { packet_size = 0; } } } *p_length = packet_size; return status; } /** * @brief Prepare the first block 准备第一个块区 * @param p_data: output buffer * @param p_file_name: name of the file to be sent * @param length: length of the file to be sent in bytes * @retval None */ static void PrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_t length) { uint32_t i, j = 0; uint8_t astring[10]; /* first 3 bytes are constant 前3个字节是常数 */ p_data[PACKET_START_INDEX] = SOH; p_data[PACKET_NUMBER_INDEX] = 0x00; p_data[PACKET_CNUMBER_INDEX] = 0xff; /* Filename written 文件名写的 */ for (i = 0; (p_file_name[i] != '\0') && (i < FILE_NAME_LENGTH); i++) { p_data[i + PACKET_DATA_INDEX] = p_file_name[i]; } p_data[i + PACKET_DATA_INDEX] = 0x00; /* file size written 写入文件大小*/ Int2Str (astring, length); i = i + PACKET_DATA_INDEX + 1; while (astring[j] != '\0') { p_data[i++] = astring[j++]; } /* padding with zeros 填充零 */ for (j = i; j < PACKET_SIZE + PACKET_DATA_INDEX; j++) { p_data[j] = 0; } } /** * @brief Prepare the data packet 准备数据包 * @param p_source: pointer to the data to be sent 指向要发送的数据的指针 * @param p_packet: pointer to the output buffer 指向输出缓冲区的指针 * @param pkt_nr: number of the packet * @param size_blk: length of the block to be sent in bytes 以字节为单位发送的块的长度 * @retval None */ static void PreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_t size_blk) { uint8_t *p_record; uint32_t i, size, packet_size; /* Make first three packet */ packet_size = size_blk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE; size = size_blk < packet_size ? size_blk : packet_size; if (packet_size == PACKET_1K_SIZE) { p_packet[PACKET_START_INDEX] = STX; } else { p_packet[PACKET_START_INDEX] = SOH; } p_packet[PACKET_NUMBER_INDEX] = pkt_nr; p_packet[PACKET_CNUMBER_INDEX] = (~pkt_nr); p_record = p_source; /* Filename packet has valid data */ for (i = PACKET_DATA_INDEX; i < size + PACKET_DATA_INDEX;i++) { p_packet[i] = *p_record++; } if ( size <= packet_size) { for (i = size + PACKET_DATA_INDEX; i < packet_size + PACKET_DATA_INDEX; i++) { p_packet[i] = 0x1A; /* EOF (0x1A) or 0x00 */ } } } /** * @brief Update CRC16 for input byte * @param crc_in input value * @param input byte * @retval None */ uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte) { uint32_t crc = crc_in; uint32_t in = byte | 0x100; do { crc <<= 1; in <<= 1; if(in & 0x100) ++crc; if(crc & 0x10000) crc ^= 0x1021; } while(!(in & 0x10000)); return crc & 0xffffu; } /** * @brief Cal CRC16 for YModem Packet * @param data * @param length * @retval None */ uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size) { uint32_t crc = 0; const uint8_t* dataEnd = p_data+size; while(p_data < dataEnd) crc = UpdateCRC16(crc, *p_data++); crc = UpdateCRC16(crc, 0); crc = UpdateCRC16(crc, 0); return crc&0xffffu; } /** * @brief Calculate Check sum for YModem Packet * @param p_data Pointer to input data * @param size length of input data * @retval uint8_t checksum value */ uint8_t CalcChecksum(const uint8_t *p_data, uint32_t size) { uint32_t sum = 0; const uint8_t *p_data_end = p_data + size; while (p_data < p_data_end ) { sum += *p_data++; } return (sum & 0xffu); } /* Public functions ---------------------------------------------------------*/ /** * @brief Receive a file using the ymodem protocol with CRC16. * @param p_size The size of the file. * @retval COM_StatusTypeDef result of reception/programming */ COM_StatusTypeDef Ymodem_Receive ( uint32_t *p_size ) { uint32_t i, packet_length, session_done = 0, file_done, errors = 0, session_begin = 0 ,packets_received; uint32_t flashdestination, ramsource, filesize; uint8_t *file_ptr; uint8_t file_size[FILE_SIZE_LENGTH], tmp ; COM_StatusTypeDef result = COM_OK; /* Initialize flashdestination variable */ flashdestination = APPLICATION_ADDRESS; while ((session_done == 0) && (result == COM_OK)) { packets_received = 0; file_done = 0; while ((file_done == 0) && (result == COM_OK)) { switch (ReceivePacket(aPacketData, &packet_length, DOWNLOAD_TIMEOUT)) { case HAL_OK: errors = 0; switch (packet_length) { case 2: /* Abort by sender */ Serial_PutByte(ACK); result = COM_ABORT; break; case 0: /* End of transmission */ Serial_PutByte(ACK); file_done = 1; break; default: /**************if (aPacketData[PACKET_NUMBER_INDEX] != (packets_received & 0xff))****************/ /**************:原始产生错误的判断条件//if (aPacketData[PACKET_NUMBER_INDEX] != packets_received) */ /**************:修改后的判断条件//if (aPacketData[PACKET_NUMBER_INDEX] != (packets_received & 0xff)) */ /* Normal packet 正常的包*/ if (aPacketData[PACKET_NUMBER_INDEX] != (packets_received & 0xff)) { Serial_PutByte(NAK); } else { if (packets_received == 0) { /* File name packet 文件名包*/ if (aPacketData[PACKET_DATA_INDEX] != 0) { /* File name extraction 文件名提取*/ i = 0; file_ptr = aPacketData + PACKET_DATA_INDEX; while ( (*file_ptr != 0) && (i < FILE_NAME_LENGTH)) { aFileName[i++] = *file_ptr++; } /* File size extraction 文件大小提取 */ aFileName[i++] = '\0'; i = 0; file_ptr ++; while ( (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH)) { file_size[i++] = *file_ptr++; } file_size[i++] = '\0'; Str2Int(file_size, &filesize); /* Test the size of the image to be sent 测试要发送的数据的大小 */ /* Image size is greater than Flash size 数据大小大于闪存大小*/ if (*p_size > (USER_FLASH_SIZE + 1)) { /* End session 结束传输*/ tmp = CA; HAL_UART_Transmit(&huart1, &tmp, 1, NAK_TIMEOUT); HAL_UART_Transmit(&huart1, &tmp, 1, NAK_TIMEOUT); result = COM_LIMIT; } /* erase user application area 擦除用户应用程序区域*/ FLASH_If_Erase(APPLICATION_ADDRESS); *p_size = filesize; Serial_PutByte(ACK); Serial_PutByte(CRC16); } /* File header packet is empty, end session 文件头数据包为空,结束会话 */ else { Serial_PutByte(ACK); file_done = 1; session_done = 1; break; } } else /* Data packet 数据包;*/ { ramsource = (uint32_t) & aPacketData[PACKET_DATA_INDEX]; /* Write received data in Flash 在闪存中写入接收到的数据 */ if (FLASH_If_Write(flashdestination, (uint32_t*) ramsource, packet_length/4) == FLASHIF_OK) { flashdestination += packet_length; Serial_PutByte(ACK); } else /* An error occurred while writing to Flash memory 写入闪存时发生错误*/ { /* End session */ Serial_PutByte(CA); Serial_PutByte(CA); result = COM_DATA; } } packets_received ++; session_begin = 1; } break; } break; case HAL_BUSY: /* Abort actually 实际上中止 */ Serial_PutByte(CA); Serial_PutByte(CA); result = COM_ABORT; break; default: if (session_begin > 0) { errors ++; } if (errors > MAX_ERRORS) { /* Abort communication */ Serial_PutByte(CA); Serial_PutByte(CA); } else { Serial_PutByte(CRC16); /* Ask for a packet */ } break; } } } return result; } /** * @brief Transmit a file using the ymodem protocol * @param p_buf: Address of the first byte * @param p_file_name: Name of the file sent * @param file_size: Size of the transmission * @retval COM_StatusTypeDef result of the communication */ COM_StatusTypeDef Ymodem_Transmit (uint8_t *p_buf, const uint8_t *p_file_name, uint32_t file_size) { uint32_t errors = 0, ack_recpt = 0, size = 0, pkt_size; uint8_t *p_buf_int; COM_StatusTypeDef result = COM_OK; uint32_t blk_number = 1; uint8_t a_rx_ctrl[2]; uint8_t i; #ifdef CRC16_F uint32_t temp_crc; #else /* CRC16_F */ uint8_t temp_chksum; #endif /* CRC16_F */ /* Prepare first block - header */ PrepareIntialPacket(aPacketData, p_file_name, file_size); while (( !ack_recpt ) && ( result == COM_OK )) { /* Send Packet */ HAL_UART_Transmit(&huart1, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack and 'C' */ if (HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == ACK) { ack_recpt = 1; } else if (a_rx_ctrl[0] == CA) { if ((HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&huart1); result = COM_ABORT; } } } else { errors++; } if (errors >= MAX_ERRORS) { result = COM_ERROR; } } p_buf_int = p_buf; size = file_size; /* Here 1024 bytes length is used to send the packets */ while ((size) && (result == COM_OK )) { /* Prepare next packet */ PreparePacket(p_buf_int, aPacketData, blk_number, size); ack_recpt = 0; a_rx_ctrl[0] = 0; errors = 0; /* Resend packet if NAK for few times else end of communication */ while (( !ack_recpt ) && ( result == COM_OK )) { /* Send next packet */ if (size >= PACKET_1K_SIZE) { pkt_size = PACKET_1K_SIZE; } else { pkt_size = PACKET_SIZE; } HAL_UART_Transmit(&huart1, &aPacketData[PACKET_START_INDEX], pkt_size + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], pkt_size); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], pkt_size); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack */ if ((HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == ACK)) { ack_recpt = 1; if (size > pkt_size) { p_buf_int += pkt_size; size -= pkt_size; if (blk_number == (USER_FLASH_SIZE / PACKET_1K_SIZE)) { result = COM_LIMIT; /* boundary error */ } else { blk_number++; } } else { p_buf_int += pkt_size; size = 0; } } else { errors++; } /* Resend packet if NAK for a count of 10 else end of communication */ if (errors >= MAX_ERRORS) { result = COM_ERROR; } } } /* Sending End Of Transmission char */ ack_recpt = 0; a_rx_ctrl[0] = 0x00; errors = 0; while (( !ack_recpt ) && ( result == COM_OK )) { Serial_PutByte(EOT); /* Wait for Ack */ if (HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == ACK) { ack_recpt = 1; } else if (a_rx_ctrl[0] == CA) { if ((HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&huart1); result = COM_ABORT; } } } else { errors++; } if (errors >= MAX_ERRORS) { result = COM_ERROR; } } /* Empty packet sent - some terminal emulators need this to close session */ if ( result == COM_OK ) { /* Preparing an empty packet */ aPacketData[PACKET_START_INDEX] = SOH; aPacketData[PACKET_NUMBER_INDEX] = 0; aPacketData[PACKET_CNUMBER_INDEX] = 0xFF; for (i = PACKET_DATA_INDEX; i < (PACKET_SIZE + PACKET_DATA_INDEX); i++) { aPacketData [i] = 0x00; } /* Send Packet */ HAL_UART_Transmit(&huart1, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT); /* Send CRC or Check Sum based on CRC16_F */ #ifdef CRC16_F temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_crc >> 8); Serial_PutByte(temp_crc & 0xFF); #else /* CRC16_F */ temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE); Serial_PutByte(temp_chksum); #endif /* CRC16_F */ /* Wait for Ack and 'C' */ if (HAL_UART_Receive(&huart1, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) { if (a_rx_ctrl[0] == CA) { HAL_Delay( 2 ); __HAL_UART_FLUSH_DRREGISTER(&huart1); result = COM_ABORT; } } } return result; /* file transmitted successfully */ }ymodem.c
/* * ymodem.h * * Created on: Jun 6, 2023 * Author: MingYi-LZQ */ #ifndef INC_YMODEM_H_ #define INC_YMODEM_H_ /** * @brief Comm status structures definition */ typedef enum { COM_OK = 0x00, COM_ERROR = 0x01, COM_ABORT = 0x02, COM_TIMEOUT = 0x03, COM_DATA = 0x04, COM_LIMIT = 0x05 } COM_StatusTypeDef; /** * @} */ /* Exported constants --------------------------------------------------------*/ /* Packet structure defines */ #define PACKET_HEADER_SIZE ((uint32_t)3) #define PACKET_DATA_INDEX ((uint32_t)4) #define PACKET_START_INDEX ((uint32_t)1) #define PACKET_NUMBER_INDEX ((uint32_t)2) #define PACKET_CNUMBER_INDEX ((uint32_t)3) #define PACKET_TRAILER_SIZE ((uint32_t)2) #define PACKET_OVERHEAD_SIZE (PACKET_HEADER_SIZE + PACKET_TRAILER_SIZE - 1) #define PACKET_SIZE ((uint32_t)128) #define PACKET_1K_SIZE ((uint32_t)1024) /* /-------- Packet in IAP memory ------------------------------------------\ * | 0 | 1 | 2 | 3 | 4 | ... | n+4 | n+5 | n+6 | * |------------------------------------------------------------------------| * | unused | start | number | !num | data[0] | ... | data[n] | crc0 | crc1 | * \------------------------------------------------------------------------/ * the first byte is left unused for memory alignment reasons */ #define FILE_NAME_LENGTH ((uint32_t)64) #define FILE_SIZE_LENGTH ((uint32_t)16) #define SOH ((uint8_t)0x01) /* start of 128-byte data packet */ #define STX ((uint8_t)0x02) /* start of 1024-byte data packet */ #define EOT ((uint8_t)0x04) /* end of transmission */ #define ACK ((uint8_t)0x06) /* acknowledge */ #define NAK ((uint8_t)0x15) /* negative acknowledge */ #define CA ((uint32_t)0x18) /* two of these in succession aborts transfer */ #define CRC16 ((uint8_t)0x43) /* 'C' == 0x43, request 16-bit CRC */ #define NEGATIVE_BYTE ((uint8_t)0xFF) #define ABORT1 ((uint8_t)0x41) /* 'A' == 0x41, abort by user */ #define ABORT2 ((uint8_t)0x61) /* 'a' == 0x61, abort by user */ #define NAK_TIMEOUT ((uint32_t)0x100000) #define DOWNLOAD_TIMEOUT ((uint32_t)1000) /* One second retry delay */ #define MAX_ERRORS ((uint32_t)5) /* Exported functions ------------------------------------------------------- */ COM_StatusTypeDef Ymodem_Receive(uint32_t *p_size); COM_StatusTypeDef Ymodem_Transmit(uint8_t *p_buf, const uint8_t *p_file_name, uint32_t file_size); /* Imported variables --------------------------------------------------------*/ extern uint8_t aFileName[FILE_NAME_LENGTH]; /* Private variables ---------------------------------------------------------*/ typedef void (*pFunction)(void); extern pFunction JumpToApplication; extern uint32_t JumpAddress; /* Base address of the Flash sectors */ #define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) /* Base @ of Page 0, 2 Kbytes */ #define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) /* Base @ of Page 1, 2 Kbytes */ #define ADDR_FLASH_PAGE_2 ((uint32_t)0x08001000) /* Base @ of Page 2, 2 Kbytes */ #define ADDR_FLASH_PAGE_3 ((uint32_t)0x08001800) /* Base @ of Page 3, 2 Kbytes */ #define ADDR_FLASH_PAGE_4 ((uint32_t)0x08002000) /* Base @ of Page 4, 2 Kbytes */ #define ADDR_FLASH_PAGE_5 ((uint32_t)0x08002800) /* Base @ of Page 5, 2 Kbytes */ #define ADDR_FLASH_PAGE_6 ((uint32_t)0x08003000) /* Base @ of Page 6, 2 Kbytes */ #define ADDR_FLASH_PAGE_7 ((uint32_t)0x08003800) /* Base @ of Page 7, 2 Kbytes */ #define ADDR_FLASH_PAGE_8 ((uint32_t)0x08004000) /* Base @ of Page 8, 2 Kbytes */ #define ADDR_FLASH_PAGE_9 ((uint32_t)0x08004800) /* Base @ of Page 9, 2 Kbytes */ #define ADDR_FLASH_PAGE_10 ((uint32_t)0x08005000) /* Base @ of Page 10, 2 Kbytes */ #define ADDR_FLASH_PAGE_11 ((uint32_t)0x08005800) /* Base @ of Page 11, 2 Kbytes */ #define ADDR_FLASH_PAGE_12 ((uint32_t)0x08006000) /* Base @ of Page 12, 2 Kbytes */ #define ADDR_FLASH_PAGE_13 ((uint32_t)0x08006800) /* Base @ of Page 13, 2 Kbytes */ #define ADDR_FLASH_PAGE_14 ((uint32_t)0x08007000) /* Base @ of Page 14, 2 Kbytes */ #define ADDR_FLASH_PAGE_15 ((uint32_t)0x08007800) /* Base @ of Page 15, 2 Kbytes */ #define ADDR_FLASH_PAGE_16 ((uint32_t)0x08008000) /* Base @ of Page 16, 2 Kbytes */ #define ADDR_FLASH_PAGE_17 ((uint32_t)0x08008800) /* Base @ of Page 17, 2 Kbytes */ #define ADDR_FLASH_PAGE_18 ((uint32_t)0x08009000) /* Base @ of Page 18, 2 Kbytes */ #define ADDR_FLASH_PAGE_19 ((uint32_t)0x08009800) /* Base @ of Page 19, 2 Kbytes */ #define ADDR_FLASH_PAGE_20 ((uint32_t)0x0800A000) /* Base @ of Page 20, 2 Kbytes */ #define ADDR_FLASH_PAGE_21 ((uint32_t)0x0800A800) /* Base @ of Page 21, 2 Kbytes */ #define ADDR_FLASH_PAGE_22 ((uint32_t)0x0800B000) /* Base @ of Page 22, 2 Kbytes */ #define ADDR_FLASH_PAGE_23 ((uint32_t)0x0800B800) /* Base @ of Page 23, 2 Kbytes */ #define ADDR_FLASH_PAGE_24 ((uint32_t)0x0800C000) /* Base @ of Page 24, 2 Kbytes */ #define ADDR_FLASH_PAGE_25 ((uint32_t)0x0800C800) /* Base @ of Page 25, 2 Kbytes */ #define ADDR_FLASH_PAGE_26 ((uint32_t)0x0800D000) /* Base @ of Page 26, 2 Kbytes */ #define ADDR_FLASH_PAGE_27 ((uint32_t)0x0800D800) /* Base @ of Page 27, 2 Kbytes */ #define ADDR_FLASH_PAGE_28 ((uint32_t)0x0800E000) /* Base @ of Page 28, 2 Kbytes */ #define ADDR_FLASH_PAGE_29 ((uint32_t)0x0800E800) /* Base @ of Page 29, 2 Kbytes */ #define ADDR_FLASH_PAGE_30 ((uint32_t)0x0800F000) /* Base @ of Page 30, 2 Kbytes */ #define ADDR_FLASH_PAGE_31 ((uint32_t)0x0800F800) /* Base @ of Page 31, 2 Kbytes */ #define ADDR_FLASH_PAGE_32 ((uint32_t)0x08010000) /* Base @ of Page 32, 2 Kbytes */ #define ADDR_FLASH_PAGE_33 ((uint32_t)0x08010800) /* Base @ of Page 33, 2 Kbytes */ #define ADDR_FLASH_PAGE_34 ((uint32_t)0x08011000) /* Base @ of Page 34, 2 Kbytes */ #define ADDR_FLASH_PAGE_35 ((uint32_t)0x08011800) /* Base @ of Page 35, 2 Kbytes */ #define ADDR_FLASH_PAGE_36 ((uint32_t)0x08012000) /* Base @ of Page 36, 2 Kbytes */ #define ADDR_FLASH_PAGE_37 ((uint32_t)0x08012800) /* Base @ of Page 37, 2 Kbytes */ #define ADDR_FLASH_PAGE_38 ((uint32_t)0x08013000) /* Base @ of Page 38, 2 Kbytes */ #define ADDR_FLASH_PAGE_39 ((uint32_t)0x08013800) /* Base @ of Page 39, 2 Kbytes */ #define ADDR_FLASH_PAGE_40 ((uint32_t)0x08014000) /* Base @ of Page 40, 2 Kbytes */ #define ADDR_FLASH_PAGE_41 ((uint32_t)0x08014800) /* Base @ of Page 41, 2 Kbytes */ #define ADDR_FLASH_PAGE_42 ((uint32_t)0x08015000) /* Base @ of Page 42, 2 Kbytes */ #define ADDR_FLASH_PAGE_43 ((uint32_t)0x08015800) /* Base @ of Page 43, 2 Kbytes */ #define ADDR_FLASH_PAGE_44 ((uint32_t)0x08016000) /* Base @ of Page 44, 2 Kbytes */ #define ADDR_FLASH_PAGE_45 ((uint32_t)0x08016800) /* Base @ of Page 45, 2 Kbytes */ #define ADDR_FLASH_PAGE_46 ((uint32_t)0x08017000) /* Base @ of Page 46, 2 Kbytes */ #define ADDR_FLASH_PAGE_47 ((uint32_t)0x08017800) /* Base @ of Page 47, 2 Kbytes */ #define ADDR_FLASH_PAGE_48 ((uint32_t)0x08018000) /* Base @ of Page 48, 2 Kbytes */ #define ADDR_FLASH_PAGE_49 ((uint32_t)0x08018800) /* Base @ of Page 49, 2 Kbytes */ #define ADDR_FLASH_PAGE_50 ((uint32_t)0x08019000) /* Base @ of Page 50, 2 Kbytes */ #define ADDR_FLASH_PAGE_51 ((uint32_t)0x08019800) /* Base @ of Page 51, 2 Kbytes */ #define ADDR_FLASH_PAGE_52 ((uint32_t)0x0801A000) /* Base @ of Page 52, 2 Kbytes */ #define ADDR_FLASH_PAGE_53 ((uint32_t)0x0801A800) /* Base @ of Page 53, 2 Kbytes */ #define ADDR_FLASH_PAGE_54 ((uint32_t)0x0801B000) /* Base @ of Page 54, 2 Kbytes */ #define ADDR_FLASH_PAGE_55 ((uint32_t)0x0801B800) /* Base @ of Page 55, 2 Kbytes */ #define ADDR_FLASH_PAGE_56 ((uint32_t)0x0801C000) /* Base @ of Page 56, 2 Kbytes */ #define ADDR_FLASH_PAGE_57 ((uint32_t)0x0801C800) /* Base @ of Page 57, 2 Kbytes */ #define ADDR_FLASH_PAGE_58 ((uint32_t)0x0801D000) /* Base @ of Page 58, 2 Kbytes */ #define ADDR_FLASH_PAGE_59 ((uint32_t)0x0801D800) /* Base @ of Page 59, 2 Kbytes */ #define ADDR_FLASH_PAGE_60 ((uint32_t)0x0801E000) /* Base @ of Page 60, 2 Kbytes */ #define ADDR_FLASH_PAGE_61 ((uint32_t)0x0801E800) /* Base @ of Page 61, 2 Kbytes */ #define ADDR_FLASH_PAGE_62 ((uint32_t)0x0801F000) /* Base @ of Page 62, 2 Kbytes */ #define ADDR_FLASH_PAGE_63 ((uint32_t)0x0801F800) /* Base @ of Page 63, 2 Kbytes */ #define ADDR_FLASH_PAGE_64 ((uint32_t)0x08020000) /* Base @ of Page 64, 2 Kbytes */ #define ADDR_FLASH_PAGE_65 ((uint32_t)0x08020800) /* Base @ of Page 65, 2 Kbytes */ #define ADDR_FLASH_PAGE_66 ((uint32_t)0x08021000) /* Base @ of Page 66, 2 Kbytes */ #define ADDR_FLASH_PAGE_67 ((uint32_t)0x08021800) /* Base @ of Page 67, 2 Kbytes */ #define ADDR_FLASH_PAGE_68 ((uint32_t)0x08022000) /* Base @ of Page 68, 2 Kbytes */ #define ADDR_FLASH_PAGE_69 ((uint32_t)0x08022800) /* Base @ of Page 69, 2 Kbytes */ #define ADDR_FLASH_PAGE_70 ((uint32_t)0x08023000) /* Base @ of Page 70, 2 Kbytes */ #define ADDR_FLASH_PAGE_71 ((uint32_t)0x08023800) /* Base @ of Page 71, 2 Kbytes */ #define ADDR_FLASH_PAGE_72 ((uint32_t)0x08024000) /* Base @ of Page 72, 2 Kbytes */ #define ADDR_FLASH_PAGE_73 ((uint32_t)0x08024800) /* Base @ of Page 73, 2 Kbytes */ #define ADDR_FLASH_PAGE_74 ((uint32_t)0x08025000) /* Base @ of Page 74, 2 Kbytes */ #define ADDR_FLASH_PAGE_75 ((uint32_t)0x08025800) /* Base @ of Page 75, 2 Kbytes */ #define ADDR_FLASH_PAGE_76 ((uint32_t)0x08026000) /* Base @ of Page 76, 2 Kbytes */ #define ADDR_FLASH_PAGE_77 ((uint32_t)0x08026800) /* Base @ of Page 77, 2 Kbytes */ #define ADDR_FLASH_PAGE_78 ((uint32_t)0x08027000) /* Base @ of Page 78, 2 Kbytes */ #define ADDR_FLASH_PAGE_79 ((uint32_t)0x08027800) /* Base @ of Page 79, 2 Kbytes */ #define ADDR_FLASH_PAGE_80 ((uint32_t)0x08028000) /* Base @ of Page 80, 2 Kbytes */ #define ADDR_FLASH_PAGE_81 ((uint32_t)0x08028800) /* Base @ of Page 81, 2 Kbytes */ #define ADDR_FLASH_PAGE_82 ((uint32_t)0x08029000) /* Base @ of Page 82, 2 Kbytes */ #define ADDR_FLASH_PAGE_83 ((uint32_t)0x08029800) /* Base @ of Page 83, 2 Kbytes */ #define ADDR_FLASH_PAGE_84 ((uint32_t)0x0802A000) /* Base @ of Page 84, 2 Kbytes */ #define ADDR_FLASH_PAGE_85 ((uint32_t)0x0802A800) /* Base @ of Page 85, 2 Kbytes */ #define ADDR_FLASH_PAGE_86 ((uint32_t)0x0802B000) /* Base @ of Page 86, 2 Kbytes */ #define ADDR_FLASH_PAGE_87 ((uint32_t)0x0802B800) /* Base @ of Page 87, 2 Kbytes */ #define ADDR_FLASH_PAGE_88 ((uint32_t)0x0802C000) /* Base @ of Page 88, 2 Kbytes */ #define ADDR_FLASH_PAGE_89 ((uint32_t)0x0802C800) /* Base @ of Page 89, 2 Kbytes */ #define ADDR_FLASH_PAGE_90 ((uint32_t)0x0802D000) /* Base @ of Page 90, 2 Kbytes */ #define ADDR_FLASH_PAGE_91 ((uint32_t)0x0802D800) /* Base @ of Page 91, 2 Kbytes */ #define ADDR_FLASH_PAGE_92 ((uint32_t)0x0802E000) /* Base @ of Page 92, 2 Kbytes */ #define ADDR_FLASH_PAGE_93 ((uint32_t)0x0802E800) /* Base @ of Page 93, 2 Kbytes */ #define ADDR_FLASH_PAGE_94 ((uint32_t)0x0802F000) /* Base @ of Page 94, 2 Kbytes */ #define ADDR_FLASH_PAGE_95 ((uint32_t)0x0802F800) /* Base @ of Page 95, 2 Kbytes */ #define ADDR_FLASH_PAGE_96 ((uint32_t)0x08030000) /* Base @ of Page 96, 2 Kbytes */ #define ADDR_FLASH_PAGE_97 ((uint32_t)0x08030800) /* Base @ of Page 97, 2 Kbytes */ #define ADDR_FLASH_PAGE_98 ((uint32_t)0x08031000) /* Base @ of Page 98, 2 Kbytes */ #define ADDR_FLASH_PAGE_99 ((uint32_t)0x08031800) /* Base @ of Page 99, 2 Kbytes */ #define ADDR_FLASH_PAGE_100 ((uint32_t)0x08032000) /* Base @ of Page 100, 2 Kbytes */ #define ADDR_FLASH_PAGE_101 ((uint32_t)0x08032800) /* Base @ of Page 101, 2 Kbytes */ #define ADDR_FLASH_PAGE_102 ((uint32_t)0x08033000) /* Base @ of Page 102, 2 Kbytes */ #define ADDR_FLASH_PAGE_103 ((uint32_t)0x08033800) /* Base @ of Page 103, 2 Kbytes */ #define ADDR_FLASH_PAGE_104 ((uint32_t)0x08034000) /* Base @ of Page 104, 2 Kbytes */ #define ADDR_FLASH_PAGE_105 ((uint32_t)0x08034800) /* Base @ of Page 105, 2 Kbytes */ #define ADDR_FLASH_PAGE_106 ((uint32_t)0x08035000) /* Base @ of Page 106, 2 Kbytes */ #define ADDR_FLASH_PAGE_107 ((uint32_t)0x08035800) /* Base @ of Page 107, 2 Kbytes */ #define ADDR_FLASH_PAGE_108 ((uint32_t)0x08036000) /* Base @ of Page 108, 2 Kbytes */ #define ADDR_FLASH_PAGE_109 ((uint32_t)0x08036800) /* Base @ of Page 109, 2 Kbytes */ #define ADDR_FLASH_PAGE_110 ((uint32_t)0x08037000) /* Base @ of Page 110, 2 Kbytes */ #define ADDR_FLASH_PAGE_111 ((uint32_t)0x08037800) /* Base @ of Page 111, 2 Kbytes */ #define ADDR_FLASH_PAGE_112 ((uint32_t)0x08038000) /* Base @ of Page 112, 2 Kbytes */ #define ADDR_FLASH_PAGE_113 ((uint32_t)0x08038800) /* Base @ of Page 113, 2 Kbytes */ #define ADDR_FLASH_PAGE_114 ((uint32_t)0x08039000) /* Base @ of Page 114, 2 Kbytes */ #define ADDR_FLASH_PAGE_115 ((uint32_t)0x08039800) /* Base @ of Page 115, 2 Kbytes */ #define ADDR_FLASH_PAGE_116 ((uint32_t)0x0803A000) /* Base @ of Page 116, 2 Kbytes */ #define ADDR_FLASH_PAGE_117 ((uint32_t)0x0803A800) /* Base @ of Page 117, 2 Kbytes */ #define ADDR_FLASH_PAGE_118 ((uint32_t)0x0803B000) /* Base @ of Page 118, 2 Kbytes */ #define ADDR_FLASH_PAGE_119 ((uint32_t)0x0803B800) /* Base @ of Page 119, 2 Kbytes */ #define ADDR_FLASH_PAGE_120 ((uint32_t)0x0803C000) /* Base @ of Page 120, 2 Kbytes */ #define ADDR_FLASH_PAGE_121 ((uint32_t)0x0803C800) /* Base @ of Page 121, 2 Kbytes */ #define ADDR_FLASH_PAGE_122 ((uint32_t)0x0803D000) /* Base @ of Page 122, 2 Kbytes */ #define ADDR_FLASH_PAGE_123 ((uint32_t)0x0803D800) /* Base @ of Page 123, 2 Kbytes */ #define ADDR_FLASH_PAGE_124 ((uint32_t)0x0803E000) /* Base @ of Page 124, 2 Kbytes */ #define ADDR_FLASH_PAGE_125 ((uint32_t)0x0803E800) /* Base @ of Page 125, 2 Kbytes */ #define ADDR_FLASH_PAGE_126 ((uint32_t)0x0803F000) /* Base @ of Page 126, 2 Kbytes */ #define ADDR_FLASH_PAGE_127 ((uint32_t)0x0803F800) /* Base @ of Page 127, 2 Kbytes */ /* Error code */ enum { FLASHIF_OK = 0, FLASHIF_ERASEKO, FLASHIF_WRITINGCTRL_ERROR, FLASHIF_WRITING_ERROR, FLASHIF_PROTECTION_ERRROR }; /* protection type */ enum{ FLASHIF_PROTECTION_NONE = 0, FLASHIF_PROTECTION_PCROPENABLED = 0x1, FLASHIF_PROTECTION_WRPENABLED = 0x2, FLASHIF_PROTECTION_RDPENABLED = 0x4, }; /* protection update */ enum { FLASHIF_WRP_ENABLE, FLASHIF_WRP_DISABLE }; /* 定义从哪里加载用户应用程序的地址 Note: 此区域为IAP代码保留 */ #define FLASH_PAGE_STEP FLASH_PAGE_SIZE /* Size of page : 2 Kbytes */ #define APPLICATION_ADDRESS (uint32_t)0x8008000 /* Start user code address: ADDR_FLASH_PAGE_8 */ //文件大小64k /* Notable Flash addresses */ #define USER_FLASH_END_ADDRESS 0x8040000 /* 定义用户应用程序大小 */ //64k #define USER_FLASH_SIZE ((uint32_t)0x00010000) /* Small default template application */ //已修改 默认 3 /* 定义表示可以写入保护的用户闪存区域的位图(检查仅限于第8-39页). */ #define FLASH_PAGE_TO_BE_PROTECTED (OB_WRP_PAGES8TO9 | OB_WRP_PAGES10TO11 | OB_WRP_PAGES12TO13 | OB_WRP_PAGES14TO15 | \ OB_WRP_PAGES16TO17 | OB_WRP_PAGES18TO19 | OB_WRP_PAGES20TO21 | OB_WRP_PAGES22TO23 | \ OB_WRP_PAGES24TO25 | OB_WRP_PAGES26TO27 | OB_WRP_PAGES28TO29 | OB_WRP_PAGES30TO31 | \ OB_WRP_PAGES32TO33 | OB_WRP_PAGES34TO35 | OB_WRP_PAGES36TO37 | OB_WRP_PAGES38TO39 | \ OB_WRP_PAGES40TO41 | OB_WRP_PAGES42TO43 | OB_WRP_PAGES44TO45 | OB_WRP_PAGES46TO47 | \ OB_WRP_PAGES48TO49 | OB_WRP_PAGES50TO51 | OB_WRP_PAGES52TO53 | OB_WRP_PAGES54TO55 | \ OB_WRP_PAGES56TO57 | OB_WRP_PAGES58TO59 | OB_WRP_PAGES60TO61) /* Exported macro ------------------------------------------------------------*/ /* ABSoulute value */ #define ABS_RETURN(x,y) (((x) < (y)) ? (y) : (x)) /* 从加载用户程序的位置获取扇区数 */ #define FLASH_SECTOR_NUMBER ((uint32_t)(ABS_RETURN(APPLICATION_ADDRESS,FLASH_START_BANK1))>>12) /* 计算掩码以测试闪存(其中将加载用户程序)是否被写入保护 */ #define FLASH_PROTECTED_SECTORS (~(uint32_t)((1 << FLASH_SECTOR_NUMBER) - 1)) /* Exported functions ------------------------------------------------------- */ void FLASH_If_Init(void); uint32_t FLASH_If_Erase(uint32_t StartSector); uint32_t FLASH_If_GetWriteProtectionStatus(void); uint32_t FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length); uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate); /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Constants used by Serial Command Line Mode */ #define TX_TIMEOUT ((uint32_t)100) #define RX_TIMEOUT HAL_MAX_DELAY /* Exported macro ------------------------------------------------------------*/ #define IS_CAP_LETTER(c) (((c) >= 'A') && ((c) <= 'F')) #define IS_LC_LETTER(c) (((c) >= 'a') && ((c) <= 'f')) #define IS_09(c) (((c) >= '0') && ((c) <= '9')) #define ISVALIDHEX(c) (IS_CAP_LETTER(c) || IS_LC_LETTER(c) || IS_09(c)) #define ISVALIDDEC(c) IS_09(c) #define CONVERTDEC(c) (c - '0') #define CONVERTHEX_ALPHA(c) (IS_CAP_LETTER(c) ? ((c) - 'A'+10) : ((c) - 'a'+10)) #define CONVERTHEX(c) (IS_09(c) ? ((c) - '0') : CONVERTHEX_ALPHA(c)) /* Exported functions ------------------------------------------------------- */ void Int2Str(uint8_t *p_str, uint32_t intnum); uint32_t Str2Int(uint8_t *inputstr, uint32_t *intnum); void Serial_PutString(uint8_t *p_string); HAL_StatusTypeDef Serial_PutByte(uint8_t param); /* Imported variables --------------------------------------------------------*/ extern uint8_t aFileName[FILE_NAME_LENGTH]; /* Private variables ---------------------------------------------------------*/ typedef void (*pFunction)(void); /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void Main_Menu(void); #endif /* INC_YMODEM_H_ */ymodem.h
在ymodem.h文件里需要指定用户APP起始地址APPLICATION_ADDRESS,用户结束地址USER_FLASH_END_ADDRESS,以及用户应用程序大小。
bootloader的Flash地址是从0x8000000-0x8007ffff 总共占用Flash大小32K.
app的Flash地址是从0x8008000-0x803ffff 总共占用Flash大小256K-32K = 224K = 0x00038000
添加完这两个文件后,只需在main.c文件添加使用即可。
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "ymodem.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* 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 */ int __io_putchar(int ch) { HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 1000); return ch; } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ 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 */ /* 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(); /* USER CODE BEGIN 2 */ if (1) { /* Execute the IAP driver in order to reprogram the Flash */ FLASH_If_Init(); /* Display main menu */ Main_Menu(); } /* Keep the user application running */ else { /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */ if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); JumpToApplication = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); JumpToApplication(); } } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1; PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */main.c
二:单片机的APP
APP部分需要修改两处地方
在STM32F091RCTX_FLASH.ld文件中修改用户APP起始地址和用户Flash大小
在main.c中重新映射中断向量表即可
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <string.h> /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* 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 */ //如果单片机不是F0系列的直接使用SCB->VTOR这个寄存器重映射中断向量表 // SCB->VTOR = 0x08008000; //F0系列的单片机没有SCB->VTOR这个寄存器,使用如下方法重映射中断向量表 memcpy((void*)0x20000000, (void*)0x08008000, 188); __HAL_SYSCFG_REMAPMEMORY_SRAM(); /* 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 */ /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */main.c
拷贝长度188的计算方法在startup_stm32f091rctx.s文件中有(171-125+1)个word中断向量,每个word四个字节,所以拷贝长度为(171-125+1)*4=188
标签:FLASH,Kbytes,IAP,Base,STM32CubeIDE,串口,PAGE,uint32,define From: https://www.cnblogs.com/lizhiqiang0204/p/17462739.html