• 串口DMA


    转载:https://www.cnblogs.com/viggogao/p/11175101.html

    typedef struct
    {
      uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */
      uint32_t DMA_MemoryBaseAddr;     /*!< Specifies the memory base address for DMAy Channelx. */
      uint32_t DMA_DIR;                /*!< Specifies if the peripheral is the source or destination.
    										This parameter can be a value of @ref DMA_data_transfer_direction */
      uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Channel. 
    										The data unit is equal to the configuration set in DMA_PeripheralDataSize
    										or DMA_MemoryDataSize members depending in the transfer direction. */
      uint32_t DMA_PeripheralInc;      /*!< Specifies whether the Peripheral address register is incremented or not.
    										This parameter can be a value of @ref DMA_peripheral_incremented_mode */
      uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register is incremented or not.
    										This parameter can be a value of @ref DMA_memory_incremented_mode */
      uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
    										This parameter can be a value of @ref DMA_peripheral_data_size */
      uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.
    										This parameter can be a value of @ref DMA_memory_data_size */
      uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Channelx.
    										This parameter can be a value of @ref DMA_circular_normal_mode.
    										@note: The circular buffer mode cannot be used if the memory-to-memory
    											  data transfer is configured on the selected Channel */
      uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Channelx.
    										This parameter can be a value of @ref DMA_priority_level */
      uint32_t DMA_M2M;                /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
    										This parameter can be a value of @ref DMA_memory_to_memory */
    }DMA_InitTypeDef;
    
    
    
    typedef struct
    {
    	uint32_t periph_addr;       /*!< peripheral base address */
    	uint32_t periph_width;      /*!< transfer data size of peripheral */
    	uint32_t memory_addr;       /*!< memory base address */
    	uint32_t memory_width;      /*!< transfer data size of memory */
    	uint32_t number;            /*!< channel transfer number */
    	uint32_t priority;          /*!< channel priority level */
    	uint8_t periph_inc;         /*!< peripheral increasing mode */
    	uint8_t memory_inc;         /*!< memory increasing mode */
    	uint8_t direction;          /*!< channel data transfer direction */
    
    } dma_parameter_struct;
    

    大神将DMA形象的比喻成
    快递员将快递投递在快递柜中,等待我(收货人)从快递柜中取快递-----DMA就是缓冲器,就是快递柜。
    我在手机上下单寄快递,选择哪家快递,哪一个快递柜,存放什么物品,将快递进行寄出去。

    DMA方式

    例如:
    (1)数据搬运,你要告诉CPU你搬的数据的源地址,目的地址,然后启动,完成一个字节搬运,要浪费很多个CPU 时钟,如果有多个字节,以上动作需要重复N次,此时,CPU完全被这些动作占用了。
    (2)如果使用DMA,你只需要告诉DMA寄存器,你的源地址,目的地址,数据长度,动作类型(复制,异或等等),启动以后就可以丢给DMA处理,解放CPU了,差不多1个CLOCK,就能完成一个字节的操作。
    所以,相比起来,如果数据不是很少的话,使用DMA能大大节约系统资源与时间。

    DMA request pending
    pending(挂起):网络处于挂起状态,指发送的请求是“进行中”的状态,但还没有接到服务端的响应。(这类似于debug模式下加断点,请求被阻止住一样)

    STM32中DMA对应的通道图

    DMA1

    DMA2

    编程

    串口用DMA方式发送和接收,分以下几步:
    1)串口初始化
    2)DMA初始化
    3)发送数据
    4)接收数据

    1)串口初始化

    #define  DMASIZE 1024
    
    // 配置串口一的发送和接收的GPIO口功能,以及中断
    static void _uart1_gpio_init(void)
    {
    	NVIC_InitTypeDef NVIC_InitStructure;
    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA   |
    					 RCC_APB2Periph_USART1  |
    						 RCC_APB2Periph_AFIO, ENABLE) ;
    
    	GPIOA->CRH&=0XFFFFF00F;
    	GPIOA->CRH|=0X000008B0;//IO状态设置 10pin_上拉输入  9pin_推挽输出
    
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	/* Configure USART1 Rx as input floating */
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    	/* Configure USART1 Tx as alternate function push-pull */
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    
    	/* Enable the USART1 Interrupt */
    	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    
    	USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送完成标志,Transmission Complete flag */
    
    	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);// 采用空闲中断,目的是在产生空闲中断时,说明接收或者发送已经结束,此时可以读取DMA中的数据了。
    	//USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    	//USART_ITConfig(USART1, USART_IT_FE, ENABLE);
    }
    // 设置对应串口的波特率
    static void _uart_setbaudrate(USART_TypeDef* USARTx,u32 value)
    {
    	USART_InitTypeDef USART_InitStructure;
    	USART_InitStructure.USART_BaudRate =value;
    	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(USARTx, &USART_InitStructure);
    	USART_Cmd(USARTx, ENABLE);
    }
    

    2)初始化DMA

    u8 sendbuf[1024];
    u8 receivebuf[1024];
    static void _uart1_dma_configuration()
    {
    	DMA_InitTypeDef DMA_InitStructure;
    
    	/* DMA1 Channel6 (triggered by USART1 Rx event) Config */
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,
    						ENABLE);
    
    	/* DMA1 Channel5 (triggered by USART1 Rx event) Config */
    	DMA_DeInit(DMA1_Channel5);
    	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;// 初始化外设地址,相当于“哪家快递”
    	DMA_InitStructure.DMA_MemoryBaseAddr =(u32)receivebuf;// 内存地址,相当于几号柜
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据来源,即为收快递
    	DMA_InitStructure.DMA_BufferSize = DMASIZE ;// 缓存容量,即柜子大小
    	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_Cmd(DMA1_Channel5, ENABLE);// 启动DMA,即与快递公司签订合同,正式生效
    
    	/* DMA1 Channel4 (triggered by USART1 Tx event) Config */
    	DMA_DeInit(DMA1_Channel4);
    	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;  // 外设地址,串口1, 即发件的快递
    	DMA_InitStructure.DMA_MemoryBaseAddr =(u32)sendbuf;// 发送内存地址
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 外设为传送数据目的地,即发送数据,即快递是发件
    	DMA_InitStructure.DMA_BufferSize = 0;  //发送长度为0,即未有快递需要发送
    	DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化
    
    	USART_ITConfig(USART1, USART_IT_TC, ENABLE);// 使能串口发送完成中断
    	USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
    }
    

    3)数据发送

    流程:串口数据发送,全部数据发送完毕之后,会产生一个发送中断,所以,发送数据分为两部分
    A.发送数据
    B.中断处理

  • 相关阅读:
    CSS——before和after伪元素
    CSS——滑动门技术及应用
    CSS案例3(在线教育网站)
    CSS——背景渐变
    CSS字体图标
    CSS——精灵技术
    CSS——溢出文字隐藏
    Intellij IDEA -01 如何配置项目!
    Intellij Idea -02 如何将项目工程横向排列变成纵向排列
    java8 --新特性汇总
  • 原文地址:https://www.cnblogs.com/xuyan123/p/14451150.html
Copyright © 2020-2023  润新知