嵌入式 Rust:进阶篇

RTC 驱动程序

(返回练习)

main.rs:

  1. #![no_main]
  2. #![no_std]
  3. mod exceptions;
  4. mod logger;
  5. mod pl011;
  6. mod pl031;
  7. use crate::pl031::Rtc;
  8. use arm_gic::gicv3::{IntId, Trigger};
  9. use arm_gic::{irq_enable, wfi};
  10. use chrono::{TimeZone, Utc};
  11. use core::hint::spin_loop;
  12. use crate::pl011::Uart;
  13. use arm_gic::gicv3::GicV3;
  14. use core::panic::PanicInfo;
  15. use log::{error, info, trace, LevelFilter};
  16. use smccc::psci::system_off;
  17. use smccc::Hvc;
  18. /// Base addresses of the GICv3.
  19. const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;
  20. const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;
  21. /// Base address of the primary PL011 UART.
  22. const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;
  23. /// Base address of the PL031 RTC.
  24. const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
  25. /// The IRQ used by the PL031 RTC.
  26. const PL031_IRQ: IntId = IntId::spi(2);
  27. #[no_mangle]
  28. extern "C" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {
  29. // SAFETY: `PL011_BASE_ADDRESS` is the base address of a PL011 device, and
  30. // nothing else accesses that address range.
  31. let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };
  32. logger::init(uart, LevelFilter::Trace).unwrap();
  33. info!("main({:#x}, {:#x}, {:#x}, {:#x})", x0, x1, x2, x3);
  34. // SAFETY: `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the base
  35. // addresses of a GICv3 distributor and redistributor respectively, and
  36. // nothing else accesses those address ranges.
  37. let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, GICR_BASE_ADDRESS) };
  38. gic.setup();
  39. // SAFETY: `PL031_BASE_ADDRESS` is the base address of a PL031 device, and
  40. // nothing else accesses that address range.
  41. let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
  42. let timestamp = rtc.read();
  43. let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
  44. info!("RTC: {time}");
  45. GicV3::set_priority_mask(0xff);
  46. gic.set_interrupt_priority(PL031_IRQ, 0x80);
  47. gic.set_trigger(PL031_IRQ, Trigger::Level);
  48. irq_enable();
  49. gic.enable_interrupt(PL031_IRQ, true);
  50. // Wait for 3 seconds, without interrupts.
  51. let target = timestamp + 3;
  52. rtc.set_match(target);
  53. info!("Waiting for {}", Utc.timestamp_opt(target.into(), 0).unwrap());
  54. trace!(
  55. "matched={}, interrupt_pending={}",
  56. rtc.matched(),
  57. rtc.interrupt_pending()
  58. );
  59. while !rtc.matched() {
  60. spin_loop();
  61. }
  62. trace!(
  63. "matched={}, interrupt_pending={}",
  64. rtc.matched(),
  65. rtc.interrupt_pending()
  66. );
  67. info!("Finished waiting");
  68. // Wait another 3 seconds for an interrupt.
  69. let target = timestamp + 6;
  70. info!("Waiting for {}", Utc.timestamp_opt(target.into(), 0).unwrap());
  71. rtc.set_match(target);
  72. rtc.clear_interrupt();
  73. rtc.enable_interrupt(true);
  74. trace!(
  75. "matched={}, interrupt_pending={}",
  76. rtc.matched(),
  77. rtc.interrupt_pending()
  78. );
  79. while !rtc.interrupt_pending() {
  80. wfi();
  81. }
  82. trace!(
  83. "matched={}, interrupt_pending={}",
  84. rtc.matched(),
  85. rtc.interrupt_pending()
  86. );
  87. info!("Finished waiting");
  88. system_off::<Hvc>().unwrap();
  89. }
  90. #[panic_handler]
  91. fn panic(info: &PanicInfo) -> ! {
  92. error!("{info}");
  93. system_off::<Hvc>().unwrap();
  94. loop {}
  95. }

