美文网首页
stm32入门学习笔记

stm32入门学习笔记

作者: 绿箭ML | 来源:发表于2019-01-12 21:58 被阅读39次

    目录

    • 1.芯片
    • 2.调试器使用,程序烧录
    • 3.编程环境
    • 4.调试

    手上芯片的型号
    STM32F407-ZGT6

    1.芯片

    了解芯片选型内部资源,系统架构,内部之间的关系,一些相关名词的解释

    芯片选型

    image.png

    内核:arm Cortex-M3 (CM3)
    体系结构:哈佛结构
    32位处理器,内部数据路径32位,寄存器32位,储存接口也是32位
    独立的指令总线和数据总线

    手上有的核心板

    STM32F103C8T6

    Cortex-M3
    CLOCK:72Mhz
    FLASH:64KB
    SRAM:20KB
    封装:LQFP48
    GPIO:37

    STM32F103C8T6

    STM32F407ZGT6

    Cortex-M4
    CLOCK:168Mhz
    FLASH:1024KB
    SRAM:192KB
    EEPROM:0KB
    封装:LQFP114
    GPIO:114
    小端(简记:低的在那边就是啥端2333)

    STM32F407ZGT6
    emm..某宝淘的核心板

    内部资源分布(寄存器地址)

    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.调试工具

    调试仿真器

    目前手上有一个JlinkOBstlinkv2,这两个东西都能正常在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)
    
    image.png
    引用博客图片
    image.png

    官网原版接口说明
    手上用的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进行烧写,支持hexbinary格式,binary格式可以指定内存地址烧录,arm-none-eabi-gcc编译出来的是elf文件,需要用arm-none-eabi-objcopy 把elf文件转成其他格式(hex或是binary)

    stlink v2

    JLink一样,stlink也是一个仿真器,它也有好几个版本,手上的是stlink v2

    image.png

    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,支持jlinkstlink调试,然而我都失败了...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

    JFlash选择芯片型号和Jlink模式
    软件界面

    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权限运行

    stlink-gui

    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吧,在点灯的过程中,顺便把大致如何创建一个项目记录下来

    原理图位置

    这个LED属于低电平驱动
    对应的是PF9和PF10管脚

    对应的管脚是PF9PF10
    管脚按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的时候输出低电平,也就是高低电平都可以输出
    他还有个功能就是可以输出的时候,有带上拉/下拉电阻,刚开始点灯,就不管这个啦

    GPIO口输出的两mos以及上下拉示意

    我这个led是低电平驱动的,开漏输出满足我的需求,那么,我只需要开漏输出就行了
    那么配置的GPIO寄存器相关的有
    GPIOF_MODER 端口模式寄存器

    MODER寄存器

    GPIOF_OTYPER 输出类型寄存器


    OTYPER
    OTYPER

    GPIOF_ODR 输出数据寄存器


    ODR

    那么对于PF9口
    MODER要设置我通用输出状态:[1:0]=0x01
    OTYPER要设置成0x1
    ODR要设置成0x0

    sw4stm32创建一个工程

    1.File>New>Project>C/C++分支下的C Project

    项目类型

    2.填写项目名称和选择项目编译链

    image.png

    3.因为没有什项目相关的要配置,advanced settings在创建项目后也能配置

    image.png

    4.选择CPU型号,因为他要设定特定的宏,以及不同的内存大小和起始地址(flash和ram的),在标准库中,包含stm32f4xx.h头文件需要指定不同的cpu型号有对应分类的宏

    设定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时钟使能相关的配置

    GPIOFEN
    GPIOFEN配置信息

    那么到此为止,所需要的寄存器就全部找完了

    #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文件

    生成elf文件和binary

    通过JFlashLite将bin文件烧录

    顺利点亮

    led

    调试

    在项目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
    
    gdbserver配置
    启动成功,等待gdb连接
    #现在可以启动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) 
    #载入成功后就可以进行调试了
    
    

    未完...

    相关文章

      网友评论

          本文标题:stm32入门学习笔记

          本文链接:https://www.haomeiwen.com/subject/tytarqtx.html