寄存器

相关阅读:

RA2快速设计指南 [1] 电源与仿真器支持

RA2快速设计指南 [2] MCU工作模式和选项设置存储器

RA2快速设计指南 [3] 时钟电路

RA2快速设计指南 [4] 复位要求和复位电路

RA2快速设计指南 [5] 存储器

8. 寄存器写保护

寄存器写保护功能可防止重要寄存器因软件错误而被覆盖。使用保护寄存器(PRCR)设置要保护的寄存器。表9列出了PRCR位与要保护的寄存器之间的关联。

1.jpg

图18. PRCR寄存器 

表9. PRCR保护位 

2.jpg

注:以上寄存器并非存在于所有的RA2产品。具体请参照各MCU硬件手册中“寄存器写操作”的章节。

Renesas FSP提供两个API(R_BSP_RegisterProtectEnable 和 R_BSP_RegisterProtectDisable),分别用于使能和禁用寄存器写保护。

9. I/O 端口配置(1)

《硬件手册》中的“I/O 端口”部分介绍了基于外设选择和其他寄存器设置的确切引脚配置。下面列出了一些一般信息。

务必注意的是,复位后,在应用配置之前,每个引脚都将处于其默认状态。就RA2产品而言,所有I/O引脚在复位后均为输入引脚。其中某些引脚可能会短暂地处于无法预期的状态。无论使用哪种配置方法,都会出现这种情况。用户应考虑这可能对每种应用产生的影响,包括这可能对其他系统功能造成哪些影响。

配置I/O端口时,可以直接写入寄存器,也可以通过FSP引脚配置功能进行配置。

9.1 多功能引脚选择设计策略

RA2系列MCU上的大多数端口都具有多种外设功能。Renesas提供了诸如FSP中的引脚配置器之类的工具,以帮助选择各RA2产品的端口。当需要多个外设功能时,请使用以下设计策略来帮助选择端口功能。

• 首先,仅通过一个端口选项分配外设功能。例如,调试功能中的每个跟踪数据信号只有一个端口选项。需要此功能时,先分配这些端口。

• 接下来,为外设功能分配有限的端口选项。例如,支持CLKOUT外设的产品的每个CLKOUT信号通常只有两个选项。

• 最后,为外设功能分配多个端口选项。一个示例是串行通信接口(SCI),该接口通常具有许多可用的端口选项。

• 从RA2系列MCU硬件手册“引脚列表”章节中可以看到一些端口的函数名称中带有后缀“_A”。为RA2

产品配置端口函数时,可以忽略此种类型的后缀。另请参见本系列文章后续的16.3节。

9.2 设置端口并将其用作GPIO

有两种方法可以设置端口并将其用作GPIO:一种是使用端口控制寄存器(PCNTR1),另一种是使用PmnPFS寄存器。

方法1:端口控制寄存器(PCNTR1)

• 通过向端口控制寄存器1(PCNTR1)的端口方向位 (PDRn) 写入“1”,选择一个引脚作为输出。

• 端口方向位 (PDRn) 是可读写的。将该值设置为“1”将选择该引脚作为输出。I/O端口的默认状态为“0”(输入)。可以在RA2 MCU上读取端口方向寄存器。

• 相应端口控制寄存器 (PCNTR1) 中的端口输出数据位 (PODRn) 是可读写的。读取PODR时,也会读取输出数据锁存器的状态(不是引脚电平)。

• 端口控制寄存器 2 (PCNTR2) 中的端口输入位 (PIDRn) 是只读的。读取PCNTR2寄存器中的 PIDRn 位以读取引脚状态。

方法2:端口mn引脚功能 选择 (PmnPFS) 寄存器

• 端口模式寄存器 (PMR) 是可读写的,用于指定各个引脚是用作GPIO还是用作外设引脚。复位后,所有PMR寄存器均置0,这会将所有引脚都设置为GPIO。如果PMR寄存器置1,则该对应的引脚将用于实现外设功能。外设功能由该引脚的MPC设置定义。

