TA的每日心情 | 开心 2018-7-5 13:19 |
---|
签到天数: 70 天 连续签到: 1 天 [LV.6]常住居民II
|
上一篇文章我们对硬件资源有了一些认识,然后通过样例程序的编译下来,了解了开发工具的使用。最后我们分析了一个简单的外设例子,对这款单片机有了初步的认识。接下来我们继续分析两个外设例子,进一步了解ST提供的HAL库的使用方法和习惯特点。
因为后面我想使用数字麦克风实现录音的功能,将会用到DMA传输数据,所以我们先分析分析DMA的例子,进阶的串口是常用的调试接口,我们再看看DMA传递串口数据的例子。本篇(上)中分析DMA的,《STM32F769 Disco学习-代码分析进阶(下)》中再分析DMA传递串口数据。
下面开始, ST库此目录下STM32Cube_FW_F7_V1.8.0\Projects\STM32F769I-Discovery\Examples提供了常用外设的例子,我们打开DMA的。
首先还是先看readme,他说将一个字从flash传递到内部的sram。然后是具体的步骤,先HAL库的初始化、时钟设置成216m,设置DMA2传输FLASH的数据到RAM。传输过程是,软件触发启动,然后原地址和目标地址同时累加,最后传输结束后出阿发一个中断并进入回调函数。
板上上LED显示传输状态,LED2亮表示传输完成,LED1以是出错了,具体错误看闪烁速度。
下面说修改main.h的配置可以选择不同的数据流。再向下是很多提示,我把握整体流程,深入代码具体看一看,有一些认识后再看这些提示。
打开main.C
第一句MPU_Config(); 内存保护单元初始化
第二句CPU_CACHE_Enable(); 启动cpu缓存,f7之后加入的cpu缓存,缓存一般配合MPU使用。这两句具体的作用不深入研究,还是关注本边主题。
三四句HAL_Init(); SystemClock_Config();和readme中介绍具体的步骤开始对应
At the beginning of the main program the HAL_Init() function is called to reset all the peripherals, initialize the Flash interface and the systick.Then the SystemClock_Config() function is used to configure the system clock (SYSCLK) to run at 216 MHz.
五六句,初始化灯
BSP_LED_Init(LED1);
BSP_LED_Init(LED2);
七八句,给两个状态标志位赋初值。
/* Set to 1 if an transfer error is detected */
transferErrorDetected = 0;
transferCompleteDetected = 0;
第九句,DMA初始化,稍后重点分析。
DMA_Config();
最后进入while loop
两个if判断上面提到的标志位,如果有错误LED1闪烁,如果完成LED2亮。
整体流程清楚了,我看重点来看看DMA_Config();
注释说的很详细,我们对着注释逐句的理解下配置代码。
__HAL_RCC_DMA2_CLK_ENABLE();使能DMA2时钟
DmaHandle.Init.Channel = DMA_CHANNEL;设置通道,goto看下DMA_CHANNEL;跳到main.h有如下描述
和readme中说的对应了It is possible to select a different stream for the DMA transferexample by modifying defines values in the file main.h.
DmaHandle.Init.Direction = DMA_MEMORY_TO_MEMORY;模式为存储器到存储器,这里要说明只有DMA2支持存储器到存储器,readme中有提到Note that only DMA2 stream are able to perform Memory-to-Memory transfers.
DmaHandle.Init.PeriphInc = DMA_PINC_ENABLE;DmaHandle.Init.MemInc = DMA_MINC_ENABLE;外设和存储器都使能增量
DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;设置成WORD,32位的。
DmaHandle.Init.Mode = DMA_NORMAL;普通模式,来由两种,不深究
DmaHandle.Init.Priority = DMA_PRIORITY_HIGH;优先级高
DmaHandle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;DmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;没有使能
DmaHandle.Init.MemBurst = DMA_MBURST_SINGLE;DmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE;单次传输
DmaHandle.Instance = DMA_INSTANCE;DMA2,数据流0
if (HAL_DMA_Init(&DmaHandle) != HAL_OK){ /* Initialization Error */ Error_Handler();}初始化,不成功提示错误。
HAL_DMA_RegisterCallback(&DmaHandle,HAL_DMA_XFER_CPLT_CB_ID,TransferComplete);HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_ERROR_CB_ID, TransferError);配置回调函数,&DmaHandle是我们配置参数结构体,HAL_DMA_XFER_CPLT_CB_ID是中断源,具体看下,枚举出了7种中断。
typedef enum{ HAL_DMA_XFER_CPLT_CB_ID = 0x00U, /*!< Full transfer */ HAL_DMA_XFER_HALFCPLT_CB_ID = 0x01U, /*!< Half Transfer */ HAL_DMA_XFER_M1CPLT_CB_ID = 0x02U, /*!< M1 Full Transfer */ HAL_DMA_XFER_M1HALFCPLT_CB_ID = 0x03U, /*!< M1 Half Transfer */ HAL_DMA_XFER_ERROR_CB_ID = 0x04U, /*!< Error */ HAL_DMA_XFER_ABORT_CB_ID = 0x05U, /*!< Abort */ HAL_DMA_XFER_ALL_CB_ID = 0x06U /*!< All */}HAL_DMA_CallbackIDTypeDef;第三个参数TransferComplete是我们自己编写的回调函数,内容是将标志位置1.
static void TransferComplete(DMA_HandleTypeDef *DmaHandle){ transferCompleteDetected = 1;}
HAL_NVIC_SetPriority(DMA_INSTANCE_IRQ, 0, 0);设置中断优先级,看下原函数
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority){ uint32_t prioritygroup = 0x00; /* Check the parameters */ assert_param(IS_NVIC_SUB_PRIORITY(SubPriority)); assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority)); prioritygroup = NVIC_GetPriorityGrouping(); NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));}第二个和第三个参数是抢占优先级和响应优先级,有点RTOS的意思
HAL_NVIC_EnableIRQ(DMA_INSTANCE_IRQ);使能中断
if (HAL_DMA_Start_IT(&DmaHandle, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK) { /* Transfer Error */ Error_Handler(); }IT是中断的方式,第一个参数:DMA参数结构体;第二个参数:flash中的数组地址;第三个参数:内存中的地址;第四个参数:数据类型,32位的。
分析完毕,我们来跑一下看看,LED1亮了。仿真来看看ram的变化。首先定位在断点在初始化DMA之前,观察aSRC_Const_Buffer[0](FLASH)和aDST_Buffer[0]的变化。
两图对比我们看到在执行完DMA初始化之后,FLASH中的数据被转移到了RAM中,CPU未参与其中。
总结,还是上一篇提到的思想,先从宏观着手,看readme,了解其功能和大概步骤,然后再深入分析代码,前后对应,细节随着使用慢慢就积累起来了。 |
|