精华内容
下载资源
问答
  • S3C2410下DMA使用

    2013-11-22 15:37:32
    DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CPU的工作效率。 DMA大容量数据传输中非常重要...那么怎么使用DMA呢,S3C2410内部集成了DMA控制器,我们只需要简单的配置一下寄存器就可以实现DMA的传输了。

    DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CPU的工作效率。

    DMA大容量数据传输中非常重要,比如图像数据传输,SD卡数据传输,USB数据传输等等。

    S3C2410有四个DMA,每个DMA支持工作方式基本相同,但支持的source Dest可能略有不同。

    那么怎么使用DMA呢,S3C2410内部集成了DMA控制器,我们只需要简单的配置一下寄存器就可以实现DMA的传输了。

    步骤与要点:

    1.       数据从哪里来,到哪里去?

    使用DMA当然首先我们要知道数据的流向,DISRCx寄存器是DMA初始源寄存器存放了数据的源地址。DIDSTxDMA的初始目的寄存器,应该存放数据的目的地址。

    2.       数据走得什么总线?地址是否是固定的?

    我们还要知道源与目的数据存储设备是在什么总线上(AHB系统总线,一般是高速的比如内存,APB外围总线低速的,比如SDUART);

    以及数据传输结束以后起始地址还原到发送前的起始地址呢,还是在现在的末尾+1做为新的起始地址。

    这些设置在DISRCCxDIDSTCx两个寄存器里面配置。

    3.       数据以什么方式传输?源与目的是什么设备?要不要自动重载?

    需要确定数据的传输方式有请求还是握手(推荐使用HANDSHAKE,根据上面的总线确定与什么时钟同步(HCLKPCLK),是单元传输还是突发传输,是以字节传输还是字传输,是否重载。是单服务(只发送一次)还是多服务(不停循环发送),以及数据的传送大小。

    选择源与目的设备,这里DMA控制器支持:

       Ch0:nXDREQ0,UART0,SDI,Timer,USB EP1

       Ch1: nXDREQ1,UART1,I2SSDI,SPI0,USB EP2

       Ch2:I2SSDO,I2SSDI,SDI,Timer, USB EP3

       Ch3:UART1,SDI,SPI1,Timer, USB EP4

    最后还要确定中断是不是传输结束发生(CURR_TC记数是不是0)。

    这些都在DCONx中设置。

    4.       怎么开始传输DMA和停止DMA,这些在DMASKTRIG中设置。

    下面是DMASD卡中使用的一段示例:

    SD卡读的DMA设置:

    pISR_DMA0=(unsigned)DMA_end; //DMA中断服务函数入口地址,一次DMA传送结束发生rINTMSK = ~(BIT_DMA0); //DMA中断

    rDISRC0=(int)(Tx_buffer); //源地址在内存 就是从内存读数据到SD

    rDISRCC0=(0<<1)+(0<<0); //内存的总线是 AHB, 地址是自动增加inc

    rDIDST0=(U32)(SDIDAT); // 目的地址SD

    rDIDSTC0=(1<<1)+(1<<0); // 在总线APB, 地址是固定的因为SDFIFO是固定大的  

    rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;

    //handshake握手模式, PCLK同步,发送完产生中断, 单元传输, 单服务, SDI

    //不自动重载,每次发送一个字,发送大小

    rDMASKTRIG0=(0<<2)+(1<<1)+0; //不停止, DMA0 channel 启动,不用SW触发

    SD卡写的相应代码

    pISR_DMA0=(unsigned)DMA_end;

    rINTMSK = ~(BIT_DMA0);

    rDISRC0=(int)(Tx_buffer);                             

    rDISRCC0=(0<<1)+(0<<0);                           

    rDIDST0=(U32)(SDIDAT);                             

    rDIDSTC0=(1<<1)+(1<<0);                            

    rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;                                                        

    rDMASKTRIG0=(0<<2)+(1<<1)+0;
    <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
    阅读(168) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
    展开全文
  • STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道...
  • 首先要解决DMA怎么知道要接收的数据何时开始,何时结束的问题。 如果把DMA设成循环模式肯定是不行的,所以把DMA设置成正常模式。 STM32的串口有监测总线是否处于空闲的功能,我们可以使用这个功能,当数据传输完总线...

    首先要解决DMA怎么知道要接收的数据何时开始,何时结束的问题。而且每次传输完数据,要改变下一次数据长度。

    如果把DMA设成循环模式肯定是不行的,所以把DMA设置成正常模式。

    STM32的串口有监测总线是否处于空闲的功能,我们可以使用这个功能,当数据传输完总线变成空闲状态时产生中断,来对收到的数据进行处理。因此整个过程就变成:当一堆数据开始传输,DMA默默地把数据搬运到内存中,当这堆数据传输完成,总线变成空闲状态时,马上产生中断,在中断服务程序中去做相应处理。

    初始化程序:

    #define DMA_Rec_Len 10  //数据缓冲区大小
    u8 value[DMA_Rec_Len];
    
    void uart_init_DMA_IN(u32 bound)
    {
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
    
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
    //   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
    
       USART_DeInit(USART1);  //复位串口1
       //USART1_TX   PA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
       
        //USART1_RX  A.10
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10
    
        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
      
       //USART 初始化设置
      USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
      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(USART1, &USART_InitStructure); //初始化串口
        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   //使能串口1 DMA接收
        USART_Cmd(USART1, ENABLE);                    //使能串口 
     
        //相应的DMA配置
      DMA_DeInit(DMA1_Channel5);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5
      DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  //DMA外设ADC基地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (u32)value;  //DMA内存基地址
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存
      DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //DMA通道的DMA缓存的大小
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
      DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
      DMA_Init(DMA1_Channel5, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
    
        DMA_Cmd(DMA1_Channel5, ENABLE);  //正式驱动DMA传输
    }
    

    中断服务程序:

    void USART1_IRQHandler(void)                 //串口1中断服务程序
    {
    	 char i;
         if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
          {
              USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
              Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度
       
             //***********帧数据处理函数************//
              printf ("The lenght:%d\r\n",Usart1_Rec_Cnt);
              printf ("The data:\r\n");
    		  for(i=0;i<Usart1_Rec_Cnt;i++)
    		  {
    				USART_SendData(USART1,value[i]);
    				while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    		  }
             printf ("\r\nOver! \r\n");
            //*************************************//
             USART_ClearITPendingBit(USART1, USART_IT_IDLE);         //清除中断标志
    	 DMA_Cmd(DMA1_Channel5,DISABLE);
    	 //重新设置传输数据长度  
             DMA_SetCurrDataCounter(DMA1_Channel5,DMA_Rec_Len); 
    	 DMA_Cmd(DMA1_Channel5,ENABLE);  //开始下一次DMA
             
         } 
    } 

    设置DMA为正常模式,即只传输一次,当完成一次数据传输后,进入中断,对接收到的数据进行处理。然后清除中断标志,重新启动DMA进行下一次传输。


    思路来自:http://www.openedv.com/thread-63849-1-1.html


    展开全文
  • STM32——使用PWM+DMA实现脉冲发送精确控制

    万次阅读 多人点赞 2018-09-07 15:17:31
    我为什么要写这个代码。。。 之前用stm32写过脉冲发送的代码,用来控制步进电机,但是缺点明显,之前是用定时器中断做的,所以一但控制的...既然是用来控制步进电机,那么脉冲的数量和频率一定要可控,要不然怎么...

    太多小伙伴问我要代码,实在是无暇回复,这里我直接把网盘发出来吧,需要的小伙伴自取就可以了:
    https://pan.baidu.com/s/1CwizNXizIqGcEvI0bvMtWA 提取码: w36x

    我为什么要写这个代码。。。

    之前用stm32写过脉冲发送的代码,用来控制步进电机,但是缺点明显,之前是用定时器中断做的,所以一但控制的电机多起来,MCU资源占用就很大,这在大多数情况下是不可接受的,更不用说多轴联动了。
    最近做的步进电机CAN总线控制系统,就想顺便重新写驱动。希望做到占用很少的MCU资源,实现脉冲发送的精确控制。既然是用来控制步进电机,那么脉冲的数量频率一定要可控,要不然怎么实现电机的加减速曲线。于是就想到了DMA。

    DMA (直接存储器访问)
    DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。(资料来自百度百科)

    在记忆里,STM32的数据手册中有提到PWM有DMA触发的模式。那么这一次终于有用武之地了。

    show me your code !!!

    main.c

    #include "delay.h"
    #include "key.h"
    #include "sys.h"
    #include "usart.h"
    #include "dma.h"
    #include "timer.h"
    #define size 100
    
    extern u16 DMA1_MEM_LEN;
    extern DMA_InitTypeDef DMA_InitStructure;  
    u16 send_buf[size];
     
    int main(void)
    {	
    	int i;
    	int feedback;
    	delay_init();	
    	uart_init(115200);
    	KEY_Init();
    	DMA_Config(DMA1_Channel6, (u32)&TIM3->ARR, (u32)send_buf, size);
    	TIM3_PWM_Init(599,7199);
    	for(i = 0; i < size; ++i)
    	{
    		if(i != size - 1)
    		send_buf[i] = 100 + 10 * i;
    		else
    		send_buf[i] = 0;
    	}
    	DMA_Enable(DMA1_Channel6);
    	while(1)
    	{
    			feedback = DMA_send_feedback(DMA1_Channel6);
    			if(feedback != 0)
    			{
    				printf("-> ");
    				printf("%d\r\n", DMA_send_feedback(DMA1_Channel6));
    			}
    			if(KEY_Scan(0) == 1)
    			{
    				DMA_Enable(DMA1_Channel6);
    			}
    	}
    }
    

    main.c中的send_buf[size]是控制信息的来源,你想要如何发送脉冲,全靠这个buffer
    这里写图片描述
    这是send_buf的数据组成,size 决定了发送脉冲的数量information决定了脉冲的频率。至于脉冲的脉宽,可以在timer.c中的初始化函数中修改。

    dma.c

    #include "dma.h"
    
    extern u16 send_buf[100];
    extern 	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    DMA_InitTypeDef DMA_InitStructure;
    u16 DMA1_MEM_LEN;	 /* 保存DMA每次数据传送的长度 */
    
    /*
     *DMA1的各通道配置
     *这里的传输形式是固定的,这点要根据不同的情况来修改
     *从存储器->外设模式/8位数据宽度/存储器增量模式
     *DMA_CHx:DMA通道CHx
     *cpar:外设地址
     *cmar:存储器地址
     *cndtr:数据传输量
     */
    void DMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
    {
    	
     	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	/* 使能DMA钟源 */
    	delay_ms(5);
    	
      DMA_DeInit(DMA_CHx);   /* 将DMA的通道1寄存器重设为缺省值 */
    
    	DMA1_MEM_LEN=cndtr;
    	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  /* DMA外设基地址 */
    	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  /* DMA内存基地址 */
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  /* 数据传输方向,从内存读取发送到外设 */
    	DMA_InitStructure.DMA_BufferSize = cndtr;  /* DMA通道的DMA缓存的大小 */
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  /* 外设地址寄存器不变 */
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  /* 内存地址寄存器递增 */
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  /* 数据宽度为16位 */
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; /* 数据宽度为16位 */
    	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  /* 工作在正常模式 */
    	DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* DMA通道 x拥有中优先级 */
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  /* DMA通道x没有设置为内存到内存传输 */
    	DMA_Init(DMA_CHx, &DMA_InitStructure);  	
    } 
    
    /* 开启一次DMA传输 */
    void DMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
    {
    	DMA_Cmd(DMA_CHx, DISABLE );
    	TIM3->ARR = 2;	/* 由于最后一项是0,所以在最后的时刻ARR会被清零,导致下一次启动无效。*/
     	DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);
      	DMA_Cmd(DMA_CHx, ENABLE);
    	TIM_Cmd(TIM3, ENABLE);  /* 使能TIM3 */
    	TIM3->EGR = 0x00000001;	/* 由于最后一次ARR值为0,这是为了停止定时器对io口的操作,但是不要忽略了一点:CNT并没有停止计数,而且是不会再停下来,如果没有手动操作的话,所以需要在每次dma使能时加上一句,将EGR里的UG位置1,清零计数器 */
    }	  
    
    /*
     *进度反馈,返回剩下的数据量
     */
    u16 DMA_send_feedback(DMA_Channel_TypeDef* DMA_CHx)
    {
    	return DMA_CHx->CNDTR;
    } 
    
    

    dma.h

    #ifndef __DMA_H
    #define	__DMA_H	   
    #include "sys.h"
    #include "delay.h"
    #include "dma.h"
    #include "timer.h"
    #include "usart.h"
    #include "stm32f10x_dma.h"
    
    void NVIC_Configuration(void);				    					    
    
    void DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);//配置DMA1_CHx
    
    void DMA_Enable(DMA_Channel_TypeDef*DMA_CHx);//使能DMA1_CHx
    
    u16 DMA_send_feedback(DMA_Channel_TypeDef* DMA_CHx);
    
    void DMA1_Channel6_IRQHandler(void);
    #endif
    
    

    timer.c

    #include "timer.h"
    #include "led.h"
    #include "usart.h"
     
     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    /*
     *TIM3 PWM部分初始化 
     *PWM输出初始化
     *arr:自动重装值
     *psc:时钟预分频数
     */
    void TIM3_PWM_Init(u16 arr,u16 psc)
    {  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	/* 使能定时器3时钟 */
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  /* 使能GPIO外设 */   
     
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; /* TIM_CH1*/
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  /* 复用推挽输出 */
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);/* 初始化GPIO */
     
       /* 初始化TIM3 */
    	TIM_TimeBaseStructure.TIM_Period = arr; /* 设置在下一个更新事件装入活动的自动重装载寄存器周期的值 */
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; /* 设置用来作为TIMx时钟频率除数的预分频值 */
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; /* 设置时钟分割:TDTS = Tck_tim */
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  /*TIM向上计数模式 */
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* 根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 */
    	 
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* 选择定时器模式:TIM脉冲宽度调制模式1 */
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; /* 比较输出使能 */
    	//TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  /* 使能TIM3在CCR1上的预装载寄存器*/
    	TIM_OCInitStructure.TIM_Pulse= 100;
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; /* 输出极性:TIM输出比较极性高 */
    	TIM_OC1Init(TIM3, &TIM_OCInitStructure);  /* 根据T指定的参数初始化外设TIM3 OC1 */
    	//TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);	/* 如果是要调节占空比就把这行去掉注释,然后注释掉下面那行,再把DMA通道6改为DMA通道3 */
    	TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
    	TIM_Cmd(TIM3, ENABLE);  /* 使能TIM3 */
    	
    }
    
    

    timer.h

    #ifndef __TIMER_H
    #define __TIMER_H
    #include "sys.h"
    
    void TIM3_PWM_Init(u16 arr,u16 psc);
    
    #endif
    
    

    看看运行效果

    这里写图片描述
    垃圾示波器,玩玩就好。。。。
    篇幅限制,结果是最终将会发送100个脉冲,频率慢慢改变。但是在这个有一点需要提醒小伙伴们注意一下,send_bufsize并不是要多大有多大的,比较STM32的RAM有限,没办法一下子给你分配那么多空间,如果你强行分配的话,那么在编译过程中一定会报错,我在测试的时候,分配到3W+的时候已经差不多是极限了,但是这仅仅只是一个demo程序,在实际应用的时候不可能把RAM都给send_buf,所以如果想要发送大量的脉冲的话,比如我想发409600个脉冲给步进驱动器,那么我需要分多次发送。这部分我后面会继续做,有空会分享给小伙伴们。

    展开全文
  • 近日调试一块H7的板子, 板上资源丰富,运行速度很快, 我移植了Lwip等应用,然后想简单打开一下串口, 使用DMA形式接收. 但是无论怎么设置都没有正常收发. 可以进入回调函数, 但是接收数组内容一直是0, 就像DMA没有搬运...

    近日调试一块H7的板子, 板上资源丰富,运行速度很快, 我移植了Lwip等应用,然后想简单打开一下串口, 使用DMA形式接收. 但是无论怎么设置都没有正常收发.

    可以进入回调函数, 但是接收数组内容一直是0, 就像DMA没有搬运过来一样.

    调试良久,终于通畅可以跑满串口带宽:
    在这里插入图片描述
    下面说我是怎么搞的:

    1. 配置UART, 再cubeMX中点选我想用得uart8 , 设置波特率.
      在这里插入图片描述
    2. DMA选项开启. RX要启用循环模式, 这样收到一次就会再启动一次.
      在这里插入图片描述
      ok,到这里cubeMX的配置就完了, 网上都是这么写的. 点击在CubeMX IDE 点击保存,就生成代码了.

    然后我在代码端再加写一些代码:

    1. 在串口配置内, USER CODE 注释空间内添加 立刻启动接收. 接收1字节帮我DMA搬运去uart8_RXdata这个数组内. 在这里插入图片描述

    下面写一个函数叫: HAL_UART_RxCpltCallback, 这个函数库函数其实已经声明好了, 就等着用户自己写逻辑, 每次串口接收完我指定的数目后就会自动进入.

    进入这个回调函数后, 我就把uart8_Rxdata数据拿出来. 放去我逻辑缓冲区, 我在Freerots里面有个任务就是慢慢去解析这些数据的. 到这里没毛病.
    在这里插入图片描述
    下面就是把Ringbuffer内的东西打印出来.
    在这里插入图片描述
    到这整个过程就结束了. 可是结果很糟糕, 无论我发送什么字符, 都只收到0, 打印0.

    开始查资料:

    1. H7 DMA 访问空间有要求, 无法访问DTCM 0x2000000区域的RAM, 如果编程环境设置了,我的变量再这个区域, DMA就搬运不了.

    参考 : https://blog.csdn.net/qq_41544116/article/details/100155203
    在这里插入图片描述

    好, 我是CubeMX IDE, 是GCC环境, 查看LD文件, 查看MAP文件
    bss段 指定是在 0x24000000区域, map显示我的uart8_RXdata也是在这个区域内, 所以没问题. DMA可以访问.
    在这里插入图片描述

    1. 又折腾半天, 想起来配置LWIP的时候, 就是要配置MPU才能正常进行以太网收发. 由于H7内核达到480Mhz, CPU访问RAM都需要透过cache才能发挥性能. 所以H7芯片做了MPU这个部分来配置内存的访问策略. CPU访问SRAM 中间有CACHE的作用. 而DMA是直接操作SRAM空间. 所以要进行Cache策略配置.

    在MPU设置中加入一个区块, 把整个0x2400000空间取消buffer.

    在这里插入图片描述
    生成代码, 串口收发正常了.

    之前考虑过这个方面,使用了volatlie关键字, 使用ST提供的函数: SCB_InvalidateDCache_by_Addr((uint32_t *)uart8_Rxdata,2);
    都不好使.

    (完)

    展开全文
  • 文章目录一. STM32的DMA PWM原理1. DMA简介2. DMA方式输出PWM是怎么回事3. HAL库DMA配置PWM的几...使用DMA输出PWM可以精确控制脉冲数量,且可以精确控制脉冲周期与占空比,更重要的是使用DMA传输不消耗CPU资源。于是乎
  • STM32串口使用心得(一)——DMA+空闲中断接收

    万次阅读 多人点赞 2017-11-14 13:06:36
    之前曾经写过一篇《关于CubeMX的串口全双工接收发送锁死的问题》的文章,讨论了STM32的串口在全双工模式下会出现锁死问题...但这几天程序不知道怎么回事,又开始频繁地出现死机现象,而且仿真的时候会进入HardFault()。
  • 最近又要重新用32做点东西,发现一两年没怎么碰的结果就是,曾经熟得不行的东西都变得极度陌生,这种重新学习记忆的过程过于痛苦,果然还是要留下一些记录给之后失忆的自己的。 1.STM32CUBE配置 1.1 pinout设置 ...
  • 近期用RGB三色灯WS2812B做了个彩虹灯的小玩意,记录下使用过程 ...使用了CubeMX初始化TIM3的Channel4作为PWM的DMA输出功能 外设初始化配置 先让灯亮起来 //用于打开PWM, void WS281x_Show(uint16_t se...
  • DMA的初始化

    2016-12-23 19:33:44
    前言前面讲解了DMA的配置,我们怎么使用它,因此今天,我们讲讲怎么初始化DMA配置已经配置好了,是不是应该启用我们的配置啊。DMA通道工作状态寄存器DMAARM故名思意,该寄存器是来控制DMA要怎么运作的。 //启用配置 ...
  • s3c2440 DMA

    2018-02-10 16:20:50
    DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CPU的工作效率。...那么怎么使用DMA呢,S3C2410内部集成了DMA控制器,我们只需要简单的配置一下寄存器就可以实现DMA的传输了。步骤与要点:1....
  • dmaengine,dmatest, DW_DMAC driver

    千次阅读 2013-12-25 11:07:08
    linux dma engine framework提供了dmatest.c测试文件,用于测试,但是怎么使用这个文件呢? 首先一定要将该文件编译为ko文件,在测试时,insmod+参数 就可以启动这个函数  module 中使用参数主要有几个函数 : modu
  • stm32DMA通道 ADC通道

    2017-07-25 18:26:00
    DMA: 1.使用DAC的时候。将转化后得到的模拟信号通过IO口输出的时候。为什么还将IO口配置能输入模式 ...波形数据从内存带DAC是怎么DMA怎么传输的?: /* 配置DMA2 */ DMA_InitStructure.DMA_P...
  • PCIE_DMA实例一:xapp1052详细使用说明

    千次阅读 2017-04-26 18:38:36
    很多和我一样初学pcie的硬件工程师都会遇到这样一个问题,看了不少pcie相关的资料,还是搞不清这玩意儿到底该怎么用。于是我们打开ISE的core_generator工具,生成了一个pcie的ip核,用modelsim仿真一下example ...
  • DMA 复制的博客园的

    2020-07-18 23:07:57
    STM32 基DMA的DAC波形发生器 DAC是STM32系列的一个基本外设,可以将...使用DMA只需告诉DMA外设它要怎么搬移数据就可以处理其他事。 首先定义一下 #define DAC_DHR12R1 (u32)&(DAC->DHR12R1) //DAC DATA ...
  • 我们都知道,使用DMA方式传输数据可以占用更少的CPU资源,因此与其它操作系统一样, Linux支持硬盘以DMA方式转输数据,但在安装Red Hat7.0时关于DMA的默认选项是Disable的,当然你可以在安装时就enable它。...
  • STM32之串口DMA接收不定长数据

    千次阅读 2019-09-03 23:05:53
    使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口中断,在中断中读取数据就行了! 中断就是打断程序...
  • 裸机系列——DMA工作

    2011-04-17 15:52:00
    转至:http://blog.csdn.net/cybertan/archive/2009/10/19/4697516.aspx<br />DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CPU的工作效率。... 那么怎么使用DMA呢,S3C2410内部集成了DMA控制
  • 如何在Linux下用DMA方式传输数据

    千次阅读 2016-11-10 11:47:52
    我们都知道,使用DMA方式传输数据可以占用更少的CPU资源,因此与其它操作系统一样,Linux支持硬盘以DMA方式转输数据,但在安装Red Hat7.0时关于DMA的默认选项是Disable的,当然你可以在安装时就enable它。...
  • 请问在Vivado中想使用ip核:DMA/Bridge Subsystem for PCI Express,我的板子是zynq UltraScale...但是我没有找到这个ip核,请问怎么使用呀?或者能找到一个替代的吗?我需要使用这个与DDR传输数据。谢谢!标准图见下:
  • STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道...
  • STM32 DMA加串口空闲中断接收数据

    千次阅读 2019-12-27 10:42:47
    STM32使用DMA加串口空闲中断接收数据 STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32...
  • DAC是STM32系列的一个基本外设,可以将数字信号转化成模拟信号,这次我将使用DAC来输出一个特定波形。...使用DMA只需告诉DMA外设它要怎么搬移数据就可以处理其他事。 首先定义一下 #define DAC_DHR12R1 (u32)&...
  • STM32并口数据通过DMA传输

    千次阅读 2020-04-19 15:40:22
    但是对于小封装类的芯片(64PIN)并未提供该功能,那么该怎么处理呢?我认为通过DMA进行并行数据的读写可以解决上述问题。 本方法有个缺陷就是必须使用同一组IO口,如PA或PB,这样直接对寄存器IDR进行读写,达到...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 143
精华内容 57
关键字:

dma怎么使用