DMA uart dma模式怎样将缓存下标清零

2.改写该驱动程序,在其基础上实现一些你想要的简;由于驱动程序的复杂性,不容易上手且又容易出问题,;结合ARMLinux的移植实验中的相关内容,把改;七、思考题;1、另外找一个Linux的设备驱动程序(在Lin;2、把UP-NETARM2410开发平台上的触摸;5.3系统中断实验-键盘中断的实现;一、实验目的;1.了解ARM的中断方式和原理;2.熟悉linu
2.改写该驱动程序,在其基础上实现一些你想要的简单功能。
由于驱动程序的复杂性,不容易上手且又容易出问题,所以建议你先只对其中的调试信 息做一些改动,在运行该驱动程序时看看其在屏幕上的打印信息。在你对整个过程及相关硬件有较多的一些了解之后再动手做一些功能上的调整。
结合ARMLinux的移植实验中的相关内容,把改动的驱动程序编译进内核,并下载内核验 证结果。你只要把该驱动在必要地方修改后(注意修改前的代码一定要做备份)保存代码,回到内核目录,make bzImage编译内核,然后下载编译好的内核。
七、思考题
1、 另外找一个Linux的设备驱动程序(在Linux源码的drivers目录下),剖析它的 结构及工作原理。
2、 把UP-NETARM2410开发平台上的触摸屏驱动从内核中卸载,自己动手写一个类似的 驱动程序,以新驱动代替旧驱动并编译进内核看看运行情况。
5.3 系统中断实验-键盘中断的实现
一、实验目的
1.了解ARM 的中断方式和原理。
2.熟悉linux中断驱动程序实现方法。 3.理解底层驱动与上层应用之间的关系。
二、实验内容
剖析键盘中断的实现过程,编写键盘上层应用程序验证中断的实现。
三、预备知识
1.掌握在Linux集成开发环境中编写和调试程序的基本过程。 2.了解ARMS3C2410的基本结构及其中断的工作原理。 3.了解Linux内核中关于中断控制的基本原理。
四、实验设备及工具
硬件:UP-NETARM2410-S嵌入式实验仪,PC机Pentumn500以上, 硬盘40G以上,内存大于128M。
软件:PC机操作系统REDHAT LINUX 9.0 +MINICOM + AMRLINUX开发环境
五、实验原理
1.ARM中断方式和原理基本知识介绍
S3C2410中断控制器可以接受来自56个中断源的中断请求。这些中断源来自DMA、UART、IIC 等这样的片内外围或片外外部引脚。其中24路为外部中断EINTn,外部中断中EINT4~7、EINT8~23是逻辑或的关系,它们共享一条中断请求线。具体可参见芯片手册中um_s3c2410.pdf P14-3部分。
中断控制器的操作
如果PSR 程序状态缓存器的F 位被设定为1,那么CPU 将不接受来自中断控制器的FIQ(快速中断请求),如果PSR的I位被设定为1,那么CPU 将不接受来自中断控制器的IRQ(中断请求)。因此,为了使能FIQ 和IRQ,必须先将PSR 程序状态寄存器的F位和I 位清零,并且中断屏蔽寄存器INTMSK 中相应的位也要清零。
中断控制器共有5中控制寄存器,它们是中断源挂起寄存器、中断模式寄存器、屏蔽寄存器、优先级寄存器和中断挂起寄存器。
来自中断源的所有中断请求首先在32位中断源挂起寄存器寄存。中断源被分为两部分,一部分为快速中断请求(FIQ),一部分为中断请求(IRQ),有中断模式寄存器来标识。CPU只响应FIRQ或IRQ中断。 中断模式(INTMOD)
ARM920提供了2 种中断模式,FIQ快速中断模式和IRQ外部中断模式。所有的中断源在中断请求时都要确定使用哪一种中断模式。ARMS3C2410中断资源如表5-11所示:
表5-11 ARMS3C2410中断资源
优先级寄存器(PRIORITY)
优先级寄存器的设置如下表5-12所示:
优先级寄存器(PRIORITY)为21位寄存器。其中0-6位对应模式仲裁控制位ARB_MODE0-ARB_MODE6,7-20位每隔两位分别对应着选择控制位ARB_SEL0-ARB_SEL6。 中断优先级产生模块
对32个中断请求做出优先级判断的逻辑模块由7个可反转的逻辑仲裁器组成。其中6
个为一级仲裁,1个为2级仲裁。如下图5-17所示:
图5-17 中断优先级产生模块
每个仲裁器由一位模式仲裁控制位(ARB_MODE)和两位选择控制位(ARB_SEL)组成,每个又可以处理6个中断请求。
如果ARB_SEL位为00b,则优先级顺序为REQ0,REQ1,REQ2,REQ3,REQ4和REQ5. 如果ARB_SEL位为01b,则优先级顺序为REQ0,REQ2,REQ3,REQ4,REQ1和REQ5. 如果ARB_SEL位为10b,则优先级顺序为REQ0,REQ3,REQ4,REQ1,REQ2和REQ5. 如果ARB_SEL位为11b,则优先级顺序为REQ0,REQ4,REQ1,REQ2,REQ3和REQ5.
我们注意到REQ0总是为最高优先级,而REQ5总是为最低优先级。另外,通过改变ARB_SEL位,我们可以反转REQ1到REQ4的优先级。
如果ARB_MODE位被置为0,则ARB_SEL不会被自动改变,仲裁器以固定的优先级方式操作(虽然我们可以手工改变ARB_SEL位来改变优先级)。换句话说,如果ARB_MODE位置1,则ARB_SEL位以循环方式进行。例如,如果当前CPU正处理REQ1的中断,则ARB_SEL位会自动切换为01b把REQ1的优先级降为最低。ARB_SEL变化的详细规则如下:
如果当前CPU正处理REQ0或REQ5的中断,则ARB_SEL位不会改变。 如果当前CPU正处理REQ1的中断,则ARB_SEL位会改变为01b。 如果当前CPU正处理REQ2的中断,则ARB_SEL位会改变为10b。 如果当前CPU正处理REQ3的中断,则ARB_SEL位会改变为11b。
如果当前CPU正处理REQ4的中断,则ARB_SEL位会改变为00b。 中断挂起寄存器
S3C2410有两个中断挂起寄存器:中断源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND),这两个挂起寄存器用于指示对应的中断是否被启动。当中断源请求中断服务时,SRCPND寄存器相应位被设定为1,同时经过仲裁处理后INTPND寄存器的一位被自动设定为1。如果中断被屏蔽,SRCPND寄存器相应位被设定为1,但并不引起INTPND寄存器位的变化。如果INTPND寄存器挂起位被设定为1,那么无论程序状态寄存器PSR的I位或F位是否被清零,都会执行相应的中断服务程序。两个中断瞬时寄存器为可读写缓存器,所以在中断服务程序中必须对SRCPND和INTPND寄存器相应位清零来清除挂起条件。
当INTMSK寄存器的屏蔽位为1 时,对应的中断被禁止;当INTMSK寄存器的屏蔽位为0 时,则对应的中断正常执行。如果一个中断的屏蔽位为1,在该中断发出请求时中断源挂起位还是会被设定为1。
中断源挂起寄存器是一个32位寄存器,每位对应一个中断源。如下表5-13所示:
中断源挂起寄存器的位描述如下表5-14所示:
包含各类专业文献、各类资格考试、幼儿教育、小学教育、文学作品欣赏、外语学习资料、高等教育、专业论文、ARM2410@linux实验指导书_图文25等内容。 
 ARM2410@linux实验指导书_IT/计算机_专业资料 暂无评价|0人阅读|0次下载|举报文档 ARM2410@linux实验指导书_IT/计算机_专业资料。目 录 第一章 嵌入式 LINUX ...  S3C2410A实验指导书_计算机硬件及网络_IT/计算机_专业资料。目录第 1 章 实验...50 第 1 章 实验要求 3 第1章实验要求 ARM 实验室是电子信息科学与技术的...  Linux 内核移植实验指导书 1、 获得 Linux 内核源码我们的光盘中提供了 linux-...[root@vm-dev linux-2.6.24.4]# cp arch/arm/configs/s3c2410_defconfig...  Linux 内核移植实验指导书一、获得 Linux 内核源码我们的光盘中提供了 linux-2....在 arch/arm/mach-s3c2410/mach-smdk2410.c 文件中添加如下内容: static ...  ARM9嵌入式Linux实验指导... 11页 免费L​i​n​u​x​实​验​...Linux 操作系统实验指导书 目录实验 1 实验 2 Linux 系统的安装 ??? - ...  本实验以 S3C2410 ARM920T 处理器的实验板为例,建立嵌入式 Linux 交叉开发环 境,完成嵌入式 Linux 开发的全过程。 通过本实验,可以掌握嵌入式 Linux 基本开发...  linux嵌入式实验指导书doc 60页 免费 嵌入式Linux入门笔记 174页 免费如要投诉...二、TAB 文件目录匹配搜索的使用例如/usr/arm2410s,假设/目录下没有其它以arm...  ARM2410经典版forUCOS实验指导书 for sprife@08.4.15_计算机软件及应用_IT/计算机_专业资料。目第一章 第二章 录 嵌入式开发系统资源概况 ...目第一章 第二...  linux实训指导书-详细版_工学_高等教育_教育专区。系统开发实训》 《嵌入式 linux...= /usr/local/arm/arm-2009q1/bin/arm-none-linux-gnueabi- 2.复制mach-...使用DMA+printf+uart1(转)