• 将引脚设置为输出时,建议先将所需的端口输出值写入数据锁存器,然后将方向寄存器设置为输出。尽管在所有系统中此操作都不太重要,但这可以防止在设置端口时出现意外的输出毛刺。

通常,使用PCNTR1配置端口有助于提高访问速度,但可用的配置功能较少。使用PmnPFS寄存器将获得更多可用的配置功能,但访问速度较慢。

Renesas FSP提供了引脚配置工具,以在复位后配置GPIO引脚,如图19所示。配置GPIO后,可以在FSP中使用HAL层API对该GPIO进行控制

3.jpg

图19. 使用FSP配置器将P107配置为输出和低电平

9.2.1 内部上拉

• 端口0到9上的大多数引脚都可以选择使能上拉电阻。上拉由每个端口mn引脚功能选择 (PmnPFS) 寄存器中的上拉 (PCR) 位控制。每个PmnPFS寄存器中的PCR位用于控制端口上的相应引脚。

• 首先,必须通过PmnPFS寄存器中的相关位将该引脚设置为输入。将PCR位置“1”以使能上拉,将其置“0”以禁用上拉。

• 复位后,会将所有PCR寄存器清零,因此将禁用所有上拉电阻。

• 每当将某个引脚指定为外部总线引脚、GPIO输出或外设功能输出引脚时,上拉就会自动关闭。

9.2.2 漏极开路输出

• 配置为输出的引脚通常用作CMOS输出。

• 端口0到上的大多数引脚都可以选择配置为NMOS漏极开路输出。

• 每个端口9mn引脚功能选择 (PmnPFS) 寄存器中的N沟道漏极开路控制 (NCODR) 位控制哪些引脚以漏极开路模式工作。将每个寄存器中的适用位置“1”会使输出形式变为漏极开路。将每个寄存器中的适用位置“0”会将端口设置为CMOS输出。

9.2.3 驱动能力

RA2A1产品可以使能驱动能力输出,其驱动能力可设为低或中驱动能力输出。其他RA2产品无此功能。

• 驱动能力的切换由每个端口mn引脚功能选择 (PmnPFS) 寄存器中的驱动能力控制寄存器 (DSCR) 位控制。

• 复位后,会将所有DSCR寄存器清零,因此会将所有引脚设置为低驱动能力输出。设置“00”以外的值会更改所选引脚的输出的驱动能力。

• 引脚的最大总输出因产品及封装而异。具体请参见MCU硬件手册“电气特性”章节的内容。

• 驱动能力的差异如下所示。实际输出电流会因产品和引脚类型而有所不同。详细信息请参见MCU硬件手册。

表10. 引脚驱动能力 

4.jpg

输出驱动能力可能会对电路板设计的整体性能造成重大影响。为每个输出选择驱动能力时,应考虑以下几点:

• 建议首先将所有引脚设置为低驱动能力(默认)并评估性能。

• 根据电路板布局的不同,驱动能力设置为中或高的引脚可能会产生较高的EMI辐射。

• 较长的走线可能需要更高的驱动能力,才能使信号正确传播到接收器。

9.3 设置和使用端口外设功能

端口mn引脚功能选择寄存器 (PmnPFS) 用于配置每个端口的特性。PSEL 位用于选择为每个端口选择的外设功能。

• 由于大多数引脚具有多种功能,因此RA2 MCU提供了引脚功能控制寄存器 (PmnPFS),可用于更改分配给引脚的功能。

• 每个引脚都有自己的PmnPFS寄存器。

• 每个PmnPFS寄存器都允许将引脚用于外设功能(PSEL位)、用作IRQ输入引脚(ISEL位)或用作模拟输入引脚(ASE位)。如果ASEL位置“1”(将引脚用作模拟输入引脚),则应将该引脚的PMR位置1以用于GPIO,并将该引脚的PDR位置1以用于输入。

• 请参见《硬件手册》中“I/O端口”一章的“每种产品的外设选择设置”部分。

• 为了确保外设引脚上没有非预期的边沿输入或输出,确保在修改引脚的PmnPFS寄存器之前将目标引脚的端口模式控制 (PMR) 位清零。

