这篇文章给大家介绍stm32f103串口如何使用DMA+FIFO,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
专注于为中小企业提供成都做网站、成都网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业沅江免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上千多家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
stm32f103若使用普通的串口接收程序,波特率设为115200,由于读取时需要占用CPU资源,所以实际速率非常慢。但如果使用DMA来处理则速度非常快,实测在波特率115200时,并且使用队列,速率可以达到10k以上。当然实际情况可能有些差别,我是用来接收上位机发来的固件,然后当从FIFO读取出的数据长度计满1024字节时,还要去写入FLASH。当然此时如果FIFO大于1024字节的话,DMA还是会继续读取从串口接收到的数据,并存储至FIFO。
1.DMA队列
/*
* File : [fifo.h]
*/
#include "stm32f10x.h"
#define RINGQ_MAX 10000 //队列大小
typedef struct
{
u32 OldLen;
u32 NewLen;
u32 TotalLen; //数据长度
u8 *BaseAddr; //缓冲区基地址
u8 *EndAddr; //缓冲区尾地址
u8 *ReadAddr; //数据读取地址
}LinkQueue;
int InitQueue (LinkQueue *Q, u8 *bufbase, u32 size);
int GetLength (LinkQueue *Q);
int EnQueue (LinkQueue *Q);
int OutQueue (LinkQueue *Q, unsigned char *buf, int len);
/*
* File : [fifo.c]
*/
#include "fifo.h"
#include "usart.h"
/*
* 初始化队列
*/
int InitQueue (LinkQueue *Q, u8 *bufbase, u32 size)
{
Q->BaseAddr = bufbase;
Q->EndAddr = bufbase + RINGQ_MAX;
Q->ReadAddr = bufbase;
Q->NewLen = 0;
Q->OldLen = 0;
Q->TotalLen = 0;
return 0;
}
/*
* 获取DMA 已传输字节数
*/
int GetLength (LinkQueue *Q)
{
Q->NewLen = RINGQ_MAX - DMA_GetCurrDataCounter(DMA1_Channel3);
return 0;
}
/*
* 入队列
*/
int EnQueue (LinkQueue *Q)
{
if (Q->NewLen > Q->OldLen)
{
//正常情况下,
Q->TotalLen += (Q->NewLen - Q->OldLen);
}
else
{
if(Q->NewLen < Q->OldLen)
{
//DMA从新开始计数
Q->TotalLen += (Q->NewLen + RINGQ_MAX - Q->OldLen);
if (Q->TotalLen > RINGQ_MAX)
{
return 1; //溢出
}
}
}
Q->OldLen = Q->NewLen;
return 0;
}
/*
* 出队列
*/
int OutQueue (LinkQueue *Q, unsigned char *buf, int len)
{
u32 i;
if(Q->TotalLen > 0)
{
if (len > Q->TotalLen)
{
//请求数大于可读取数
len = Q->TotalLen;
}
// Q->TotalLen -= len;
for (i = 0; i < len; i++)
{
buf[i] = *(Q->ReadAddr++);
Q->TotalLen--;
if(Q->TotalLen == 0)
{
while(0);
}
if (Q->ReadAddr == Q->EndAddr)
{
//读到缓冲区尾部,返回基址
Q->ReadAddr = Q->BaseAddr;
}
}
}
else
{
len = 0;
}
return len;
}
2. DMA串口配置程序
/*
* File : [usart.c]
*/
#include "stm32f10x.h"
#include "usart.h"
#include "fifo.h"
#define USART3_DR_Base 0x40013804
u8 TxBuffer1[RINGQ_MAX] ; //发送缓冲区
u8 RxBuffer1[RINGQ_MAX]; //接收缓冲区
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA1 Channel4 (triggered by USART3 Tx event) Config */
DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART3->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = RINGQ_MAX;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
}
void DMA_Send( unsigned char *buf,int len)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA1 Channel4 (triggered by USART3 Tx event) Config */
DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = len;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
//while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET){} // 等待传输完成
DMA_ClearFlag(DMA1_FLAG_TC2) ;//功能
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA1_Channel2->CNDTR=len; //DMA1,传输数据量
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_Cmd(DMA1_Channel2, ENABLE);
}
/*****************************************************************
USART3 初始化 baud 波特率
*****************************************************************/
void USART3_Init(unsigned int baud)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
/* Enable USART3 DMA Rx and TX request */
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
USART_Cmd(USART3, ENABLE);
/* Enable DMA1 Channel4 */
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
}
关于stm32f103串口如何使用DMA+FIFO就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。