自制脱机烧录器(一)

脱机烧录器(一)串口Xmode协议


前言

自己想做一个脱机烧录器已经很久了,网上开源的脱机烧录器很多,但是大多数都比较复杂,奈何网上大神们都不出手,自己又想做一个简便的脱机烧录,所以就自己尝试了做了下,经过几天不懈的努力下做了一个简陋版的脱机下载器:通过串口将.bin文件发送给STM32G070单片机,单片机将数据存到W25Q32里面,支持存储两个不同的程序,单片机通过SWD协议下载到目标芯片。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Xmodem协议

XModem是很早的文件传输协议之一,是几乎所有的通讯程序支持的文件传输协议,它每包数据均传输128字节信息块。格式如下:
在这里插入图片描述
1.数据包包头,固定为01H。
2.数据包序列号,记录当前发送的是第几个数据包,单个文件超过ff个数据包时,从零开始计算。
3.数据包序列号的反码。
4.要发送的数据。
5.CRC16校验。
我使用的是128字节的Xmodem协议,加上包头,CRC校验,一包数据总共133个字节。如果传输数据不足128字节时,会用0X1A补充到数据包里面。接收数据时,接收方要发送0X0C告诉发送方,已经准备好接收数据,当接收方接收到数据后,要发送ASK指令(指令十六进制为0x06)告诉发送方已经正确接收到数据。如果数据接收不正确,则通过发送0x15告诉发送方,数据不对,发送方接收到0x15以后,会再次发送当前数据包,直到返回0x06为止,当数据发送完后,发送方会发送EOT指令(0x04),告诉接收方数据发送完毕了,接收方返回0x06后,通讯结束。

二、串口接收(DMA+空闲中断)

1.使用Cubemx配置串口

如下图所示:
在这里插入图片描述
主要配置串口空闲中断,以及串口DMA接收,因为要接收的数据比较多,只使用中断的话CPU会接收不及时,导致串口ORE错误,就算能够及时接收,过于频繁的中断会使CPU的效率降低(时间都浪费在了进出中断),所以此时使用DMA是最好的选择,使CPU不用干预,它就能把数据搬到你想要放的地方。

	__HAL_UART_CLEAR_IDLEFLAG(&huart1);                                 //清除串口空闲中断,防止误触发
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);   											//使能串口空闲中断
	HAL_UART_Receive_DMA(&huart1,U1_RxBuff,U1_RX_MAX+1); 								//开启串口DMA接收

打开串口空闲中断之前先清除一下,开启串口DMA接收,U1_RX_MAX为255,这个值只需要大于Xmodem一包数据的最大值就可以。

2.串口缓冲区设置

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
//  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
  if(__HAL_UART_GET_IT(&huart1,UART_IT_IDLE) != RESET)       //如果UART_IT_IDLE置位,表示一帧数据接受完毕
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);                          //清除空闲中断
		U1CB.URxCounter += (U1_RX_MAX + 1) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);  //+=操作,将本次接受到的数据累计到URxCounter变量
		U1CB.URxDataIN->end = &U1_RxBuff[U1CB.URxCounter - 1];       //
		U1CB.URxDataIN ++;
		if(U1CB.URxDataIN == U1CB.URxDataEND) {
			U1CB.URxDataIN = &U1CB.URxDataPtr[0];
		}
		if(U1_RX_SIZE - U1CB.URxCounter >= U1_RX_MAX) {             //
			U1CB.URxDataIN->start = &U1_RxBuff[U1CB.URxCounter];
		}else {
			U1CB.URxDataIN ->start = U1_RxBuff;
			U1CB.URxCounter = 0;
		}
	  HAL_UART_DMAStop(&huart1);                           //如重置DMA接收数据长度,必须要在关闭DMA的条件进行,否则操作无效。
		HAL_UART_Receive_DMA(&huart1,U1CB.URxDataIN->start,U1_RX_MAX+1); //开启DMA通道,等待下一次的数据接收
	}
  /* USER CODE END USART1_IRQn 1 */
}

当进入串口空闲中断时表示一帧数据接受完毕,U1CB.URxDataIN->end是一个指针,指向每次接受数据的末尾,U1CB.URxDataIN->start也是一个指针,指向每次接受数据开始的地址,他们都在同一个结构体UCB_URxBuffptr。

typedef struct{                         
	uint8_t *start;                     //s用于标记起始位置
	uint8_t *end;                       //e用于标记结束位置
}UCB_URxBuffptr;                        //se指针对结构体

串口接受放在了一个U1_RxBuff数组里面,大小为2048。在UCB_CB结构体中定义了一个URxDataPtr[NUM]的数组,NUM为10,初始化参数时让URxDataIN指向了URxDataPtr,在接受数据时,URxDataPtr[NUM]里面的start,end指针,指向每次接收数据的开始和结束如图所示:
在这里插入图片描述

