STM32F769 Disco学习-代码分析进阶(上)

作者: houwenbo-417669
上传时间为: 2017-12-05 09:02 AM
2017-12-05
阅读:

上一篇文章我们对硬件资源有了一些认识,然后通过样例程序的编译下来,了解了开发工具的使用。最后我们分析了一个简单的外设例子,对这款单片机有了初步的认识。接下来我们继续分析两个外设例子,进一步了解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,了解其功能和大概步骤,然后再深入分析代码,前后对应,细节随着使用慢慢就积累起来了。

作者其它经验
全部评论 ()
条评论
写评论

创建讨论帖子

登录 后参与评论
系统提示