• PikaScript实践记录(2)之移植PikaScript(1)


    PikaScript实践记录之最小BSP包工程

    Author:onceday Date:2022年9月3日

    也信美人终做土,不堪幽梦太匆匆!

    前言: 本文章基于PikaScript脚本语言在阿波罗Stm32F429开发板的实践记录。PikaScript是跨平台的超轻量级嵌入式 Python 引擎,零依赖,零配置,中文资料非常丰富。可获取关于它们的详细资料:

    1.引言

    上次说到,PikaScript上面缺少必要的BSP包,所需暂时无法使用PikaScript,所以我们需要编一个最简单的BSP包。

    对于Stm32F429来说,其基于Cortex-M4处理器,属于ARMv7-M架构,支持Thumb-2指令集,能同时在16位和32指令下工作,如何理解呢?

    简单来说,16位指令可以提高代码密度,即二进制文件更小,比如立即数数据只存2个字节。

    32指令执行更快,一次可以取更多的数据。

    但是这些都不重要,因为指令集,或者说ISA就是用来屏蔽底层硬件的差异。另外一方面,编译器会帮助我们搞定这些优化任务。贯穿我们本文的核心思想就是,简单能用。

    在ARM处理器结构中,作为应用软件开发人员,只需要了解常见的汇编指令、编程模型、调试方法。

    至于接口信号、指令执行时序和流水线阶段的相关实现细节,则属于处理器设计相关。但是它们也会影响我们编程的方式,即必须遵循C语言的规范,比如数据对齐,如果我们严格对齐数据,就不会触发错误。

    在这里,我们需要先准备一些资料,对于嵌入式开发,查阅官方手册,是最有效的解决方法!

    首先是arm keil,集成IDE的用户手册,这是里面有如何建立工程,对编译工具链的解释和预处理指令手册:

    这些手册很多,大部分还要求专业域的知识,但是你应该知道它们在哪里,并且在遇到难以解决问题的时候可以翻阅查找。

    然后是ARM官网对处理器架构设计和解释的手册,在官网上也可以免费下载:

    最后是ST意法半导体生产的单片机手册,在官网也可以免费下载,还有很多编程和应用实例:

    此外还有什么地方有参考手册可下载呢?对,没错,就是服务和培训机构的教程手册,比如野火和正点原子,可见PikaScript实践记录(1)之hello world_Once_day的博客-CSDN博客

    这里虽然提到的是具体的Keil、Arm、Stm32、野火/正点原子,但是并不限于他们,因为MCU的种类很多,CPU架构也不一定都是Arm结构,生产厂家很多,服务培训机构也很多,所以你的选择同样很多。

    但是背后的规律就是,CPU架构手册、MCU手册、编译手册、教程手册等等,这些一定基本都有,这就是学习的方法,归纳总结。

    当然如果某些厂家不提供怎么办?最简单的方法就是不用他们的产品,学习单片机的时候,咱们不受这气。

    2.ARM Cortex-M4 处理器

    Cortex-M处理器包含的种类非常多了,性能一般都比较强大,它们之间都是非常相似的,所以程序一般不用改进多少就能移植。

    Cortex-M4和Cotex-M3都是基于ARMv7-M架构,因此它们很类似,例如Stm32F1系列和Stm32F4系列。

    主要特点如下:

    • 三级流水线架构
    • 哈佛总结架构,RISC精简指令集,可同时取指令和取数据
    • 统一的内存储存空间,32位,4GB
    • 具有NVIC嵌套向量中断控制器,有多种中断优先级
    • 固定的sysclock滴答计时器,可用于OS
    • 可选的浮点计算单元

    具体特点可以取手册了解,这里必须着重强调的是Cortex-M4处理器没有MMU内存管理单元,虽然这很明显,但是这会给我们的编程带来显而易见的影响,即我们访问的都是物理地址,如果在某个地址做了不该做的事情,那就不是”coredump“(核心转储,Linux上常见于内存访问错误),而是“hardfault”(一个固有异常中断)。

    Cortex-M处理器有一套标准的软件接口—CMSIS。主要有五部分:

    • CMSIS-Core,对处理器内核寄存器的接口
    • CMSIS-DSP,支持FFT和滤波器等常见的DSP应用
    • CMSIS-RTOS,为嵌入式OS提供支持
    • CMSIS-DAP, 为调试程序提供支持
    • CMSIS-SVD,格式化描述语言,描述MCU的外设视图

    一般编程有用的,是CMSIS-Core和CMSIS-DSP,至于调试器和OS,相关提供服务商会自行搞定。

    常见的用户级CPU,如PC和手机,一般都是有多个操作模式,Cortex-M4也不例外,它具有两个栈指针:

    • MSP,主栈指针,用于OS内核和中断
    • PSP,进程栈指针,用于应用任务

    我们一般用的,一个main函数,里面一个大while形式的,基本都是直接一个MSP指针就行了。

    操作模式也有两种,特权模式和非特权模式,在系统启动之后,默认运行的就是特权模式。非特权模式会有一些限制,比如对NVIC寄存器的访问。

    Cotex-M4处理器是支持可选大端和小端模式的,在内核寄存器能看到这个设置,但一般情况下都被指定为小端模式。

    关于Cortex-M4和Cotex-M3处理器的详细介绍可以在《Arm Cortex M3/M4 权威指南》里面查看:

    在这里插入图片描述

    图2.1 ARM Cortex-M3/M4 权威指南
    3.C语言

    Cortex-M4处理器的架构很适合用C语言来编程,这是它的一大优势所在。

    C语言学习可以参考书籍《C Primer Plus》。

    基础语法总结:C语言之基础语法_Onceday CSDN博客

    通常意义上C代码编译成可执行程序需要经过以下步骤:

    在这里插入图片描述

    图3.1 通常C源码到执行文件的步骤

    但这里简化了,对于Cortex-M4处理器而言,需要额外的汇编启动文件,以及分散加载脚本—用于指定代码所处的地址位置。

    关于这部分可在《Arm Cortex M3/M4 权威指南》的第二章:嵌入式软件开发简介,里面找到具体的介绍。

    在集成的keil开发环境里面,我们仅仅只需要关注源代码,即source.c这个层次,下面的编译工具,各类库代码等Keil都帮助我们搞定了。

    4.Stm32F429基本概述
    4.1 整体情况

    首先,我们需要通过以下的资料来查阅有关该单片机的信息,详细的获取方式上面已经列出来了。

    我们这里用到的PDF全部来自正点原子的资料:

    在这里插入图片描述

    图4.1 Stm32F429的必备参考资料

    可自行在正点原子资料网站下载:正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

    或者百度网盘:链接:stm32f429 pdf资料,提取码:tezy。

    其中最重要、最基础的是《STM32F4xx参考手册》和《数据手册》,请注意大部分厂家的参考手册和数据手册都是一个或多个系列通用的,所以不要光看表面的名字,需要看内容是否支持手上的产品。

    如Stm32F4xx就表示支持F4系列的常见MCU,如F407,F411等,但是它们之间也有细微差别,这些在手册里都会特别提示出来。

    首先打开数据手册,在这里面可以快速概览该MCU的各类参数,如CPU信息,存储器信息,外设信息等,可以快速把握了解MCU。

    但这不代表所有该系列的CPU都具有这个性能,因为还要根据封装的不同来确定具体的参数:

    在这里插入图片描述

    图4.2 Stm32F4xx系列的不同封装

    关于封装和产品的种类和不同,可以在《STM mcu的选型手册》里面查看:

    在这里插入图片描述

    图4.3 Stm32产品后缀的命名含义

    现在ST意法半导体推出了一个应用程序ST-MCU-Finder,可以更方便的进行选型和查看相关参数资料,具体下载连接:

    下面来看一下阿波罗Stm32F429开发板的信息:

    在这里插入图片描述

    图4.4 Stm32F429最小系统板

    首先,可以从芯片的丝印上读取具体型号:Stm32F429IGT6,根据选型手册上面,可以得知具有176管脚和1M内置Flash,256KB的组合SRAM。其他的存储芯片都是外扩,我们熟悉他们的样貌和接口,以便日后快速在一块新的开发板上将他们识别出来。

    在一些资料不充分的MCU开发板上,我们只能根据以前积累的经验去快速判断未知芯片类型,从而进一步确定型号和作用。

    在最开始的时候,我们只能使用内置的flash和SRAM,想驱动外置的flash、EEPROM和SDRAM并不是一键简单的事情。

    下载烧录Flash的接口是USART1串口和SWD调试口,推荐使用调试口,串口下载并不适合程序开发测试,特别是新手。淘宝买一个仿真器很便宜。

    4.2 最小开发版的硬件设计信息

    这部分信息需要在《Stm32f42x数据手册》中查看,一般在第二章部分,会对基本的芯片外接电源电路做一个介绍。

    在这里插入图片描述

    图4.5 Stm32F1/2/4系列的兼容供电设计(部分)

    这里需要强烈注意,虽然整个Stm32F1/2/4系列的供电设计是兼容的,但不同封装之间差异是真实存在的。

    而且千万不要根据自己的“浅显理解”擅自改变或减少供电管脚和GND管脚的实际连接,除非你明确清楚自己在做什么。 比如芯片内部的模拟电路和数字电路可能是分开供电的,不一定所有的VCC都是并联一起的。

    每一个电容和电阻的接法和值大小都是有限制范围的,切记乱接。

    对初学者的建议是抄袭已有的设计,至少保证它能正常运行,但是千万不要在商业或盈利项目中抄袭。

    没错,仅供学习和交流!

    4.3 如何阅读MCU参考手册

    一般MCU参考都是至少500页往上,正常都是1K页以上,对于复杂的高级MCU,4-5K页都有可能。

    如何有效的阅读这些手册就是一个非常有效的技能。建议如下:

    • 外设章节只有使用时才需要阅读,称为用时再读策略。
    • 调试章节和设备电子信息无需阅读,只要不影响使用就不管,这些和正常编程关系不大。
    • 存储器和总线架构,flash接口,复位和时钟,中断,GPIO等五部分为必读。

    特别是第三部分,包含了非常重要信息!

    总线架构最关键的是架构图:

    在这里插入图片描述

    图4.6 Stm32F42xxx系列的总线架构

    那些信息比较关键?主要涉及内存的可访问性,比如64KB的CCM数据RAM,挂在D总线上,那么只有CPU能够访问,其他的外设是不能够访问。

    也许你好奇,什么外设可以访问内存?其实最简单的例子就是DMA,在基础编程是遇不到这个问题,但是如果一开始就不养成习惯,后面接触到高级MCU使用,就会被这些“小问题”弄到心态爆炸

    此外,千万不要以为所有CPU都是这副矩阵总线,Cortex-M处理器上这个总线矩阵是标配,但是部分高级MCU可能拥有多个总线矩阵。没错,比如Stm32H743就有3个总线矩阵,其可访问特性更是受限颇多,需要极其注意。 在一些其他的MCU中,可能完全是另外一套架构,比如TI(德州仪器)自有的MSP430x架构。

    其次我们还要获取有关存储器映射的信息,外设寄存器这部分MCU厂家已经帮我们写好头文件了,我们可以直接使用结构体去设置寄存器的值。 但我想说得是,如果没有这个头文件怎么?你不能排除这个可能性,某些恶心的厂家可能懒得写这个,此时,可以根据MCU参考手册中寄存器的位信息和偏移量,以及这个外设映射的存储器位置,自行编写相关结构体定义。

    如果某些厂家连寄存器信息都不给呢?直接掀桌子吧!Fuck these people !

    回到主题,我们需要关注flash和SRAM的位置,其是Cortex-M结构的存储位置大体上是有分区的:

    总线接口描述
    I-CODE0x0-0x1fffffff,主要用于程序存储器,取指令,如flash,一般都从0x80000000开始。
    D-CODE0x0-0x1fffffff,主要用于程序存储器,取数据,如flash。
    系统总线0x20000000-0xfffffff(除去PPB),外设和存储器,如SRAM就是从0x20000000开始的,外设是从0x40000000开始的。
    PPB0xE0040000-0xE00FFFFF,外部私有外设总线,用于私有调试器件

    下面是一张简化的接口图:

    在这里插入图片描述

    图4.7 Stm32F42xxx系列的总线接口架构

    从这张图上应该可以非常清楚看出为什么说DMA无法访问CCM数据RAM了吧。 我们不需要非常深入了解它们具体的工作原理,这是芯片设计人员的责任。但我们需要有一个整体的宏观认知,以便于合理的进行编程。

    在存储器这里接下来需要了解的地方就和Flash烧录程序有关了,即自举配置

    在这里插入图片描述

    图4.8 Stm32F42xxx系列的自举配置

    自举配置和Cortex-M处理器是无关的,在复位后,它总是通过I-CODE总线从地址0x00000000处开始执行。在初学阶段,我们只会通过两个部分来自举,即主flash和系统存储器。

    主flash就是存放我们写的代码位置,系统存储器是系统bootloader,使我们通过串口能下载代码的关键程序,很多单片机都会有这个BootLoader。但关键是不同单片机的启动方法很不同,Stm32系列单片机只需要给定BOOT0和BOOT1管脚的电平值就可以切换,而其他的单片机,如TI,可能需要通过下载线发送一段特殊的序列值才能启动。 这个地方需要根据官方手册来确定使用方法。

    需要注意,使用Bootloader,可以通过以下方法下载程序(重新编程flash):

    • USART1(PA9/PA10)
    • USART3(PB10/11 和 PC10/11)
    • CAN2(PB5/13)
    • USB OTG FS(PA11/12)从设备模式

    在这里存在一个问题,CPU从0x00000000启动,可是MCU的主flash可是在0x80000000开始的,那怎么启动我们的代码?

    有人可能会觉得是系统存储器是不是放在0x00000000?这个想法很好,比如STC宏晶科技的C51/52单片机就是从BootLoader启动,如果启动阶段收到特殊指令,就会进入FLASH编程程序并接收串口数据,否则就直接去运行主程序。

    但是很可惜,Stm32的MCU不是这样做的,而是通过存储器重映射来实现的,默认情况下会把主flash(0x80000000)重映射到0x00000000。如下图所示:

    在这里插入图片描述

    图4.9 Stm32F42xxx系列的自举模式和重映射

    可能第一眼看见这个图,感觉无法理解。这样来看,地址竖栏写明了具体的地址范围,后面四个竖栏代表不同自举模式的内存视图,其中FSMC是属于自定义的外扩存储器。 比如对于自举模式为嵌入式的SRAM,flash在地址0x80000000,系统存储器在地址0x1fff0000,sram还是从0x20000000开始。不同的是此时0x00000000也可以访问SRAM1,因此,CPU就会从SRAM1开始执行代码了。

    系统总线和flash接口的信息非常丰富,而且也影响我们编程的具体细节,因此一定要在一款新的MCU仔细阅读该部分信息。

    时钟系统是单片机初始化最重要的部分,不仔细阅读这部分,初始化这部分就无法自行完成设计。

    我们首先要有一个概念,我们的单片机是从复位开始运行的,什么是复位?CPU从0x00000000开始执行代码,这里是中断向量的入口,离执行我们的main程序还有十万八千里远。中间CPU在干啥?这里我们要建立第一步概念,即Reset_Handler,复位处理程序,这个向量其实可以简单看是函数(指针)地址。

    当然,这个Reset_Handler只是大家都喜欢这么取名,实际上这个名字在程序里可以随便取,只要你高兴,叫它First_function也行。

    复位的发生有很多种,系统复位和电源复位,里面又细分很多细节,我们常用有一个按钮key,按一下它,就重启单片机,那么这个就是NRST引脚复位,此外还有软件(代码)、看门狗复位。电源复位有掉电/上电复位、欠压复位等,具体细节可以在参考手册的电源控制器PWR一章浏览。

    所以说,单片第一次上电,就会触发复位中断,这是优先级最高的中断,不可屏蔽。

    ; Reset handler
    Reset_Handler    PROC
            EXPORT  Reset_Handler             [WEAK]
            ;IMPORT  SystemInit	
            ;寄存器代码,不需要在这里调用SystemInit函数,故屏蔽掉,库函数版本代码,可以留下
    		;不过需要在外部实现SystemInit函数,否则会报错.
            IMPORT  __main
            LDR     R0, =0xE000ED88    ; 使能浮点运算 CP10,CP11
            LDR     R1,[R0]
            ORR     R1,R1,#(0xF << 20)
            STR     R1,[R0]
    
            ;LDR    R0, =SystemInit	;寄存器代码,未用到,屏蔽
            ;BLX    R0				    ;寄存器代码,未用到,屏蔽
            LDR     R0, =__main
            BX      R0
            ENDP
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    图4.10 Stm32F429的Start_up.s启动汇编文件部分代码

    这就是复位中断处理函数。在0x00000000地址存放的,实际是MSP主栈指针初始值,然后0x00000004是Reset_Handler函数的地址,后面就是其他中断向量的地址了。

    简而言之,复位之后,先初始化栈指针,然后执行Reset_Handler。

    这里屏蔽了SystemInit函数,这个函数就是CMSIS-Core里面的系统时钟初始化函数,我们将自己完成这部分代码。

    __main函数是C语言的初始化函数,比如你在sram里面定义了一个有很多数据的数组,那么在C语言运行环境初始化的时候,就会将这段数据从flash搬运至sram中。

    这里需要注意,C语言执行是有环境的,比如全局变量,静态变量,但是这不代表C代码在C环境未初始化时就无法使用。因此,我们可以在复位的地方直接使用C函数来初始化,这常用于某些重要外设的初始化,因为C语言运行环境的初始化也要颇费一段时间。 必须注意此时C代码将丧失部分特性

    4.4 时钟树

    这是最重要的MCU必看知识,常位于RCC,Reset and Clock control。

    在这里插入图片描述

    图4.11 Stm32F429的时钟树

    这种图要挑重点来看,其他外设时候可以用时在看

    • 首先是时钟输入源,Stm32记住为两高两低,两内两外,即LSE,LSI,HSE,HSI。
    • PLL是锁相环倍频,主要用途就是生成高频率的时钟。
    • SYSCLK可由HSI、HSE、PLLCLK输入,然后输出供绝大数外设使用,像独木桥

    LSE clock即low-speed externa clock,低速外部时钟,HSI clock就是 high-speed internal clock,高速内部时钟,名字就是几个词的搭配,非常好记。

    两个低速晶振都是32.768Khz,一般都是用于RTC(Real-time clock)和看门狗模块,也可以用这个时钟倍频给SYSCLK使用,倍频的方法不止PLL这一种,例如TI MSP系列的DCO数控振荡器。

    MCO可输出内部的时钟,如果连接到示波器,可用判断当前时钟的频率是否符合预期。其他的情况可用于给其他设备供给时钟信号。

    在Stm32单片机复位启动后,一般都是默认选为HSI RC时钟,16Mhz,不是很准。 此时SYSCLK=16MHz,其后的AHB和APB分频系数都是默认值,即最小值分频值1。

    需要注意,内部时钟是集成在芯片内部,而外部晶振需要在最小系统板上额外焊接。

    在硬件上,就需要设计外部晶振电路,新手以模仿最好。在参考手册和数据手册的RCC章节都可以找到相关的晶振参数限制和电路模板。

    时钟切换并非是一个简单的过程,最大的原因是,对于外部晶振,我们一般需要先要初始化它,然后再切换SYSCLK时钟源,这部分也会引申出最刺激的部分CPU超频,可以超出官方限定的频率来运行CPU。

    总所周知,CPU运行频率和CPU供电有关,Cortex-M处理器也不例外,供电电压的大小限制了CPU最大频率的上限。此外还有来自flash的限制,flash的读取速度是受限的,而SRAM静态随机存储器的速度是非常快的,因为桌面级CPU就是拿SRAM做缓存的。

    关于如何改变CPU的运行频率SYSCLK的步骤在参考手册的嵌入Flash章节的read interface部分有详细介绍。在后续的文章也会专门进行讲解。

    4.5 中断和异常

    在Stm32单片机上的参考手册,一般对中断向量只是简单展示具体的向量类别。更多的细节展示了外部中断的设置方法,我们这里暂时不讨论外部中断,也就是事件的设置方法,后续章节会继续这部分内容。

    对于Cortex-M处理器,最多支持240个中断请求(IRQ),以及多个预设的系统异常。如下:

    异常优先级类型描述地址
    --MSP栈地址0x0000 0000
    -3(固定)复位各类复位事件触发0x0000 0004
    -2(固定)NMI不可屏蔽中断,外部输入,如RCC安全系统0x0000 0008
    -1(固定)硬件错误HardFault,所有类型的错误都可能引发0x0000 000C
    可编程存储器管理错误MemManage错误0x0000 0010
    可编程总线错误BusFault,预取指失败,存储器访问失败0x0000 0014
    可编程使用错误UsageFault,未定义的指令或非法状态,用于协处理器0x0000 0018
    保留未使用4个保留的向量0x0000 001C-28
    可编程SVCall通过 SWI 指令调用的系统服务0x0000 002C
    可编程调试监控Debug Monitor,调试监控器0x0000 0030
    保留未使用1个保留的向量0x0000 0034
    可编程PendSV可挂起的系统服务,OS一般通过它进行进程切换0x0000 0038
    可编程SysTick系统嘀嗒定时器0x0000 003C
    可编程外部中断MCU厂家绑定到外设中断源0x0000 0040-198
    图4.12 Stm32F429的中断表(部分)

    我们使用单片机,用的中断几乎都是外部中断,即MCU厂家已经跟我们绑定好外部外设中断源。

    因此,我们必须把写好的中断,如串口中断的处理函数地址填写到对应外部中断的地址处,即0x0000 0040-0x0000 00198处,随着不同封装和MCU型号,其外部中断向量的实际数量也就不同,因此其结束地址(0x0000 00198)也就不同。

    大部分部分优先级是可以手动设置的,但有三个异常的优先级是固定的,他们正常情况下是不可屏蔽的,即复位、NMI、HardFault。

    关于中断的部分属于内核部分,在《Arm Cortex M3/M4 权威指南》的第7章异常和中断里面有详细介绍,这里不具体展开,后续将会继续讨论。

    我们设置中断的时候可以简单起见,即无需中断分组,只需要中断优先级,因为常见的RTOS都不支持中断分组,那我们也无需使用复杂的中断分组功能。此外也只需要使能和关闭中断,无需过多操作,在后面搭载RTOS时再考虑复杂的功能使用。

    4.6 GPIO 通用输入和输出

    为什么GPIO放在一开始就去需要了解呢?因为这实际上是单片机最基础的使用功能了,很简单,所以大部分人都忽略了它,但往往带来致命的问题。

    此外,不同的MCU厂家的GPIO的特性也不一样,但整体来说,可以归纳出一些共同点:

    • 输入,输出状态
    • IO的速率和中断特性
    • 复用IO功能到外设上

    Stm32的IO功能做得非常简洁易看,某些厂家,IO功能长达数十篇章,引脚之间差异较大,使用不兼容,体验很差。

    在这里插入图片描述

    图4.13 Stm32F429的GPIO基本结构(部分)

    这张图可以看出什么呢?最开始有一堆保护二极管,这是用来容忍5v管脚的,单片机的电压域是3.3v域(1.8v-3.6v),但可以和5v电平直接相连,而无需串联限流电阻(一般4.7KΩ),但诸如C51/52和arduino单片机是5v电压域。

    然后输入和输出走的是不同的路线,输入方面,无论是复用的数字输入还是模拟输入,都无需经过IO的控制。输出量需要经过开漏和推挽的控制,开漏状态下,“0”会激活N-MOS,因此,在低电平上具有较高的驱动能力,但在高电平下负载能力较弱,需要通过上拉来增强。 推挽模式下,高低电平都具有较大的驱动能力,但是需要注意过大的电流烧毁管脚。

    关于这部分可参考文档:开漏输出与推挽输出 Kevin Zhang - 知乎 (zhihu.com)

    我们一般都会使用推挽模式来从管脚输出,最常见的应用是LED灯,自然驱动能力较强比较好。外设复用情况下,可能需要根据外设的要求选择推挽和开漏模式,这部分可在参考手册GPIO部分了解

    在输出模式下,有以下情况,此外还有速率OSPEEDE可以配置

    MODER模式类型上下拉电阻配置情况
    01普通输出推挽无/上拉/下拉电阻带可选上下拉电阻的普通推挽输出
    01普通输出开漏无/上拉/下拉电阻带可选上下拉电阻的普通开漏输出
    10复用输出推挽无/上拉/下拉电阻带可选上下拉电阻的复用推挽输出
    10复用输出开漏无/上拉/下拉电阻带可选上下拉电阻的复用开漏输出

    输入模式下,速率配置和开漏推挽配置是无效的,图4.13可以看出其电路是不同的,主要情况如下:

    MODER模式上下拉电阻配置情况
    00复用输入浮空/上拉/下拉电阻带可选上下拉电阻的普通输入
    11模拟输入00ADC等模拟外设的输入,无需额外配置

    此外需要注意的是,有部分管脚一开始被用于调试端口,在复位时默认是复用状态:

    在这里插入图片描述

    图4.14 Stm32F429的GPIO基本结构(部分)

    这些管脚,若是想用于IO功能或其他外设复用功能,必须清除到已有的状态。另外一方面,如果调试器连接芯片失败,很有可能是程序代码使用了这些管脚,因此要把自举模式调到系统存储器或者SRAM,然后就可以进入调试模式了,此外,一直按住复位键也可以。

    管脚具体的复用功能如何配置需要查阅数据手册->第四章,引脚排列和引脚说明->表12,复用功能映射,可以查看仔细信息。

    5.创建keil project,项目工程

    首先需要对keil最一些配置,第一个是编辑器,在edit->configuration,首先注意这个编码是ANSI,这个不是ASCII编码,而是多字节编码,是Windows的产物,对应中文就是GBK等,另外一种常见的编码是UTF-8,这两个之间不能直接线性转换,因此我们必须规定其中一种,现在一般选择UTF-8就好。

    然后是下面的各类文件选项,主要是勾选Insert spaces for tabs,我们的文件不需要tab符号,而且每个tab符号都应该被转化为4个空格,即Tab size为4。

    这里并不在keil上编码,因为界面属实太糟糕了,当然,可以美化,可以自行去网上寻找相关配置文件。

    关于如何创建keil工程,这里不再赘述,在正点原子的教程里面是有详细步骤,晚上也能收到大把的教程。

    先创建项目文件夹,结构如下,这套模板非常常见,没有为什么,只是几个文件夹而已,高兴可以随便放:

    E:\F429\429BSP
    ├─HARDWARE 	  //存放外设代码
    ├─OBJ		  //存放编辑的中间文件
    ├─README	  //帮助说明文档
    ├─SYSTEM	  //系统关键代码,即初始化、串口输出,时钟等
    ├─SYSTEM-CORE //存放CMSIS-core和MCU头文件
    └─USER		  //存放主函数文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    首先是获取启动汇编文件,一般而言,可以直接拿别人工程里面的直接使用,如正点原子的例程。这里想起来keil下载了一个Stm32Fx系列的支持包,那里面有没有我们需要的文件呢?确实有,如:

    //F是安装keil的盘符,cg是系统的用户名字
    目录: F:\Users\cg\AppData\Local\Arm\Packs\Keil\STM32F4xx_DFP\2.16.0\Drivers\CM 
        SIS\Device\ST\STM32F4xx\Source\Templates
    
    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    d-----         2022/8/26     22:56                arm
    d-----         2022/8/26     22:56                gcc
    d-----         2022/8/26     22:56                iar
    -ar---          2021/8/9     13:44          27018 system_stm32f4xx.c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    STM32F4xx_DFP就是我们下载的支持包。system_stm32F4xx.c是ST厂家给我们写好的系统时钟初始化代码。arm、gcc、iar里面就是三种不同编译工具链所需的启动文件,keil属于arm范畴,所以复制这些文件到工程目录下的SYSTEM文件夹。

    接下来在下面文件夹获取对应的头文件:

    //F是安装keil的盘符,cg是系统的用户名字
    F:\Users\cg\AppData\Local\Arm\Packs\Keil\STM32F4xx_DFP\2.16.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include
    	-ar---          2021/8/9     13:44        1463228 stm32f429xx.h
    	-ar---          2021/8/9     13:44          12261 stm32f4xx.h
    	-ar---          2021/8/9     13:44           3674 system_stm32f4xx.h
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意,这里我们选择的是Stm32F429开发板,所以要选取对应的头函数和启动汇编文件,但如果是其他的F4系列,就要选取对应的头文件了,很容易就能类推到其他单片机上。

    所以目前SYSTEM下有以下文件:

    +---SYSTEM
    |       startup_stm32f429xx.s
    |       stm32f429xx.h
    |       stm32f4xx.h
    |       system_stm32f4xx.c
    |       system_stm32f4xx.h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是还缺了一部分,即内核的头文件,还有一些内核定义和内核寄存器,以及一些相关的函数,即CMSIS-Core部分代码

    需要注意,我们是完全可以自己写这些内核函数,并且用C代码直接读写寄存器,但是问题是这部分代码并不冗余,自己去写也简化不了多少,但不如直接使用比较好。

    这部分内核代码在以下路径,里面有所有的Cortex-M内核头文件:

    //F是安装keil的盘符,cg是系统的用户名字
    F:\Users\cg\AppData\Local\Arm\Packs\ARM\CMSIS\5.9.0\CMSIS\Core\Include
    	-ar---          2022/5/2     11:07          27999 cmsis_armclang.h
    	-ar---          2022/5/2     11:07           9481 cmsis_compiler.h
    	-ar---          2022/5/2     11:07           1680 cmsis_version.h
    	-ar---          2022/5/2     11:07         120975 core_cm4.h
    	-ar---          2022/5/2     11:07          11731 mpu_armv7.h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Stm32F4xx需要的内核头文件是core_cmFunc.h,此外还有几个内核函数头文件,包含编译和内存保护相关的信息。

    这里已经很明确了,内核架构为armv7,编译器为armclang,但查看这些头文件,可以发现支持非常多的编译工具链。

    在armclang和armcc都是keil所支持的,一个对应版本5(armcc),一个对应版本6(支持C++,以及C的新标准)。

    具体可见:ARM 之七 主流编译器(armcc、iar、gcc for arm、LLVM(clang))详细介绍_ShouZC的博客-CSDN博客_armcc

    我们将用最新的版本ARMCLANG六来学习,不再使用老版本的ARMCC。

    接下来,我们的项目文件将要创建在429BSP文件夹下,也就是SYSTEM和USER的根目录下,开发板类型选择Stm32F429IGTx,支持包一个都不选。

    然后在导航栏的魔法棒这里开始项目配置:

    • Target选项卡,ARM Compiler选择6,版本6可以支持C++语法,版本5只能支持C99为止。用版本6。Floating Point Hardware 选择Single Precision,单精度浮点数。其他暂时保持原样就好。
    • Output选项卡,Select Folder for Objects 选择输出文件到OBJ文件夹,并且勾选创建HEX文件,HEX是串口下载的源文件。
    • Listing选项卡,Select Folder for Listing 选择输出文件到OBJ文件夹,其他保持原样。
    • USER这里可以定义一些预处理的命令,比如脚本之类,暂时用不着。
    • C/C++这里主要Optimization优化选到-O0等级,开发代码的时候不优化代码可以方便调试。Wamings开启All Wamings,要严格要求自己。勾选PlainChar is Signed,如果不勾选,char类型默认是无符号数。 C和C++的语言标准都选为C11,比较新的版本。

    其实keil会默认包含STM32F4xx_DFP里面的设备头文件,但这不影响我们放在工程下一份,无论是分发给别人还是使用VSCode进行开发,都将比较方便。

    然后在红绿白三色矩形选项配置项目目录,整体如下,具体步骤可在正点原子的教程PDF前几章中查看:

    在这里插入图片描述

    图5.1 Stm32F429的基本项目目录架构

    然后需要在魔法棒里面的C/C++选项卡里添加预设宏头文件包含路径

    在这里插入图片描述

    图5.2 Stm32F429的C/C++编译参数添加

    这里主要就是把自己的头文件路径包含进去,注意,这是不能递归子路径的,必须包含所有路径。

    到这里,工程就搭建完毕了,下面是目录拓扑图:

    BSP429:
    |   keilkill.bat //一些del命令,删除OBJ里面的编译中间件内容
    |   429bsp.uvguix.cg
    |   429bsp.uvoptx
    |   429bsp.uvprojx
    |
    +---HARDWARE
    +---OBJ
    |
    +---README
    +---SYSTEM
    |       delay.c
    |       delay.h
    |       sys.c
    |       sys.h
    |       usart.c
    |       usart.h
    |
    +---SYSTEM-CORE
    |       cmsis_armclang.h
    |       cmsis_compiler.h
    |       cmsis_version.h
    |       core_cm4.h
    |       mpu_armv7.h
    |       startup_stm32f429xx.s
    |       stm32f429xx.h
    |       stm32f4xx.h
    |       system_stm32f4xx.c
    |       system_stm32f4xx.h
    |
    +---USER
    |		main.c
    |
    \---DebugConfig
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    6.结束

    写到这里已经好多字了,本来想这里移植完Pikascript并输出helloworld的,但是篇幅太大了,那就分成两篇来些吧,MCU的初始化代码,编程风格等等还有好多要讲述。内容挺繁琐了,不过周末闲来也无事,就下周再见吧!

    下周应该是真正的编码介绍了。 O(∩_∩)O哈哈~

    (----------------------------------------未完待续--------------------------------------------)
  • 相关阅读:
    Ubuntu18.04下载安装基于使用QT的pcl1.13+vtk8.2,以及卸载
    我开源了一个Go学习仓库|笔记预览
    vue中screenfull组件实现全屏和非全屏+怎么给页面全屏加一张图片且不需要设置js获取页面高度
    <script>标签内容详解
    计算机毕业设计Java毕业设计流程管理(源码+系统+mysql数据库+lw文档)
    一文细谈SNN的基本数学原理,LIF模型,STDP与STBP学习方法
    每日三题 11.22
    二叉搜索树
    03【解构赋值】
    vue3使用element-plus
  • 原文地址:https://blog.csdn.net/Once_day/article/details/126697158