• 复位后,所有PmnPFS寄存器均受到写保护。为了对这些寄存器执行写入操作,必须首先使用写保护寄存器 (PWPR) 来使能写入。

• 设置PmnPFS寄存器时应格外小心,切勿将一个功能分配给多个引脚。用户不应这样做,但MCU允许上述操作。如果发生这种情况,则引脚上的功能将处于未定义状态。

• 图20为使用Renesas FSP的引脚配置器使能QSPI引脚的示例。 

5.jpg

图20. 使用Renesas FSP中的引脚配置器使能QSPI引脚

9.4 设置和使用IRQ引脚

• 某些端口引脚可以用作硬件中断线(IRQ)。有关哪些引脚可用于您的MCU的信息,请参见《硬件手册》中“I/O端口”一章的“每种产品的外设选择设置”部分。

• 要将端口引脚设置为用作IRQ引脚,必须将其PFS寄存器中的中断输入功能选择位(ISEL)置“1”。

• 引脚可同时用于IRQ和外设功能。要使能此功能,需设置引脚的PFS寄存器的ISEL位和PSE位。

• 具有相同编号的IRQ功能必须在一个引脚上使能。

• IRQ引脚可以在检测到以下情况时触发中断:

⎯ 低电平

⎯ 下降沿

⎯ 上升沿

⎯ 上升沿和下降沿

使用IRQ控制寄存器(IRQCRi)选择要使用的触发器。

• 数字滤波可用于IRQ引脚。滤波器基于以四个可选时钟速率(PCLKB、PCLKB/8、PCLKB/32、PCLKB/64)之一进行的重复信号采样。它们可以滤除短脉冲:在特定滤波速率下,任何少于3个样本的高脉冲或低脉冲。滤波器可用于滤除这些线路中的振铃和噪声,但是由于速率过快而无法滤除诸如机械开关弹跳之类的长时间事件。使能滤波会给硬件IRQ线增加一小段响应延迟时间(滤波时间)。

• 可以针对每个IRQ引脚单独使能数字滤波。此过程通过设置每个IRQ的IRQCRi寄存器中的IRQ引脚数字滤波器使能(FLTEN)位来实现。

• 可为每个IRQ引脚单独配置数字滤波的时钟速率。此过程通过设置每个IRQ的IRQCRi寄存器中的IRQ引脚数字滤波器设置(FCLKSEL[1:0])位来实现。

• 图21和图22给出了使用Renesas FSP使能和配置IRQ引脚的示例。

6.jpg

图21. 使用Renesas FSP配置器将P004配置为IRQ03

7.jpg

图22. 使用Renesas FSP配置器配置IRQ03

9.5 未使用引脚的处理

注:某些引脚需要特定的端接:有关具体建议,请参见《硬件手册》中的“未使用引脚的处理”部分。

悬空的未使用引脚会消耗额外的功率,并使系统更容易受到噪声问题的影响。使用下面详述的方法之一对未使用的引脚进行处理:

1、第一种选择是将引脚设置为输入(复位后的默认状态),然后使用电阻将其连接至Vcc或Vss。不同的连接方法对MCU来说没有区别;但是,从系统噪声的角度来看,有的方法可能更具优势。Vss可能是最典型的选择。避免将引脚直接连接到Vcc或Vss,因为对端口的方向寄存器(用于将端口设置为输出)执行意外的写入操作可能会导致输出短路。

2、第二种方法是将引脚设置为输出。无论是将引脚电平设置为高还是低都无关紧要;但是,将引脚设置为输出并将输出设置为低电平会在内部将引脚连接至接地层。这可能有助于解决整个系统的噪声问题。将未使用的引脚设置为输出有一个缺点,即必须通过软件控制来完成端口配置。在将方向寄存器设置为输出前MCU一直保持在复位状态时,该引脚将为悬空输入,可能会消耗额外的电流。如果可以接受在此期间消耗额外的电流,则该方法可消除第一种方法所需的外部电阻。

