目录
时钟(Clock)概念 (AI生成,有错误请在评论区指出,我会进行修改)
RCC(Reset and Clock Control)的作用
为什么用结构体封装,不用枚举,结构体的地址是连续的,我们操作寄存器的地址也是连续的
1.安装STM32MP157开发环境
1.1.虚拟机安装
需注意 toStuUbuntu的版本越高效率越高,尽量使用高版本(本人用20.04)
1.2组外网




外网组建完成
1.3.交叉编译工作链

1.安装兼容32位的库
sudo apt-get install lib32z1
2.在家目录下创建一个toolchain文件夹
mkdir toolchain
3.将交叉编译工具链拷贝到~/toolchain文件夹中
4.进入~/toolchain文件夹中,对交叉编译工具链进行解压
linux@ubuntu:~/toolchain$ tar -vxf gcc-linaro-7.5.0-2019.12-i686_arm-linux-gnueabihf.tar.xz
5.将交叉编译工具链进行重命名
linux@ubuntu:~/toolchain$ mv gcc-linaro-7.5.0-2019.12-i686_arm-linux-gnueabihf gcc-7.5.0
6.将交叉编译工具链配置到ubuntu中
linux@ubuntu:~/toolchain$ sudo vi /etc/bash.bashrc
7.打开配置文件后,添加如下一行配置信息
export PATH=$PATH:/home/ubuntu/toolchain/gcc-7.5.0/bin
8.重启脚本文件
source /etc/bash.bashrc
9.验证交叉编译工具链是否安装成功
2.点亮一个LED
在linux内打开命令行
输入
mkdir arm

建立一个 arm文件夹
我没有收费,直接下载即可
将压缩包放进Linux-arm

两种解压方式
1.输入命令行
tar -vxf led-c.tar.xz
2.图形化操作解压
操作后查看自己的文件夹是否完成操作。

.c 文件都放在 src中 如 I2C.c LED.c src为顶层文件。
.h 文件都放在 include 如 I2C.h LED.H include为底层文件。
最终在 main.c 中调用 .c .h文件。
编译:多个文件进行编译是用Makefile进行编译。
系统文件存放位置:系统提供的头文件在 common
-O 命令:将三个文件以竖屏的方式分别打开。

2.1.分析芯片手册
查看stm32mp157的官方文档,硬件原理图

得知板载led的三个引脚

LED1 ===> PE10 ===》 PE10 引脚 为0时灯熄灭 ,为1时灯点亮。
2.2.芯片手册
2.2.1分析GPIOx_MODER寄存器

如LED1,引脚为PE10,找 MODER10[1:0] (21 20),用00,01,10,11来控制端口状态

在库函数中找到具体函数
位操作


ox3 为 0011 取反为1100 向左位移20次 21 20便是00 这就是清零操作
0x1 为 0001 向左位移20次 21 20便是01 这就是置一操作
以此来实现对寄存器的位操作
2.2.2.分析GPIOx_ODR

