基础知识:
1. STM32库
这个库是针对STM32开发板提供的函数接口,可以用来配置寄存器。采用库开发的方式,使用结构体封装寄存器参数,用宏表示参数,用函数封装对于寄存器的操作。
2. Cortex-M3芯片
ARM公司设计内核,其他厂商设计之外的部件(片上外设如串口,定时器)。解决兼容性问题提出了CMSIS标准,这一层位于硬件与OS或者用户层之间,屏蔽了硬件差异,提供简单的接口。CMSIS核心层是标准中最重要的部分,包含内核函数层,设备外设访问层。
3. STM32库中的一些重要文件
1. system_stm32f10x.c
设置系统时钟和总线时钟
2. stm32f10x.h
包含了STM32中的寄存器地址和结构体类型定义,在使用固件库的地方都要包含它
3. 启动文件
任何处理器在上电复位后最先运行的一段汇编程序,为C语言的运行建立环境。如我们使用的是STM32F107VC系列的产品,故采用startup_stm32f10x_cl.s为启动文件。
4. misc.c
提供外设对内核中的中断向量控制器(NVIC)的访问函数,配置中断时必须添加该文件。
5. stm32f10x_conf.h 和stm32f10x_it.c
conf是用来配置使用了什么外设的头文件,添加或删除外设驱动函数库,配置是否使用断言编译选项等。
It用来编写中断服务函数,已经定义了一些系统异常的接口。
6. stm32f10x_gpio.c 和 stm32f10x_rcc.c
用于操作I/O和配置系统时钟及外设时钟(必须添加)。
7. 固件库文件间的关系
1. 用户层:
stm32f10x_conf.h 片上外设配置
stm32f10x_it.h / stm32f10x_it.c 中断服务函数
xxx.c 用户自定义的文件
2. CMSIS层:
misc.c等,
8. 点灯工程的文件(我建立的不标准,在配置环境时选择了需要的库就没有像书上建立很多文件夹,分门别类放文件)
初步建立点灯工程:
1. 新建工程,选择开发板型号,所要包含的库文件,然后新建user文件夹,创建用户自定义文件
2. 配置工程:
第一个宏使用ST的官方库,第二个宏是根据芯片而定,CL是我们使用的芯片系列对应的文件名缩写。
选择我们使用的调试器,选择使用的DLL以及相应参数。
3. 编译和下载程序
我们需要修改USER文件夹下的main.c,stm32f10x_it.c,xxx.c,xxx.h。
注:我没找到stm32f10x_it.c
两种下载方式:Keil自带的LOAD按钮和串口下载(需要mcuisp,一个小软件,我没用过)
软件仿真有问题,我们采用直接把程序注入开发板运行的方式:
把ST 调试器和STM32输出端的USB口接到电脑上,在电脑上下载更新驱动(控制面板,设备管理器中)
我们使用的LED灯属于GPIOB(PB的含义),引脚为0,1,14,15
驱动更新完成后,可以出现调试设置。
点击LOAD,把程序注入到STM32的芯片中,可以开始运行。
分析点灯工程:
1. GPIO
A-G组引脚。每组有16个引脚。
控制LED灯的步骤:
1.选引脚如PC3
2.配置功能,如利用GPIOA_CRL/CRH等寄存器配置低八位/高八位引脚。
3.设置GPIO输出电压的高低。如让GPIOA_BSRR端口位设置清除寄存器的BR3/BS3=1,可以使引脚输出低/高电平。
2. 地址映射
把芯片上的存储器或I/O资源等与地址建立一一对应的关系。
Cortex-M3有32根地址线,寻址空间为4GB,其中0X40000000(外设基地址PERIPH_BASE)-0X5FFFFFFF共512MB地址给片上外设,对应着片上外设的寄存器。Stm32f10x.h就是做地址映射的,类似一张大表。
主要的有APB2总线(挂载GPIO,ADC,串口1等外设,还有APB1,AHB总线)外设基地址0X40010000(APB2PERIPH_BASE),寄存器组基地址GPIOx_BASE,我们可以利用(GPIO_TypeDef*)GPIOC_BASE,使得地址转变为结构体指针类型,这样可以利用GPIOC->CRL等方式访问寄存器。
3.时钟
分为高速/低速/外部/内部时钟。使用外设时,一定要开启时钟。
重要时钟:
1. SYSCLK:系统时钟,是STM32大部分部件时钟来源,由AHB预分频器分配到各个部件。
2. HCLK:由AHB预分频器直接输出得到,是高速总线AHB的时钟信号,提供存储器,DMA,Cortex内核使用,CPU的主频就是这个信号,与STM32运算速度和数据存取速度密切相关。
3. FCLK:也由AHB预分频器输出得到,自由运行时钟,在HCLK停止时仍可存在,在休眠时可采样到中断和跟踪休眠事件。
4. PCLK1:外设时钟,APB1预分频器得到,最大频率36MHz,提供给APB1总线上的外设。PCLK2类似。
代码分析:
GPIO初始化完成后,需要设置时钟,在启动文件中调用SystemInit(),设置系统时钟SYSCLK,把配置时钟相关的寄存器都复位为默认值,再调用另一个函数SetSysClock(),根据预定义的条件编译宏来进行时钟配置,调用相应的配置函数,如SetSysClockTo72()。
附:一些位操作方法
a &= ~(1<<6) //左移六位的奥01000000,对第七位(bit 6)清零
a |= (1<<6) //把第七位置1
a ^= (1<<6) //把第七位取反
我们可以用为操作或者直接GPIOC->CRL等方式来操作寄存器,难得是要确定后面的数值。
软件编译过程:
.c ---gcc---> .o |
|---> 连接器脚本---> 连接器LD --->可执行的映像文件 .afx ---> .bin / .hex
.s ---as(汇编器)---> .o |
下载到芯片FLASH的代码就是.hex文件,上电后,内核把代码加载到SRAM中执行。Flash相当于硬盘,SRAM相当于内存,在内存的代码直接运行。
总结:
1. 控制LED灯需要要使用GPIO外设。
2. 了解GPIO外设的功能,要如何使用。
3. 了解GPIO的地址映射,知道它所挂载的总线APB2。
4. 了解ST官方库对于寄存器的封装。
5. 了解时钟树,查看GPIOC的时钟来源,即PCLK2。
6. 在stm32f10x_conf.h文件中包含用到的头文件stm32f10x_gpio.h,stm32f10x_rcc.h
7. 在工程模板的基础上添加led.c,led.h用户文件
8. 编写驱动初始化函数LED_GPIO_Config
9. 开启外设GPIOC时钟,分析有SystemInit()配置的默认的72MHz的时钟频率是否符合要求
10. 根据控制要求,定义并填充初始化结构体GPIO_InitStructure,向相应的结构体成员中写入适当的参数
11. 调用初始化函数GPIO_Init()
12. 编写相应的头文件led.h
13. 针对不同应用,完成main.c
14. 调试程序,总结。
编写linux的驱动程序,所有驱动实质上都是向各种结构体成员写入适当的控制参数,填充好结构体。