3、将引脚保留为输入并使用外部电阻将它们处理的一种变化方式是使用MCU多个端口上的内部上拉电阻。这与将引脚设置为输出有相同的限制(需要程序来设置端口),但是由于产品不会驱动引脚,因此确实可以减少因引脚意外接地、短接到相邻引脚或Vcc而产生的影响。

9.6 不存在的引脚

每个RA2 MCU系列都有多种封装尺寸,总引脚数也各有不同。对于小于该MCU系列最大封装尺寸(通常为100引脚、64引脚、24引脚)的任何封装,需将PDR寄存器中不存在的端口的对应位置“1”(输出),并将PODR寄存器中不存在的端口的对应位置“0”。通过查看《硬件手册》中“I/O端口”部分的“I/O端口规范”表,用户可以查看每个MCU封装上可用的端口。例如,端口0上的P007和P008仅在100引脚封装中可用。请注意,不需要对不存在的引脚进行额外处理。

9.7 电气特性

常规GPIO端口通常需要CMOS电平输入(高电平≥ 0.8 * Vcc,低电平≤ 0.2 * Vcc)。某些GPIO端口具有施密特触发输入,在输入要求方面略有不同。有关更多信息,请参见《硬件手册》中的“电气特性”部分。

来源:瑞萨MCU小百科

https://mp.weixin.qq.com/s/FMxRvDbDi1R43nu9Hn8Nsg

https://mp.weixin.qq.com/s/Xknl8CQ0lbxm642YSRcpyA

https://mp.weixin.qq.com/s/oL7o1DdWw4QJat3hjPo4uA

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 75

1.问题原因

某客户测试 STM32H753xi 板子上的 ECC 功能,用于监控 AXI-SRAM 区域,但不是很明白 RAMECC FAR 寄存器在 RM0433 中的描述, “Bits 31:0 FADD[31:0]: ECC error failing address”。

比如在 AXI-SRAM 中,如果客户示例显示的是 FAR = 0x2004,但是这个地址值 0x2004 并不在 AXI-SRAM 范围之内,客户该如何理解 FAR 寄存器?希望能够有详尽的描述,这个 FAR 寄存器的偏移地址是 Word 地址还是 Byte 地址或其他?我们先来看看相关参考手册中关于 RAMECC 的介绍去寻找答案。

2.RAMECC 控制单元

RAM ECC 控制单元的数量取决于不同的 STM32H7 系列。比如,对于STM32H74x/5x 和 STM32H72x/3x 它们的每一个域都有一个 RAMECC 的控制器单元,为了描述简单,表述如下: 

Domain 1 (D1) RAMECC unit = RAMECC1Domain 2 (D2) RAMECC unit = RAMECC2Domain  3  (D3)   RAMECC  unit   =  RAMECC3

详细的说明请参考 RM0433 参考手册 rev7 中的截图:

1.jpg

3.RAMECC 寄存器地址

对于上图 Table 11 的 RAMECC 控制单元的地址总结成如下表格,具体的参考RM0433 的第二章节 Memory and bus architecture 中的 table 8.

2.jpg

4.RAMECC 寄存器

每一个 RAMECC 控制单元(RAMECC1、RAMECC2、RAMECC3)的监控单元Monitor number 均分别含有如下的一套寄存器组(其中 RAMECC_IER 为共同拥有)。 

接下来我们以 RAMECC1 为例进行分析,其边界地址为:0x52009000 -0x520093FF,那么对于该 RAMECC1 控制单元中的寄存器组,对于每一个寄存器:

3.jpg

以 RAMECC1 的起始地址 0x52009000 为基准:RAMECC_IER:中断使能,偏移地址 0x00,该寄存器地址即为:0x52009000。

RAMECC_MxCR:配置寄存器,偏移地址 0x20 *x,x 为 ECC 监控单元号,该寄存器地址的表达式为:0x52009000 + 0x20 * x ,x 取值范围= [1..5](见上面表格 Table 11 ECC controller mapping),所以: 

