【瑞萨RA系列FSP库开发】初识寄存器

news2025/1/7 7:37:36

文章目录

  • 一、寄存器是什么
  • 二、瑞萨RA6M5 芯片内部模块与资源
  • 三、存储器映射
    • 1. 存储器映射表
    • 2. 存储器区域划分
    • 3. 外设寄存器
  • 四、C语言操作寄存器
    • 1. C语言对寄存器的封装
      • (1)外设模块基地址定义
      • (2)寄存器结构体定义
      • (3)外设模块寄存器定义
    • 2. 修改寄存器操作的本质:读-改-写
      • (1)清零寄存器上的某 N 个位
      • (2)对寄存器上的某 N 个位进行置位
      • (3)对寄存器上的某 N 个位进行取反


一、寄存器是什么

寄存器实际上与 RAM、FLASH 一样,也是芯片内部的一种存储器(Memory)。 一般而言,RAM 是程序运行的内存,FLASH 则是用来保存程序本身。 寄存器与 RAM、FLASH 等存储器的不同之处在于:寄存器除了保存了芯片的功能状态之外, 还是配置和控制芯片的桥梁,我们可以通过寄存器配置和操作芯片的功能。

一般而言,我们在对 MCU 芯片进行编程时有两种编程方式, 一种是寄存器编程,另外一种是固件库编程(或者说库函数编程)。 那么,固件库又是什么东西?固件库说白了其实是通过寄存器编程之后的产物, 它是对寄存器操作的一种封装,最终提供给开发者一套固定的函数API进行调用。

我们可以从以下两种角度来了解寄存器编程与固件库编程的区别。 从程序执行效率的角度来看:一般而言,寄存器编程生成的程序执行效率高, 而固件库编程生成的程序执行效率不如寄存器编程的。 然而从开发者的角度来看:固件库编程使得开发者不必深入理解硬件层面的寄存器细节, 在开发时只需要调用库函数以实现所需的功能,因此可以提高开发者的开发效率。

二、瑞萨RA6M5 芯片内部模块与资源

在这里插入图片描述
上图中,我们可以看到有一个标着 “Arm Cortex-M33” 的方框,其所表示的便是 CPU 内核, 其中包含的小方框(DSP、FPU、MPU、NVIC等)属于内核的设备。

除了 “Arm Cortex-M33” 的方框以外,还有很多个大方框,它们对片上的全部外设模块进行了一个分类, 大方框当中的小方框表示的是外设模块,如下:
在这里插入图片描述
RA6M5 芯片 Cortex-M33 CPU 内核结构如图所示:在这里插入图片描述

三、存储器映射

前文所述,寄存器与 RAM、FLASH 一样都是芯片内部的一种存储设备。 那么,当我们需要访问它们的时候,我们需要知道它们的存储地址。

1. 存储器映射表

如下图所示为 RA6M5 的存储器映射表,可以看到 RA6M5 芯片内部的存储器被映射到这一整块 4G(0 ~ 0xFFFF FFFF)的地址空间中。 我们还可以看到,除了寄存器和 SRAM、Flash 的地址空间区域以外,还存在着其他类型的地址空间区域,比如 QSPI area 和 OSPI area。 Reserved area 表示的是保留区域,尚未用到。
在这里插入图片描述

2. 存储器区域划分

存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射。 如果给存储器再次分配一个地址就叫存储器重映射。

对于 RA6M5 (176 pin) 芯片,其内部线性地址空间划分为如下区域:在这里插入图片描述
表格中的 “0x4000_0000 ~ 0x4018_0000 - 1” 区域,也就是 “0x4000_0000 ~ 0x4017_FFFF” 区域, 它映射到了绝大部分外设模块的寄存器。

3. 外设寄存器

在这里插入图片描述
说明:

①寄存器名称。

②外设模块基地址及其寄存器偏移地址。

③寄存器位表格。32位MCU的寄存器大小一般为 32 位(bit),占四个字节。 “Bit position”为位号,指示该位处于该寄存器中的位置; “Bit field”为位域,一般不同的位域有不同的作用; “Value after reset”为复位值,指示该位的复位值。