typedef struct{
	uint16_t URxCounter;                //累计接收数据量
	UCB_URxBuffptr URxDataPtr[NUM];     //se指针对结构体数组
	UCB_URxBuffptr *URxDataIN;          //指针 用于标记接收数据
	UCB_URxBuffptr *URxDataOUT;         //OUT指针 用于提取接收的数据
	UCB_URxBuffptr *URxDataEND;         //IN和OUT指针的结尾标志
}UCB_CB;                                //串口控制结构体

进入中断后,URxCounter表示本次接收的数据量,URxDataIN++,此时URxDataIN不等于URxDataOUT,表示缓冲区此时接收到数据了,需要进行处理。串口最后复位DMA重新开始下一轮接收。

三、Xmodem协议实现

		if(StateFlag&XMODEMD_FLAG){                                             //如果 XMODEMD_FLAG 置位表示开始Xmodem协议接收数据
		if((datalen==133)&&(data[0]==0x01)){                                               //判断 Xmodem协议一包总长133字节 且 第一个字节帧头是0x01
			StateFlag &=~ XMODEMC_FLAG;                                              //已经收到数据包了,所以清除 XMODEMC_FLAG,不再发送大写C
			DataSta.XmodemCRC = Xmodem_CRC16(&data[3],128);                                //计算本次接收的数据包数据的CRC
			if(DataSta.XmodemCRC == data[131]*256 + data[132]){                            //计算的CRC 和 接收的CRC 比较,一样说明正确,进入if
				DataSta.XmodemNB++;                                                        //已接收的数据包数量+1
				memcpy(&DataSta.databuff[((DataSta.XmodemNB-1)%(PAGE_SIZE/128))*128],&data[3],128);   //将本次接收的数据,暂存到DataSta.databuff缓冲区
				if((DataSta.XmodemNB%(PAGE_SIZE/128))==0){                            //如果已接收数据包数量是8的整数倍,说明都满1扇区1024字节,进入if
						for(i=0;i<4;i++){                                                  //W25Q32每次写入256字节,1扇区1024字节,需要循环4次写
							W25QXX_Write_Page(&DataSta.databuff[i*256],FLASH_CAP * DataSta.W25Q16_BlockNB + (DataSta.XmodemNB/8 -1 ) * PAGE_SIZE + i * 256,256);    //将接受的数据写入W25Q32
						}					
					}
				printf("\x06");    //正确,返回ACK给CRT软件
			}else{                    //如果CRC校验错误,进入else
				printf("\x15");    //返回NCK给CRT软件
			}
		}
		if((datalen==1)&&(data[0]==0x04)){                          //如果收到1个字节数据 且 是0x04,进入if,说明收到EOT,表明数据已经发生完毕
			printf("\x06");                                          //返回ACK给CRT软件
			if((DataSta.XmodemNB%(PAGE_SIZE/128))!=0){             //判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
			for(i=0;i<4;i++){                                   //W25Q64每次写入256字节,1扇区1024字节,需要循环4次写
						W25QXX_Write_Page(&DataSta.databuff[i*256],FLASH_CAP * DataSta.W25Q16_BlockNB + (DataSta.XmodemNB/8  )*PAGE_SIZE+i*256,256); //将接受的数据写入W25Q64
			  }
		  }

首先判断是否为Xmodem协议接收数据为133个字节第一个字节为0x01H,然后再判断数据传输是否出错,进行CRC校验,如果正确将数据拷贝到DataSta.databuff中,此数组用来保存写入W25Q32的数据,也就是我们的程序,然后返回0x06表示数据接收正确。如果错误,则返回0x15表示数据接收错误,需要重新发送。

总结

通过Xmodem协议将.bin文件能够发送给我们的单片机,单片机通过双缓冲区,来接受发送的数据,最后单片机通过SPI写到W25Q32里面进行保存,这样就实现了文件的传输,下一章讲解SWD协议的移植:SWD协议移植

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SWD脱机烧录器是一种用于单片机烧录的设备,可以通过SWD接口将代码下载到单片机中。脱机烧录器的源代码可以说是其开发者编写的程序,用于控制烧录器的工作流程和功能。 SWD脱机烧录器的源代码可能涉及以下几个方面: 1. 与硬件相关的代码:这部分代码通常用于与硬件进行通信,例如配置和控制SWD接口的引脚,读取和写入单片机的内存和寄存器等。开发者需要编写适配于具体硬件的代码以实现与单片机的数据传输。 2. 烧录算法:这部分代码用于实现将目标文件烧录到单片机中的算法。开发者需要编写适合目标单片机的烧录算法,以确保代码正确地下载到单片机中,并能够正确执行。 3. 用户界面代码:为了方便用户使用脱机烧录器,一般会设计一个用户界面。开发者需要编写与用户交互的代码,实现功能例如选择目标文件、设置下载参数等。 脱机烧录器的源代码通常使用一种编程语言(如C/C++、Python等)编写,然后通过编译生成可执行文件。用户可以根据自己的需求修改源代码,以定制烧录器的功能或适配特定的单片机。 总之,SWD脱机烧录器源代码是一套编写用于控制烧录器的程序,主要包括与硬件通信、烧录算法和用户界面等方面的代码。使用该源代码,我们可以自行修改和定制烧录器的功能,以适应不同的单片机和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值