#include "stm32f10x_lib.h"
#include "stdio.h"
#include "VarData.h"
#include "stdarg.h"
#define USART1_DR_Base& 0x
#define SENDBUFF_SIZE&&
u8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
u32 DMA1_4 = RESET;
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(u8 *uiSendBuf,u32 uiLength);
void USART1_Configuration(void);
void Delay(void);
int printf(const char *format ,... )
&while(DMA1_4 == SET);
va_start(arg, format);
vsprintf(SendBuff, format, arg);
va_end(arg);
DMA_Configuration(SendBuff,rv);
&//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);
&LEDRUN(LAMP_ON);
int main(void)
#ifdef DEBUG
&&& recv_ptr =
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
USART1_Configuration();
for(i=0;i&SENDBUFF_SIZE;i++)
SendBuff[i] = i&0
//printf("Initial success!\r\nWaiting for
transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));
&& // printf("Start DMA
transmission!\r\n");
//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
printf("Initial success!\r\nWaiting for transmission %d
...\r\n",i);
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);
printf("\r\nDMA transmission successful!\r\n");
printf("\r\nDMA transmission
successful!successful,successful,successful\r\n");
void Delay(void)
for(i=0;i&0xF0000;i++);
void RCC_Configuration(void)
&&& ErrorStatus
HSEStartUpS
//使能外部晶振
RCC_HSEConfig(RCC_HSE_ON);
//等待外部晶振稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//如果外部晶振启动成功,则进行下一步操作
if(HSEStartUpStatus==SUCCESS)
//设置HCLK(AHB时钟)=SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//PCLK1(APB1) = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);
//PCLK2(APB2) = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);
//FLASH时序控制
//推荐值:SYSCLK = 0~24MHz&&
Latency="0"
SYSCLK = 24~48MHz& Latency="1"
SYSCLK = 48~72MHz& Latency="2"
FLASH_SetLatency(FLASH_Latency_2);
//开启FLASH预取指功能
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//PLL设置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
//系统时钟SYSCLK来自PLL输出
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//切换时钟后等待系统时钟稳定
while(RCC_GetSYSCLKSource()!=0x08);
//下面是给各模块开启时钟
//启动GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB
&&&&&&&&&&&&&&&&&&&&&&&&&&
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\
&&&&&&&&&&&&&&&&&&&&&&&&&&
//启动AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//启动USART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//启动DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
void GPIO_Configuration(void)
GPIO_InitTypeDef GPIO_InitS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//USART1_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
void NVIC_Configuration(void)
NVIC_InitTypeDef NVIC_InitS
#ifdef& VECT_TAB_RAM
&&& // Set the
Vector Table base location at 0x
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
&&& // Set the
Vector Table base location at 0x
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//串口接收中断打开&&&
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQC
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel =
DMA1_Channel4_IRQC
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
void USART1_Configuration(void)
USART_InitTypeDef USART_InitS
USART_InitStructure.USART_BaudRate = 9600;
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_N
USART_InitStructure.USART_Mode = USART_Mode_Tx |
USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
void DMA_Configuration(u8 *uiSendBuf,u32 uiLength)
DMA_InitTypeDef DMA_InitS
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存--&外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_B
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)uiSendB
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = uiL
DMA_InitStructure.DMA_PeripheralInc =
DMA_PeripheralInc_D
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_E
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_B
DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_B
DMA_InitStructure.DMA_Mode = DMA_Mode_N
DMA_InitStructure.DMA_Priority = DMA_Priority_M
DMA_InitStructure.DMA_M2M = DMA_M2M_D
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
& DMA_ITConfig(DMA1_Channel4, DMA_IT_TC,
void DMA1_Channel4_IRQHandler(void)
&if(DMA_GetITStatus(DMA1_IT_TC4))
&&DMA_ClearITPendingBit(DMA1_IT_TC4);
& &LEDRUN(LAMP_OFF);
&if(DMA_GetITStatus(DMA1_IT_HT4))
&&DMA_ClearITPendingBit(DMA1_IT_HT4);
&if(DMA_GetITStatus(DMA1_IT_TE4))
&&DMA_ClearITPendingBit(DMA1_IT_TE4);
&if(DMA_GetITStatus(DMA1_IT_GL4))
&&DMA_ClearITPendingBit(DMA1_IT_GL4);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。下次自动登录
现在的位置:
& 综合 & 正文
ARM中基于DMA的高效UART通讯及其应用
  由于UART串行口的广泛应用,在传统的8位和16位的处理器以及32位处理器中,一般都带有UART串行口。传统的基于UART的数据通讯中,采用的方式一般有两种,查询式和中断式。查询方式下CPU的负担较重,浪费了处理器的能力,不能够很好的处理其他的事件;中断方式可以在接收到信息或需要发送数据时产生中断,在中断服务中完成数据的接收与发送。相对于查询方式,中断方式的CPU利用率要高。在CPU任务简单的系统中,使用中断方式确实是一种好方法。但是在复杂的系统中,比如移动机器人,处理器需要处理串行口通信,多个传感器数据的采集以及处理,实时轨迹的生成,运动轨迹插补以及位置闭环控制等等任务,牵扯到多个中断的优先级分配问题。为了保证数据发送与接收的可靠性,需要把UART的中断优先级设计较高,但是系统可能还有其他的需要更高优先级的中断,必须保证其定时的准确,这样就有可能造成串行通讯的中断不能及时响应,从而造成数据丢失。为此,笔者在采用S3c44b0x设计移动机器人控制器时,为了保证串行通讯的数据及时可靠的接收,同时兼顾其它任务不受影响,采用了基于DMA和中断方式相结合的UART串行通信方式。DMA是
Direct Memory Access的缩写,意思是“存储器直接访问”,它是一种高速的数据传输操作,允许在外部设备和存储器之间直接读/写数据,即不通过CPU,也不需要 CPU干预。整个数据传输操作是在一个称作DMA控制器的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中可以进行其他的工作。这样,在大部分时间里,CPU和输入/输出设备都处于并行的操作状态。其基本原理可以查阅教科书,此处不赘述。这里仅介绍S3c44c0x的DMA控制器。
  2、S3c44b0x中的DMA控制器和UART的特性
  S3c44b0x采用ARM7TDMI核,具有4 通道的DMA控制器,并且对应有4个中断。其中两个DMA通道称做ZDMA(通用DMA),连接在SSB(系统总线)上,另外两个DMA通道称做 BDMA(桥DMA),连接于SSB和SPB(外设总线)之间的接口层。连接于SSB上的ZDMA控制器可以用于从存储器到存储器,从存储器到固定目标的 I/O存储器,和从I/O 设备到存储器之间的数据传输。另外的两个BDMA 控制器主要作用是在外部存储器和内部外设之间传输数据,这里的I内部外设包括SIO,IIS,TIMER和UART等。BDMA与ZDMA可以通过软件启动,也可以通过硬件启动。此设计中我们使用UART0,与其对应的DMA通道为BDMA0。其控制器框图如图1所示。
  S3c44b0x的UART单元提供2个独立的异步串行I/O口,每个口均可以工作于中断模式或者DMA模式,即 UART可以产生内部中断请求或者DMA请求,在CPU的串行I/O口之间传送数据,支持高达115.2KBPS的传输速率,每个UART通道包含2个 16位的分别用于发送和接收的FIFO通道。
  3、硬件电路设计
  由于S3c44b0x自带支持UART的DMA控制器,所以关于DMA硬件部分不需要作任何的工作。S3C44B0X的I/O口电压为3.3V,而PC机一端的串口采用RS232电平,所以中间要经过电平转换,在此采用SP3232E芯片。连接电路如图2所示。
4、基于DMA和中断相结合的通讯软件设计
  在以S3C44B0X为核心组成的移动机器人中,采用3路PWM定时器驱动3个直流电机,通用的GPIO口和A/D口连接外部的红外和超声以及激光传感器,使用UART0完成与上位机(PC)的数据交换,这些数据是单向的(从上位机发送给S3c44b0x),主要是上位机传给机器人控制器的各种命令信息,但是命令信息的发送时间上是不具有规律性的,即间隔时间不定。为了充分的利用CPU,减少数据丢失的风险,我们利用UART的DMA模式来完成数据的接收。软件部分主要是针对具体的应用,对DMA控制器以及UART作适当的初始化。UART的初始化比较简单,主要是通讯数据格式、波特率等的设置,这些与其他控制器相同,只要设置相关的寄存器即可。注意UART设置成不使用自动流控制,不使用红外线传输模式,关键要注意UART0设置成DMA模式而不是中断模式,并且要使能FIFO缓冲区(根据需要,使用16字节的接收缓冲区),这样在接收缓冲区满时,会产生DMA请求而不是中断请求。限于篇幅,具体的寄存器定义以及串行口的初始化不做详悉介绍,可以参考文献[1][2]。
  DMA控制器的初始化也比较简单,主要是相关寄存器的设置。与BDMA0相关的在本系统中用到的寄存器以及相关定义见表1,具体寄存器的名称定义以及物理地址见参考文献[1][2]。
  表1 S3c44b0x的BDMA相关寄存器的定义
  在初始化时要正确设置目标(缓冲区的)首地址、数据传输的方向、源寄存器的首地址、地址指针是否递增以及递增方向、DMA计数器等等。相关以及注释如下:
  #define RAM_ADDRESS 0xc200000 //定义接收数据的缓冲区,根据硬件而定。在我们的系统中扩展的SDRAM 存储空间从0x0CC7fffff,占用S3c44b0x的bank 6。
  #define size 16 //定义DMA的计数器,根据需要设定,可以选择的选项是4、8、2和16
  char *B
  Buf=(unsigned char*) RAM_ADDRESS; //指针指向起始地址
  BDISRC0=(11&&28)+(int)(rURxH0); /*以字节为单位传送;因为DMA操作时是将UART的寄存器中的数据读出放置到设定的缓冲区,所以源寄存器的地址应该是固定到;UART的接收保存寄存器rURxH0,同时位[29:28]应该设置成 0b11。*/
  BDIDES0=(10&&30)+(01&&28)+ Buf); /*传输方向模式设定为从内部设备(UART口)到外部存储器(SDRAM),目标存储器(SDRAM)使用地址递增的方向,将数据顺次放置到缓冲区中*/
  BDICNT0=(10&&30)+(1&&26)+(3&&22)+(1&&21)+(0&&20)+/*设置UART0使用BDMA0通道,在DMA计数到0时自动重载和自动启动,计数结束产生中断,每次DMA操作移动 16字节数据到设定地缓冲区*/
  BDICNT0 |= (1&&20);//使能DMA
  BDCON0 = 0x0&&2;//允许外部DMA请求
  数据接收:这一部分工作由初始化好后的DMA控制器依靠硬件来完成。接收数据不定时,初始化UART0的接收缓冲区为16字节,当接收缓冲区满时,会产生DMA请求,然后在DMA控制器的控制下,将UART的接收FIFO中的16字节的数据转移到指定的缓冲区中(SRAM),当数据转移完毕(DMA 计数到0)后,要做两件事情:一是自动重载和自动启动,即自动重新设置好目标(缓冲区)首地址和源地址(UART接收寄存器)以及DMA计数器,准备好下次DMA请求;另外产生DMA中断。DMA中断服务程序要做的工作很简单,只要对全局标志RECEIVE_FLAG置位,通知主程序有新的命令需要处理。这样主程序可以直接处理RAM中的数据,而不需要花费时间去读取UART的接收缓冲区。
  数据处理:当主程序通过查询全局标志RECEIVE_FLAG,如果为1,则知道有新的命令,可以直接读取命令缓冲区,同时对RECEIVE_FLAG清零。然后按照一定的对接收的数据做出解析,这部分内容不做重点讨论。
  5、试验及结论
  为了验证基于DMA的通讯的有效性,笔者做了对比试验。把负责轨迹插补的定时中断优先级设计成最高(中断时间间隔50毫秒,中断服务程序执行时间约需要30毫秒),然后一个机器人采用中断方式接收上位机连续发送的100组命令,另一个采用基于DMA的方式接收上位机连续发送的100组命令。然后在机器人主程序中通过读取UART的状态寄存器判断出现错误(主要是数据溢出错误,即缓冲区有接收数据而没有及时读取,被新的数据覆盖)的次数。软件采用C语言,用ADS1.2编译调试。试验结果如表2。实验证明了第二种方式的有效性。
  表2:对比试验结果
  本文作者的创新点在于:在UART通讯中,通过采取DMA方式,直接将UART接收的数据转移到设定好的RAM区,然后设置相应的全局标志,通知主程序数据可用就可以了。开发人员不需要到UART的缓冲区中读取数据,直接读RAM就可以了。与采用中断方式或者查询方式的串行口通讯方式相比较,不仅仅可以节省CPU通讯时用于接收数据的时间,同时可以防止UART接收的数据由于没有及时被读取而丢失,提高了通讯的可靠性。