Monitor 1 - AXI SRAM ECC 监控单元,该寄存器地址即为 0x52009020,监控大小为整个 AXI SRAM 的 512KB 字节(0x24000000 -0x2407FFFF)。 

Monitor 2 - ITCM-RAM ECC 监控单元,该寄存器地址0x52009040, 监控大小为整个ITCM RAM的64KB字节(0x00000000 -0x0000FFFF)。  

Monitor 3、Monitor 4、Monitor 5 中该 RAMECC_MxCR 寄存器的地址,以此类推。

RAMECC_MxSR -- 状态寄存器,偏移地址: 0x24 + 0x20 * (x - 1),x 为 ECC monitor number 号码(见上面表格 Table 11 ECC controller mapping)。那么该寄存的地址为:0x52009000 + 0x24 + 0x20 * (x-1) ,x 取值范围 = [1..5]:

Monitor 1:0x52009024

Monitor 2:0x52009044

Monitor 3 : 0x52009064 

Monitor 4 : 0x52009084 

Monitor 5 : 0x520090a4 

RAMECC_MxFAR --失败地址寄存器,表达式:0x52009000 + 0x28 + 0x20 * (x-1) , x取值 = [1..5]: 

Monitor 1:0x52009028

Monitor 2:0x52009048

Monitor 3:0x52009068

Monitor 4:0x52009088

Monitor 5:0x520090a8

RAMECC_MxFDRL -- 失败数据低位,表达式 0x52009000 + 0x2c + 0x20 * (x-1) ,x 取值= [1..5] 

Monitor 1:0x5200902c

Monitor 2:0x5200904c

Monitor 3:0x5200906c

Monitor 4:0x5200908c

Monitor 5:0x520090ac

RAMECC_MxFDRH -- 失败数据高位,表达式 0x52009000 + 0x30 + 0x20 * (x-1),x 取值= [1..5] 

Monitor 1:0x52009030 

Monitor 2:0x52009050 

Monitor 3:0x52009070 

Monitor 4:0x52009090 

Monitor 5:0x520090b0 

RAMECC_MxFECR --失败 ECC 错误代码,表达式 0x52009000 + 0x34 + 0x20 * (x1) ,x 取值 = [1..5]

Monitor 1:0x52009034

Monitor 2:0x52009054

Monitor 3:0x52009074

Monitor 4:0x52009094

Monitor 5:0x520090b4

5.解决问题

通过查询资料与试验,FADD[31:0]中表述的地址是 word 而不是 bit。为了计算真实的地址,客户需要用如下公式计算:真实地址= 所处内存的首地址 + FADD x 字节数。 


现在举个例子,如上述提到的 FADD= 0x2004 : 

- 对于 64-bit word 的内存 :如 AXI RAM : 0x2400 0000 + 0x2004 * 8 = 0x2401 0020; 

- 对于 32-bit word 的内存 :如 SRAM1 : 0x3000 0000 + 0x2004 * 4=0x3000 8010 ;

来源: STM32单片机

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 47

1.寄存器

Cortex-M3拥有R0~R15通用寄存器和一些特殊功能寄存器。

R0~R12这些通用寄存器,复位初始值都是不可预料的。

2.Cortex-M3有R0到R15的通用寄存器组

“”

注:绝大部分的16位thumb只能访问R0到R7,而32位thumb-2可以访问全部寄存器

3.特殊功能寄存器

“”

3.1程序状态寄存器组(应用程序PSR+中断号PSR+执行PSR)

3.2中断屏蔽寄存器组:用于控制异常的除能和使能

3.3控制寄存器:用于定义特权级别和当前使用哪个堆栈指针

4.操作模式和特权级别:

两种操作模式(处理器模式):Handler模式和线程模式(用于区分异常服务例程的代码和普通程序的代码)

两种特权等级:特权级和用户级(是指在硬件层面上对存储器访问权限的设置)

注:Cortex-M3在运行主程序(即线程模式)可以使用特权级别和用户级别;但是异常服务例程(即handler模式)只能使用特权级别。当处于线程+用户模式时一些访问权限将被禁止

