如何处理 "没有无效的地址"?安全访问

239 阅读4分钟

在上一篇博客中,我们试图直接写到BSRR寄存器的地址,这不是安全访问,因为我们陷入了硬件故障异常。你可以阅读那篇博客 来自这里.

现在在这篇博客中,我们将以一种非常不同的方式工作。我们不打算使用BSRR寄存器,而是要使用寄存器块来访问GPIO 块的寄存器。

由于我们正在使用嵌入式系统,它们使我们的任务快速而可靠。另外,与传统的计算机相比,它们的体积要小得多,这使得它们结构紧凑,便于携带,有利于大规模生产。嵌入式系统的管理是相当容易的,因为在其创建过程中使用的元素是廉价和持久的。嵌入式系统也具有成本效益。

直接使用十六进制地址是容易出错的,这一点我们在上一篇博客中已经看到了,我们是如何面对硬件异常的。现在我们要以一种 "安全 "的方式来工作。让我们看看我们如何做到这一点。

我们将在工作中牢记寄存器的3个规则。

  1. 不乱用实际地址
  2. 应尊重读/写权限
  3. 应该防止修改寄存器的保留部分。

寄存器块

Register Block safe accessRegister Block safe access

寄存器块是一组与外设相关的寄存器,这些寄存器组位于_内存的_一个_连续的区域内。_

为什么我们在这里谈论寄存器块?

寄存器块是一种结构类型,它的每个字段都代表一个寄存器。这些寄存器是以下方法的组合:根据其读/写权限,读、写或修改。我们可以使用寄存器块访问的寄存器的数量是。

我们可以在寄存器块结构的帮助下访问所有这些寄存器。


代码

是时候编写一个安全的程序了,它将帮助我们使用寄存器块访问**"bsrr "**寄存器。

#![no_main]
#![no_std]

use cortex_m::asm::delay;
use cortex_m_rt::entry;
use panic_itm as _;
use stm32f3_discovery::leds::Leds;
use stm32f3_discovery::stm32f3xx_hal::{pac::GPIOE, prelude::*, stm32};

#[entry]
fn main() -> ! {
    let gpioe = unsafe { &*GPIOE::ptr() };
    let device_peripherals = stm32::Peripherals::take().unwrap();
    let mut reset_and_clock_control = device_peripherals.RCC.constrain();

    // initialize user leds
    let mut gpio_pe = device_peripherals
        .GPIOE
        .split(&mut reset_and_clock_control.ahb);
    let _leds = Leds::new(
        gpio_pe.pe8,
        gpio_pe.pe9,
        gpio_pe.pe10,
        gpio_pe.pe11,
        gpio_pe.pe12,
        gpio_pe.pe13,
        gpio_pe.pe14,
        gpio_pe.pe15,
        &mut gpio_pe.moder,
        &mut gpio_pe.otyper,
    );

    loop {
        // Turn "on" the North LED
        gpioe.bsrr.write(|write| write.bs9().set_bit());
        delay(3_0000_00);
        // Turn "on" the North LED
        gpioe.bsrr.write(|write| write.bs11().set_bit());
        delay(3_0000_00);
        // Turn "off" the North LED
        gpioe.bsrr.write(|write| write.br9().set_bit());
        delay(3_0000_00);
        // Turn "off" the North LED
        gpioe.bsrr.write(|write| write.br11().set_bit());
        delay(3_0000_00);
    }
}

**注意:**你可以从这里看到代码和使用的依赖性。 储存器.

这里你可以注意到我们使用了 "stm32f3_discovery::stm32f3xx_hal::pac::GPIOE",它为我们提供了RegisterBlock。我们必须使用不安全块来访问这个寄存器块,因为我们必须取消对原始指针的引用。

  • 你注意到的第一件事。这里没有涉及任何神奇的地址。相反,我们使用一个更人性化的方式,例如,gpioe.bsrr,来指代GPIOE寄存器块中的BSRR寄存器
  • 然后,我们有这样的写入方法,它需要一个闭包。如果使用身份闭合(|w|w),这个方法将把寄存器设置为_默认_(复位)值,即微控制器上电/复位后的值。
  • 这个值是BSRR寄存器的0x0。因为我们想给寄存器写一个非零的值,所以我们使用构建器的方法,比如bs9和br9,对默认值的一些位进行构建。

现在逐一应用这些命令

  • 加载
  • 断开主程序
  • 继续
  • 步骤
  • 下一步
  • print gpioe

你会看到这样的输出。

这个打印出的寄存器块的地址和**"bsrr "寄存器的地址将在一个连续的内存中,即0x48001018**。


使用寄存器块闪烁LEDs-

现在让我们试着用这种安全的方式来闪烁LEDs。现在运行命令"continue"。

输出...

这就是你如何以安全的方式使用寄存器块访问LEDs。

我希望你喜欢这种使用寄存器的工作方式。谢谢你的阅读...!


如果你想阅读更多这样的内容? 请订阅《锈蚀时代》通讯,每两周一次,直接在您的收件箱中收到见解和最新更新。订阅《锈蚀时代》通讯:https://bit.ly/2Vdlld7