ARM微处理器编程模型与linux驱动开发

2024-09-05 05:52

本文主要是介绍ARM微处理器编程模型与linux驱动开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 微处理器
    • 指令系统
      • 数据类型
      • 字节对符号位扩展
    • ARM体系结构
      • ARM处理器工作模式
      • 寄存器
      • 异常
      • 过程调用标准
      • 程序内存划分
      • STM32的使用
        • 常用资源
        • GPIO口的使用
      • GPIO固件库的使用
      • STM固件库
      • Proteus常用元器件
      • 中断
      • AD转换
    • BootLoader的定制: 嵌入式系统上电以后硬件的初始化
    • Linux Kernel定制
    • 驱动程序开发:
      • 驱动程序的分类
      • 设备的属性
      • 设备驱动程序的组成
      • Linux驱动程序的基本结构
      • 驱动程序随内核一起编译

微处理器

微处理器=控制单元+算术逻辑单元+寄存器

指令系统

  • RISC:精简指令集 ARM
    • 寻址方式:10种以内
    • 指令集中指令数量:100条左右
    • load/store结构(加载数据在寄存器中,操作针对寄存器操作,而非存储器)
    • 大的统一的寄存器文件
    • 统一固定的指令域,化简了指令的编码,便于流水线设计,大多数指令执行时间是相等的,可以在一个时钟周期内完成
  • CISC:复杂指令集 X86、51
    • 寻址方式:比较多(10种以上)
    • 指令集中指令数量:每个功能都有专门的指令

数据类型

  • 字节8位:byte
  • 半字16位:halfword
  • 字32位:word

ARM指令集以4字节对齐,thumb指令集以2字节对齐,每执行一个指令,ARM的pc增加4,thumb的pc增加2

字节对符号位扩展

// 符号位扩展
struct s1{char a:2;char b:2;char c:2;int a:6;
}t;
t.a = 3;
printf("%d\n", t.a);// -1

符号位扩展:按符号位扩展到32位

ARM体系结构

ARM:RISC结构

ARM处理器工作模式

  • 用户模式

  • 快速中断模式

  • 中断模式

  • 管理模式

  • 中止模式

  • 未定义模式

  • 系统模式

  • Monnitor模式

  • hypervisor模式

寄存器

ARM寄存器有37个寄存器,在不同运行模式下使用的寄存器是不完全一致的
所有寄存器分为两大类:

  • 31个通用寄存器
  • 6个状态寄存器 CPSR(当前)、SPSR(保存)(NZCV)
    在这里插入图片描述

其中R0~R7为未分组的寄存器,对于任何模式,这些寄存器都对应相同的32位物理寄存器
R8~R14为分组的寄存器,他们所对应的物理寄存器取决于当前的处理器模式,几乎所有允许使用的通用寄存器指令都允许使用这些寄存器
R8~R12有两个分组物理寄存器,一个用于除FIQ模式之外所有寄存器模式,另一个用于FIQ模式。这样在发生FIQ中断后,库加速FIQ的处理速度

R13 堆栈寄存器SP:指向堆栈栈顶
R14 链接寄存器LR:作为(子程序)函数返回用,每种模式下保存子程序返回地址,当发生中断时将其设置为异常返回地址
R15 程序寄存器PC:下一条指令的地址

当前程序状态寄存器(CPSR)
在这里插入图片描述

条件码标志:

  • N:负(Negative)
  • Z:零(Zero)
  • C:进位(Carry)
  • V:溢出(Overflow)

中断进制位:I 和 F,为1时,禁止中断,为0时,允许中断
模式位:M0、M1、M2、M3… 0:用户模式,1:快速中断模式,2:中断模式,3:管理模式,4:中止模式,5:未定义模式,6:系统模式,7:Monnitor模式,8:hypervisor模式

异常

  • 中断 来自IO设备的信号,异步,总是返回下一条指令
  • 陷阱 有意的信号,同步,返回下一条指令,处理干扰的一种常用方法
  • 故障 潜在可恢复的错误,同步,返回到当前指令
  • 终止 严重不可恢复的错误,同步,不返回