将代码区分成用户级和特权级,有利于程序架构的稳定,如某一个用户代码出问题,不会使其成为害群之狗,因为用户级别的代码是禁止对一些要害寄存器操作的。

5.异常处理

5.1CONTROL[0]=0;

“”

5.2CONTROL[0]=1;

“”

CONTROL[0]只有在特权级别下可以访问,若在用户级别想访问先通过"系统服务呼叫指令(SVC)"来触发SVC异常,然后在该异常的服务例程中可以修改CONTROL[0]。

6.下面是各操作模式的转换

“”

7.异常和中断

可以有11个系统异常和最多240个外部中断(IRQ),具体芯片使用了多少要看芯片制造厂商。 

作为中断功能的强化,NVIC 还有一条NMI输入信号线,具体做什么由芯片制造商决定,NMI(not masked interrupted)

8.向量表:当一个异常被Cortex-M3内核接受。对应的异常Handler就会执行,向量表用来决定Handler的入口地址。

9.Cortex-M3的双堆栈:主堆栈(MSP)和进程堆栈(PSP)。是由CONTROL[1]控制的。

10.复位序列:

先从0X00地址取出MSP的值再从0x04地址取出PC的初始值,0X04处存的值是复位向量,而不是跳转指令。

“”

此处Cortex-M3与ARM及单片机不同。以前ARM都是从0X00地址开始执行第一条指令,一般第一条指令都是跳转指令

11.MSP及PC初始化的一个例程

“”

本文转载自:网络
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:
cathy@eetrend.com)。

围观 416

我们需要在外部定义一个SystemInit 函数设置 STM32 的时钟;STM32 上电后,会执行 SystemInit 函数,最后执行我们 C 语言中的 main 函数。

下面就开始使用寄存器来操作 STM32 使 PC0 输出一个低电平。要操作 STM32寄存器,我们就需要使用 C 语言对其封装,这部分程序我们都放在 stm32f10x.h中。具体代码如下:

#define PERIPH_BASE ((unsigned int)0x40000000)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)

要控制 PF9 输出低电平,需知道 GPIO 这个外设它是挂接在哪个总线上的,通过Block2外设基地址及APB2总线的偏移地址就可以得到APB2外设的基地址。

GPIO 就是挂接在 APB2 总线上的,根据 GPIOC 的偏移地址就可以得到 GPIOC 外设的基地址,GPIOC 外设内部含有很多个寄存器,比如GPIOC_CRL、GPIOC_CRH 端口配置寄存器、GPIOC_BSRR 置位复位寄存器等,通过他们各自的偏移地址就可以获取对应的寄存器地址,然后要操作地址里面的内容就需要使用到指针,将其强制转换为 unsigned int*指针类型,然后在通过一个*指针来操作该地址里面的内容。在 STM32 中凡是使用到外设功能,都要使能对应的外设时钟,否则即使配置好端口初始化也无法正常使用。因此还需要知道时钟 RCC 外设的基地址,通过数据手册“存储器映射”章节可以知道 RCC 时钟外设是挂接在 AHB 总线上, 根据其偏移值可以得到 RCC 时钟外设的基地址,然后可通过《STM32F1xx 中文参考手册》的“6 小容量、中容量和大容量产品的复位和时钟控制(RCC)”的“6.3.7 APB2 外设时钟使能寄存器(RCC_APB2ENR)”可找到对应的端口 RCC 使能寄存器,只要将 GPIOC 端口时钟使能即可。

使用 C 语言封装好寄存器后,就开始编写 main 函数。

main.c代码:

#include "stm32f10x.h"