&&&&推荐文章:
【上篇】【下篇】基于DMA的UART发送的使用_中华文本库
第2页/共3页
若取回值为NULL则说明没有可用缓存区;而执行入队操作时,会将一个非NULL空缓存区的地址加入FIFO队列中,执行读取队列长度操作时,返回队列中可用空缓存地址的数量。 (IV) 建立DMAx的链表地址FIFO队列,记作DMAx_LINK_LIST_FILL_TABLE,用来放置占用并填充了链表内容的结构体缓存区地址。当执行出队操作时,返回一个非NULL已占用缓存区地址,若取回值为NULL则说明没有可用的已占用缓存区地址;而执行入队操作时,会将一个非NULL已占用缓存区的地址加入FIFO队列中,执行读取队列长度操作时,返回队列中可用的已占用缓存地址数量。
(V) 建立UARTn TX的地址保存FIFO队列UART_LINK_LIST_STORE_TABLE,用于保存一次DMA发送的时所用到的DMAx_LINK_LIST_INFOR_CACHE地址。队列容量可与DMAx_LINK_LIST_FILL_TABLE的容量相同,或根据需求设置成更小。
四、UARTn的DMA 数据发送
UARTn的DMA数据发送实现如下:
(I) 轮询检测是否有数据需要UARTn的发送,如果有则从UARTn_BUF_FREE_TABLE队列中取出一个UARTn_BUF缓存,填充欲发送的数据,然后从DMAx_LINK_LIST_FREE_TABLE队列中取出一个DMAx_LINK_LIST_INFOR_CACHE,将UARTn_BUF的地址赋给DMAx_LINK_LIST_INFOR_CACHE的LinkList_SrcAddress,并设置其LinkList_DstAddress为UnTHR的地址,LinkList_NextListAddress暂为0、LinkList_ControlValue为UARTn_BUF中数据大小、源和目的BURST SIZE为0、源和目的传输宽度的1字节、源地址自增、目标地址不自增和Terminal Count中断使能。最后将该DMAx_LINK_LIST_INFOR_CACHE值入队到DMAx_LINK_LIST_FILL_TABLE队列中。 (II) 设置定时器UART_DMA_TX_TIMER,定时值为T秒,即每T秒定时器UART_DMA_TX_TIMER发生一次中断。中断服务为检查DMAx_LINK_LIST_FILL_TABLE的队列长度L,判断是否有可用的链表地址。如果有,则执行出队操作取出一个缓存地址FILL_CACHE_0,将其入队到UART_LINK_LIST_STORE_TABLE中。然后利用其中的源地址、目标地址和ControlValue值,将其分配给DMA通道x的相应寄存器。若L&1,则再取出一个地址,入队到UART_LINK_LIST_STORE_TABLE,将其值赋给DMAx的LLI寄存器。如果仍有可用链表地址,则取出,入队到UART_LINK_LIST_STORE_TABLE,将其值赋给上一个链表地址中的LinkList_NextListAddress,然后依次类似操作,直到最一个取出后,将其LinkList_NextListAddress赋为0。若L=1,则将DMAx的LLI寄存器的值置为0。最后设置DMAx的Config寄存器,设置内容有目标外设为UART_TX、传送类型为MEMORY TO PERIPHERAL、不屏避Terminal Count中断、DMAx通道使能,启动DMAx传输。
第2页/共3页
寻找更多 ""

我要回帖

更多关于 stm32f4 uart dma 的文章

 

随机推荐