目录
- 1.芯片
- 2.调试器使用,程序烧录
- 3.编程环境
- 4.调试
手上芯片的型号
STM32F407-ZGT6
1.芯片
了解芯片选型内部资源,系统架构,内部之间的关系,一些相关名词的解释
芯片选型
内核:arm Cortex-M3
(CM3)
体系结构:哈佛结构
32位处理器,内部数据路径32位,寄存器32位,储存接口也是32位
独立的指令总线和数据总线
手上有的核心板
STM32F103C8T6
Cortex-M3
CLOCK:72Mhz
FLASH:64KB
SRAM:20KB
封装:LQFP48
GPIO:37
STM32F407ZGT6
Cortex-M4
CLOCK:168Mhz
FLASH:1024KB
SRAM:192KB
EEPROM:0KB
封装:LQFP114
GPIO:114
小端(简记:低的在那边就是啥端2333)
内部资源分布(寄存器地址)
STM32F103
SRAM:6k 10k 20K 48k 64k
起始地址:0x1FFF F000
FLASH:16K 32K 64K 128K 256K 384K 512K
0x0800 0000
OptionBytes:0x1FFF F800
其他寄存器 0x4000 0000
2.调试工具
调试仿真器
目前手上有一个JlinkOB
和stlinkv2
,这两个东西都能正常在debian下运作,并且都可以用swd
模式进行调试,只是他们用的工具包不一样,使用方法有所差异
支持的模式
JLinkOB: swd
stlink v2 : swim
(这个在stm8有用) swd
工具包差异:
JLinkOB: jlink
在non-free分支
stlink:stlink-tools
图形化的烧写工具 stlink-gui
uart串口调试相关的可以使用的工具有
xgcom
图形化的串口调试工具
下面开始记录关于这两个调试器软件的使用
JLINK OB
硬件信息
jlink接口定义,我用的是JlinkOB,只有vcc
,gnd
,swclk
,swdio
对应下图的就是(参考SWD接口的定义)
vcc 不用接
gnd <-> 10号管脚(gnd)
swdio <-> 7号管脚(swdio)
swclk <-> 9号管脚(swclk)
引用博客图片
官网原版接口说明
手上用的JlinkOB用的是swd
模式,四个管脚说明
vcc:提供电压
gnd:公共接地
swdio:串行线跟踪端口
swclk:时钟信号
debian下jlink工具包
aptitude install jlink
工具包信息
软件包:jlink
版本号:6.40h
新: 是
状态: 已安装
自动安装: 否
优先级:额外
部分:non-free/devel
维护者:SEGGER <support@segger.com>
体系:amd64
未压缩尺寸:59.8 G
依赖于: libncurses5 (>= 5.5), libc6 (>= 2.7)
推荐: libqt4-gui (>= 4.8.6)
描述:SEGGER J-Link tools
This package provides software tools for SEGGER J-Link debug probes.
主页:https://www.segger.com
注意他是在
non-free
分支的,要吧non-free分之加到源里去,如果是查看/etc/apt/sources.list
确认项目中有non-free
分支
#这里是deepin的,已经包含了non-free分支
deb https://mirrors.aliyun.com/deepin panda main contrib non-free
jlink包一览
/usr/bin/JLinkRTTClientExe
#Jlink 命令行工具
/usr/bin/JLinkExe
/usr/bin/JLinkRemoteServer
#STM32重置option bytes
/usr/bin/JLinkSTM32Exe
/usr/bin/JLinkRemoteServerCLExe
/usr/bin/JLinkLicenseManager
/usr/bin/JLinkGDBServerCLExe
/usr/bin/JLinkRTTClient
/usr/bin/JLinkRTTLogger
#gdbserver
/usr/bin/JLinkGDBServer
/usr/bin/JTAGLoadExe
/usr/bin/JLinkSWOViewerCLExe
/usr/bin/JLinkRegistrationExe
/usr/bin/JLinkRemoteServerExe
/usr/bin/JLinkRegistration
/usr/bin/JLinkLicenseManagerExe
/usr/bin/JLinkGDBServerExe
/usr/bin/JLinkSWOViewer
/usr/bin/JLinkRTTLoggerExe
#图形化烧录工具
/usr/bin/JFlashLite
/usr/bin/JFlashLiteExe
/usr/bin/JFlashSPICLExe
/usr/bin/JFlashSPI_CL
#有一些只相差Exec名称可能是软连接来的,例如
$ls -l `which JFlashLite`
lrwxrwxrwx 1 root root 36 10月 26 21:09 /usr/bin/JFlashLite -> /opt/SEGGER/JLink_V640/JFlashLiteExe
貌似deb包没有包含教程(难道是我没找到?),但是官网倒有基本的user manual,可惜了没找到翻译版的,对着有道凑合着看,包含了一些工具的使用方法,命令参数
重要的章节在J-Link sotfware and documentation package
它有包括JLinkExec软件常用的命令参数说明,里面阐述了大致都有什么软件包,也有对应有图形化的工具,方便使用,例如jflash和jlink gdb都有图形化的工具
暂时用到的有三个(JLinkExec
JFlashLiteExe
JLinkGDBServer
)
J-Link Commander(JLink命令行工具)
JLinkExec
它支持一系列基本调试命令,clrBP
(清除断点),go
(启动cpu),halt
(停止cpu),mem
(读取内存),等等,大致包含
basic
(前面几个也属于基本命令),
Flasher I/O
(flash文件读写,他说需要支持,大概就是在flash里对文件进行基本操作把),
Connection
(连接命令,可以通过网络连接jlink或者usb,我这里使用的是usb的JLinkOB)
三部分命令,主要用的是basic部分的命令
紧接着就是列出命令的用法了
J-Link GDB Server
JLinkGDBServer
gdb调试服务,大致的调试方式是,J-Link这边的gdb服务开始了,监听端口,然后arm-none-eabi-gdb输入target remote :端口号
,然后把elf文件加载,读取符号,进行调试
J-Flash
JFlashLiteExe
这个工具可以对flash进行烧写,支持hex
和binary
格式,binary格式可以指定内存地址烧录,arm-none-eabi-gcc
编译出来的是elf
文件,需要用arm-none-eabi-objcopy 把elf文件转成其他格式(hex或是binary)
stlink v2
和JLink
一样,stlink
也是一个仿真器,它也有好几个版本,手上的是stlink v2
linux下的工具包是stlink-tools
,以及图形工具stlink-gui
stlink源码的项目地址https://github.com/texane/stlink
包括一些使用方法,说明,问题,可以到里面去看
他主要有三个工具
st-flash
烧写flash命令,参数指定编程器类型,文件名,起始地址,手上stm32f407的flash起始地址是
0x08 00 00 00
st-info
st-util
需要用root权限去执行他们,执行命令的时候,要在前面加sudo ,然后输入密码后以root用户的身份去执行
或者可以设置uid,让他们用所有者的身份(uid)去执行,这样就不用每次sudo输密码,当然这样是有隐患的,并不推荐
sudo chmod u+s `which st-info`
stlink-gui使用了gtk,并不能这样设置,否则会有警告
安装:
sudo aptitude install stlink-tools
sudo aptitude install stlink-gui
这个软件感觉还是问题挺多的,烧录的时候,坑多,新手不知道怎么回事把flash锁了,只读,用jlink读写正常,用这个st-flash各种毛病,也能上项目的地址找人家遇上的问题了,大概解决办法都是说先切换boot模式,重置读写,然后再切回来,脑瓜痛,知识限制了我的行动2333
3.开发环境
编译器
gcc-arm-none-eabi支持ARM Cortex-A/R/M 系列的处理器
它适用于没有操作系统的
binutils-arm-none-eabi
gcc-arm-none-eabi
gdb-arm-none-eabi
//相关的库
libnewlib-arm-none-eabi
libstdc++-arm-none-eabi-newlib
用aptitude install
安装即可
IDE
sw4stm32
linux下有基于eclipse的sw4stm32
,支持jlink
和stlink
调试,然而我都失败了...jlink使用的是openocd
,还没开始就死在了起跑线上...一堆error脑瓜痛,手上的stlink没有被他识别(它到底怎么调用stlink的),反正最终就没搞..基本的编译倒没问题,也正常生产binary文件,编译通过,它其实就是集成了arm-none-eabi-gcc,也可以用Makefile+arm-none-eabi交叉编译链替代
openocd
使用Jlink JTAG模式的调试工具...emm...我怎么在配置文件里还看到了stlink...它的说明很迷...而且用起来也很迷...没看懂怎么配置的..只能先放下了
#openocd安装
sudo aptitude install openocd
头文件
单纯编译器是不够的,还需要头文件支持,定义寄存器位置方便在程序里调用,STM32提供了库,如果不用库,对应的头文件还是可以用的,而且这个头文件挺有意思的:
文件名:stm32f4xx.h
头文件获得的方式:下载官方的提供的库,官网下载起来比较麻烦...去淘宝里看卖stm的宝贝也有资料连接的2333...或者入手开发板的时候,都能找到相关资料,copy到某个文件夹就行了2333,
include前要先定义对应型号cpu的宏,在头文件中有找到这样的说明
#if !defined(STM32F40_41xxx) && !defined(STM32F427_437xx) && !defined(STM32F429_439xx) && !defined(STM32F401xx) && !defined(STM32F410xx) && \
69 !defined(STM32F411xE) && !defined(STM32F412xG) && !defined(STM32F413_423xx) && !defined(STM32F446xx) && !def ined(STM32F469_479xx)
70 /* #define STM32F40_41xxx */ /*!< STM32F405RG, STM32F405VG, STM32F405ZG, STM32F415RG, STM32F415VG, STM32F415 ZG,
71 STM32F407VG, STM32F407VE, STM32F407ZG, STM32F407ZE, STM32F407IG, STM32F407 IE,
72 STM32F417VG, STM32F417VE, STM32F417ZG, STM32F417ZE, STM32F417IG and STM32F 417IE Devices */
后面还有很长一段,大概就是对不同的cpu型号进行了分类,可能是寄存器的地址和数量有所差异把,一些外设之类的,例如我的cpu是STM32F407ZG
,那么对应属于STM32F40_41xxx
这个宏,使用前我就需要
#define STM32F40_41xxx
#include "stm32f4xx.h"
这样就能保证我的头文件正确的被包含了,如果我不用stm提供的库函数,寄存器的方式编程,那么这个头文件够用了。但是这个头文件定义的东西比较多,而且有个比较有意思的
1471 typedef struct
1472 {
1473 __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
1474 __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
1475 __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
1476 __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
1477 __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
1478 __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
1479 __IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
1480 __IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
1481 __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
1482 __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
1483 } GPIO_TypeDef;
这里,因为GPIO相关的寄存器按分组都放在相邻的位置了,他可以通过base+offset
计算得出寄存器位置,在C中,结构体的成员就表示的是偏移量嘛...这个GPIO_TypeDef
结构体定义方便了后续操作寄存器的方式
再看头文件是怎么定义IO口的
2385 #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
2386 #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
2387 #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
2388 #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
2389 #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
2390 #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
2391 #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
2392 #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
2393 #define GPIOI ((GPIO_TypeDef *) GPIOI_BASE)
2394 #define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE)
2395 #define GPIOK ((GPIO_TypeDef *) GPIOK_BASE)
GPIOx_BASE
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400)
通过base+偏移的方式,一层一层嵌套,GPIOx_BASE
是一个具体的数值,也就是GPIO相关寄存器的地址啦,刚好可以套到GPIO_TypeDef
这个结构体。使用指针取成员内容
的方式就可以操作一组寄存器
GPIOF->ODR |= 0x01;
//上面的就等价于
((GPIO_TypeDef *) GPIOF_BASE)->ODR |= 0x01;
//或者可以写成
(*((GPIO_TypeDef *) GPIOF_BASE)).ODR |= 0x01;
GPIOF这个符号并不是指针,他只是计算出来一个具体的地址
大概编译后是成这样的(删除了部分,保留关键部分)
main:
;前面一大段删了
;这里是 GPIOF->ODR |= 0x01; 的汇编
;++++++++++++++++++++++++++++++++++++++++++++++++++
;arm的cpu不能直接访问内存,需要借助ldr str指令交换内存和寄存器的数据
;ldr(load register) ldr dst,src 把src的数据放到dst,右边的放到左边去(str刚刚操作数顺序相反)
;ldr r2,.L3相当于 把地址为1073878016的内存取4字节(32)位放到r2寄存器,下面r3的同理
ldr r2, .L3
ldr r3, .L3
;因为我们用到的成员ODR的偏移量是0x14 也就是20啦,ldr r3,[r3,#20]相当于r3 = *(r3+20) 原来r3放的是地址,通过ldr把r3+20的地址上的数据放到r3,这是个32位寄存器
ldr r3, [r3, #20]
;orr是位或指令,
orr r3, r3, #1
;因为r3已经是数据了,之前还把地址放到了r2去,现在要把数据放回去
;str src,dst
str r3, [r2, #20]
;+++++++++++++++++++++++++++++++++++++++++++++++
;while (1) ;汇编部分
;++++++++++++++++++++++++++++
;b是跳转指令,这里相当于while (1) ;
.L2:
b .L2
;++++++++++++++++++++++++++++
.L4:
.align 2
;L3是个标签,记录了常数1073878016所在的地址,1073878016的十六进制是:0x40021400,就是GPIOF的值,.word是个伪指令,指示当前位置(.L3)存放的数据是一个数值,并非指令
.L3:
.word 1073878016
.size main, .-main
.ident "GCC: (15:6.3.1+svn253039-1+b1) 6.3.1 20170620"
编译
编译主要要注意指定cpu类型,以及包含
stm32f4xx.h
头文件路径。
#Makefile
CROSS=arm-none-eabi
CC=$(CROSS)-gcc
OBJ_COPY=$(CROSS)-objcopy
#编译参数这里的--specs=nosys.specs有个梗
#如果不指定,会报这个错误:undefined reference to `_exit'...emm没搞懂,-g是生产调试符号, -mcpu指定CPU类型(target),支持cortex-m4,
#更多target支持通过arm-none-eabi-gcc --target-help去看
CFLAGS= -g -mcpu=cortex-m4 --specs=nosys.specs
#头文件所在目录
INCLUDE=~/.arm/include
#源文件
SRC=main.c
#elf文件
DEST=main
#指定烧录文件格式
HEX_FORMAT=binary
#烧录文件
HEX=main.bin
all:$(DEST)
@make $(HEX)
$(HEX):$(DEST)
@echo "生成hex文件..."
@$(OBJ_COPY) -O $(HEX_FORMAT) $(DEST) $(HEX) && echo "成功!"
$(DEST):$(SRC)
$(CC) $(CFLAGS) -g -I $(INCLUDE) -o $(DEST) $(SRC)
clean:
@-rm $(HEX)
@-rm $(DEST)
@echo "clean!"
2019.1.15笔记:
make
就可以生成了,虽然生成的代码可以被stm32f4执行,然这样生成的并不能正确执行
,O(∩_∩)O哈哈~,惊喜不惊喜,意外不意外(MMP...),为什么,,因为我并没有初始化堆栈
呀,在有系统的情况下,系统帮你做了这个操作,初始化了相应的堆栈指针,但是如果是这种裸机,只能自己动手丰衣足食了,在arm-none-eabi交叉编译链中,有个demo(位于/usr/share/doc/gcc-arm-none-eabi/examples
),有介绍到,需要用到startup.s
,以及设置相关的脚本设定相关的ram和flash大小
,以及起始地址,查阅了一些资料,起始地址有映射到0x0000 0000(原来的0x0800 0000还是可以读取和写入的,也就是说,如果是flash启动的时候,往0x0000 0000写和往0x0800 0000,效果是一样的
),程序的刚开始并不就是大概是一些什么鬼中断向量(后续在看看吧),并不是直接就是main函数开始,如果要生成被正确读取执行的代码,需要参考它提供的demo,暂时没折腾来编译参数,向sw4stm32
低头了23333...这大概就是菜吧,那就暂时先用sw4stm32
吧
烧录和调试
根据上面介绍的工具,可以通过
st-flash
(stlink)JFlashLite
(Jlink图形化flash编程工具)烧录,烧录的格式是hex
或者binary
把程序写入flash的几种方式
Flash起始地址:0x0800 0000
JLink
JFlashLiteExe
图形化烧录工具,或者JLinkExec
调试过程中使用loadfile
命令把文件载入指定地址(0x0800 0000)
JFlashLiteExec
JLinkExec
载入文件的方式
#JLink后进入命令行模式
$ JLinkExe
SEGGER J-Link Commander V6.40 (Compiled Oct 26 2018 15:08:38)
DLL version V6.40, compiled Oct 26 2018 15:08:28
Connecting to J-Link via USB...O.K.
Firmware: J-Link ARM-OB STM32 compiled Aug 22 2012 19:52:04
Hardware version: V7.00
S/N: 20090928
License(s): RDI,FlashDL,FlashBP,JFlash,GDB
VTref=3.300V
Type "connect" to establish a target connection, '?' for help
J-Link>
#输入connect连接到JLink
J-Link>connect
Please specify device / core. <Default>: STM32F407ZG
Type '?' for selection dialog
Device>
#选择芯片型号,他读取到我的是STM32F407ZG,默认回车
#选择通讯的模式,我的JLinkOB只能用SWD
Please specify target interface:
J) JTAG (Default)
S) SWD
T) cJTAG
TIF>S
#选择速率,默认4000Khz,回车就行了
Specify target interface speed [kHz]. <Default>: 4000 kHz
Speed>
#连接成功后一堆信息刷出来,最后提示
Cortex-M4 identified.
J-Link>
#使用loadfile载入文件到stm32
J-Link>loadfile OLED.hex 0x08000000
Downloading file [LED.hex]...
Comparing flash [100%] Done.
Erasing flash [100%] Done.
Programming flash [100%] Done.
Verifying flash [100%] Done.
J-Link: Flash download: Bank 0 @ 0x08000000: 1 range affected (16384 bytes)
J-Link: Flash download: Total time needed: 0.414s (Prepare: 0.035s, Compare: 0.002s, Erase: 0.346s, Program: 0.025s, Verify: 0.000s, Restore: 0.004s)
O.K.
#下载成功,复位就可以正常运行了,注意BOOT模式要是从flash开始执行
stlink
st-flash
或者stlink-gui
提供命令行/图形烧录工具
stlink-gui
需要root权限运行
st-flash
#st-flash --flash=flash大小 write 文件名 起始地址
st-flash --flash=1024k write OLED.ihex 0x08000000
关于烧录
烧录文件的格式可以使用ihex,也就是intel hex的格式,通过
arm-none-eabi-objcopy
把elf格式的文件转成ihex格式,后缀名是.ihx .hex .ihex都行
格式转换 -O 指定输出文件格式,支持什么格式的--help最后有说明,-I (大写i)可以指定输入文件格式
arm-none-eabi-objcopy -O ihex main main.hex
点灯
2019.1.15:还没学会配置编译脚本,暂时得先用
sw4stm32
吧,在点灯的过程中,顺便把大致如何创建一个项目记录下来
原理图位置
对应的管脚是PF9
和PF10
管脚按ABCD...
分组,根据参考手册说明,它一组IO口有16
个引脚(当然编号是从0-15),刚开始接触stm32,我并不打算从库入手,而是先从寄存器入手了解它的工作和寄存器配置顺序
,所以使用官方库的头文件进行翻阅,对于一些寄存器的宏定义,还是需要自己慢慢搜索官方的库,同时配合一些视频教程进行学习,毕竟寄存器太多了,自己闭门查手册无疑增加了学习难度
emm...咋这么多寄存器,脑壳痛
//四个配置相关的,这些寄存都是32位的
GPIOx_MODER
GPIOx_OTYPER
GPIOx_OSPEEDR
GPIOx_PUPDR
//两个数据寄存器
GPIOx_IDR
GPIOx_ODR
//一个复位寄存器
GPIOx_BSRR
//两个复用功能选择寄存器,看名字应该是高低4字节的
GPIOx_AFRH
GPIOx_AFRL
//锁定寄存器,冻结IO配置的
GPIOx_LCKR
在开始之前,首先确定我的IO口需要什么类型的输出
GPIO口的套路基本都一样,输出的话有:
开漏输出
:可以理解为1的时候是断路
(阻值很高),0的时候是接地gnd
,也只是只输出低电平
推挽输出
:1的时候输出高电平,0的时候输出低电平,也就是高低电平都可以输出
他还有个功能就是可以输出的时候,有带上拉/下拉电阻,刚开始点灯,就不管这个啦
我这个led是低电平驱动的,开漏输出满足我的需求,那么,我只需要开漏输出
就行了
那么配置的GPIO寄存器相关的有
GPIOF_MODER 端口模式寄存器
GPIOF_OTYPER 输出类型寄存器
GPIOF_ODR 输出数据寄存器
那么对于PF9口
MODER要设置我通用输出状态:[1:0]=0x01
OTYPER要设置成0x1
ODR要设置成0x0
在sw4stm32
创建一个工程
1.File>New>Project>C/C++分支下的C Project
2.填写项目名称和选择项目编译链
3.因为没有什项目相关的要配置,advanced settings在创建项目后也能配置
4.选择CPU型号,因为他要设定特定的宏,以及不同的内存大小和起始地址(flash和ram的),在标准库中,包含stm32f4xx.h头文件需要指定
不同的cpu型号有对应分类的宏
5.开发方式的选择(库选择)
6.项目界面
他已经提供好基本的模板了,那么就开始吧
在手册中有说到,cm4刚上电的时候,外设时钟是关闭的,ram和flash是打开的,所以有用到gpio.还得吧他的时钟使能打开,通过查头文件和手册,找到这样的一个结构体
//1632行
typedef struct
{
__IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */
__IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */
__IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */
__IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */
__IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */
__IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */
__IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */
uint32_t RESERVED0; /*!< Reserved, 0x1C */
__IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */
__IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */
uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */
__IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */
__IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */
__IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */
uint32_t RESERVED2; /*!< Reserved, 0x3C */
__IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */
__IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */
uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */
__IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */
__IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */
__IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */
uint32_t RESERVED4; /*!< Reserved, 0x5C */
__IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */
__IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */
uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */
__IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */
__IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */
uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */
__IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */
__IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */
__IO uint32_t PLLSAICFGR; /*!< RCC PLLSAI configuration register, Address offset: 0x88 */
__IO uint32_t DCKCFGR; /*!< RCC Dedicated Clocks configuration register, Address offset: 0x8C */
__IO uint32_t CKGATENR; /*!< RCC Clocks Gated Enable Register, Address offset: 0x90 */ /* Only for STM32F412xG, STM32413_423xx and STM32F446xx devices */
__IO uint32_t DCKCFGR2; /*!< RCC Dedicated Clocks configuration register 2, Address offset: 0x94 */ /* Only for STM32F410xx, STM32F412xG, STM32413_423xx and STM32F446xx devices */
} RCC_TypeDef;
//同时RCC是这样被定义的
#define RCC ((RCC_TypeDef *) RCC_BASE)
再在手册中找到,RCC_AHB1ENR
中有对GPIOF时钟使能相关的配置
那么到此为止,所需要的寄存器就全部找完了
#include "stm32f4xx.h"
int main(void)
{
//外设的时钟打开
RCC->AHB1ENR |= (0x01 << 5);
//PF9低电平的时候驱动LED
//设置0x01是通用输出状态
//擦除//设置为0x01 通用输出
GPIOF->MODER &= ~(0x03 << (2 * 9));
GPIOF->MODER |= (0x01 << (2 * 9));
GPIOF->ODR &= ~(0x01 << 9);
for(;;);
}
编译项目生成elf和bin文件
通过JFlashLite将bin文件烧录
顺利点亮
调试
在项目Debug目录下,如下
$ls
LED2.bin LED2.elf makefile objects.list objects.mk output.map sources.mk src startup StdPeriph_Driver
LED2.elf
是elf格式的文件,包含调试符号,LED2.bin
是烧录到stm32f4的flash里的程序,已经是机器码来的,我们要用arm-none-eabi-gdb
进行硬件调试,首先,确保gdb-arm-none-eabi
软件包已经安装
sudo aptitude install gdb-arm-none-eabi
1.启动JLinkGDBServer
新开一个终端窗口启动JLink提供图形化的GDBServer工具
$JLinkGDBServerExe
#现在可以启动gdb了,使用target remote,上图中监听的端口是2331
$arm-none-eabi-gdb
(gdb) target remote :2331
Remote debugging using :2331
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x00000000 in ?? ()
(gdb)
#因为此时并没有载入elf文件,没有符号,所以gdb并不知道它现在的状态,用load载入elf文件
(gdb) load LED2.elf
Loading section .isr_vector, size 0x1a8 lma 0x8000000
Loading section .text, size 0x3b4 lma 0x80001a8
Loading section .rodata, size 0x4 lma 0x800055c
Loading section .init_array, size 0x8 lma 0x8000560
Loading section .fini_array, size 0x4 lma 0x8000568
Loading section .data, size 0x42c lma 0x800056c
Start address 0x800038c, load size 2456
Transfer rate: 2398 KB/sec, 409 bytes/write.
(gdb)
#载入成功后就可以进行调试了
未完...