#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10) 
//在引用的头文件中声明过GPIOC_BASE
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
void SystemInit(){}
u32 i;
void Delay(i)
{
while(i--);
}
int main()
{
RCC_APB2ENR =(0X01<<4); //使能时钟
while(1)
{
//D1点亮  
GPIOC_CRL &= ~( 0x0F<< (4*0)); //设置推挽输出模式
GPIOC_CRL |= (3<<4*0);
GPIOC_BSRR = (0x01<<(16+0));   //PC0管脚输出低电平
Delay(0x3FFFF);   //延时
GPIOC_BSRR = (0x0000ffff);//D1输出高电平
//D2亮
GPIOC_CRL &= ~( 0x0F<< (4*1));
GPIOC_CRL |= (3<<4*1);
GPIOC_BSRR = (0x01<<(16+1));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);
                //D3
GPIOC_CRL &= ~( 0x0F<< (4*2));
GPIOC_CRL |= (3<<4*2);
GPIOC_BSRR = (0x01<<(16+2));
Delay(0x3FFFF);  
GPIOC_BSRR = (0x0000ffff);
//D4
GPIOC_CRL &= ~( 0x0F<< (4*3));
GPIOC_CRL |= (3<<4*3);
GPIOC_BSRR = (0x01<<(16+3));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);
//D5
GPIOC_CRL &= ~( 0x0F<< (4*4));
GPIOC_CRL |= (3<<4*4);
GPIOC_BSRR = (0x01<<(16+4));
Delay(0x3FFFF);  
GPIOC_BSRR = (0x0000ffff);
//D6
GPIOC_CRL &= ~( 0x0F<< (4*5));
GPIOC_CRL |= (3<<4*5);
GPIOC_BSRR = (0x01<<(16+5));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);
//D7
GPIOC_CRL &= ~( 0x0F<< (4*6));
GPIOC_CRL |= (3<<4*6);
GPIOC_BSRR = (0x01<<(16+6));
Delay(0x3FFFF);   
GPIOC_BSRR = (0x0000ffff);
//D8
GPIOC_CRL &= ~( 0x0F<< (4*7));
GPIOC_CRL |= (3<<4*7);
GPIOC_BSRR = (0x01<<(16+7));
Delay(0x3FFFF);   
GPIOC_BSRR = (0x0000ffff);
}
}

注意:

①包含 stm32f10x.h 头文件,在这个头文件中我们定义的都是寄存器,因此如果要在其他文件中使用这些寄存器就需要把这个头文件包含进来, 否则编译就会报错。

②SystemInit 函数,在前面讲解启动文件时已经说明,程序运行的时候先进入这个函数进行 STM32 的初始化,如果不写这个函数编译器就会报错。这里我们编写这个函数,里面并不对其操作。

③开启 GPIOC 时钟。要使 PC0 正常工作输出一个低电平,必须要打开它的时钟。RCC_APB2ENR 寄存器是在 stm32f10x.h 头文件中定义好的,只要查下《STM32F1xx 中文参考手册》RCC 时钟使能寄存器内容就可以知道此寄存器的第4 位是控制 GPIOC 外设的时钟使能位,只有该位为 1 时才使能,如果为 0 即关闭GPIOC 时钟。所以要让 1 左移 4 位。

④配置 GPIOC 为通用推完输出模式。STM32 的 GPIO 模式有很多,可根据CRx 寄存器设置,CRL 对应 GPIO 的低 8 位,CRH 对应 GPIO 的高 8 位。如果不是特殊需求,一般输出采用推挽输出模式。我们要让 PC0 管脚输出一个低电平,故使用推挽输出模式。只要查下《STM32F1xx 中文参考手册》GPIO 配置寄存器内容就可以知道此寄存器内每 4 位控制一个管脚。

⑤使 PC0 输出低电平。GPIOC_BSRR 为置位、复位寄存器,只要查下《STM32F1xx 中文参考手册》GPIO 置位复位寄存器内容就可以知道,其高 16 位用于复位,如果当高 16 位某位为 1,表示那一位管脚输出低电平,为 0 不影响其输出电平。如果当低 16 位的某位为 1,表示那一位管脚输出高电平,为 0 不影响其输出电平。所以要让 1 左移 16+0 位。

本文转载自:STM32嵌入式开发
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:
cathy@eetrend.com)。

围观 90

一、STM32 芯片架构简图


STM32 有三种启动方式,从 FLASH 启动(包含系统存储器),从内部 SRAM 启动,从外部 RAM 启动。

二、存储器映射

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