~ !两个取反的区别
~ 按位取反:
- 符号:
~(在C/C++等语言中) - 操作对象: 对一个数的每一个二进制位进行取反(0变1,1变0)。
- 结果: 返回一个与操作数位数相同的数值,每一位都取反。
- 用途:
- 通常用于硬件寄存器操作,例如翻转某些特定位。
- 也可以用于某些低级位操作算法。
uint8_t value = 0b00001111; // 十进制 15
uint8_t result = ~value; // 0b11110000 (十进制 240)
!逻辑取反:
- 操作对象: 对整个布尔表达式或变量的“真值”进行取反。
- 结果: 返回一个布尔值(
true或false)。- 如果操作数为0(假),结果为
true。 - 如果操作数为非0(真),结果为
false。
- 如果操作数为0(假),结果为
- 用途:
- 用于条件判断,例如在
if语句中检查某个条件是否不成立。
- 用于条件判断,例如在
bool flag = true;
bool result = !flag; // false
int num = 10;
if (!num) {
// 这个条件为假,因为 num 非0
}
2.3.时钟配置
在 STM32MP1 系列微处理器(如 STM32MP157)中,时钟(Clock) 是一个核心的抽象概念,用于管理和控制处理器及其外设的工作频率。时钟系统决定了 CPU、总线、外设等模块的运行速度,直接影响芯片的性能和功耗。
时钟(Clock)概念 (AI生成,有错误请在评论区指出,我会进行修改)
-
时钟源:STM32MP1 的时钟可以来自多个内部或外部源,例如:
- HSI(High-Speed Internal):内部高速 RC 振荡器,通常为 16MHz 或 64MHz。
- HSE(High-Speed External):外部高速晶振,通常为 4~48MHz。
- LSI(Low-Speed Internal):内部低速 RC 振荡器,通常为 32kHz,用于独立看门狗或 RTC。
- LSE(Low-Speed External):外部低速晶振,通常为 32.768kHz,用于 RTC。
- PLL(Phase-Locked Loop):锁相环,用于生成更高频率的时钟。
-
时钟树(Clock Tree):STM32MP1 的时钟系统是一个复杂的树状结构,包含多个时钟源、分频器、倍频器和选择器,用于生成不同模块所需的时钟频率。
-
时钟域:不同的硬件模块(如 CPU、DMA、GPIO、USB 等)可能运行在不同的时钟频率下,形成多个时钟域。
RCC(Reset and Clock Control)的作用
RCC(Reset and Clock Control) 是 STM32MP1 中负责时钟管理和系统复位的硬件模块。它的主要功能包括:
- 时钟源选择:选择 HSI、HSE、LSI、LSE 或 PLL 作为系统时钟源。
- 时钟分频和倍频:通过分频器(Prescaler)和 PLL 调整时钟频率。
- 时钟使能/禁用:控制各个外设的时钟开关,以降低功耗。
- 系统复位管理:控制芯片的复位行为。
RCC的关键寄存器
- RCC_CR(Control Register):控制时钟源的使能和就绪状态。
- RCC_PLLCFGR(PLL Configuration Register):配置 PLL 的分频和倍频参数。
- RCC_CFGR(Clock Configuration Register):选择系统时钟源和总线分频。
- RCC_AHBxENR / RCC_APBxENR:使能或禁用 AHB/APB 总线上外设的时钟。
时钟与 RCC 的关系
- RCC 是时钟系统的控制中心:所有时钟源的选择、分频、倍频和分配都由 RCC 模块管理。
- 时钟配置通过 RCC 寄存器实现:开发者通过配置 RCC 的寄存器来调整时钟频率和分配。
- 时钟使能依赖 RCC:外设的时钟使能/禁用由 RCC 的使能寄存器控制,例如
RCC_AHB1ENR用于使能 GPIOA 的时钟。
时钟配置流程(以 STM32MP1 为例)
- 选择时钟源:例如,选择 HSE 作为系统时钟源。
- 配置 PLL:如果需要更高频率,可以通过 PLL 倍频。
- 设置分频器:调整 AHB、APB 总线的分频系数。
- 使能外设时钟:通过 RCC 的使能寄存器打开所需外设的时钟。
- 等待时钟稳定:某些时钟源(如 HSE)需要等待就绪标志位。
总结
- 时钟 是 STM32MP1 中所有模块运行的基础,决定了芯片的性能和功耗。
- RCC 是时钟系统的核心控制模块,负责时钟源选择、分频、倍频和分配。
- 开发者需要通过配置 RCC 寄存器或使用 HAL 库函数来管理时钟系统。
理解时钟和 RCC 的关系是开发 STM32MP1 应用的关键,特别是在需要优化性能或降低功耗的场景下。
2.4.时钟与RCC





led.h
#ifndef __LED_H_
#define __LED_H_
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
//LED1 --> PE10
void led1_init();
void led1_on();
void led1_off();
//LED2 --> PF10
void led2_init();
void led2_on();
void led2_off();
//LED3 --> PE8
void led3_init();
void led3_on();
void led3_off();
#endif
led.c
#include"led.h"
//LED1 --> PE10
void led1_init()
{
//设置GPIOE组时钟使能 [4]=1
RCC->MP_AHB4ENSETR |= (0x01<<4);
//1.shezhi PE10引脚为输出模式 MODER[21:20] = 01 保证其他位不变
//& 与0清0 与1不变
//| 或1置1 或0不变
//先将[21:20]清零
GPIOE->MODER &= (~ (0x3 << 20));
//在将[20]置1
GPIOE->MODER |= ( 0x1 << 20 );
}
void led1_on()
{
//设置PF10 引脚输出高电平 灯点亮 ODR[10]=1
GPIOE->ODR |= (0x1 << 10 );
}
void led1_off()
{
//设置PF10 引脚输出低电平 灯熄灭 ODR[10]=0
GPIOE->ODR &= ( ~(0x1<<10) );
}
//LED2 --> PF10
void led2_init()
{
//设置GPIOE组时钟使能 [5]=1
RCC->MP_AHB4ENSETR |= (0x01<<5 );
//1.shezhi PE10引脚为输出模式 MODER[21:20] = 01 保证其他位不变
//& 与0清0 与1不变
//| 或1置1 或0不变
//先将[21:20]清零
GPIOF->MODER &=(~ (0x3 << 20) );
//在将[20]置1
GPIOF->MODER |=( 0x1 << 20 );
}
void led2_on()
{
//设置PF10 引脚输出高电平 灯点亮 ODR[10]=1
GPIOF->ODR |= (0x1 << 10 );
}
void led2_off()
{
//设置PF10 引脚输出低电平 灯熄灭 ODR[10]=0
GPIOF->ODR &= ( ~(0x1<<10) );
}
//LED3 --> PE8
void led3_init()
{
//因LED1与LED3都是E引脚,并且LED1已经进行时钟使能,所以LED3不在进行时钟使能
//先将[17:16]清零
GPIOE->MODER &=(~ (0x3 << 16) );
//在将[16]置1
GPIOE->MODER |=( 0x1 << 16 );
}





335

被折叠的 条评论
为什么被折叠?



