STM32L496 Discovery kit时钟和串口

作者: NumBerOneFrog
上传时间为: 2018-02-02 01:57 PM
2018-02-02
阅读:

代码还是从stm32cubel4开始说起吧,该封装包括微控制器底层(LL)和硬件抽象层(HAL),另外每一个开发板还有支持板子特性的封装(BSP),这三类构成了底层软件,通过中间件就可以到上层应用。

然后开始看我的第一个工程LED,选择的代码阅读工具是sourceinsight,该工具可以方便地定位代码。

硬件相关的代码都是从启动代码开始,也就是板子一上电开始执行的代码位置,在stm32系列微控制器中一般是startup_stm32xxxxx.s文件名,根据处理器类型在这里是startup_stm32l496xx.s文件。启动文件主要的作用是:

设置初始化堆栈指针SP

设置初始程序计数器PC

设置异常向量表入口

设置C库的__mian分支,最终调用主函数main()

Reset异常,也是上电之后会进入的异常,执行系统初始化,进入主函数

Reset_HandlerPROC

EXPORTReset_Handler[WEAK]

IMPORTSystemInit

IMPORT__main

LDRR0, =SystemInit

BLXR0

LDRR0, =__main

BXR0

ENDP

void SystemInit(void)位于system_stm32l4xx.c文件中,用于设置微控制器系统。像FPU、RCC的设置。

然后就会跳到主函数,也是自己创建的C入口,一般文件名是main.c。在LED工程中,使用HAL来配置和使用GPIO控制LED等的亮与灭。因此在操作GPIO之前需要对HAL库初始化,并且在系统时钟初始化之前调用HAL_StatusTypeDef HAL_Init(void),主要作用是:

配置Flash预读取使能,指令和数据缓存使能

配置滴答计时器作为时间基准

设置向量中断控制器分组优先级

底层硬件初始化

在主函数里面配置系统时钟为80MHz,系统时钟源是PLL。时钟的具体配置在之后详细介绍,主要是设置PLL为时钟源,对RCC Oscillators配置,CPU, AHB 和APB总线时钟配置。

然后就进入到外设功能模块的设置,void BSP_LED_Init(Led_TypeDef Led),首先是对LED对应引脚设置,使能对应GPIO时钟,设置为输出模式,默认关闭LED。

最后在一个无限循环中开启LED1,关闭LED2,延时500ms,关闭LED1,开启LED2,延时500ms。对应的LED开关为void BSP_LED_On(Led_TypeDef Led),void BSP_LED_Off(Led_TypeDef Led),延时函数使用void HAL_Delay(uint32_t Delay)。

接下来就在此工程基础上实现其他功能。

另外上一节发现的不添加stm32l4xx_it.c和对应的头文件LED灯就跑不起来,究其原因,主要是在stm32l4xx_it.c中有一个中断void SysTick_Handler(void)处理滴答时钟,与时钟有很大的关系。当然stm32l4xx_it相关的头文件和源文件可以不使用而是把SysTick_Handler中断处理放在其他文件中。

然后细致分析一下STM32L496的时钟树和对应的时钟配置。时钟控制器可以从不同的振荡器配置内核和外设的时钟。时钟控制器管理低功耗模式的时钟选通和确保时钟的鲁棒性。特点包括:时钟预分频、安全切换时钟源、时钟管理、系统时钟源、RC48时钟恢复系统(HSI48)、辅助时钟源(32.768kHz低速振荡器(LSE)和32kHz低速内部RC(LSI))、外设时钟源、启动时钟、时钟安全系统(CSS)、时钟输出性能。四种系统时钟源用来驱动SYSCLK,包括4-48MHz高速外部晶振或者陶瓷谐振器(HSE)应用于PLL,在bypass模式HSE可以配置为一种外部时钟;16MHz高速内部RC振荡器(HSI16),软件微调,可以应用于PLL;多速内部RC振荡器(MSI),软件微调,可以产生100kHz到48MHz 的12种频率,当32.768kHz时钟源在系统中可用(LSE),MSI频率可以通过硬件自动调整达到大约±0.25% 的精度,MSI可以应用于PLL;由HSE,HSI16或者MSI产生的系统PLL最大频率可达80MHz。几个预分频器允许配置AHB频率、高速APB(APB2)和低速APB(APB1)。AHB和APB的最大频率是80MHz。

代码在启动的时候进入void SystemInit(void),该函数对Reset and clock control(RCC)进行复位配置到默认的复位状态,主要操作是:

  • 1.设置控制寄存器CR的MSION位,置1,使能MSI时钟
  • 2.复位时钟配置寄存器CFGR,所有位设置为0
  • 3.HSEON, CSSON , HSION, PLLON位复位
  • RCC->CR &= (uint32_t)0xEAF6FFFF;
  • 1110 1010 1111 0110 1111 1111 1111 1111

