本帖最后由 zero949079783 于 2024-7-14 10:27 编辑
基于STM32(串口+DMA+空闲中断+环形缓冲区)实现 YMODEM协议IAP在线烧写程序
BootLoader 扇区: 0x08000000 - 0x08004000 共16K大小
生成BIN: fromelf.exe --bin -o "$L@L.bin" "#L
上位机软件:SecureCRT
Ymodem_STM32F1:
链接:https://pan.baidu.com/s/1SO34uS3flsdE8MdL4HHU0g?pwd=802v
提取码:802v
Ymodem_STM32F4:
链接:https://pan.baidu.com/s/13Kh6QzgNosYnYE5fJ-TB4Q?pwd=u5tj
提取码:u5tj
https://gitee.com/csx949089783/ymodem_-stm32-f4.git
YMODED接口函数:
- #include "ymodem.h"
- #include "crc.h"
- #include "usart.h"
- #include "inner_flash.h"
- #include "delay.h"
- #include "key.h"
- #define YMODEM_TIME 10
- typedef void (*pFunction)(void);
- pFunction Jump_To_Application;
- typedef struct{
- uint8_t OTA_FLAG : 1;
- uint8_t YMODE_FLAG : 1;
- uint8_t YMODE_Frist_FLAG :1;
- uint8_t YMODE_Frist_Pack_FLAG: 1;
- uint8_t YMODE_EOH_STX_DATALEN_FLAG :1;
- uint8_t fileName[256]; //文件名
- uint8_t UpdataBuffer[STM32_PAGE_SIZE]; //接收数据缓冲区
- uint16_t time; //OTA退出时间
- uint16_t count;
- uint32_t num; //接收数据包数
- uint32_t STXnum; //接收数据包数
- uint32_t crc; //CRC校验
- uint32_t remanider; //数据余数
- uint32_t packnum; //数据总包数
- uint32_t remaniderpacknum; //数据余数总包数(1024时)
- uint32_t fileSize; //文件大小
- uint32_t JumpAddress; //APP跳转地址
- }YMODEM_T ;
- YMODEM_T ymodem_t;
- void Ymodem_Init(void)
- {
- memset(&ymodem_t,0,sizeof(ymodem_t));
- ymodem_t.time = YMODEM_TIME;
- }
- static void BootLoader_To_App(void)
- {
- Delay_ms(1);
- printf("\r\n");
- printf("BootLoader_To_App.....\r\n");
- Delay_ms(1);
- FLASH_Lock();
-
- SysTick->CTRL &= SysTick_CTRL_TICKINT_Msk; //关滴答定时器
-
- ymodem_t.JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
- /* Jump to user application */
- Jump_To_Application = (pFunction) ymodem_t.JumpAddress;
- /* Initialize user application's Stack Pointer */
- __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
- Jump_To_Application();
- }
- static void BootLoader_SendByte(uint8_t data)
- {
- Usartx_SendArray(USART1,&data,1);
- }
- /*************************************************************************
- * 函 数 名: BootLoader_EraseFlash
- * 功能说明: Flash扇区擦除
- * 形 参:startSectorAddr:起始扇区地址 numSector:扇区个数
- * 返 回 值: 无
- **************************************************************************/
- void BootLoader_EraseFlash(void)
- {
- STM32_EraseFlash(STM32_A_SADDR,11);
- }
- /*************************************************************************
- * 函 数 名: BootLoader_WriteFlash
- * 功能说明: 数据写入
- * 形 参:startAddr:起始地址 writeData:写入数据 numByte:写入字节数
- * 返 回 值: 无
- **************************************************************************/
- static void BootLoader_WriteFlash(uint32_t startAddr, uint32_t* writeData, uint32_t numByte)
- {
- STM32_WriteFlash(startAddr,writeData,numByte);
- }
- void BootLoader_Meun(void)
- {
- static uint16_t times = 0;
- times ++;
- if(ymodem_t.OTA_FLAG == YMODEM_DISABLE && times%1000 == 0)
- {
- ymodem_t.time --;
-
- printf(" \r\n %ds后退出BootLoader\r\n ",ymodem_t.time);
- if(ymodem_t.time <= 0)
- {
- BootLoader_To_App();
- }
- }
- else if(ymodem_t.YMODE_FLAG == YMODEMD_ENABLE && times %500 == 0)
- {
- ymodem_t.time = YMODEM_TIME;
- BootLoader_SendByte(CA); //发送握手
- }
- //按键双击进入OTA
- if( get_Key_Val() == 0x51 && ymodem_t.YMODE_FLAG == YMODEM_DISABLE && ymodem_t.OTA_FLAG == YMODEM_DISABLE)
- {
- printf("EraseFlash......\r\n");
- BootLoader_EraseFlash();
- printf("EraseFlash successfully \r\n");
- ymodem_t.OTA_FLAG = 1;
- ymodem_t.YMODE_FLAG = 1;
- }
- }
- static void BootLoader_Com(uint8_t *data)
- {
- if(memcmp(data,"1",1)==0 ) //当接收到上位机或者双击时,进入OTA
- {
- printf("EraseFlash......\r\n");
- BootLoader_EraseFlash();
- printf("EraseFlash successfully \r\n");
- ymodem_t.OTA_FLAG = 1;
- ymodem_t.YMODE_FLAG = 1;
- }
- }
- /***************************************************************************
- Ymodem数据帧:
- 帧头 包号 包号反码 信息块 校验
- SOH/STX PN XPN DATA 128/1024 CRC16(CRCH CRCL)
- 1:对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
- 2:对于STX帧需考虑几种情况
- 帧长度:
- 1:以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节
- 2:以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节
- a:●余下数据等于1024字节,以1029长度帧发送;
- b:●余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充
- c:●余下数据等于128字节,以133字节帧长度发送
- d:●余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充
- 包序号:
- 数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。
- 校验:
- Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码
- 起始帧:
- Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下
- 帧头 包号 包号反码 文名件称 文件大小 填充区 校验
- SOH/STX PN XPN fileName+0x00 fileSize+0x00 0x00 CRC16(CRCH CRCL)
- Ymodem结束帧
- 帧头 包号 包号反码 信息块 校验
- SOH PN XPN 0x00 CRC16(CRCH CRCL)
-
-
- 文件传输过程
- 文件的传输过程,以具体的例子说明。把foo.c,大小为4196Byte(16进制为0x1064)的文件作为传输的对象,则它的传输过程如下:
- 发送端----------------------------------------------------------------接收端
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
- SOH 00 FF “foo.c” "1064’’ NUL[118] CRC CRC >>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
- STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- SOH 05 FA data[100] 1A[28] CRC CRC>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK
- EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
- SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>>>>>>>>
- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
- *******************************************************************************************/
- void Ymodem_Receive(uint8_t *data,uint16_t datalen)
- {
- char *fileSizebuff;
- char fileSize[50]; //文件大小
- uint8_t i = 0,j=0;
-
- if(ymodem_t.OTA_FLAG == YMODEM_DISABLE)
- {
- BootLoader_Com(data);
- }
-
- //当是第0包数据时,和最1后才能进入,
- if((data[0] == SOH && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_SOH_PACKLEN) || ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE ) //Ymodem起始帧: 113
- {
- ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
- if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1])) //CRC
- {
-
- if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE) //第1次
- {
- ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
- ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE ; //第1包接收标志位置使能,说时第一包接好
- for(i=0;data[3+i] !='\0';i++) //读取文件名
- {
- ymodem_t.fileName[i] = data[3+i];
- }
- i++;
- for(j=0;data[3+i+j] != '\0';j++) //读取文件大小
- {
- fileSize[j] = data[3+i+j];
- }
-
- ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
- ymodem_t.remanider = ymodem_t.fileSize % YMODE_SOH_DATALEN;
- ymodem_t.packnum = ymodem_t.fileSize / YMODE_SOH_DATALEN;
- if(ymodem_t.remanider > 0)
- ymodem_t.packnum = ymodem_t.packnum+1;
-
- BootLoader_SendByte(ACK); //正确发送ACK
- BootLoader_SendByte(CA);
- }
- else if(ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE)
- {
-
- BootLoader_SendByte(ACK); //正确发送ACK
-
- BootLoader_SendByte(CA); //正确发送ACK
- Delay_ms(20);
- printf("\r\n");
- printf("fileName :%s \r\n",ymodem_t.fileName);
- printf("fileSize :%d Byte\r\n",ymodem_t.fileSize);
- printf("File uploaded successfully \r\n");
- printf("\r\n");
- Ymodem_Init();
- BootLoader_To_App();
-
- }
- }
- else{
- BootLoader_SendByte(NAK); //错误发送NAK
- }
-
- }
- else if((data[0] == STX && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_STX_PACKLEN)) ////Ymodem起始帧: 1024
- {
- ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
- if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1])) //CRC
- {
- if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE) //第1次
- {
- ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
- ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE; //第1包接收标志位置使能,说时第一包接好
-
- for(i=0;data[3+i] !='\0';i++) //读取文件名
- {
- ymodem_t.fileName[i] = data[3+i];
- }
- i++;
- for(j=0;data[3+i+j] != '\0';j++) //读取文件大小
- {
- fileSize[j] = data[3+i+j];
- }
- ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
-
-
- //数据1024时,数据是1024时,按1024接收,当小于1024时,以每包128个字传接收,直到所有数据收完
- ymodem_t.remanider = ymodem_t.fileSize % YMODE_STX_DATALEN; //余下字节个数
-
- ymodem_t.remaniderpacknum = ymodem_t.remanider / YMODE_SOH_DATALEN; //余下字节以128接收的包数据
-
- ymodem_t.packnum = (ymodem_t.fileSize / YMODE_STX_DATALEN) ; //1024总包数
- if(ymodem_t.remanider > 0)
- {
- ymodem_t.remaniderpacknum = ymodem_t.remaniderpacknum +1;
- ymodem_t.packnum = ymodem_t.packnum+1;
- }
-
- ymodem_t.YMODE_EOH_STX_DATALEN_FLAG = YMODEMD_ENABLE;
-
- BootLoader_SendByte(ACK); //正确发送ACK
- BootLoader_SendByte(CA);
-
- }
- }
- else{
- BootLoader_SendByte(NAK); //错误发送NAK
- }
- }
- else if(data[0] == SOH && datalen == YMODE_SOH_PACKLEN) //Ymodem数据帧:当数据以大小是128字节时
- {
- ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
- if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1])) //CRC
- {
- ymodem_t.num ++; //已接收的数据包数量+1
-
- //将本次接收的数据,暂存到ymodem_t.UpdataBuffer缓冲
- memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.num - 1) % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN],&data[3], YMODE_SOH_DATALEN); //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
- if(ymodem_t.YMODE_EOH_STX_DATALEN_FLAG == YMODEM_DISABLE) //当是128每包数据时
- {
- if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.num )) //每满一个扇区写入Flash
- {
- //写入到单片机A区相应的扇区
- BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE); //写入到单片机A区相应的扇区
-
- //备份FLASG写入
- }
- else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.packnum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
- {
- //写入到单片机A区相应的扇区
- BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN); //写入到单片机A区相应的扇区
-
- //备份FLASG写入
- }
- }
- else {
- if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.remaniderpacknum!=ymodem_t.num )) //每满一个扇区写入Flash
- {
- //写入到单片机A区相应的扇区
- BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE)+(((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE); //写入到单片机A区相应的扇区
-
- //备份FLASG写入
- }
- else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.remaniderpacknum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
- {
- //写入到单片机A区相应的扇区
- BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE) + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN); //写入到单片机A区相应的扇区
-
- //备份FLASG写入
- }
- }
- BootLoader_SendByte(ACK); //正确发送ACK
-
- }
- else{
- BootLoader_SendByte(NAK); //错误发送NAK
- }
- }
- else if(data[0] == STX && datalen == YMODE_STX_PACKLEN) //Ymodem数据帧:当数据是1029字节时
- {
- ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
- if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1])) //CRC
- {
- ymodem_t.STXnum++;
- memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.STXnum- 1) % (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) * YMODE_STX_DATALEN],&data[3], YMODE_STX_DATALEN); //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
- if(((ymodem_t.STXnum % (STM32_PAGE_SIZE/YMODE_STX_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.STXnum)) //每满一个扇区写入Flash
- {
- //写入到单片机A区相应的扇区
- BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.STXnum/ (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE); //写入到单片机A区相应的扇区
-
- //备份FLASG写入
-
- }
-
- BootLoader_SendByte(ACK); //正确发送ACK
- }
- else{
- BootLoader_SendByte(NAK); //错误发送NAK
- }
-
- }
- else if(data[0] == EOT && datalen == YMODE_EOT_DATALEN) //当接收到EOT
- {
- if(ymodem_t.count == 0)
- {
- ymodem_t.count ++;
- BootLoader_SendByte(NAK); //正确发送NAK
- }
- else if(ymodem_t.count == 1)
- {
- ymodem_t.YMODE_Frist_FLAG = YMODEMD_ENABLE;
- ymodem_t.count = 0;
- BootLoader_SendByte(ACK); //正确发送ACK
- BootLoader_SendByte(CA); //正确发送C
- }
- }
- else if(data[0] == CAN && data[1] == CAN && data[2] == CAN && data[3] == CAN && data[4] == CAN ) //取消传输命令,连续发送5个该命令
- {
- ymodem_t.OTA_FLAG = YMODEM_DISABLE;
- Ymodem_Init();
- }
- }
- #ifndef __YMODEM_H
- #define __YMODEM_H
- #include "stm32f4xx.h"
- #define STM32_FLASH_SADDR 0x08000000 //FLASH扇区起始地址
- #define STM32_PAGE_SIZE 1024 //FLASH扇区大小
- #define STM32_PAGE_NUM 1024 //FLASH扇区总个数
- #define STM32_B_PAGE_NUM 16 //BootLoader 扇区个数
- #define STM32_A_PAGE_NUM (STM32_PAGE_NUM - STM32_B_PAGE_NUM) //APP扇区个数
- #define STM32_A_START_PAGE (STM32_B_PAGE_NUM) //APP扇区起始数
- #define STM32_A_SADDR (STM32_FLASH_SADDR + STM32_A_START_PAGE * STM32_PAGE_SIZE) //APP扇区起始地址
- #define APPLICATION_ADDRESS (STM32_A_SADDR) //APP跳转地址
- #define YMODE_SOH_PACKLEN 133 //SOH数据包长度
- #define YMODE_STX_PACKLEN 1029 //SOH数据包长度
- #define YMODE_SOH_DATALEN 128 //SOH有效数据长度
- #define YMODE_STX_DATALEN 1024 //SOH有效数据长度
- #define YMODE_EOT_DATALEN 1
- typedef enum {YMODEM_DISABLE = 0, YMODEMD_ENABLE = !YMODEM_DISABLE} YmodemState;
- typedef enum{
- SOH = 0X01,//133字节长度帧
- STX = 0X02,//1024字节长度帧
- EOT = 0X04,//文件传输结束命令
- ACK = 0X06,//接收正确应答命令
- NAK = 0X15,//重传当前数据包请求命令
- CAN = 0X18,//取消传输命令,连续发送5个该命令
- CA = 0X43,//字符C ,发送握手
- }YMODEM_COM;
- void Ymodem_Init(void);
- void BootLoader_Meun(void);
- void Ymodem_Receive(uint8_t *data,uint16_t datalen);
- #endif
usart.c- #include "usart.h"
- #include "delay.h"
- uint8_t Usart1_RxBuffer[UARTx_RX_SIZE] = {0}; //串口1接收缓冲区
- uint8_t Usart1_TxBuffer[UARTx_TX_SIZE] = {0}; //串口1发送缓冲区
- Usartx_Control_Block usart1; //串口1控制结构体
- void (*usartTakeFunCb)(uint8_t *data,uint16_t datalen);
- void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen))
- {
- usartTakeFunCb = pFunc;
- }
- void usart1_take(void)
- {
- if(usart1.RxOutPtr != usart1.RxInPtr)
- {
- usartTakeFunCb(usart1.RxOutPtr->start,(usart1.RxOutPtr->end - usart1.RxOutPtr->start+1));
-
- usart1.RxOutPtr++;
- if(usart1.RxOutPtr == usart1.RxEndPtr)
- {
- usart1.RxOutPtr = &usart1.RxLocation[0];
- }
- }
- if((usart1.TxOutPtr != usart1.TxInPtr) &&( usart1.TxState == 0))
- {
- usart1.TxState = 1;
-
- DMA_Cmd(DMA2_Stream7,ENABLE);
- while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); //确保DMA可以被设置
- DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);
- usart1.TxOutPtr++;
- if(usart1.TxOutPtr == usart1.TxEndPtr)
- {
- usart1.TxOutPtr = &usart1.TxLocation[0];
- }
-
- }
- }
- void USART1_Init(uint32_t bandRate)
- {
- Usart1_PtrInit();
- USART1_GPIO_Init();
- Delay_ms(1);
- USART1_Config_Init(bandRate);
- Delay_ms(1);
- USART1_DMA_Init();
- }
- /*************************************************************************
- * 函 数 名: Uart1_RX_PtrInit
- * 功能说明: 串口1控制结构体各个指针初始化
- * 形 参:无
- * 返 回 值: 无
- **************************************************************************/
- void Usart1_PtrInit(void)
- {
- usart1.RxInPtr = &usart1.RxLocation[0];
- usart1.RxOutPtr = &usart1.RxLocation[0];
- usart1.RxEndPtr = &usart1.RxLocation[9];
- usart1.RxCounter = 0;
- usart1.RxInPtr->start = Usart1_RxBuffer;
- usart1.TxInPtr = &usart1.TxLocation[0];
- usart1.TxOutPtr = &usart1.TxLocation[0];
- usart1.TxEndPtr = &usart1.TxLocation[9];
- usart1.TxCounter = 0;
- usart1.TxInPtr->start = Usart1_TxBuffer;
-
- memset(Usart1_RxBuffer,0,UARTx_RX_SIZE);
- memset(Usart1_TxBuffer,0,UARTx_RX_SIZE);
- }
- /*************************************************************************
- * 函 数 名: Usart1_GPIO_Config
- * 功能说明: 串口1 GPIO初始化
- * 形 参:无
- * 返 回 值: 无
- **************************************************************************/
- void USART1_GPIO_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);
-
- /* 配置Tx引脚为复用功能 */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
-
- /*串口上电发送0x00的解决*/
- /* 连接 PXx 到 USARTx_Tx*/
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource6, GPIO_AF_USART1);
- /* 连接 PXx 到 USARTx__Rx*/
- GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_USART1);
- }
- /*************************************************************************
- * 函 数 名: Usart1_Config
- * 功能说明: 串口1初始化
- * 形 参:bandRate:波特率
- * 返 回 值: 无
- **************************************************************************/
- void USART1_Config_Init(uint32_t bandRate)
- {
- /* 使能 UART 时钟 */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- usart1.usart.USART_BaudRate = bandRate;
- usart1.usart.USART_WordLength = USART_WordLength_8b; //8bit数据位
- usart1.usart.USART_StopBits = USART_StopBits_1; //1bit停止位
- usart1.usart.USART_Parity = USART_Parity_No; //无校验
- usart1.usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- usart1.usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(USART1, &usart1.usart);
- // USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //开启空闲中断
- USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //开启空闲中断
- // USART_ITConfig(USART1,USART_IT_TC,ENABLE); //开启发送完成中断
- USART_Cmd(USART1, ENABLE); //使能串口
-
- USART_DMACmd(USART1,USART_DMAReq_Rx, ENABLE); //使能RX DMA
- USART_DMACmd(USART1,USART_DMAReq_Tx, ENABLE); //使能RX DMA
- }
- /*************************************************************************
- * 函 数 名: Uart1_DMA_Init
- * 功能说明: 串口1 DMA初始化
- * 形 参:无
- * 返 回 值: 无
- **************************************************************************/
- void USART1_DMA_Init(void)
- {
-
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
- /* 复位初始化DMA数据流 */
- DMA_DeInit(DMA2_Stream5);
- /* 确保DMA数据流复位完成 */
- while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE) {
- }
- /*usart1 rx对应dma2,通道4,数据流2*/
- usart1.dmarx.DMA_Channel = DMA_Channel_4;
- /*设置DMA源:串口数据寄存器地址*/
- usart1.dmarx.DMA_PeripheralBaseAddr = (USART1_BASE + 0x04);
- /*内存地址(要传输的变量的指针)*/
- usart1.dmarx.DMA_Memory0BaseAddr = (uint32_t)Usart1_RxBuffer;
- /*方向:从内存到外设*/
- usart1.dmarx.DMA_DIR = DMA_DIR_PeripheralToMemory;
- /*传输大小DMA_BufferSize=RECEIVEBUFF_SIZE*/
- usart1.dmarx.DMA_BufferSize = UARTx_RX_MAX+1;
- /*外设地址不增*/
- usart1.dmarx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- /*内存地址自增*/
- usart1.dmarx.DMA_MemoryInc = DMA_MemoryInc_Enable;
- /*外设数据单位*/
- usart1.dmarx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- /*内存数据单位 8bit*/
- usart1.dmarx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- /*DMA模式:不断循环*/
- usart1.dmarx.DMA_Mode = DMA_Mode_Circular;
- /*优先级:中*/
- usart1.dmarx.DMA_Priority = DMA_Priority_Medium;
- /*禁用FIFO*/
- usart1.dmarx.DMA_FIFOMode = DMA_FIFOMode_Disable;
- usart1.dmarx.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
- /*存储器突发传输 16个节拍*/
- usart1.dmarx.DMA_MemoryBurst = DMA_MemoryBurst_Single;
- /*外设突发传输 1个节拍*/
- usart1.dmarx.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
- /*配置DMA2的数据流2*/
- DMA_Init(DMA2_Stream5, &usart1.dmarx);
-
- // /*使能DMA*/
- DMA_Cmd(DMA2_Stream5, ENABLE);
-
- /* 等待DMA数据流有效*/
- while(DMA_GetCmdStatus(DMA2_Stream5) != ENABLE)
- {
- }
- /* 复位初始化DMA数据流 */
- DMA_DeInit(DMA2_Stream7);
- /* 确保DMA数据流复位完成 */
- while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
- }
- /*usart1 tx对应dma2,通道4,数据流7*/
- usart1.dmatx.DMA_Channel = DMA_Channel_4;
- /*设置DMA源:串口数据寄存器地址*/
- usart1.dmatx.DMA_PeripheralBaseAddr = (USART1_BASE+0x04);
- /*内存地址(要传输的变量的指针)*/
- usart1.dmatx.DMA_Memory0BaseAddr = (uint32_t)Usart1_TxBuffer;
- /*方向:从内存到外设*/
- usart1.dmatx.DMA_DIR = DMA_DIR_MemoryToPeripheral;
- /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/
- usart1.dmatx.DMA_BufferSize = UARTx_TX_MAX;
- /*外设地址不增*/
- usart1.dmatx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- /*内存地址自增*/
- usart1.dmatx.DMA_MemoryInc = DMA_MemoryInc_Enable;
- /*外设数据单位*/
- usart1.dmatx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- /*内存数据单位 8bit*/
- usart1.dmatx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
- /*DMA模式:不断循环*/
- usart1.dmatx.DMA_Mode = DMA_Mode_Circular;
- /*优先级:中*/
- usart1.dmatx.DMA_Priority = DMA_Priority_Medium;
- /*禁用FIFO*/
- usart1.dmatx.DMA_FIFOMode = DMA_FIFOMode_Disable;
- usart1.dmatx.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
- /*存储器突发传输 16个节拍*/
- usart1.dmatx.DMA_MemoryBurst = DMA_MemoryBurst_Single;
- /*外设突发传输 1个节拍*/
- usart1.dmatx.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
- /*配置DMA2的数据流7*/
- DMA_Init(DMA2_Stream7, &usart1.dmatx);
- //
- // /*使能DMA*/
- // DMA_Cmd(DMA2_Stream7, ENABLE);
- //
- // /* 等待DMA数据流有效*/
- // while(DMA_GetCmdStatus(DMA2_Stream7) != ENABLE)
- // {
- // }
- DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);
- DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);
- // NVIC
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
- void Usart1_Txdata(uint8_t *tdata,uint16_t datalen)
- {
- if(datalen == 0)
- {
- DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);
- return;
- }
- if((UARTx_TX_SIZE - usart1.TxCounter) >= datalen) //发送空间大于等于发数据
- {
- usart1.TxInPtr ->start = &Usart1_TxBuffer[usart1.TxCounter];
- }else
- {
- usart1.TxCounter = 0; //发送空间小于发送数据,清0
- usart1.TxInPtr->start = Usart1_TxBuffer;
- }
-
-
- while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); //确保DMA可以被设置
- DMA_SetCurrDataCounter(DMA2_Stream7,datalen); //设置数据传输长度
-
- memcpy(usart1.TxInPtr ->start,tdata,datalen); //数据拷贝
-
- usart1.TxCounter += datalen; //统计每次发送量
- usart1.TxInPtr ->end = &Usart1_TxBuffer[usart1.TxCounter-1];//标记end位,为下次作准备
- DMA2_Stream7->M0AR = (uint32_t)usart1.TxInPtr->start;
- usart1.TxInPtr++;
- if(usart1.TxInPtr == usart1.TxEndPtr){
- usart1.TxInPtr = &usart1.TxLocation[0];
- }
- }
- void Usartx_SendArray( USART_TypeDef * pUSARTx, uint8_t *data, uint16_t datalen)
- {
- uint16_t i;
- for(i=0;i<datalen;i++)
- {
- /* 发送一个字节数据到USART */
- pUSARTx->DR = data[i];
- while(!(pUSARTx->SR & USART_FLAG_TXE) );
- }
- while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
- }
- void Usartx_SendStr( USART_TypeDef * pUSARTx, const char *SendStr)
- {
- while(*SendStr != '\0')
- {
- /* 发送一个字节数据到USART */
- // pUSARTx->DR = *SendStr;
- USART_SendData(pUSARTx,*SendStr);
- //while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE));
- while(!(pUSARTx->SR & USART_FLAG_TXE) );
- SendStr++;
- }
- while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
- }
- //uint8_t tempbuff[256];
- //void u1_printf(char *fmt, ...)
- //{
- // uint16_t i=0;
- // va_list ap;
- // va_start(ap,fmt);
- //
- // vsprintf((char *)tempbuff,fmt,ap);
- //
- // va_end(ap);
- // DMA_Cmd(DMA2_Stream7,DISABLE);
- // for(i=0;i<strlen((char *)tempbuff);i++)
- // {
- // while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));
- // USART1->DR = tempbuff[i];
- // }
- // //while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
- //}
- void USART1_IRQHandler(void)
- {
- //发送中断
- if(USART_GetITStatus(USART1,USART_IT_TC) != RESET)
- {
- USART_ClearITPendingBit(USART1,USART_IT_TC);
- //usart1.TxState = 0;
- }
- //空闲中断
- if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
- {
-
- USART1->SR; //清中断
- USART1->DR; //清中断
-
- usart1.RxCounter +=((UARTx_RX_MAX+1)- DMA_GetCurrDataCounter(DMA2_Stream5));
- usart1.RxInPtr->end = &Usart1_RxBuffer[usart1.RxCounter - 1];
-
- usart1.RxInPtr++;
- if(usart1.RxInPtr == usart1.RxEndPtr)
- {
- usart1.RxInPtr = &usart1.RxLocation[0];
- }
- if((UARTx_RX_SIZE - usart1.RxCounter) >= UARTx_RX_MAX){
- usart1.RxInPtr->start = &Usart1_RxBuffer[usart1.RxCounter]; //标记接位置
-
- }else{
- usart1.RxInPtr->start = Usart1_RxBuffer;
- usart1.RxCounter = 0;
- }
-
- DMA_Cmd(DMA2_Stream5, DISABLE); //关闭DMA
- DMA_SetCurrDataCounter(DMA2_Stream5, UARTx_RX_MAX+1);
- DMA2_Stream5->M0AR = (uint32_t)usart1.RxInPtr->start;
- DMA_Cmd(DMA2_Stream5, ENABLE); //打开DMA
- }
- }
- void DMA2_Stream7_IRQHandler(void)
- {
- if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7)!=RESET)//等待DMA2_Steam7传输完成
- {
- DMA_Cmd(DMA2_Stream7,DISABLE); //关闭使能
- DMA_ClearITPendingBit(DMA2_Stream7,DMA_FLAG_TCIF7); //清除DMA2_Steam7传输完成标志
-
- DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);
- usart1.TxState = 0;
- }
- if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_HTIF7)!=RESET)
- {
- DMA_ClearITPendingBit(DMA2_Stream7,DMA_IT_HTIF7);
- }
- }
- void DMA2_Stream5_IRQHandler(void)
- {
- if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_TCIF5)!=RESET)//等待DMA2_Steam2传输完成
- {
- DMA_ClearITPendingBit(DMA2_Stream5,DMA_FLAG_TCIF5); //清除DMA2_Steam2传输完成标志
- DMA_Cmd(DMA2_Stream5, ENABLE);
- }
- if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_HTIF5)!=RESET)
- {
- DMA_ClearITPendingBit(DMA2_Stream5,DMA_FLAG_TCIF7);
- }
- }
- /* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */
- #if 1
- #if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */
- __asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
- __asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */
- #else
- /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
- #pragma import(__use_no_semihosting)
- struct __FILE
- {
- int handle;
- /* Whatever you require here. If the only file you are using is */
- /* standard output using printf() for debugging, no file handling */
- /* is required. */
- };
- #endif
- /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
- int _ttywrch(int ch)
- {
- ch = ch;
- return ch;
- }
- /* 定义_sys_exit()以避免使用半主机模式 */
- void _sys_exit(int x)
- {
- x = x;
- }
- char *_sys_command_string(char *cmd, int len)
- {
- return NULL;
- }
- /* FILE 在 stdio.h里面定义. */
- FILE __stdout;
- /* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
- int fputc(int ch, FILE *f)
- {
- while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */
- USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */
-
-
- return ch;
- }
- #endif
- /***********************************************END*******************************************/
usart.h
- #ifndef __USART_H
- #define __USART_H
- #include "stm32f4xx.h"
- #include <stdint.h>
- #include "string.h"
- #include "signal.h"
- #include "stdarg.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include <stdbool.h>
- #define UARTx_RX_SIZE 4096 //接收缓冲区长度
- #define UARTx_TX_SIZE 4096 //发送缓冲区长度
- #define UARTx_RX_MAX 1029 //单次接收最大量
- #define UARTx_TX_MAX 256 //单次接收最大量
- #define SE_PTR_NUM 10 //se指针对结构体数组长度
- typedef struct{
- uint8_t *start; //start用于标记起始位置
- uint8_t *end; //end用于标记结束位置
- }LCB; //se 指针对结构体
- typedef struct{
-
-
- uint16_t RxCounter; //累计接收数据量
- uint16_t TxCounter;
- uint16_t TxState;
- LCB RxLocation[SE_PTR_NUM]; //se指针对结构体数组
- LCB *RxInPtr; //IN指针用于标记接收数据
- LCB *RxOutPtr; //OUT指针用于提取接收的数据
- LCB *RxEndPtr; ////IN和OUT指针的结尾标志
-
- LCB TxLocation[SE_PTR_NUM]; //se指针对结构体数组
- LCB *TxInPtr; //IN指针用于标记发送数据
- LCB *TxOutPtr; //OUT指针用于提取发送的数据
- LCB *TxEndPtr; ////IN和OUT指针的结尾标志
- USART_InitTypeDef usart;
- DMA_InitTypeDef dmatx;
- DMA_InitTypeDef dmarx;
-
- }Usartx_Control_Block;
- extern uint8_t Usart1_RxBuffer[UARTx_RX_SIZE]; //串口1接收缓冲区
- extern uint8_t Usart1_TxBuffer[UARTx_TX_SIZE]; //串口1发送缓冲区
- extern Usartx_Control_Block usart1; //串口控制结构体
-
- void USART1_Init(uint32_t bandRate);
- void USART1_GPIO_Init(void);
- void USART1_Config_Init(uint32_t bandRate);
- void USART1_DMA_Init(void);
- void Usart1_PtrInit(void);
- void Usart1_Txdata(uint8_t *tdata,uint16_t datalen);
- //void u1_printf(char *fmt, ...);
- void Usart1_Rx_Data(uint8_t *rdata);
- void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen));
- void usart1_take(void);
- void Clearsart3_RxBuffer(void);
- void Usartx_SendStr( USART_TypeDef * pUSARTx, const char *SendStr);
- void Usartx_SendArray( USART_TypeDef * pUSARTx, uint8_t *data, uint16_t datalen);
- #endif
|
|