本帖最后由 潜龙探渊 于 2016-11-3 16:45 编辑
最近工程上用到了LCD显示及W25Q256存储字库,硬件上就是没有SD卡,然后这就很困扰我怎么才能把字库放到外部FLASH里?
想来想去唯一的办法就是通过串口接收数据再把它烧到W25q256里面,然后我就先上论坛搜索有没有相关资料,然后搜了好久才找到一个“
采用串口DMA双缓冲方法,快速更新外部FLASH中文字库。更新原子哥例程的4个字库仅需一分钟左右!”这个帖子!(在这我要小小吐槽一下我们论坛的关键字搜索,感觉没有以前隔壁论坛的好用。需要你搜索的关键字要准确不支持模糊搜索,这就是我的个人使用感受不知道各位有没有同感的
希望原子看到不要怪我八婆
)
找到资料后当然就是开始吸收咯~这位群主的硬件是STM32F407的开发板而我手上又没有这个开发板,我现在手上就一个STM32F429的阿波罗开发板,我本来想仿照那位群主写的程序用HAL库仿写的,但是最后发现HAL跟407的标准库差太多了有些设置根本找不到,最后实在不行就改成用寄存器来仿写,反正寄存器操作无非就是多看芯片寄存器手册就可以了。
仿写了二天终于写完了,但是调试还是遇到了各种问题,然后我就慢慢看他的程序思路然后再继续修改BUG,后面我就成功更新了一次!
成功了一次就继续测试发现,这个程序的下载成功率好像不高!!!又是用了一天的时间继续调程序BUG,后面终于把程序下载成功率提到了90%以上!
然后我又把本来群主没有添加的32*32字体也给添加进去了,后面就只要把dma.c和dma.h、TXT文件烤到你工程目录下你也可以直接使用串口来更新字库了,可以造福没有SD卡的朋友们
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 par,u32 mar0,u32 mar1,u16 ndtr)
{
DMA_TypeDef *DMAx;
u8 streamx;
USART1->CR3 |= 1<<6; //使能串口1的DMA接收
if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
{
DMAx=DMA2;
RCC->AHB1ENR|=RCC_AHB1ENR_DMA2EN;//DMA2时钟使能
}else
{
DMAx=DMA1;
RCC->AHB1ENR|=RCC_AHB1ENR_DMA1EN;//DMA1时钟使能
}
while(DMA_Streamx->CR&0X01); //等待DMA可配置
streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18; //得到stream通道号
if(streamx>=6)DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16); //清空之前该stream上的所有中断标志
else if(streamx>=4)DMAx->HIFCR|=0X3D<<6*(streamx-4); //清空之前该stream上的所有中断标志
else if(streamx>=2)DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志
else DMAx->LIFCR|=0X3D<<6*streamx; //清空之前该stream上的所有中断标志
DMA_Streamx->CR=0; //先全部复位CR寄存器值
DMA_Streamx->
AR=par; //DMA外设地址
DMA_Streamx->M0AR=mar0; //DMA 存储器0地址
DMA_Streamx->NDTR=ndtr; //数据传输量
DMA_Streamx->CR|=0<<6; //外设到存储器模式
DMA_Streamx->CR|=1<<8; //注意:这里设置为循环模式,不然不能启动第二次传输
DMA_Streamx->CR|=0<<9; //外设非增量模式
DMA_Streamx->CR|=1<<10; //存储器增量模式
DMA_Streamx->CR|=0<<11; //外设数据长度:8位
DMA_Streamx->CR|=0<<13; //存储器数据长度:8位
DMA_Streamx->CR|=1<<16; //中等优先级
DMA_Streamx->CR|=0<<21; //外设突发单次传输
DMA_Streamx->CR|=0<<23; //存储器突发单次传输
DMA_Streamx->CR|=(u32)chx<<25; //通道选择
DMA_Streamx->FCR=0<<2; //FIFO 模式禁止
DMA_Streamx->FCR=0X03; //FIFO 阈值
//使能DMA双缓冲模式
DMA_Streamx->CR|=0<<19; //CT=0当前目标存储器为存储器0
DMA_Streamx->M1AR=mar1; //DMA 存储器1地址
DMA_Streamx->CR|=1<<18; //DBM=1设置双缓存模式
//DMA_Streamx->CR|=1<<0; //EN=1开启DMA传输
DMA_Streamx->CR|=1<<4; //使能DMA传输完成中断TCIE使能
DMAx->HIFCR|=1<<11; //清除TCIF5中断标志
//DMA NVIC 配置
MY_NVIC_Init(3,2,DMA2_Stream5_IRQn,2);//组2,抢占2,优先级2 DMA2_Stream5_IRQn中断通道
DMA_Streamx->CR|=1<<0; //EN=1开启DMA传输
}
//重新开启一次DMA传输
//DMA_Streamx
MA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量
void MYDMA_REST_Enable(DMA_Stream_TypeDef *DMA_Streamx,u32 par,u32 mar,u16 ndtr)
{
DMA_Streamx->CR&=~(1<<0); //关闭DMA传输
while(DMA_Streamx->CR&0X1); //确保DMA可以被设置
DMA_Streamx->
AR=par; //DMA外设地址
DMA_Streamx->M0AR=mar; //DMA 存储器0地址
DMA_Streamx->NDTR=ndtr; //数据传输量
DMA_Streamx->CR|=1<<0; //开启DMA传输
}
/********************************************************************
*函数名称:void DMA2_Stream5_IRQHandler(void)
*功 能
MA2_Stream5_IRQHandler中断服务程序
*说 明
MA2数据流5中断服务函数
*输入参数:无
*输出参数:无
*********************************************************************/
void DMA2_Stream5_IRQHandler(void)
{
if(DMA2->HISR&(1<<11))//判断TCIF5传输完成
{
DMA2->HIFCR|=1<<11; //清除TCIF5中断标志
LED2=~LED2;
//***************数据接收完处理******************//
if(DMA2_Stream5->CR&(1<<19)) //得到CT当前目标存储器
{
GBK_BUF_Flag=1; //存储器1
}
else
{
GBK_BUF_Flag=0; //存储器0
}
//**************************************************//
}
}
u8 updata_fontx(u16 x,u16 y,u8 size,u8 fx)
{
u32 flashaddr=0;
u32 offx=0; //接收到的文件大小
u32 fsize=0; //总文件大小
u16 over_len =0; //最后数据长度
switch(fx)
{
case 0: //更新UNIGBK.BIN
ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo); //信息头之后,紧跟UNIGBK转换码表
fsize=ftinfo.ugbksize=UNIGBK; //UNIGBK大小
flashaddr=ftinfo.ugbkaddr; //UNIGBK的起始地址
printf("
lease send UNIGBK.bin
");
break;
case 1:
ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize; //UNIGBK之后,紧跟GBK12字库
fsize=ftinfo.gbk12size=GBK12_FONSIZE; //GBK12字库大小
flashaddr=ftinfo.f12addr; //GBK12的起始地址
printf("
lease send GBK12.FON
");
break;
case 2:
ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size; //GBK12之后,紧跟GBK16字库
fsize=ftinfo.gbk16size=GBK16_FONSIZE; //GBK16字库大小
flashaddr=ftinfo.f16addr; //GBK16的起始地址
printf("
lease send GBK16.FON
");
break;
case 3:
ftinfo.f24addr=ftinfo.f16addr+ftinfo.gbk16size; //GBK16之后,紧跟GBK24字库
fsize=ftinfo.gbk24size=GBK24_FONSIZE; //GBK24字库大小
flashaddr=ftinfo.f24addr; //GBK24的起始地址
printf("
lease send GBK24.FON
");
break;
case 4:
ftinfo.f32addr=ftinfo.f24addr+ftinfo.gbk24size; //GBK24之后,紧跟GBK32字库
fsize=ftinfo.gbk32size=GBK32_FONSIZE; //GBK32字库大小
flashaddr=ftinfo.f32addr; //GBK32的起始地址
printf("
lease send GBK32.FON
");
break;
}
fupd_prog(x,y,size,fsize,offx); //进度显示
GBK_BUF_Flag = 2; //清除标志等待下一次DMA中断
GBK_OVER_Flag = 0; //停止计时
printf("请发送文件...
");
do
{
if(GBK_OVER_Flag)GBK_OVER_Flag++; //不为0开始计时
if(GBK_BUF_Flag!=2)//判断是否进入DMA中断
{
LED0 = ~LED0; //指示灯
GBK_OVER_Flag=1; //开始计时
if(GBK_BUF_Flag==0) //当前目标在存储器0
{
W25QXX_Write(Usart1_Rece_Buf1,offx+flashaddr,Usart1_DMA_Len); //开始写入Usart6_DMA_Len个数据
}
else
if(GBK_BUF_Flag==1) //当前目标在存储器0
{
W25QXX_Write(Usart1_Rece_Buf0,offx+flashaddr,Usart1_DMA_Len); //开始写入Usart6_DMA_Len个数据
}
offx+=Usart1_DMA_Len; //加上已写完的数据量
fupd_prog(x,y,size,fsize,offx); //进度显示
GBK_BUF_Flag=2; //清除标志等待下一次DMA中断
}
delay_us(100); //延时100us
}
while(GBK_OVER_Flag<=WATE_TIME); //判断超时?
over_len = Usart1_DMA_Len-DMA2_Stream5->NDTR; //最后数据长度
if(DMA2_Stream5->CR&(1<<19)) //得到CT当前目标存储器
{
W25QXX_Write(Usart1_Rece_Buf1,offx+flashaddr,over_len);//将DMA最后的一帧数据写入FLASH
}
else
{
W25QXX_Write(Usart1_Rece_Buf0,offx+flashaddr,over_len);//将DMA最后的一帧数据写入FLASH
}
offx+=over_len; //加上已写完的数据量
fupd_prog(x,y,size,fsize,offx); //进度显示
//重新开启一次DMA传输
MYDMA_REST_Enable(DMA2_Stream5,(u32)&USART1->DR,(u32)Usart1_Rece_Buf0,Usart1_DMA_Len); //重置DMA
printf("已写完数据,本次接收到%d字节!!!
",offx);
printf("
");
delay_ms(100); //延时100ms
if((offx > (fsize-1024))&(offx < fsize)) //误差在正负1K之内都认为是更新成功
return 0; //更新成功
else
printf("更新失败,重新开始!
");
return 1; //更新失败
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------还有我本想把最新的F429的芯片手册上传上去的,可是文件太大上传不了就算了~~~
还有各位如果你觉得我分享的程序有用,就来给我盖盖楼吧!让这个论坛活跃起来~~~~~~~~~~
这里的通道选择有没有问题,我觉得是DMA_Streamx->CR|=(u32)chx<<27;
在f429中文手册里usart1的接收dma stream2和5都是在通道4上的,为何选择通道1???、
其实这两种都可以正常使用啦~其实这两个就是二选一,你想用数据流2通道4也能正常使用,用数据流5通道4也行,反正只要是USART1_RX都行,看你怎么选择咯?
一周热门 更多>