STM32USB虚拟COM刷新W25XXX数据
单片机需要显示多张图片,以及显示中文,但数据量太大,单片机内部的ROM不够,只能存在外部flash中,所以需要将大量的数据写入flash中。最近一直在查阅资料,怎么更新外部flash中的数据。
方法一:将数据存入ROM中,程序执行时,读取ROM中的数据,写入flash。这种方法一次性写入的数据比较少,若是下载一次程序,写入一次,再改动flash地址,再下载程序,再写入~~~~~说不下去了。
方法二:使用串口调试助手,将图片数据制作成bin文件,发送给单片机,单片机在串口中断中写入flash。当STM32的串口总线被其他设备占用时,这种方法就行不通了。
方法三:使用USB模拟串口,再如方法二的步骤刷新flash数据。
本次内容讲述的就是串口总线被其他设备占用,使用方法三刷新flash数据。我也会简单介绍一下怎么使用USB模拟串口回显数据。
W25XXX写入数据
flash内部只能由1变为0,所以每次写入数据时,需要先将flash擦除。
扇区擦除:每个扇区4K大小,擦除的最小单位。
块擦除:每个块64K大小。
片擦除:将整个flash擦除。
步骤如下
1.打开cube软件
2.配置USB
3.配置USB_DEVICE
4.时钟那些不作介绍,直接生成文件。
打开工程
1.打开usbs_cdc_if.c文件
2.在接收函数里加上发送数据函数,贴上代码
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, &Buf[0], *Len);
USBD_CDC_TransmitPacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
3.如果使用串口回显,就不需要更改其他的了,下载程序。打开串口调试助手发送数据,结果如下图
64字节以内,发送什么数据,返回的也是什么数据。因为USB一次性只能接收64字节数据,所以我发送70字节的数据,只返回了64字节。发送一大串数据,也会返回,只不过我没有仔细核对。
改动程序,可以返回大量数据
1.改动接收缓冲区大小
#define APP_RX_DATA_SIZE 256 //将1000改为256
#define APP_TX_DATA_SIZE 1000
2.修改CDC_Receive_FS函数
uint16_t Data_Len, temp, timeout; //定义的全局变量
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
Data_Len +=*Len;
if(Data_Len<APP_RX_DATA_SIZE)
{
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS + Data_Len); //设置下一次接收数据的位置
USBD_CDC_ReceivePacket(&hUsbDeviceFS); //准备接收数据
}
else //接收缓冲区已满
{
timeout = 0xffff;
temp = !(Data_Len%64); //判断长度是否为64整数倍
while( CDC_Transmit_FS(UserRxBufferFS, Data_Len - temp) != USBD_OK && timeout--);
if(temp) //当发送数据为64整数倍时,无法发送成功,故分成2次发送
{
while( CDC_Transmit_FS(UserRxBufferFS + Data_Len -1, temp) != USBD_OK && timeout--);
}
//发送完毕,再次设置
Data_Len = 0;
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS + Data_Len); //设置下一次接收数据的位置
USBD_CDC_ReceivePacket(&hUsbDeviceFS); //准备接收数据
}
return (USBD_OK);
/* USER CODE END 6 */
}
当发送的数据为64的整数倍时,需要将数据分为两次发送(经其他博主验证)
3.下载程序,查看结果
设置的缓冲区大小为256,当缓冲区存满了数据,才会输出。
步入正题,使用USB虚拟串口刷新flash数据
1.每次上电,初始化时,就将flash整片擦除。
2.每满256字节时,就写入一次数据。
3.修改CDC_Receive_FS函数
uint32_t FlashAdd = 0x00000;
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
//将已接收数据长度赋值给USB_S.ReLen
USB_S.ReLen += *Len;
//判断是否有结束标志以及接收数据长度是否达到UserRxBufferFS长度上限
if( USB_S.ReLen<APP_RX_DATA_SIZE)
{
//设置下一次接收数据的位置
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS + USB_S.ReLen);
USBD_CDC_ReceivePacket(&hUsbDeviceFS); //准备接收数据
}
else //长度达到,或者检测到标志位,触发数据输出
{
SPI_FLASH_PageWrite(UserRxBufferFS, FlashAdd, 256);
FlashAdd += 256;
USB_S.ReLen = 0;
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
}
return (USBD_OK);
}
4.打开Image2LCD制作bin文件
5.打开串口调试助手,写入数据
换了个串口调试助手,这个是正点原子的,这一个串口调试助手末尾会发0X0D,0X0A,如有需要可以以这两个数据写协议,或者自己写一个协议,并在程序中进行校验数据是否写入正确。
flash驱动文件在上一篇文章,也可以直接找野火的例程。
结尾
发送数据时,有时候开头的数据写不进flash,暂未找到原因。