pl031.rs

  1. #![allow(unused)]
  2. fn main() {
  3. use core::ptr::{addr_of, addr_of_mut};
  4. #[repr(C, align(4))]
  5. struct Registers {
  6. /// Data register
  7. dr: u32,
  8. /// Match register
  9. mr: u32,
  10. /// Load register
  11. lr: u32,
  12. /// Control register
  13. cr: u8,
  14. _reserved0: [u8; 3],
  15. /// Interrupt Mask Set or Clear register
  16. imsc: u8,
  17. _reserved1: [u8; 3],
  18. /// Raw Interrupt Status
  19. ris: u8,
  20. _reserved2: [u8; 3],
  21. /// Masked Interrupt Status
  22. mis: u8,
  23. _reserved3: [u8; 3],
  24. /// Interrupt Clear Register
  25. icr: u8,
  26. _reserved4: [u8; 3],
  27. }
  28. /// Driver for a PL031 real-time clock.
  29. #[derive(Debug)]
  30. pub struct Rtc {
  31. registers: *mut Registers,
  32. }
  33. impl Rtc {
  34. /// Constructs a new instance of the RTC driver for a PL031 device at the
  35. /// given base address.
  36. ///
  37. /// # Safety
  38. ///
  39. /// The given base address must point to the MMIO control registers of a
  40. /// PL031 device, which must be mapped into the address space of the process
  41. /// as device memory and not have any other aliases.
  42. pub unsafe fn new(base_address: *mut u32) -> Self {
  43. Self { registers: base_address as *mut Registers }
  44. }
  45. /// Reads the current RTC value.
  46. pub fn read(&self) -> u32 {
  47. // SAFETY: We know that self.registers points to the control registers
  48. // of a PL031 device which is appropriately mapped.
  49. unsafe { addr_of!((*self.registers).dr).read_volatile() }
  50. }
  51. /// Writes a match value. When the RTC value matches this then an interrupt
  52. /// will be generated (if it is enabled).
  53. pub fn set_match(&mut self, value: u32) {
  54. // SAFETY: We know that self.registers points to the control registers
  55. // of a PL031 device which is appropriately mapped.
  56. unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }
  57. }
  58. /// Returns whether the match register matches the RTC value, whether or not
  59. /// the interrupt is enabled.
  60. pub fn matched(&self) -> bool {
  61. // SAFETY: We know that self.registers points to the control registers
  62. // of a PL031 device which is appropriately mapped.
  63. let ris = unsafe { addr_of!((*self.registers).ris).read_volatile() };
  64. (ris & 0x01) != 0
  65. }
  66. /// Returns whether there is currently an interrupt pending.
  67. ///
  68. /// This should be true if and only if `matched` returns true and the
  69. /// interrupt is masked.
  70. pub fn interrupt_pending(&self) -> bool {
  71. // SAFETY: We know that self.registers points to the control registers
  72. // of a PL031 device which is appropriately mapped.
  73. let ris = unsafe { addr_of!((*self.registers).mis).read_volatile() };
  74. (ris & 0x01) != 0
  75. }
  76. /// Sets or clears the interrupt mask.
  77. ///
  78. /// When the mask is true the interrupt is enabled; when it is false the
  79. /// interrupt is disabled.
  80. pub fn enable_interrupt(&mut self, mask: bool) {
  81. let imsc = if mask { 0x01 } else { 0x00 };
  82. // SAFETY: We know that self.registers points to the control registers
  83. // of a PL031 device which is appropriately mapped.
  84. unsafe { addr_of_mut!((*self.registers).imsc).write_volatile(imsc) }
  85. }
  86. /// Clears a pending interrupt, if any.
  87. pub fn clear_interrupt(&mut self) {
  88. // SAFETY: We know that self.registers points to the control registers
  89. // of a PL031 device which is appropriately mapped.
  90. unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }
  91. }
  92. }
  93. // SAFETY: `Rtc` just contains a pointer to device memory, which can be
  94. // accessed from any context.
  95. unsafe impl Send for Rtc {}
  96. }