④位域功能说明。这部分为对每一个位域的功能的详细说明。

四、C语言操作寄存器

1. C语言对寄存器的封装

(1)外设模块基地址定义

在编程上为了方便理解和记忆,我们要把外设模块基地址以相应的宏定义起来,外设基地址都以它们的名字作为宏名的组成部分。 以下是 IO 端口外设基地址的宏定义。

IOPORT 外设基地址宏定义

/* 外设基地址 */
#define R_PORT0_BASE          0x40080000
#define R_PORT1_BASE          0x40080020
#define R_PORT2_BASE          0x40080040
#define R_PORT3_BASE          0x40080060
#define R_PORT4_BASE          0x40080080
#define R_PORT5_BASE          0x400800A0
#define R_PORT6_BASE          0x400800C0
#define R_PORT7_BASE          0x400800E0
#define R_PORT8_BASE          0x40080100
#define R_PORT9_BASE          0x40080120
#define R_PORT10_BASE         0x40080140
#define R_PORT11_BASE         0x40080160
#define R_PFS_BASE            0x40080800
#define R_PMISC_BASE          0x40080D00

(2)寄存器结构体定义

由于寄存器的数量是非常之多的,如果每个寄存器都用像 *( (uint32_t )(0x40080000 + 0x00201) ) 这样的方式去访问的话,会显得很繁琐、很麻烦。 为了更方便地访问寄存器,我们会借助C语言结构体的特性去定义寄存器和寄存器位域,这是通用的做法。

使用结构体封装外设寄存器

// 注:关于输入输出端口的声明
/* C语言: IO definitions (access restrictions to peripheral registers) */
//#define     __I     volatile const       /*!< Defines 'read only' permissions */
//#define     __O     volatile             /*!< Defines 'write only' permissions */
//#define     __IO    volatile             /*!< Defines 'read / write' permissions */

/* 下面的宏定义用于结构体成员 */
/* following defines should be used for structure members */
//#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
//#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
//#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */

//typedef unsigned          char uint8_t;
//typedef unsigned short     int uint16_t;  /* 无符号16位整型变量 */
//typedef unsigned           int uint32_t;  /* 无符号32位整型变量 */

/**
* @brief I/O Ports (R_PORT0)
*/
typedef struct                         /*!< (@ 0x40040000) R_PORT0 Structure */
{
   union
   {
      union
      {
            __IOM uint32_t PCNTR1;        /*!< (@ 0x00000000) Port Control Register 1 */

            struct
            {
               __IOM uint32_t PDR  : 16; /*!< [15..0] Pmn Direction(引脚Pmn 方向)*/
               __IOM uint32_t PODR : 16; /*!< [31..16] Pmn Output Data(引脚Pmn 输出数据)*/
            } PCNTR1_b;
      };

      /* ... 代码过长省略 ... */
   };

   union
   {
      union
      {
            __IM uint32_t PCNTR2;        /*!< (@ 0x00000004) Port Control Register 2 */

            struct
            {
               __IM uint32_t PIDR : 16; /*!< [15..0] Pmn Input Data(引脚Pmn 输入数据)*/
               __IM uint32_t EIDR : 16; /*!< [31..16] Pmn Event Input Data(引脚Pmn 事件输入数据)*/
            } PCNTR2_b;
      };

      /* ... 代码过长省略 ... */
   };

   union
   {
      union
      {
            __OM uint32_t PCNTR3;        /*!< (@ 0x00000008) Port Control Register 3 */

            struct
            {
               __OM uint32_t POSR : 16; /*!< [15..0] Pmn Output Set(引脚Pmn 输出置位)*/
               __OM uint32_t PORR : 16; /*!< [31..16] Pmn Output Reset(引脚Pmn 输出复位)*/
            } PCNTR3_b;
      };

      /* ... 代码过长省略 ... */
   };

   union
   {
      union
      {
            __IOM uint32_t PCNTR4;        /*!< (@ 0x0000000C) Port Control Register 4 */

            struct
            {
               __IOM uint32_t EOSR : 16; /*!< [15..0] Pmn Event Output Set(引脚Pmn 事件输出置位)*/
               __IOM uint32_t EORR : 16; /*!< [31..16] Pmn Event Output Reset(引脚Pmn 事件输出复位)*/
            } PCNTR4_b;
      };

      /* ... 代码过长省略 ... */
   };
} R_PORT0_Type;                        /*!< Size = 16 (0x10) */