第16位,使能HSE时钟

第19位,使能时钟安全系统CSSON

第24位,使能PLL

第26位,使能SAI1 PLL

第28位,使能SAI2 PLL

  • 4.复位PLL配置寄存器PLLCFGR,RCC->PLLCFGR = 0x00001000;

00000 00 0 0 00 0 0 0 0 0 0 0010000 0 000 0 0 00

从低位到高位解析

PLLSRC:00 关闭PLL, PLLSAI1和PLLSAI2的时钟源

PLLM:000 设置为1

PLLN:001000016

PLLPEN:0 失能PLLSAI3CLK

PLLP:PLLSAI3CLK (SAI1 and SAI2 clock)分频系数 0->7 1->17

PLLQEN:失能PLL48M1CLK输出

PLLQ:PLL48M1CLK分频系数 00->2

PLLREN:失能PLLCLK输出

PLLR:PLLCLK(系统时钟)分频系数 00->2

PLLPDIV:PLLSAI3CLK00000->PLLSAI3CLK由PLLP控制

PLL的计算方式

  • f(VCO clock) = f(PLL clock input) × (PLLN / PLLM)
  • f(PLL_P) = f(VCO clock) / PLLP
  • f(PLL_Q) = f(VCO clock) / PLLQ
  • f(PLL_R) = f(VCO clock) / PLLR
    • 5.CR的HSEBYP复位,设置为0,不饶过HSE振荡器
    • 6.时钟中断使能寄存器CIER,禁止所有时钟中断

    以上就是一开始对时钟的reset配置。

    在处理器启动起来之后进入应用就要重新对时钟进行配置。void SystemClock_Config(void)就是在运行应用前的一种配置。在分析SystemClock_Config之前,先看看HAL_StatusTypeDef HAL_Init(void)中对时钟的初始化配置,在时钟配置之前应该先调用HAL_Init。HAL_Init调用HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)函数使用SysTick作为时间基准源,并且配置1ms的滴答声(MSI)。HAL_InitTick函数配置时钟基准源包括配置SysTick为1ms的中断,配置SysTick中断优先级。MSI为SYSCLK的时钟源,并且默认值为4MHz,复位的时候使用的是默认值并且没有改变,systick没有分频,时钟源是AHB,这样就可以设置systick的RELOAD值为(4000-1)。

    然后进入SystemClock_Config配置,主要是系统时钟配置:

    系统时钟源PLL(MSI)

    SYSCLK 80MHz,HCLK 80MHz,AHB分频1,APB1分频1, APB2分频1,MSI 4MHz,PLL_M 1,PLL_N 40,PLL_R 2,PLL_P 7,PLL_Q 4,Flash延迟(WS) 4

    除了在线调试外,常用的方式就是打印信息到串口,分析串口的输出信息来调试代码。首先分析stm32l4xx_hal_uart.c文件

    UART_HandleTypeDef:串口相关结构,像波特率,传输位数,停止位等等

    HAL_UART_MspInit():用来初始化底层资源

    HAL_UART_Init():异步模式初始化串口寄存器

    HAL_HalfDuplex_Init():半双工模式初始化串口寄存器

    HAL_LIN_Init():本地互联模式初始化串口寄存器

    HAL_MultiProcessor_Init():多处理器模式初始化串口寄存器

    HAL_RS485Ex_Init():RS485驱动使能模式初始化串口寄存器

    该文件函数定义之前有一个宏#ifdef HAL_UART_MODULE_ENABLED,因此要使用包含的函数,必须定义对应的宏,HAL的宏均在一个指定的文件stm32l4xx_hal_conf.h定义。stm32l4xx_hal_conf.h文件定义了HAL的大部分功能宏,如果要使用对应的功能只需要取消宏的注释即可。然后把stm32l4xx_hal_uart.c加入到工程中,编译工程会出现未定义HAL_UARTEx_WakeupCallback,该函数在tm32l4xx_hal_uart_ex.c中,添加再编译没问题。

    接下来开始串口的功能实现。由于开发板上没有USB转串口功能,因此需要外加一个USB转串口模块把数据传输到PC上。

    开发板发送IO口TX对应到GPIO PB6,接收IO RX对应到GPIO RX。对应的串口初始化包括串口协议像波特率,数据位,奇偶校验设置、底层硬件配置和接收中断处理。

    可惜最后开发板只能发送数据而不能接收数据,经验证并没有触发串口接收中断,具体改进待下一步验证。

    全部评论 ()
    条评论
    写评论

    创建讨论帖子

    登录 后参与评论
    系统提示