大家好:
我想实现的功能是串口以DMA方式接收数据,然后将数据以通过SPI写入FLASH中. 环境:MINI STM32开发板 发送数据:串口助手
现在的问题:
1 按照原子的例程写falsh没有问题,验证了SPI 和FLASH基本功能正常.
2 串口以DMA双缓冲形式接收数据后,将数据写入FLASH中,这个也实现了. 在试验过程中会出现串口助手发送数据停止,DMA最后一次接收未完成,则最后接收的数据不能写入 FLASH中.
3 为了改进2中的问题,引入了定时时钟.每次写FLASH完成后开启时钟开始5S钟计时,若5S中内DMA接收完成则将数据写入FLASH,然后设置定时器重新开始计时;若5S中内DMA接收未完成,则将DMA接收到的数据写入FLASH.(注: 串口助手没500ms发送100个数据,DMA接收数据长度为200)
4 出现问题就在3中开启定时器后,DMA接收3次后会出现复位的现象,DMA接收也停止.
针对问题4 以为是中段优先级的设置问题,然后将DMA中段和定时器中段的优先级 组、子优先级设置相同,抢占优先级设置不同. 现象依旧存在,仔细看用户手册定时器设置没有问题。程序如下:
#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "flash.h"
#include "dma.h"
#define SIZE 200
char ReceiveBuffer0[SIZE]; //DMA接收缓冲0
char ReceiveBuffer1[SIZE]; //DMA接收缓冲1
u16 count=0;
u16 len;
u8 Timeout=0;
int Buff_OK=0; //DMA已经有接受完数据
int Free_Buff_No; //DMA缓冲可以进行处理的数据
void Set_DMA_ISR(void);
void USART_Receive_DMA(void);
void Timer3_Init(u16 arr, u16 psc);
int main(void)
{
u16 i=0;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口1初始化
LED_Init(); //LED初始化
KEY_Init(); //按键初始化
LCD_Init(); //TFTLCD液晶初始化
SPI_Flash_Init(); //SPI FLASH 初始化
  OINT_COLOR=RED;//设置字体为红色
LCD_ShowString(17,30,"MINISTM32 Flash Test!");
while(SPI_Flash_ReadID()!=FLASH_ID)//检测不到W25X16
{
i=SPI_Flash_ReadID();
printf("ID:%d",i);
LCD_ShowString(60,110,"W25X16 Check Failed!");
delay_ms(500);
LCD_ShowString(60,110," Please Check! ");
delay_ms(500);
LED0=!LED0; //DS0闪烁
}
LCD_ShowString(60,110,"W25X16 Ready!");
SPI_Flash_Erase_Chip(); //擦出整个FLASH
USART_Receive_DMA(); //DMA开始第一次接收数据
while(1)
{
if(Buff_OK==1){
Buff_OK=0;
switch(Free_Buff_No){
case 0: SPI_Flash_Write((u8*)ReceiveBuffer0,(SIZE*(count-1)),SIZE);
break;
case 1: SPI_Flash_Write((u8*)ReceiveBuffer1,(SIZE*(count-1)),SIZE);
break;
default: break;
}
Timer3_Init(50000,7199);
TIM3->CR1|=0x01; //使能定时器3
}
if(Timeout==1){ //5秒钟内DMA接收没有完成
TIM3->CR1|=0x0; //停止定时器3
len=SIZE-DMA1_Channel5->CNDTR; //计算DMA接收数据长度
if(Free_Buff_No==1)
SPI_Flash_Write((u8*)ReceiveBuffer1,SIZE*count,len);
else
SPI_Flash_Write((u8*)ReceiveBuffer0,SIZE*count,len);
count+=1;
break; //这句删除就可以实现了 但是还是有点小问题
}
}
}
//DMA中断设置
void Set_DMA_ISR(void){
DMA1_Channel5->CCR|=1<<1; //允许TC中断
MY_NVIC_Init(0,3,DMA1_Channel5_IRQChannel,2); //中断优先级 抢占0,子优先级3,组2
}
//DMA1中断函数
void DMAChannel5_IRQHandler(void){
if(DMA1->ISR&(1<<17)){ //DMA1通道5传输完成
DMA1->IFCR|=1<<17; //清除DMA1通道5传输完成标志
count++;
LCD_ShowNum(60,90,count,5,16);
if(Free_Buff_No==0){
MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)ReceiveBuffer0,SIZE);//DMA1通道5,外设为串口1,存储器为SendBuff,长度200.
Set_DMA_ISR();
USART1->CR3=1<<6; //使能串口1的DMA接收
MYDMA_Enable(DMA1_Channel5); //开始一次DMA接收
Free_Buff_No=1;
}
else{
MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)ReceiveBuffer1,SIZE);//DMA1通道5,外设为串口1,存储器为SendBuff,长度200.
Set_DMA_ISR();
USART1->CR3=1<<6; //使能串口1的DMA接收
MYDMA_Enable(DMA1_Channel5); //开始一次DMA接收
Free_Buff_No=0;
}
Buff_OK=1;
}
}
//USART1用DMA方式接收数据
void USART_Receive_DMA(void){
Free_Buff_No=1;
MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)ReceiveBuffer0,SIZE);//DMA1通道5,外设为串口1,存储器为SendBuff,长度200.
Set_DMA_ISR(); //开启中段
USART1->CR3=1<<6; //使能串口1的DMA接收
MYDMA_Enable(DMA1_Channel5);//开始一次DMA接收
}
//定时器3中断服务程序
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
Timeout=1;
}
TIM3->SR&=~(1<<0);//清除中断标志位
}
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void Timer3_Init(u16 arr, u16 psc)
{
RCC->APB1ENR|=1<<1;//TIM3时钟使能
TIM3->ARR=arr; //设定计数器自动重装值//刚好1ms
TIM3-> SC=psc; //预分频器7200,得到10Khz的计数时钟
//这两个东东要同时设置才可以使用中断
TIM3->DIER|=1<<0; //允许更新中断
TIM3->DIER|=1<<6; //允许触发中断
// TIM3->CR1|=0x01; //使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//抢占1,子优先级3,组2
}
大家帮忙看下是不是有什么地方设置不对,谢谢啦!
|