(3)外设模块寄存器定义

我们在上一步已经定义好了 R_PORT0_Type 类型的结构体,它包含了 IOPORT 的寄存器定义。 接下来使用宏定义来表示结构体指针,指针指向 IOPORT 外设的每个端口的寄存器首地址。

寄存器定义

#define R_PORT0           ((R_PORT0_Type *) R_PORT0_BASE)
#define R_PORT1           ((R_PORT0_Type *) R_PORT1_BASE)
#define R_PORT2           ((R_PORT0_Type *) R_PORT2_BASE)
#define R_PORT3           ((R_PORT0_Type *) R_PORT3_BASE)
#define R_PORT4           ((R_PORT0_Type *) R_PORT4_BASE)
#define R_PORT5           ((R_PORT0_Type *) R_PORT5_BASE)
#define R_PORT6           ((R_PORT0_Type *) R_PORT6_BASE)
#define R_PORT7           ((R_PORT0_Type *) R_PORT7_BASE)
#define R_PORT8           ((R_PORT0_Type *) R_PORT8_BASE)
#define R_PORT9           ((R_PORT0_Type *) R_PORT9_BASE)
#define R_PORT10          ((R_PORT0_Type *) R_PORT10_BASE)

2. 修改寄存器操作的本质:读-改-写

有了以上的对 IOPORT 这个外设模块的寄存器的定义, 我们便完成了“C语言对寄存器的封装”这个步骤,接下来我们便可以使用C语言对寄存器进行各种操作了。

对寄存器进行操作可以是忽略寄存器原本的值,而直接覆盖写入新的值; 但是更为一般的操作是根据原本的寄存器值进行修改,即:先读出寄存器原本的值,然后修改该值,最后重新写入到寄存器里面, 让新的值生效。

接下来将介绍修改寄存器的几种通用方法。

(1)清零寄存器上的某 N 个位

使用 C 语言的按位与 “&” 运算符可以将位进行清零。

位清零:按位与 &

//清零某个位
R_PORT0->PODR &= ~(1u<<0); //清零PODR寄存器的第0位
R_PORT0->PODR &= ~(1u<<6); //清零PODR寄存器的第6位

//清零多个位
R_PORT0->PODR &= ~(3u<<0); //清零PODR寄存器的第0,1位
R_PORT0->PODR &= ~(3u<<6); //清零PODR寄存器的第6,7位

(2)对寄存器上的某 N 个位进行置位

使用 C 语言的按位或 “|” 运算符可以将位进行置一。

位置位:按位或 |

//置位某个位
R_PORT0->PODR |= 1u<<0; //PODR寄存器的第0位置1
R_PORT0->PODR |= 1u<<6; //PODR寄存器的第6位置1

//置位多个位
R_PORT0->PODR |= 3u<<0; //PODR寄存器的第0,1位置1
R_PORT0->PODR |= 3u<<6; //PODR寄存器的第6,7位置1

(3)对寄存器上的某 N 个位进行取反

使用 C 语言的按位异或 “^” 运算符可以将位进行取反。

位取反:按位异或 ^

//取反某个位
R_PORT0->PODR ^= 1u<<0; //取反PODR寄存器的第0位
R_PORT0->PODR ^= 1u<<6; //取反PODR寄存器的第6位

//取反多个位
R_PORT0->PODR ^= 3u<<0; //取反PODR寄存器的第0,1位
R_PORT0->PODR ^= 3u<<6; //取反PODR寄存器的第6,7位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/534814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LLM系列之BLOOM】BLOOM: A 176B-Parameter Open-Access Multilingual Language Model

