查看: 1386|回复: 0

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

[复制链接]
  • TA的每日心情
    开心
    2018-7-5 13:19
  • 签到天数: 70 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2017-12-5 09:02:38 | 显示全部楼层 |阅读模式
    分享到:
    上一篇文章我们对硬件资源有了一些认识,然后通过样例程序的编译下来,了解了开发工具的使用。最后我们分析了一个简单的外设例子,对这款单片机有了初步的认识。接下来我们继续分析两个外设例子,进一步了解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,了解其功能和大概步骤,然后再深入分析代码,前后对应,细节随着使用慢慢就积累起来了。
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-19 06:49 , Processed in 0.129311 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.