文档章节

stm32f103串口使用DMA+FIFO

Ice99
 Ice99
发布于 2017/01/04 09:16
字数 719
阅读 89
收藏 0

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);

}

© 著作权归作者所有

共有 人打赏支持
Ice99
粉丝 0
博文 2
码字总数 719
作品 0
美国
STM32F10x单片机Flash写操作导致中断不响应问题

昨天遇到一个问题,在写入数据到STM32F103单片机的Flash中时会出现串口中断接收数据丢失现象,但是我设置的串口接收中断优先级是最高的,并且没有哪里将全局中断关闭很长时间(除了操作系统部...

tq384998430
05/05
0
0
STM32串口接收不定长数据原理与源程序

转载:http://blog.csdn.net/u014515202/article/details/73293917 http://www.51hei.com/bbs/dpj-39885-1.html 方法1:串口接受数据,定时器来判断超时是否接受数据完成。 方法2:DMA接受+...

u013184273
2017/12/13
0
0
IAR ITM机制调试信息打印

打印调试信息几种途径: 1.串口打印: 将fputc映射到UART,通过USB-TLL转接板打印调试信息。 STM32F103官方提供的代码: /** * @brief Retargets the C library printf function to the USAR...

Jr小王子
2015/02/04
0
0
MQTT 移植STM32+GPRS(串口透传)(三)

昨天,去参观了AWE(中国家电及消费电子博览会),智能家居,智能插座、智能LED灯、智能摄像头、智能橱柜等等,大开眼界,原来这些别的公司的产品都正式投产了。还顺便打听了几家提供云服务的公...

qq_20251069
2017/03/18
0
0
使用arduino开发环境来开发普通单片机开发板

arduino开发板正常情况下是通过在代码中嵌入bootloader代码,利用单片机的IAP功能通过USB口来实现程序下载。其实通过合理的设置产生程序的hex或者bin文件然后用下载器下载到单片机里也可以实...

Okimbin
2014/02/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

C++ std::function 和 std::bind

C++11提供了std::function和std::bind两个工具,用于引用可调用对象。这些可调用对象包括 普通函数,Lambda表达式,类的静态成员函数,非静态成员函数以及仿函数等。引用可调用对象,可以用于...

yepanl
59分钟前
1
0
python:可迭代对象的索引

关于 python的range的用法: 注意是[ 开始,结束)的半开区间,不包括结束 http://www.runoob.com/python/python-func-range.html import collectionsfrom collections import Iterable字符串......

Oh_really
今天
2
0
docker-compose ,docker-stack

1.例子 version: "3"services: php: image: registry.cn-hangzhou.aliyuncs.com/lxepoo/apache-php5 ports: - "38080:80" networks: - my_php_mysql volum......

chenbaojun
今天
3
0
SQL_Server2000示例数据库NorthWind的分析(转)

SQL_Server2000示例数据库NorthWind的分析 表名:Categories(食品类别表) 表结构: 字段名称 数据类型 长度 允许为空 CategoryID(主键) int 4 否 CategoryName nvarchar 15 否 Description ...

QQZZFT
今天
1
0
laravel 5.5 Session store not set on request.

laravel 5.5 数据存入session,会出现Session store not set on request.错误。查了下laravel 5.5将session放到global middleware中,需要laravel的文件 ./app/Http/Kernel.php中的加上一句:...

MichaelShu
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部