STM32裸机编程指南-1

STM32裸机编程指南-1

系列目录

这个系列将介绍STM32裸机编程的基础知识,以便更好地理解STM32Cube、Keil等框架和IDE是如何工作的。本指南完全从头开始,只需要编译器和芯片数据手册,而不依赖任何其它软件工具和框架。

这个系列涵盖了以下话题:

  • 存储和寄存器
  • 中断向量表
  • 启动代码
  • 链接脚本
  • 使用make进行自动化构建
  • GPIO外设和闪烁LED
  • SysTick定时器
  • UART外设和调试输出
  • printf重定向到UART
  • 用Segger Ozone进行调试
  • 系统时钟配置
  • 实现一个带设备仪表盘的web服务器

我们将使用Nucleo-F429ZI开发板(淘宝购买)贯穿整个指南的实践,每个章节都有一个相关的完整小项目可以实战。最后一个web服务器项目非常完整,可以作为你自己项目的框架,因此这个示例项目也提供了其他开发板的适配:

对其他板子的适配支持还在进行中,可以提交issue来建议适配你正在用的板子。

工具配置

为继续进行,需要以下工具:

  • ARM GCC, https://launchpad.net/gcc-arm-embedded - for compiling and linking
  • GNU make, http://www.gnu.org/software/make/ - for build automation
  • ST link, https://github.com/stlink-org/stlink - for flashing

Mac安装

打开终端,执行:

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install gcc-arm-embedded make stlink

Linux(Ubuntu)安装

打开终端,执行:

$ sudo apt -y install gcc-arm-none-eabi make stlink-tools

Windows安装

scoop install gcc-arm-none-eabi make stlink

验证安装:

  1. 下载这个仓库,解压到 C:\
  2. 打开命令行,执行:
cd C:\bare-metal-programming-guide-main\step-0-minimal
make

数据手册

微控制器介绍

微控制器(microcontroller,uC或MCU)是一个小计算机,典型地包含CPU、RAM、存储固件代码的Flash,以及一些引脚。其中一些引脚为MCU供电,通常被标记为VCC和GND。其他引脚通过高低电压来与MCU通信,最简单的通信方法之一就是把一个LED接在引脚上:LED一端接地,另一端串接一个限流电阻,然后接到MCU信号引脚。在固件代码中设置引脚电压的高低就可以使LED闪烁:

存储和寄存器

MCU的32位地址空间按区分割。例如,一些存储区被映射到特定的地址,这里是MCU的片内flash,固件代码指令在这些存储区读和执行。另一些区是RAM,也被映射到特定的地址,我们可以读或写任意值到RAM区。

从STM32F429数据手册的2.3.1节,我们可以了解到RAM区从地址0x20000000开始,共有192KB。从2.4节我们可以了解到flash被映射到0x08000000,共2MB,所以flash和RAM的位置像这样:

从数据手册中我们也可以看到还有很多其它存储区,它们的地址在2.3节"Memory Map"给出,例如:"GPIOA"区从地址0x40020000开始,长度为1KB。

这些存储区被关联到MCU芯片内部不同的外设电路上,以特殊的方式控制外设引脚的行为。一个外设存储区是一些32位寄存器的集合,每个寄存器有4字节的空间,在特定的地址,控制着外设的特定功能。通过向寄存器写入值,或者说向特定的地址写一个32位的值,我们就可以控制外设的行为。通过读寄存器的值,我们就可以得到外设的数据或配置。

MCU通常有许多不同的外设,其中比较简单的就是GPIO(General Purpose Input Output,通用输入输出),它允许用户将MCU引脚设为输出模式,然后置“高”或置“低”;或者设置为输入模式,然后读引脚电压的“高”或“低”。还有UART外设,可以使用串行协议通过两个引脚收发数据。还有许多其它外设。

在MCU中,一个相同外设通常会有多个“实例”,比如GPIOA、GPIOB等等,它们控制着MCU引脚的不同集合。类似地,也有UART1、UART2等等,可以实现多通道。在Nucleo-F429上,有多个GPIO和UART外设。

例如,GPIOA外设起始地址为0x40020000,我们可以从数据手册8.4节找到GPIO寄存器的描述,上面说 GPIOA_MODER 寄存器偏移为0,意味着它的地址是 0x40020000 + 0,寄存器地址格式如下:

数据手册显示MODER这个32位寄存器是由16个2位的值组成。因此,一个MODER寄存器控制16个物理引脚,0-1位控制引脚0,2-3位控制引脚1,以此类推。这个2位的值编码了引脚模式:‘00’代表输入,‘01’代表输出,‘10’代表替代功能——在其它部分进行描述,‘11’代表模拟引脚。因为这个外设命名为’GPIOA’,所以对应引脚名为’A0’、‘A1’,等等。对于外设’GPIOB’,引脚则对应叫’B0’、‘B1’,等等。

如果我们向MODER寄存器写入32位的值’0’,就会把从A0到A15这16个引脚设为输入模式:

  * (volatile uint32_t *) (0x40020000 + 0) = 0;  // Set A0-A15 to input mode

通过设置独立的位,我们就可以把特定的引脚设为想要的模式。例如,下面的代码将A3设为输出模式:

  * (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6);  // CLear bit range 6-7
  * (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6;     // Set bit range 6-7 to 1

我来解释下上面的位操作。我们的目标是把控制GPIOA外设引脚3的位,也就是6-7,设为特定值,在这里是1。这个需要2步,首先,我们必须将6-7位的当前值清除,也就是清’0’,因为这两位可能已经有值;然后,我们再将6-7设为期望值。

所以,第一步,我们先把6-7位清’0’,怎么做呢?4步:

  • 使一个数有连续的N位’1’
    • 1位用1: 0b1
    • 2位用3: 0b11
    • 3位用7: 0b111
    • 4位用15: 0b1111
    • 以此类推,对于N位,数值应为 2^N - 1。对于2位,数值为 3,或者写为二进制 0b00000000000000000000000000000011
  • 将数字左移位。如果我们需要设置位 X-Y,则将数字左移X位。在我们的例子中,左移6位:(3 << 6),得到 0b00000000000000000000000011000000
  • 取反:0变1,1变0:~(3 << 6), 得到 0xb11111111111111111111111100111111
  • 现在,将寄存器值与我们的数字进行逻辑"与"操作,6-7位与’0’后会变0,其它位与’1’后不变,这就是我们想要的:REG &= ~(3 << 6)。注意,保持其它位的值不变是重要的,我们并不想改变其它位的配置。

一般地,如果我们想将 X-Y 位清除,或者说设为0,这样做:

PERIPHERAL->REGISTER &= ~(NUMBER_WITH_N_BITS << X);

最后,我们把那些位设为我们想要的值,则需要把想要的值左移X位,然后与寄存器当前值进行逻辑"或"运算:

PERIPHERAL->REGISTER |= VALUE << X;

现在,你应该明白了,下面的两行代码将把GPIOA MODER寄存器的6-7位设为1,即输出模式:

  * (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6);  // CLear bit range 6-7
  * (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6;     // Set bit range 6-7 to 1

还有一些寄存器没有被映射到MCU外设,而是被映射到了ARM CPU的配置和控制。例如,有一个"Reset and clock control"单元(RCC),在数据手册第6节有描述,这些寄存器用来配置系统时钟和一些其它的事情。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值