论文题目&#xff1a;《BLOOM: A 176B-Parameter Open-Access Multilingual Language Model》 论文链接&#xff1a;https://arxiv.org/abs/2211.05100 github链接&#xff1a;https://github.com/huggingface/transformers-bloom-inference/tree/main huggingface链接&#xf…

LeetCode35. 搜索插入位置(二分法入门)

写在前面&#xff1a; 题目链接&#xff1a;LeetCode35. 搜索插入位置 编程语言&#xff1a;C 题目难度&#xff1a;简单 一、题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会…

Linkage Mapper:从栖息地连通性到物种保护的连通性指南针

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Linkage Mapper解密数字世界链接 文章目录 引言一、Linkage Mapper工具包简介1.1 什么是Linkage Mapper工具包⭐️ Linkage Mapper工具包的概述

Vite4 + Vue3 项目打包并发布Nginx服务器 (前端必看)

一、环境 &#x1f604; &#x1f604; &#x1f604; 这里因为我们有的小伙伴可能不太需要服务器&#xff0c;单纯学习的话也没有必要去买一个服务器。如果需要把自己的东西部署到公网上&#xff0c;有很多方式&#xff0c;自行百度。你也可以购买阿里云或者腾讯云。逻辑都是…

MSQL系列(二) Mysql实战-索引结构B+Tree

Mysql实战-索引结构 BTree 上一篇 我们讲解了二叉树&#xff0c;平衡二叉树&#xff0c;红黑树&#xff0c;BTree的结构及特点&#xff0c;本文我们着重讲解一下BTree&#xff0c;为什么Mysql的存储结构采用BTree而不是上面的那几种 1.BTree的缺点 我们用上篇文章中的BTree的…

第四十二天学习记录:C语言进阶:笔试题整理Ⅲ

问&#xff1a;解释一下int(*a[20])(int)是什么&#xff1f; ChatAI答&#xff1a; int (*a[20])(int) 是一个数组&#xff0c;该数组中每个元素都是一个指向函数的指针&#xff0c;该函数具有一个int类型的参数&#xff0c;并返回一个int类型的值。 具体来说&#xff0c;a是一…

宝塔服务器(linux)服务器搭建

搭建服务器 nginx 搭配 PM2( 集合了node的功能 ) 搭建服务器 域名: http://kissface.top 流程如下: 服务器既做assets文件目录挂载 , 也当做nodejs服务使用 当我访问http://kissface.top 根目录时 展示index.html文件 同时能访问静态资源如 js/css/img/font 等 当我访问 http…

Linux:初识【VI / VIM编辑器】

Linux系统版本&#xff1a;centos 7.5 x64位 VMware版本&#xff1a; VMware Workstation Pro 16 文章目录 一、VI / VIM是什么&#xff1f;1.1 VI编辑器1.2 VIM编辑器 二、为什么要使用VI / VIM编辑器&#xff1f;三、如何使用VI / VIM编辑器&#xff1f;3.1 一般模式3.2 编辑…

keil MDK5插件推荐——Astyle代码格式化插件

前言 代码格式化是提高代码质量和可读性的重要手段之一。然而&#xff0c;在Keil MDK5中并没有内置代码格式化工具&#xff0c;因此需要寻找第三方工具来解决这个问题。开源的代码格式化工具Astyle能以插件的形式集成到Keil中以满足我们对代码格式化的需求。 本文将详细介绍如…

《永恒之塔sf私服》“龙战前传”里的更高挑战-

关于这个新版本的各种更新内容已经屡见不新&#xff0c;无论是最新关注的玩家&#xff0c;抑或是一直坚守在永恒之塔阵地的老玩家们&#xff0c;相信已经对各种感兴趣的更新倒背如流。这里就不再重复。 每一款MMO游戏升级&#xff0c;伴随着玩家技术和战术的长进&#xff0c;游…

【Unity-UGUI控件全面解析】| ScrollView 滚动视图组件详解

