本人是个大三学生,同时也是小白,16年10月份开始接触STM32F4。
想问论坛里的大神,几个DMA的问题。
首先感谢各位大神的回答,同时也恳请各位大神不要喷我,因为我是学机械专业的.......
我想知道DMA1本身之间的关系,数据流和通道,是一个通道只能有一个数据流么?这个视频里没说到,我就有点懵。
还有就是DMA1和DMA2之间会干涉嘛?
我这里有一个DJI官方提供的程序,还有一个我自己仿照着它的写的,单独使用的时候都正常,如果放在一块用,就卡住了,肯定各位指出毛病,小弟感激不谢。
DJI官方:
#include "dbus.h"
volatile unsigned char sbus_rx_buffer[25];
RC_Ctl_t RC_Ctl;
/* ----------------------- Function Implements ---------------------------- */
/******************************************************************************
* @fn RC_Init
*
* @brief configure stm32 usart2 port
* - USART Parameters
* - 100Kbps
* - 8-N-1
* - DMA Mode
*
* @return None.
*
*
@note This code is fully tested on STM32F405RGT6 Platform, You can port it
* to the other platform.
*/
void DBUS_Init(void)
{
/* -------------- Enable Module Clock Source ----------------------------*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource3, GPIO_AF_USART2);
/* -------------- Configure GPIO ---------------------------------------*/
{
GPIO_InitTypeDef gpio;
USART_InitTypeDef usart2;
gpio.GPIO_Pin = GPIO_Pin_3 ;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Speed = GPIO_Speed_100MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
USART_DeInit(USART2);
usart2.USART_BaudRate = 100000;
usart2.USART_WordLength = USART_WordLength_8b;
usart2.USART_StopBits = USART_StopBits_1;
usart2.USART_Parity = USART_Parity_Even;
usart2.USART_Mode = USART_Mode_Rx;
usart2.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2,&usart2);
USART_Cmd(USART2,ENABLE);
USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);
}
/* -------------- Configure NVIC ---------------------------------------*/
{
NVIC_InitTypeDef nvic;
nvic.NVIC_IRQChannel = DMA1_Stream5_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 1;
nvic.NVIC_IRQChannelSubPriority = 2;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
}
/* -------------- Configure DMA -----------------------------------------*/
{
DMA_InitTypeDef dma;
DMA_DeInit(DMA1_Stream5);
dma.DMA_Channel = DMA_Channel_4;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR);
dma.DMA_Memory0BaseAddr = (uint32_t)sbus_rx_buffer;
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 18;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_VeryHigh;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
dma.DMA_MemoryBurst = DMA_Mode_Normal;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5,&dma);
DMA_ITConfig(DMA1_Stream5,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA1_Stream5,ENABLE);
}
}
/******************************************************************************
* @fn DMA1_Stream5_IRQHandler
*
* @brief USART2 DMA ISR
*
* @return None.
*
* @note This code is fully tested on STM32F405RGT6 Platform, You can port it
* to the other platform.
*/
void DMA1_Stream5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5))
{
DMA_ClearFlag(DMA1_Stream5, DMA_FLAG_TCIF5);
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
RC_Ctl.rc.ch0 = (sbus_rx_buffer[0]| (sbus_rx_buffer[1] << 8)) & 0x07ff; //!< Channel 0
RC_Ctl.rc.ch1 = ((sbus_rx_buffer[1] >> 3) | (sbus_rx_buffer[2] << 5)) & 0x07ff; //!< Channel 1
RC_Ctl.rc.ch2 = ((sbus_rx_buffer[2] >> 6) | (sbus_rx_buffer[3] << 2) | //!< Channel 2
(sbus_rx_buffer[4] << 10)) & 0x07ff;
RC_Ctl.rc.ch3 = ((sbus_rx_buffer[4] >> 1) | (sbus_rx_buffer[5] << 7)) & 0x07ff; //!< Channel 3
RC_Ctl.rc.s1 = ((sbus_rx_buffer[5] >> 4)& 0x000C) >> 2; //!< Switch left
RC_Ctl.rc.s2 = ((sbus_rx_buffer[5] >> 4)& 0x0003); //!< Switch right
RC_Ctl.mouse.x = sbus_rx_buffer[6] | (sbus_rx_buffer[7] << 8); //!< Mouse X axis
RC_Ctl.mouse.y = sbus_rx_buffer[8] | (sbus_rx_buffer[9] << 8); //!< Mouse Y axis
RC_Ctl.mouse.z = sbus_rx_buffer[10] | (sbus_rx_buffer[11] << 8); //!< Mouse Z axis
RC_Ctl.mouse.press_l = sbus_rx_buffer[12]; //!< Mouse Left Is Press ?
RC_Ctl.mouse.press_r = sbus_rx_buffer[13]; //!< Mouse Right Is Press ?
RC_Ctl.key.v = sbus_rx_buffer[14] | (sbus_rx_buffer[15] << 8); //!< KeyBoard value
}
}
小弟自己仿照着改写的:
#include "main.h"
volatile unsigned char gyro_rx_buffer[25];
MPU6050_t MPU6050;
/* ----------------------- Function Implements ---------------------------- */
/******************************************************************************
* @fn MPU6050_Init
*
* @brief configure stm32 usart2 port
* - USART Parameters
* - 100Kbps
* - 8-N-1
* - DMA Mode
*
* @return None.
*
* @note This code is fully tested on STM32F405RGT6 Platform, You can port it
* to the other platform.
*/
void MPU6050_Init(void)
{
/* -------------- Enable Module Clock Source ----------------------------*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10, GPIO_AF_USART1);
/* -------------- Configure GPIO ---------------------------------------*/
{
GPIO_InitTypeDef gpio;
USART_InitTypeDef usart1;
gpio.GPIO_Pin = GPIO_Pin_10 ;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_Speed = GPIO_Speed_100MHz;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
USART_DeInit(USART2);
usart1.USART_BaudRate = 115200;
usart1.USART_WordLength = USART_WordLength_8b;
usart1.USART_StopBits = USART_StopBits_1;
usart1.USART_Parity = USART_Parity_No;
usart1.USART_Mode = USART_Mode_Rx;
usart1.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&usart1);
USART_Cmd(USART1,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}
/* -------------- Configure NVIC ---------------------------------------*/
{
NVIC_InitTypeDef nvic;
nvic.NVIC_IRQChannel = DMA2_Stream5_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 1;
nvic.NVIC_IRQChannelSubPriority = 1;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
}
/* -------------- Configure DMA -----------------------------------------*/
{
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Stream5);
dma.DMA_Channel = DMA_Channel_4;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
dma.DMA_Memory0BaseAddr = (uint32_t)sbus_rx_buffer;
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 13;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_VeryHigh;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
dma.DMA_MemoryBurst = DMA_Mode_Normal;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream5,&dma);
DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA2_Stream5,ENABLE);
}
}
/******************************************************************************
* @fn DMA2_Stream5_IRQHandler
*
* @brief USART1 DMA ISR
*
* @return None.
*
* @note This code is fully tested on STM32F405RGT6 Platform, You can port it
* to the other platform.
*/
void DMA2_Stream5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream5, DMA_IT_TCIF5))
{
DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5);
DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5);
MPU6050.check = ((gyro_rx_buffer[0]<< 24) | (gyro_rx_buffer[1]) << 16| (gyro_rx_buffer[2])<< 8 | (gyro_rx_buffer[3]));
MPU6050.pitch = ((gyro_rx_buffer[7]) | (gyro_rx_buffer[8]<<8));
MPU6050.roll = ((gyro_rx_buffer[9]) | (gyro_rx_buffer[10]<<8));
MPU6050.yaw = ((gyro_rx_buffer[11])| (gyro_rx_buffer[12]<<8));
}
}
感谢您看到最后,还有一个问题就是,您觉得串口MPU6050用DMA接收数据合适嘛0.0
你可以这样想。其实就跟中断接收是一个道理,只是DMA没有执行具体的中断接收代码,也没用中断那样灵活的控制方案。
例如:DMA1的channel1和channel2设置为相同优先级(但是其实1的优先级比2高。因为硬件里默认是,两个通道设置为相同优先级的时候,编号号小的优先)。都在同一个时间(即同一个时钟周期)接收到传输数据请求。
这个请求有可能是来自CPU core,也有可能是来自外设usart等。
这时候DMA1会进行优先级判断,低优先的channel2会被挂起,DMA1先安排channnel1的任务,传输完channel1的数据后,再安排channnel2的动作。数据都不会丢,只是谁先完成谁后完成。
完成的时间,跟传输的速度和数据量有关。例如channnel1从串口2(只是假设,实际看处理器型号)接收速度115200bps的数据,channnel1在接收完1个byte后,第2个byte的请求要很久之后(10*1/115200=86.8us)才会到来,这段空余时间里DMA并不知道channnel1还有数据要接收,他会自动安排所有其他的传输请求,如果这时候channnel2是被挂起的,就会去传输channnel2的数据
如果channnel1是用的M2M模式,这种情况下,数据请求是一个接着一个的,直到传输CNDTR数量为0,DMA就会一直忙于执行channnel1的请求,直到channnel1完成后,转为执行channnel2的请求。这个执行时间跟数据量和总线的竞争仲裁有关。
这些东西建议详细看一下NVIC和总线仲裁的知识,其中逻辑是相通的
一周热门 更多>