DMA发送数据
启动DMA并发送完成后,产生DMA发送完成中断,在DMA中断服务函数中执行以下操作:
在数据发送缓冲区内放好要发送的数据(此数据缓冲区的首地址必须要在DMA初始化时写入到DMA配置中去)
将数据缓冲区内要发送的数据字节数传给DMA通道(串口发送和接收不是同一个通道)
开启DMA,一旦开启,则DMA开始发送数据,
等待数据发送完成标志!
判断数据发送完成:
清DMA发送完成标志
关闭串口发送DMA通道
给前台(应用)程序设置一个软件标志位,说明数据发送完成。
DMA接收数据
串口接收DMA在初始化时就处于开启状态,一直等待数据的到来,串口中断IDLE在串口一直没有数据时,是不会产生的,产生的条件是:当清除IDLE标志位后,必须有接收到第一个数据后才触发,一旦接收的数据断流,即产生IDLE中断。
这里判断接收数据完成是通过串口的空闲方式实现,即当串口的数据流停止后,就会产生IDLE中断,在中断里做关闭串口接收的DMA通道。一是防止又有数据接收到,产生干扰;二是便于DMA重新配置赋值。
清除DMA中断标志位
从DMA寄存器中获取接收到的数据字节数(对于上层应用很有必要)
重新设置DMA下次需要接收到的数据字节数(必须大于预期的接收值长度,否则计数减到0时又会复位,覆盖接收缓冲区中的数据,导致数据丢失!)
开启DMA通道,等待下一次的数据接收
可以设置信号量,通知应用程序数据接收完成,传递接收的数据长度,便于应用程序对数据的处理。
有待思考的
!!! 此处的接收缓冲区时来自哪里? uart1的数据缓冲区,还是DMA的接收数据缓冲区,最大支持多少个字节???
!!! DMA发送数据,网上也有看到将配置封装在发送函数中,如
uart1_dma_send_data(uint8_t* buf, uint32_t len),这个好处是,可以变化mem地址(buf数组,以及长度可以适当配置变化),不错!
!!! DMA接收函数,应用DMA中断判断接收完成只能依赖于DMA配置中字节长度,支持DMA传输完成,传输过半,传输错误,但对于不固定长度接收数据,this is a question.
注意:
DMA外设和DMA通道有对应关系,需要参考stm32手册
DMA传输数据时,需要明确传输的字节数目
DMA使能情况下,不能配置传输字节数到DMA寄存器,所以也不会产生DMA数据传输(因为传输字节数目为0)
hal_uart_dma.c
#include "includes.h"
/*
DMA方式介绍:
DMA使用流程:
1. 配置
外设端:
- 串口引脚GPIO配置
- 串口功能参数配置(数据位格式,波特率等),此处还需要**配置对应的DMA请求允许**。
- 如果有中断,还需要配置中断优先级
DMA端:
- DMA功能配置
- 初始化DMA通道DMA_Init(DMA1_Channel4,&DMA_InitStructure);
。 DMA源(Memory)/目的(外设)地址
。 DMA的传输方向
。 DMA的buffer size
。 DMA外设(DISABLE)/Memory(ENABLE)地址自增使能配置
。 DMA传输字节格式(支持byte,half-word,word)
。 DMA传输方式(Normal和Circle)
。 DMA传输优先级(共有四种,)
。 DMA m2m使能/失能配置(此处不是用于m2m所以配置为DISABLE)
- 清除中断标志位
- 此处应DISABLE DMA通道,否则配置完成即会产生DMA数据传输(非期望数据)
- 使能DMA发送完成中断
- DMA中断服务函数
发送数据完成后,即关闭DMA通道,发送信号量到应用程序
外设部分配置
2. 使能(使用)
应用程序需要发送数据时:
- 将要发送的数据准备好,并且要知道发送多少单位数据(发送字节数)
- 配置DMA要发送的字节数,使能DMA即可.
*/
//#define DMA_USART1_DR_Base (USART1_BASE + 0x4) //0x40013804
#define DMA_USART1_DR_Base 0x40013804
//1. 串口1端口配置
void hal_debug_gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//DBTX PA9 uart1_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);
//DBRX PA10 uart1_rx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//2. 串口功能配置
void hal_debug_func_config(void)
{
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
//config uart DMA request
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//enable usart1 dma send request
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //enable usart1 dma recieve request
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE); //enable usart1 idle interrupt
USART_Cmd(USART1,ENABLE);
}
//
void hal_debug_nvic_config(void){
NVIC_InitTypeDef NVIC_InitStructure;
//uart1 interrupt
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//dma interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; //
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//3. 串口初始化
void hal_debug_init(void)
{
hal_debug_gpio_config();
hal_debug_func_config();
hal_debug_nvic_config();
}
//////////////////////DMA config/////////////////////////////////
//1. uart dma configs
void uart_dma_init(void){
DMA_InitTypeDef DMA_InitStructure;
//Tx DMA CONFIG
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //enable DMA1 clock
DMA_Cmd(DMA1_Channel4,DISABLE); //close DMA Channel
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = DMA_USART1_DR_Base; //(uint32_t)(&USART1->DR)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_Tx_Buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = USART1_TX_BSIZE;
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_Channel4,&DMA_InitStructure);
DMA_ClearFlag(DMA1_FLAG_GL4); // clear all DMA flags
//DMA_Cmd(DMA1_Channel4,ENABLE); // close DMA Channel
DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); //open DMA send inttrupt
//Rx DMA CONFIG
DMA_Cmd(DMA1_Channel5, DISABLE); //
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_Rx_Buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = USART1_RX_BSIZE;
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_Channel5, &DMA_InitStructure);
DMA_ClearFlag(DMA1_FLAG_GL5);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
///////////////////////uart dma send//////////////////////
void DMA1_Channel4_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_FLAG_TC4)==SET)
{
DMA_ClearFlag(DMA1_FLAG_GL4);
DMA_Cmd(DMA1_Channel4, DISABLE);
OSMboxPost(mbLumModule_Tx, (void*)1);
}
}
void uart_dma_send_enable(uint16_t size)
{
DMA1_Channel4->CNDTR = (uint16_t)size;
DMA_Cmd(DMA1_Channel4, ENABLE);
}
void uart1_dma_send_data(void)
{
uint8_t err;
uint16_t i;
uint16_t USART1_Tx_Index=0;
for(i=0;i<8;i++){
USART1_Tx_Buf[USART1_Tx_Index++]=i;
}
uart_dma_send_enable(USART1_Tx_Index);
OSMboxPend(mbLumModule_Tx, 5000, &err);
}
///////////////////////uart dma send//////////////////////
///////////////////////uart dma recv//////////////////////
void uart1_dma_recv_data(void)
{
uint16_t index = 0;
DMA_Cmd(DMA1_Channel5, DISABLE);
DMA_ClearFlag(DMA1_FLAG_GL5);
//index = USART1_RX_BSIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
DMA1_Channel5->CNDTR = USART1_RX_BSIZE;
DMA_Cmd(DMA1_Channel5, ENABLE);
//OSMboxPost(mbLumModule_Rx,USART1_Rx_Buf);
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
{
uart1_dma_recv_data();
USART_ClearITPendingBit(USART1,USART_IT_IDLE);
}
}
///////////////////////uart dma recv//////////////////////
2. app_test.c
该文件为app_test线程,用于1s发送一次串口数据,其中发送串口数据中应用了信号量,如果没有等待到信号量,最大等待时间为5s(加上此处的1s周期则为6s)。
#include "includes.h"
OS_STK gTest[APP_TEST_STK_SIZE];
uint8_t USART1_Tx_Buf[USART1_TX_BSIZE] = {0};
OS_EVENT *gSemEvent1 = NULL;
OS_EVENT *mbLumModule_Tx = NULL;
void app_test(void* p_arg){
(void)p_arg;
//create new event
gSemEvent1 = OSSemCreate(2);
mbLumModule_Tx = OSMboxCreate((void*)0);
while(1){
//OSSemPost(gSemEvent1);
OSTimeDly(1000);
//printf("hello world!\r\n");
uart1_dma_send_data();
}
}
ucos_main.c
该函数用于创建ucos任务,一个main函数,一个创建任务的任务函数。
其中app_test任务就是这边uart DMA发送数据的任务。
#include "includes.h"
/*
1. 主函数
用于启动ucos-ii操作系统,启动第一个启动任务
2. 启动任务启动其他的任务
*/
static OS_STK gTaskStartStk[APP_TASK_START_STK_SIZE]; //定义栈
static void App_TaskStart(void *p_arg);
static void app_task_create (void);
//1. main
int main(void){
INT8U os_err;
OSInit();
os_err = OSTaskCreateExt((void (*)(void *)) App_TaskStart, /* Create the start task. */
(void * ) 0,
(OS_STK * )&gTaskStartStk[APP_TASK_START_STK_SIZE - 1],
(INT8U ) APP_TASK_START_PRIO,
(INT16U ) APP_TASK_START_PRIO,
(OS_STK * )&gTaskStartStk[0],
(INT32U ) APP_TASK_START_STK_SIZE,
(void * )0,
(INT16U )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
#if (OS_TASK_NAME_SIZE >= 11)
OSTaskNameSet(APP_TASK_START_PRIO, (INT8U *)"Start Task", &os_err);
#endif
OSStart();
}
//2. start task
static void App_TaskStart(void *p_arg)
{
(void)p_arg;
/*hal init*/
hal_dirvers_init();
//printf("uCos-II V2.86 FM.\r\n");
#if (OS_TASK_STAT_EN > 0)
OSStatInit(); /* Determine CPU capacity.*/
#endif
//printf("Create App Task.\r\n");
/*creat other app*/
app_task_create();
while(1){
OSTimeDly(1000);
hal_led_toggle(1); //led_toggle
}
}
/*
Create APP Task
*/
static void app_task_create (void){
INT8U os_err;
//test task
os_err = OSTaskCreate(app_test,
(void *)0,
&gTest[APP_TEST_STK_SIZE-1],
APP_TEST_PRIO);
#if (OS_TASK_NAME_SIZE >= 20)
OSTaskNameSet(APP_TEST_PRIO, (INT8U *)"test task", &os_err);
#endif
//led toggle task
/*****************************************************************************************/
os_err = OSTaskCreate((void (*)(void *))app_led_toggle,
(void*)0,
(OS_STK*)&gTaskLedToggle[APP_TASK_LED_STK_SIZE-1],
(INT8U)APP_TASK_LED_PRIO
);
#if (OS_TASK_NAME_SIZE >= 20)
OSTaskNameSet(APP_TASK_LED_PRIO, (INT8U *)"led_toggle", &os_err);
#endif
/*****************************************************************************************/
#if 0
//task 1
/*****************************************************************************************/
os_err = OSTaskCreate(app_task1,
(void*)0,
&gTask1[APP_TASK1_STK_SIZE-1],
APP_TASK1_PRIO);
/*****************************************************************************************/
//task 2
/*****************************************************************************************/
os_err = OSTaskCreate(app_task2,
(void*)0,
&gTask2[APP_TASK2_STK_SIZE-1],
APP_TASK2_PRIO);
/*****************************************************************************************/
//task 3
/*****************************************************************************************/
os_err = OSTaskCreate(app_task3,
(void*)0,
&gTask3[APP_TASK3_STK_SIZE-1],
APP_TASK3_PRIO);
/*****************************************************************************************/
#endif
}
上一篇:向STM32串口发送数据的标准函数
下一篇:如何下载stm32系列单片机的固件库
推荐阅读
史海拾趣
对于光检测T型反馈电路,网友可能提出多方面的问题,以下是一些可能的问题及相应的回答:
一、电路结构与原理
问题1:光检测T型反馈电路的基本结构是怎样的?
回答:光检测T型反馈电路通常由光电探测器(如光电二极管、光电三极管等)、运算放大器、T型反馈网络及相关的电阻、电容等元件组成。光电探测器负责将光信号转换为电信号,运算放大器对电信号进行放大,而T型反馈网络则用于调整放大电路的增益和稳定性。
问题2:T型反馈电路相比传统反馈电路有哪些优势?
回答:T型反馈电路的主要优势在于其能够使用较小的电阻组合来实现较大的放大倍数,从而避免了使用高阻值电阻带来的实装困难和稳定性问题。此外,T型反馈电路还能有效减少温度漂移引起的静态误差,提高电路的整体性能。
二、电路设计与调试
问题3:在设计光检测T型反馈电路时,如何选择合适的电阻值?
回答:在设计电路时,电阻值的选择应基于所需的放大倍数、稳定性及功耗等因素。通常,R1和R11的阻值应相等或相近,而R12和R13的阻值则根据所需的增益进行调整。此外,还应注意选择稳定性高的电阻,以减少温度漂移对电路性能的影响。
问题4:如何进行光检测T型反馈电路的调试?
回答:电路调试时,首先应检查各元件的连接是否正确,然后逐步加电观察电路的工作状态。在调试过程中,可使用可调电阻对电路的增益进行微调,以达到预期的放大效果。同时,还应注意观察电路的稳定性和噪声水平,确保电路满足设计要求。
三、应用与性能
问题5:光检测T型反馈电路在哪些领域有应用?
回答:光检测T型反馈电路在光电检测、信号处理、通信技术等领域有着广泛的应用。例如,在光电传感系统中,它可用于将微弱的光信号转换为放大的电信号;在信号处理电路中,它可用于提高信号的信噪比和动态范围;在通信系统中,它可用于增强信号的传输距离和稳定性。
问题6:如何评估光检测T型反馈电路的性能?
回答:评估光检测T型反馈电路的性能时,应关注其增益、稳定性、噪声水平、带宽等关键指标。增益是指电路对输入信号的放大能力;稳定性则是指电路在不同工作环境下的工作可靠性;噪声水平则反映了电路内部噪声对信号质量的影响;带宽则决定了电路能够处理信号的频率范围。这些指标的综合表现将直接影响电路在实际应用中的效果。
为了挽救Elpida Memory,日本政府采取了积极的援助措施。2009年,日本政府通过《产业再生法》修正案,向Elpida Memory提供了数百亿日元的公共资金和融资支持。这些资金帮助Elpida Memory度过了最困难的时期,并为其后续的重组和发展提供了有力的支持。
Helium公司成立于2013年,由Shawn Fanning、Amir Haleem和Sean Carey共同创立。在创立初期,Helium专注于物联网无线网络技术的研究,但并未迅速获得市场关注。这一时期,电子行业正处于创新与转型阶段,物联网作为新兴领域展现出巨大潜力。Helium团队预见到了物联网的发展趋势,但由于缺乏明确的商业模式,其网络发展并未大规模铺开。然而,这段时期的积累为Helium后续的技术突破和市场拓展奠定了坚实基础。
ET Enterprises Ltd公司的历史可以追溯到1930年代,当时它作为EMI公司的一部分,开始涉足光检测技术领域。在这个早期阶段,公司致力于研究光信号的特性及其检测方法,为后续的光电倍增管技术奠定基础。
近年来,ET Enterprises Ltd公司经历了一系列的收购和战略合作。这些举措不仅进一步增强了公司的实力和市场地位,也为公司的未来发展注入了新的活力。例如,公司成为得克萨斯州Ludlum Measurements Inc.的子公司后,受益于美国光电倍增管生产商ADIT的生产设施和ET Enterprises的开发设施的综合资源,为公司的持续发展提供了有力支持。
以上五个故事概述了ET Enterprises Ltd公司的发展历程和关键阶段,展示了公司在电子行业中不断崛起和持续发展的过程。
随着技术的不断进步和市场需求的增长,ET Enterprises Ltd公司开始推出多种类型的光电倍增管产品,包括普通可见光型、紫外灵敏型、日盲型等。同时,公司也积极拓展国际市场,与全球各地的客户建立合作关系,进一步巩固了其在光电倍增管领域的领先地位。
一种具有功耗管理特性的DSP处理器的结构设计。该处理器采用4级流水线和增强型的哈佛并行系统结构及完善的时钟管理模块,提供了一种DSP处理器的集成设 … 查看全部问答∨ |
|
史玉柱的巨人网络于11月初赴美上市,成为国内首家登陆纽交所的网络公司;距此三个多月前,郭广昌旗下内地最大的综合民企复星国际,在香港联交所正式挂牌。 史、郭二位,前者是擅长实操、性情偏执独裁、几经坎坷沉浮的“著名失败者”,后者是深谙资 ...… 查看全部问答∨ |
|
把 LM4F230 系列 和 9000 系列 结构框图 做个对照,了解它们各自的特点 见彩色框框中 [ 本帖最后由 蓝雨夜 于 2011-10-8 09:51 编辑 ]… 查看全部问答∨ |
KEIL-MDK下,采用最简单的BLANKY程序模拟仿真,设备选用LM3S9B96,外设窗口下只有内核外设窗口,且仿真出错,显示某些内存单元不可读写等内容;若器件选用LM3S8986则不存在任何问题,不知何故? 是否是MDK目前还不完全支持LM3S9B96?… 查看全部问答∨ |
这个片子已经调试了两天了,之前跑一些LED灯,串口什么的程序都没问题,焊接之后测量电压也正确。 焊接之后,出现过几次Wrong AHB ID的错误,导致程序不能下载。第一次出现之后,发现是LDO引脚有点虚焊,电压不对。后来重新点了锡,电压就对了,程 ...… 查看全部问答∨ |