在这 4GB 的地址空间中, ARM 已经粗线条的平均分成了 8 个块,每块 512MB,每个块也都规定了用途,具体分类见下表。每个块的大小都有 512MB,显然这是非常大的,芯片厂商在每个块的范围内设计各具特色的外设时并不一定都用得完,都是只用了其中的一部分而已。


在这 8 个 Block 里面,有 3 个块非常重要,也是我们最关心的三个块。 Boock0 用来设计成内部 FLASH, Block1 用来设计成内部 RAM, Block2 用来设计成片上的外设,下面我们简单的介绍下这三个 Block 里面的具体区域的功能划分。

1、存储器 Block0 内部区域功能划分

Block0 主要用于设计片内的 FLASH, F429 系列片内部 FLASH 最大是 2MB,STM32F429IGT6 的 FLASH 是 1MB。


2、储存器 Block1 内部区域功能划分

Block1 用于设计片内的 SRAM。 F429 内部 SRAM 的大小为 256KB,其中 64KB 的CCM RAM 位于 Block0,剩下的 192KB 位于 Block1,分 SRAM1 112KB, SRAM2 16KB,SRAM3 64KB, Block 内部区域的功能划分具体见下表。


3、储存器 Block2 内部区域功能划分

Block2 用于设计片内的外设,根据外设的总线速度不同, Block 被分成了 APB 和 AHB两部分,其中 APB 又被分为 APB1 和 APB2, AHB 分为 AHB1 和 AHB2,具体见下表。还有一个 AHB3 包含了 Block3/4/5/6,这四个 Block 用于扩展外部存储器,如 SDRAM,NORFLASH 和 NANDFLASH 等。


三、寄存器映射

根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。

1、STM32 的外设地址映射

片上外设区分为四条总线,根据外设速度的不同,不同总线挂载着不同的外设, APB挂载低速外设, AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。其中 APB1 总线的地址最低,片上外设从这里开始,也叫外设基地址。

(1)总线基地址


(2)外设基地址

总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为“ XX 外设基地址”,也叫 XX 外设的边界地址。


(3)外设寄存器

GPIO 有很多个寄存器,每一个都有特定的功能。每个寄存器为 32bit,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。


2、C 语言对寄存器的封装
(1)封装总线和外设基地址

为了方便理解和记忆,我们把总线基地址和外设基地址都以相应的宏定义起来,总线或者外设都以他们的名字作为宏名。


(2)封装寄存器列表

GPIOA-GPIOH 都各有一组功能相同的寄存器,如 GPIOA_MODER/GPIOB_MODER/GPIOC_MODER 等等,它们只是地址不一样,但却要为每个寄存器都定义它的地址。为了更方便地访问寄存器,我们引入 C 语言中的结构体语法对寄存器进行封装。



这样的地址偏移与 STM32 GPIO 外设定义的寄存器地址偏移一一对应,只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结构体的形式访问寄存器了。


3、修改寄存器的位操作方法

用 C 语言对寄存器赋值时,我们常常要求只修改该寄存器的某几位的值,且其它的寄存器位不变,这个时候我们就需要用到 C 语言的位操作方法了。

(1)把变量的某位清零

此处我们以变量 a 代表寄存器,并假设寄存器中本来已有数值,此时我们需要把变量a 的某一位清零,且其它位不变。


(2)把变量的某几个连续位清零

由于寄存器中有时会有连续几个寄存器位用于控制某个功能,现假设我们需要把寄存器的某几个连续位清零,且其它位不变。


(3)对变量的某几位进行赋值

寄存器位经过上面的清零操作后,接下来就可以方便地对某几位写入所需要的数值了,且其它位不变,这时候写入的数值一般就是需要设置寄存器的位参数。


(4)对变量的某位取反

某些情况下,我们需要对寄存器的某个位进行取反操作,即 1 变 0 , 0 变 1,这可以直接用如下操作,其它位不变。


本文为CSDN博主 Sumjess 原创文章,
遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:
https://blog.csdn.net/qq_38351824/article/details/104157958

围观 152

页面

订阅 RSS - 寄存器