STM32裸机编程的基础知识(1)

这个系列将介绍 stm32 裸机编程的基础知识,以便更好地理解 stm32cube、keil 等框架和 ide 是如何工作的。本指南完全从头开始,只需要编译器和芯片数据手册,而不依赖任何其它软件工具和框架。
这个系列涵盖了以下话题:
存储和寄存器中断向量表启动代码链接脚本使用 make 进行自动化构建gpio 外设和闪烁 ledsystick 定时器uart 外设和调试输出printf 重定向到 uart用 segger ozone 进行调试系统时钟配置实现一个带设备仪表盘的 web 服务器我们将使用 nucleo-f429zi 开发板 (淘宝购买) 贯穿整个指南的实践,每个章节都有一个相关的完整小项目可以实战。最后一个 web 服务器项目非常完整,可以作为你自己项目的框架,因此这个示例项目也提供了其他开发板的适配:
stm32 nucleo-f429ziti ek-tm4c1294xl树莓派 pico-w对其他板子的适配支持还在进行中,可以提交 issue 来建议适配你正在用的板子。
工具配置为继续进行,需要以下工具:
arm gcc, https://launchpad.net/gcc-arm-embedded - for compiling and linkinggnu make, http://www.gnu.org/software/make/ - for build automationst link, https://github.com/stlink-org/stlink - for flashingmac 安装打开终端,执行:
$ /bin/bash -c $(curl -fssl https://raw.githubusercontent.com/homebrew/install/head/install.sh)$ brew install gcc-arm-embedded make stlinklinux (ubuntu) 安装打开终端,执行:
$ sudo apt -y install gcc-arm-none-eabi make stlink-toolswindows 安装scoop install gcc-arm-none-eabi make stlink验证安装:
下载这个仓库,解压到 c:\\打开命令行,执行:cd c:\\bare-metal-programming-guide-main\\step-0-minimalmake数据手册stm32f429 mcu datasheetnucleo-f429zi board datasheet微控制器介绍微控制器(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: 0b12 位用 3: 0b113 位用 7: 0b1114 位用 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 * (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 节有描述,这些寄存器用来配置系统时钟和一些其它的事情。

提升ADI测量工程的堆栈挑战
苹果A17仍难超过自家M1芯片吗?
搭建做数字货币交易所平台系统开发
跑步耳机哪款好用,最好的跑步耳机骨传导式分享!
Web漏洞靶场搭建(OWASP Benchmark)
STM32裸机编程的基础知识(1)
红外光学雨量传感器的场景应用
用电炉丝制作低压电热褥,Electric mattress
Nreal发力全球市场,注册开发者已超3500个
勒索软件的仍将持续作恶,备份策略或成解决方法
网龙华渔教育VR产品运用到教育和职业培训
RetNet架构和Transformer架构对比分析
Google Cloud 推出 TPU v5p 和 AI Hypercomputer: 支持下一代 AI 工作负载
怎样进行离心机的选购
高通放弃收购NXP,面临强大挑战
使用LoRaWAN网关快速建立本地LoRaWAN网络
INTEL展示激动人心的VR、4K视频和游戏体验
基于AT89C52单片机的语音录放系统实现
智能电力运维无人化的值守方式发生了什么变化
CXL的重要性