异常过程:

  1. 上下文切换
    • 保存CPSR到对应的SPSR —— 保护状态寄存器
    • 将当前程序中的数压栈 —— 保护数据
    • 保存PC到LR —— 保存返回地址
    • 将跳转的入口地址保存到PC中 —— 实现跳转
  2. 异常返回,函数结束后,内循环转到外循环
    • 将SPSR恢复到CPSR
    • 将保护数据从栈中弹出到寄存器中
    • 将LR恢复到PC

过程调用标准

ATPCS:过程调用标准ATPCS(ARM-Thumb Produce Call Standard)规定了子程序间相互调用的基本规则,ATPCS规定子程序调用过程中寄存器的使用规则、数据栈的使用规则及参数的传递规则。

寄存器使用规则:
R0~R3:参数传递,返回值使用R0(32位)或R0R1(64位),用来存放前4个函数参数并存放返回值,参数超过4个时,使用栈空间传递
R4~R11 :通用变量寄存器,程序中使用的变量,最常用的是R4~R8,调用函数时,
R12:IP,临时过渡寄存器,在函数调用过程会变

程序内存划分

  • 代码段
  • 只读数据段
  • 可读写数据段
  • 堆段
  • 栈段

STM32的使用

48的引脚 大多数引脚复用功能

常用资源
  • ADC:模拟/数字转换控制 —— 模拟转感器数据的使用
  • DAC:数字/模拟转换
  • USART:串行口 —— 调试串口设备(蓝牙)
  • 串行总线端口:SPI、IIC、CAM
  • 定时器TIM:
  • EXIT:外部中断
  • GPIO:通用IO口 —— 开关信号的输入输出 37个引脚
  • RTC:实时时钟 —— 日历、时钟

总线:
AMBA片上总线已经成为了一种流行的工业片上总线标准

  • AHB(Advance High performance Bus) 系统总线
  • APB(Advance Peripheral Bus) 外设总线
    • APB 1 低速
    • APB 2 高速

最小系统:STM21F103C8T6小系统板,主要由单片机、金振电路、复位电路几部分组成,板载的资源能满足进行单片机GPIO、ADC、RTC、USART、IIC、SPIUSB数据通信等实验

GPIO口的使用
  1. 要控制一个设备,首先要使能该设备的端口的时钟系统
  2. 配置端口:设置工作模式(输入、输出…),设置工作属性(输出速度…)
    引脚:每一个端口理论上有16个引脚,通过GPIO_IDB(9-15)、GPIO_ODB(0-8)
    端口的配置:通过端口(PA、PB、PC)寄存器来进行,每个端口通过7个端口寄存器来进行设置,一般只用2 3个,通过GPIO_CRL、CPIO_CRH配置

端口配置:

  • 端口: PA, PB, PC, …

  • 引脚: 每一个端口理论上有16个引脚,Pin_0 ~ Pin_15,每一个端口通过7个端口寄存器来进行设置(对于简单的设置一般只使用2~3个端口寄存器就可以了)

    • ①两个32位的配置寄存器(GPIOx_CRL,GPIOx_CRH) – 一个配置寄存器管理8个引脚(一个引脚通过配置寄存器的四位来进行设置)
      (GPIOx_CRL) (x=A…G): GPIOx configuration register low, GPIOx端口低配置寄存器,用于配置GPIOx端口的第0位~第7位。
      (GPIOx_CRH) (x=A…G): GPIOx configuration register high, GPIOx端口低配置寄存器,用于配置GPIOx端口的第8位~第15位。

    • ②两个32位的数据寄存器(GPIOx_IDR,GPIOx_ODR) – 每一个引脚对应数据寄存器中的一位
      (GPIOx_IDR) (x=A…G): GPIOx input data register – 输入数据寄存器
      (GPIOx_ODR) (x=A…G): GPIOx output data register – 输出数据寄存器

    • ③一个32位的置位/复位寄存器 (GPIOx_BSRR)
      (GPIOx_BSRR) (x=A…G): GPIOx bit set/reset register

    • ④一个16位的复位寄存器(GPIOx_BRR)

    • ⑤一个32位的锁定寄存器(GPIOx_LCKR)
      (GPIOx_LCKR) (x=A…G): GPIOx configuration lock register

    一般情况下,对于输入引脚的操作通过CPIOx_CRL或者GPIOx_CRH、GPIOx_IDR就可以了;
    对于输出引脚的操作通过CPIOx_CRL或者GPIOx_CRH、GPIOx_ODR就可以了

  • 工作模式
    输入引脚的工作模式: 浮空输入、上拉输入、下拉输入和模拟输入
    输出引脚的工作模式: 推挽输出、开漏输出、复用推挽输出、复用开漏输出(最大输出速度有10MHz,2MHz和50MHz三种)

  • 端口配置寄存器:
    端口配置低寄存器(GPIOx_CRL)(x=A…G)
    端口配置高寄存器(GPIOx_CRH) (x=A…G)
    每一个引脚的配置使用寄存器的4位,包含两位Mod位和两位CNF位
    MODE位:
    00:输入模式(复位后的状态)
    01:输出模式,最大速度10MHz
    10:输出模式,最大速度2MHz
    11:输出模式,最大速度50MHz
    CNF位:
    在输入模式(MODE[1:0]=00):
    00:模拟输入模式
    01:浮空输入模式(复位后的状态)
    10:上拉/下拉输入模式
    11:保留
    在输出模式(MODE[1:0]>00):
    00:通用推挽输出模式
    01:通用开漏输出模式
    10:复用功能推挽输出模式
    11:复用功能开漏输出模式

