Spooky action at a distance

BSRR is not the only register that can control the pins of Port E. The ODR register also letsyou change the value of the pins. Furthermore, ODR also lets you retrieve the current outputstatus of Port E.

ODR is documented in:

Section 11.4.6 GPIO port output data register - Page 239

Let’s try this program:

  1. #![no_main]
  2. #![no_std]
  3. use core::ptr;
  4. #[allow(unused_imports)]
  5. use aux7::{entry, iprint, iprintln};
  6. #[entry]
  7. fn main() -> ! {
  8. let mut itm = aux7::init().0;
  9. unsafe {
  10. const GPIOE_BSRR: u32 = 0x4800_1018;
  11. const GPIOE_ODR: u32 = 0x4800_1014;
  12. iprintln!(
  13. &mut itm.stim[0],
  14. "ODR = 0x{:04x}",
  15. ptr::read_volatile(GPIOE_ODR as *const u16)
  16. );
  17. // Turn on the NORTH LED (red)
  18. ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 9);
  19. iprintln!(
  20. &mut itm.stim[0],
  21. "ODR = 0x{:04x}",
  22. ptr::read_volatile(GPIOE_ODR as *const u16)
  23. );
  24. // Turn on the EAST LED (green)
  25. ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << 11);
  26. iprintln!(
  27. &mut itm.stim[0],
  28. "ODR = 0x{:04x}",
  29. ptr::read_volatile(GPIOE_ODR as *const u16)
  30. );
  31. // Turn off the NORTH LED
  32. ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (9 + 16));
  33. iprintln!(
  34. &mut itm.stim[0],
  35. "ODR = 0x{:04x}",
  36. ptr::read_volatile(GPIOE_ODR as *const u16)
  37. );
  38. // Turn off the EAST LED
  39. ptr::write_volatile(GPIOE_BSRR as *mut u32, 1 << (11 + 16));
  40. }
  41. loop {}
  42. }

If you run this program, you’ll see:

  1. $ # itmdump's console
  2. (..)
  3. ODR = 0x0000
  4. ODR = 0x0200
  5. ODR = 0x0a00
  6. ODR = 0x0800

Side effects! Although we are reading the same address multiple times without actually modifying it,we still see its value change every time BSRR is written to.