🎬【Unity-UGUI控件全面解析】| ScrollView 滚动视图组件详解一、组件介绍二、组件属性面板三、代码操作组件四、组件常用方法示例💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉 🎄 学习专栏推荐:Unity系统学习…

火线、零线和地线及开关接线参考

火线、零线和地线及开关接线参考 1. 火线、零线和地线 1.1. What is Live wire? Live wire&#xff0c;L&#xff1a;火线&#xff0c;相线火线是电路中输送电的电源线。 1.2. What is Neutral wire? Neutral wire&#xff0c;N&#xff1a;零线零线是由发电机或变压器二…

AD 实现多 DC + 多 ADFS 高可用部署

总览 在本篇文章中, 我将记录部署多 DC 多 ADFS 实现高可用方案的详细步骤, 期间我会尽量使用 PowerShell 来实现相应的动作, 实在找不到命令或者 GUI 更方便的再附截图. 主要步骤分为: 部署 2 台 DC 服务器提供 AD 服务 (AD域名 alian.com)安装 ADCS 角色为 ADFS 提供证书服…

NodeJs模块化之下半部分

Node.js 中的模块化 更多精彩内容&#xff0c;请微信搜索“前端爱好者“&#xff0c; 戳我 查看 。 官网地址&#xff1a;https://nodejs.cn/api/ fs 文件系统 地址&#xff1a;https://nodejs.cn/api/fs.html#%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F node:fs 模块能够以标准…

GPT-3 面试题

简介 1、GPT-3 是什么&#xff1f;它是基于什么模型的&#xff1f; GPT-3是一种基于深度学习原理的语言预测模型。它是由OpenAI开发的&#xff0c;可以从互联网数据中生成任何类型的文本。它只需要一小段文本作为输入&#xff0c;就可以生成大量的准确和复杂的机器生成文本⁴…

Akura Medica:新型静脉血栓切除系统,完成首次人体试验

Akura Medical公司宣布&#xff0c;其机械血栓切除平台在人体首次使用成功&#xff0c;这是一项具有突破性的技术&#xff0c;可以有效地治疗肺栓塞、深静脉血栓等血栓栓塞疾病。该平台使用了一种与众不同的方法&#xff0c;可以高效地清除血管内的血栓&#xff0c;同时保护血管…

测试分词工具Lucene.Net.Analysis.PanGu(盘古分词)

从微信公众号及百度文章来看&#xff0c;全文检索的前置工作是分词&#xff0c;首先将要做全文检索的内容分词&#xff0c;然后采用全文检索模块或工具进行全文检索。参考文献4介绍了基于Lucene.net实现全文检索的大致思路&#xff0c;其采用的是Lucene.net盘古分词的方式实现。…

蓝桥:前端开发笔面必刷题——Day1 数组(一)

文章目录 &#x1f4cb;前言&#x1f3af;数组中重复的数字&#x1f4da;题目内容✅解答 &#x1f3af;两数之和&#x1f4da;题目内容✅解答 &#x1f3af;替换空格&#x1f4da;题目内容✅解答 &#x1f3af;二维数组中的查找&#x1f4da;题目内容✅解答 &#x1f4dd;最后 …

C语言-程序环境与预处理

程序环境与预处理 程序环境翻译环境&#xff08;编译链接&#xff09;预编译编译汇编链接 执行环境 预处理预定义符#define定义的标识符 宏#define定义宏#define替换规则宏的命名约定带副作用的宏参数宏和函数的比较 其它#和##的使用字符串常量化运算符#标记粘贴运算符## 命令行…

fastled教程

文章目录 EVERY_N_MILLISECONDS(10)EVERY_N_SECONDS(5)fill_solid(leds, NUM_LEDS, CRGB::Red);fill_gradient_RGBfill_rainbow(leds, NUM_LEDS, i, 255 / NUM_LEDS);效果1fadeToBlackBy(leds, NUM_LEDS, 1); 效果2FastLED.setBrightness(2*i);// 效果3leds[i] CHSV(hue (i *…