假如: LED连接在GPIOC_Pin_13, 设置对应的寄存器
使用的寄存器是: GPIOC_CRH
MOD位为: GPIOC_CRH[21:20] == 11
CNF位为: GPIOC_CRH[23:22] == 00

数据寄存器IDR或者ODR的每一位对应一个引脚的输入或者输出数据
比如: LED要亮
要设置GPIOC_ODR[13] = 0

  • 寄存器地址计算:
    GPIOA: 0x4001 0800 - 0x4001 0BFF
    GPIOA_CRL: 0x4001 0800
    GPIOA_CRH: 0x4001 0804
    GPIOA_IDR: 0x4001 0808
    GPIOA_ODR: 0x4001 080C
    GPIOB: 0X4001 0C00 - 0x4001 0FFF
    GPIOB_CRL: 0X4001 0C00
    GPIOB_CRH: 0X4001 0C04
    GPIOB_IDR: 0X4001 0C08
    GPIOB_ODR: 0X4001 0C0C
    GPIOC: 0x4001 1000 - 0x4001 13FF
    GPIOC_CRL: 0x4001 1000
    GPIOC_CRH: 0x4001 1004
    GPIOC_IDR: 0x4001 1008
    GPIOC_ODR: 0x4001 100C

  • 实时时钟寄存器基础地址: 0x4002 1000
    APB2 外设时钟使能寄存器(RCC_APB2ENR) 偏移地址:0x18 – 0x4002 1018
    GPIOC的时钟使用RCC_APBENR的bit[4], 为1使能,为0失能

GPIO固件库的使用

  1. GPIO寄存器
//GPIO_TypeDef: 定义了STM32外部设备GPIO的所有寄存器
typedef struct 
{ vu32 CRL; vu32 CRH; vu32 IDR; vu32 ODR; vu32 BSRR; vu32 BRR; vu32 LCKR; 
} GPIO_TypeDef;//GPIO_InitTypeDef: 定义于文件“stm32f10x_gpio.h”:
typedef struct 
{ u16 GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; 
} GPIO_InitTypeDef;
  1. 端口地址定义
