开发板:华清远见FSMP1A
主板:
扩展板:
芯片:STM32MP157A 架构:ARMV7 内核:Cortex®-A7 650 MHz *2 + Cortex®-M4 MPU
串口工具:SecureCRT.exe
分析硬件电路图
(1)分析LED灯工作原理
LED灯电路图及拓展接口电路图:
LED灯原理图:
通过电路图分析可知LD1\LD2\LD3工作原理 1.PE10/PF10/PE8引脚写高电平,灯点亮 2.PE10/PF10/PE8引脚写低电平,灯熄灭
(2)分析芯片框图
1.A7核执行程序如何控制GPIO控制器? 汇编指令:ldr/str 通过特殊功能寄存器,向特殊功能寄存器中写入指定的值,或者读取里面的内容 2.软件编程控制硬件的思想? 通过特殊功能寄存器,向特殊功能寄存器中写入指定的值,或者读取里面的内容。控制相应的外设工作 3.什么是特殊功能寄存器? 特殊功能寄存器是内存一块寻址空间 芯片厂家出厂的时候,对这块空间做了特殊的用途,不可以作为普通的寄存器使用 4.通过以上框图进行分析,需要分析芯片手册哪几个章节? GPIO章节(13章节General-purpose I/Os ) RCC章节(10章节Reset and clock control)
(3)分析手册RCC章节
分析RCC_MP_AHB4ENSETR 使AHB4总线使能 RCC_MP_AHB4ENSETR地址=基地址+偏移地址 = 0x50000000 + 0xA28 = 0x50000A28 RCC_MP_AHB4ENSETR[4] = 1 -------->设置GPIOE控制器使能工作 如何确定基地址
(4)分析手册GPIO章节
通过这个章节分析可知:GPIOx_MODER,GPIOx_OTYPER, GPIOx_OSPEEDR, GPIOx_PUPDR作用 1) GPIOx_MODER:GPIO模式寄存器----->设置为输出模式 2) GPIOx_OTYPER:GPIO输出类型寄存器----->设置为推挽/开漏输出 3) GPIOx_OSPEEDR:GPIO输出速度寄存器----->设置为输出速率 4) GPIOx_PUPDR:GPIO是否需要上下拉电阻 5) GPIOx_ODR:GPIO输出数据寄存器------>输出高低电平,实现LED灯点亮核熄灭
1) 分析GPIOx_MODER寄存器
LED1------>PE10引脚分析 1.如何确定GPIOE_MODER寄存器的地址? 地址=基地址+偏移地址=0x50006000+0x00=0x50006000 2.通过GPIOE_MODER设置PE10引脚设置为输出模式? GPIOE_MODER[21:20]=01------>输出模式 向0x50006000地址中的第[21:20]写入01
2) 分析GPIOx_OTYPER寄存器
LED1------>PE10引脚分析 1.如何确定GPIOE_OTYPER寄存器的地址? 地址=基地址+偏移地址=0x50006000+0x04=0x50006004 2.通过GPIOE_OTYPER设置PE10引脚设置为推挽输出模式? GPIOE_OTYPER[10] = 0 ----->设置为推挽输出模式 向0x50006004地址中的第[0]写入0 推挽输出: PMOS管和NMOS管都可以正常工作,可以输出高低电平 开漏输出: 只有NMOS管可以正常工作,只可以输出低电平,如果想输出高电平,需要外接上拉电阻
3) 分析GPIOx_OSPEEDR寄存器
LED1------>PE10引脚分析 1.如何确定GPIOE_OSPEEDR寄存器的地址? 地址=基地址+偏移地址=0x50006000+0x08=0x50006008 2.通过GPIOE_OSPEEDR设置PE10引脚设置为低速输出模式? GPIOE_OSPEEDR[21:20] = 00 ----->设置为低速输出模式 向0x50006008地址中的第[21:20]写入00
4) 分析GPIOx_PUPDR寄存器
LED1------>PE10引脚分析 1.如何确定GPIOE_PUPDR寄存器的地址? 地址=基地址+偏移地址=0x50006000+0x0C=0x5000600C 2.通过GPIOE_PUPDR设置PE10引脚设置为禁止上下拉? GPIOE_PUPDR[21:20] = 00 ----->设置为禁止上下拉 向0x5000600C地址中的第[21:20]写入00
5) 分析GPIOx_ODR寄存器
LED1------>PE10引脚分析 1.如何确定GPIOE_ODR寄存器的地址? 地址=基地址+偏移地址=0x50006000+0x14=0x50006014 2.通过GPIOE_ODR设置PE10引脚输出高低电平? GPIOE_ODR[10] = 0 ----->设置PE10引脚输出低电平 GPIOE_ODR[10] = 1 ----->设置PE10引脚输出高电平 向0x50006014地址中的第[10]写入0,输出低电平 向0x50006014地址中的第[10]写入1,输出高电平
.global _start
_start:
/**********LED1点亮**************/
LED1_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOE控制器使能 0x50000A28[4] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 4)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOE_MODER:0x50006000寄存器设置PE10引脚为输出模式 0x50006000[21:20]= 01
ldr r0,=0x50006000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
orr r1,r1,#(0x1 << 20)
str r1,[r0]
@3.通过GPIOE_OTYPER:0x50006004寄存器设置PE10引脚为推挽输出模式 0x50006004[10]= 0
ldr r0,=0x50006004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
@4.通过GPIOE_OSPEEDR:0x50006008寄存器设置PE10引脚为低速输出模式0x50006008[21:20]= 00
ldr r0,=0x50006008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
@5.通过GPIOE_PUPDR:0x5000600C寄存器设置PE10引脚为禁止上下拉0x5000600C[21:20]= 00
ldr r0,=0x5000600C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
/**********LED2点亮PF10**************/
LED2_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOF控制器使能 0x50000A28[5] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 5)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOF_MODER:0x50006000寄存器设置PF10引脚为输出模式 0x50007000[21:20]= 01
ldr r0,=0x50007000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
orr r1,r1,#(0x1 << 20)
str r1,[r0]
@3.通过GPIOF_OTYPER:0x50006004寄存器设置PF10引脚为推挽输出模式 0x50007004[10]= 0
ldr r0,=0x50007004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
@4.通过GPIOF_OSPEEDR:0x50006008寄存器设置PE10引脚为低速输出模式0x50007008[21:20]= 00
ldr r0,=0x50007008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
@5.通过GPIOF_PUPDR:0x5000700C寄存器设置PE10引脚为禁止上下拉0x5000700C[21:20]= 00
ldr r0,=0x5000700C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 20))
str r1,[r0]
/**********LED3点亮PE8**************/
LED3_INIT:
@1.通过RCC_AHB4_ENSETR:0x50000A28寄存器设置GPIOE控制器使能 0x50000A28[4] = 1
ldr r0,=0x50000A28
ldr r1,[r0] @将r0寄存器地址中的值,读到r1寄存器中
orr r1,r1,#(0x1 << 4)
@将r1寄存器中的第4位置1
str r1,[r0]
@2.通过GPIOE_MODER:0x50006000寄存器设置PE8引脚为输出模式 0x50006000[17:16]= 01
ldr r0,=0x50006000
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
orr r1,r1,#(0x1 << 16)
str r1,[r0]
@3.通过GPIOE_OTYPER:0x50006004寄存器设置PE8引脚为推挽输出模式 0x50006004[8]= 0
ldr r0,=0x50006004
ldr r1,[r0]
and r1,r1,#(~(0x1 << 8))
str r1,[r0]
@4.通过GPIOE_OSPEEDR:0x50006008寄存器设置PE8引脚为低速输出模式0x50006008[17:16]= 00
ldr r0,=0x50006008
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
str r1,[r0]
@5.通过GPIOE_PUPDR:0x5000600C寄存器设置PE8引脚为禁止上下拉0x5000600C[17:16]= 00
ldr r0,=0x5000600C
ldr r1,[r0]
and r1,r1,#(~(0x3 << 16))
str r1,[r0]
loop:
bl LED1_ON
bl delay_1s
bl LED1_OFF
bl delay_1s
bl LED2_ON
bl delay_1s
bl LED2_OFF
bl delay_1s
bl LED3_ON
bl delay_1s
bl LED3_OFF
bl delay_1s
b loop
LED1_ON:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出高电平 0x50006014[10]= 1
ldr r0,=0x50006014
ldr r1,[r0]
orr r1,r1,#(0x1 << 10)
str r1,[r0]
mov pc,lr
LED2_ON:
@1.通过GPIOF_ODR:0x50007014寄存器设置PF10引脚为输出高电平 0x50007014[10]= 1
ldr r0,=0x50007014
ldr r1,[r0]
orr r1,r1,#(0x1 << 10)
str r1,[r0]
mov pc,lr
LED3_ON:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE8引脚为输出高电平 0x50006014[8]= 1
ldr r0,=0x50006014
ldr r1,[r0]
orr r1,r1,#(0x1 << 8)
str r1,[r0]
mov pc,lr
LED1_OFF:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出低电平 0x50006014[10]= 0
ldr r0,=0x50006014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
mov pc,lr
LED2_OFF:
@1.通过GPIOE_ODR:0x50007014寄存器设置PE10引脚为输出低电平 0x50007014[10]= 0
ldr r0,=0x50007014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 10))
str r1,[r0]
mov pc,lr
LED3_OFF:
@1.通过GPIOE_ODR:0x50006014寄存器设置PE10引脚为输出低电平 0x50006014[8]= 0
ldr r0,=0x50006014
ldr r1,[r0]
and r1,r1,#(~(0x1 << 8))
str r1,[r0]
mov pc,lr
@ 大概1s的延时函数
delay_1s:
mov r3, #0x10000000
mm:
cmp r3, #0
subne r3, r3, #1
bne mm
mov pc, lr
.end
#ifndef __GPIO_H__
#define __GPIO_H__
//1.RCC寄存器封装,用宏定义进行封装
#define RCC_AHB4_ENSETR (*(unsigned int *)0x50000A28)
//2.GPIO寄存器进行封装,用结构体封装
typedef struct{
volatile unsigned int MODER; //00
volatile unsigned int OTYPER; //04
volatile unsigned int OSPEEDR; //08
volatile unsigned int PUPDR; //0C
volatile unsigned int IDR; //10
volatile unsigned int ODR; //14
}gpio_t;
#define GPIOE ((gpio_t*)0x50006000)
#define GPIOF ((gpio_t*)0x50007000)
//引脚封装
#define GPIO_PIN_0 0
#define GPIO_PIN_1 1
#define GPIO_PIN_2 2
#define GPIO_PIN_3 3
#define GPIO_PIN_4 4
#define GPIO_PIN_5 5
#define GPIO_PIN_6 6
#define GPIO_PIN_7 7
#define GPIO_PIN_8 8
#define GPIO_PIN_9 9
#define GPIO_PIN_10 10
#define GPIO_PIN_11 11
#define GPIO_PIN_12 12
#define GPIO_PIN_13 13
#define GPIO_PIN_14 14
#define GPIO_PIN_15 15
//封装模式寄存器
typedef enum{
INPUT,
OUTPUT,
ALT,
ANALOG,
}gpio_mode_t;
//封装输出类型寄存器
typedef enum{
PP,
OD,
}gpio_otyper_t;
//封装输出速度寄存器
typedef enum{
LOW,
MED,
HIGH,
VERY_HIGH,
}gpio_ospeedr_t;
//封装是否需要上下拉电阻
typedef enum{
NO_PUPD,
PU,
PD,
}gpio_pupdr_t;
//封装输出高低电平
typedef enum{
GPIO_RESET,
GPIO_SET,
}gpio_status_t;
//结构体初始化
typedef struct{
gpio_mode_t moder;
gpio_otyper_t otyper;
gpio_ospeedr_t speedr;
gpio_pupdr_t pupdr;
}gpio_init_t;
//初始化函数
void hal_gpio_init(gpio_t* gpiox,gpio_init_t* init,unsigned int pin);
//写操作函数
void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t state);
#endif
#include "gpio.h"
//初始化函数
void hal_gpio_init(gpio_t* gpiox,gpio_init_t* init,unsigned int pin)
{
//1.设置输出模式
gpiox->MODER &= (~(0x3 << (pin * 2)));
gpiox->MODER |= (init->moder << (pin *2));
//2.设置输出类型
gpiox->OTYPER &= (~(0x1 << pin));
gpiox->OTYPER |= (init->otyper << pin);
//3.设置输出速度
gpiox->OSPEEDR &= (~(0x3 << (pin *2)));
gpiox->OSPEEDR |= (init->speedr << (pin * 2));
//4.设置是否需要上下拉
gpiox->PUPDR &= (~(0x3 << (pin * 2)));
gpiox->PUPDR |= (init->pupdr << (pin * 2));
}
//写操作函数
void hal_gpio_write(gpio_t* gpiox,unsigned int pin,gpio_status_t state)
{
if(state == GPIO_RESET)
{
gpiox->ODR &= (~(0x1 << pin));
}
else
{
gpiox->ODR |=(0x1 << pin);
}
}
#include "gpio.h"
extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
int i,j;
for(i = 0; i < ms;i++)
for (j = 0; j < 1800; j++);
}
void led_init()
{
//1.时钟使能
RCC_AHB4_ENSETR |= (0x3 << 4);
//2.led灯结构体初始化
gpio_init_t init = {OUTPUT,PP,LOW,NO_PUPD};
hal_gpio_init(GPIOE,&init,GPIO_PIN_10);
hal_gpio_init(GPIOF,&init,GPIO_PIN_10);
hal_gpio_init(GPIOE,&init,GPIO_PIN_8);
}
int main()
{
led_init();
while(1)
{
hal_gpio_write(GPIOE,GPIO_PIN_10,GPIO_SET);
delay_ms(500);
hal_gpio_write(GPIOE,GPIO_PIN_10,GPIO_RESET);
delay_ms(500);
hal_gpio_write(GPIOF,GPIO_PIN_10,GPIO_SET);
delay_ms(500);
hal_gpio_write(GPIOF,GPIO_PIN_10,GPIO_RESET);
delay_ms(500);
hal_gpio_write(GPIOE,GPIO_PIN_8,GPIO_SET);
delay_ms(500);
hal_gpio_write(GPIOE,GPIO_PIN_8,GPIO_RESET);
delay_ms(500);
}
return 0;
}
1.配置PE10/PF10/PE8,鼠标左键,设置位输出模式
2.鼠标右键,配置为M4核