#define PERIPH_BASE ((u32)0x40000000) 
#define APB1PERIPH_BASE PERIPH_BASE 
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) 
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) 
... 
#define AFIO_BASE (APB2PERIPH_BASE + 0x0000) 
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)  //0x40010800
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) 
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) 
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) 
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)#ifdef _GPIOA 
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)   //GPIOA代表指向端口A的起始地址的指针
#endif /*_GPIOA */ 
#ifdef _GPIOB 
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) 
#endif /*_GPIOB */ 
#ifdef _GPIOC 
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) 
#endif /*_GPIOC */ 
#ifdef _GPIOD 
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) 
#endif /*_GPIOD */ 
#ifdef _GPIOE 
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) 
#endif /*_GPIOE */ 
...
  1. 接口
    GPIO_DeInit 将外设GPIOx寄存器重设为缺省值
    GPIO_Init 根据GPIO_InitStruct中指定的参数初始化外设GPIOx寄存器 – 设置具体某个引脚的工作模式和参数
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
    GPIO_Pin_x 选中管脚x(x=0,1,… 15)
    GPIO_Pin_All 选中全部管脚
    GPIO_Speed_10MHz 最高输出速率 10MHz
    GPIO_Speed_2MHz 最高输出速率 2MHz
    GPIO_Speed_50MHz 最高输出速率 50MHz

    GPIO_Mode_AIN 模拟输入
    GPIO_Mode_IN_FLOATING 浮空输入
    GPIO_Mode_IPD 下拉输入
    GPIO_Mode_IPU 上拉输入
    GPIO_Mode_Out_OD 开漏输出
    GPIO_Mode_Out_PP 推挽输出
    GPIO_Mode_AF_OD 复用开漏输出
    GPIO_Mode_AF_PP 复用推挽输出

STM固件库

端口引脚初始化实例:

//定义初始化结构体
GPIO_InitTypeDef GPIO_InitStructure; //设置端口引脚的工作模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //使用GPIO_Init()接口将设置的引脚的属性写入到端口寄存器的地址中
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_ReadInputDataBit 读取指定端口管脚的输入 – 用来读取GPIOx_IDR的一位(获取一个引脚的状态:0/1)
u8 GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)
实例:

u8 ReadValue; 
ReadValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7);

GPIO_ReadInputData 读取指定的 GPIO 端口输入 – 用来读取GPIOx_IDR的值(得到一个端口16个引脚的状态)
GPIO_ReadOutputDataBit 读取指定端口管脚的输出 – 判定某个特定的引脚是输出高电平还是低电平
GPIO_ReadOutputData 读取指定的 GPIO 端口输出 – 获取一个端口16个引脚的输出状态

GPIO_SetBits 设置指定的数据端口位 – 置位特定的引脚(指定的引脚输出高电平)
void GPIO_SetBits(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)

GPIO_ResetBits 清除指定的数据端口位 – 复位特定的引脚(指定的引脚输出低电平)
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, u16 GPIO_Pin)

GPIO_WriteBit 设置或者清除指定的数据端口位 – 向指定的引脚写0或者写1
GPIO_Write 向指定 GPIO 数据端口写入数据 – 一个端口16个引脚的状态一次性写入

…\cmsis\CoreSupport;…\user;…\stdlib\inc

按键控制LED参考代码:

#include "stm32f10x.h"#define KEY_ON 0
#define KEY_OFF 1
GPIO_InitTypeDef GPIO_InitStructure; 
void delay_ms(uint32_t ms)  
{uint32_t i_cnt,j_cnt;for(i_cnt=0;i_cnt<3000;i_cnt++);for(j_cnt=0;j_cnt<ms;j_cnt++);	
}
uint32_t i;void Key_Configure(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}int main(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  GPIO_Init(GPIOC, &GPIO_InitStructure); GPIOC->BSRR=0xff;  GPIO_Write(GPIOC,0xff);GPIO_ResetBits(GPIOC, GPIO_Pin_0); delay_ms(99000);GPIO_SetBits(GPIOC, GPIO_Pin_0);GPIO_ResetBits(GPIOC, GPIO_Pin_1);delay_ms(99000);GPIO_SetBits(GPIOC, GPIO_Pin_1);GPIO_ResetBits(GPIOC, GPIO_Pin_2);delay_ms(99000);GPIO_SetBits(GPIOC, GPIO_Pin_2);GPIO_ResetBits(GPIOC, GPIO_Pin_3);delay_ms(99000);GPIO_SetBits(GPIOC, GPIO_Pin_3);GPIO_ResetBits(GPIOC, GPIO_Pin_4);delay_ms(99000);GPIO_SetBits(GPIOC, GPIO_Pin_4);GPIO_ResetBits(GPIOC, GPIO_Pin

这篇关于ARM微处理器编程模型与linux驱动开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138133

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor