In some cases we may want information from the Raspberry without having to look at the UART output. In this case we can use either the green activity LED or an external LED connected via the pins.
After some research I could figure out that the ACT LED can be set via the GPIO29 on a Raspberry PI 3B+. When using an external LED, choose a GPIO pin that is not in use(ex. GPIO17).
Step 0: Setting up the GPIO Link to heading
GPIO29
Here we just have to go the same route as mentioned in previous section by setting the GPIO function. Instead of ALT0 we will use output which is 001 in binary.
Step 1: Changing state Link to heading
To set the GPIO low and high, broadcom gives us 2 register types; GPCLRn to pull a pin to ground(0V); GPSETn to pull a pin high(3.3V).
Each register typ has 2 x 32bit registers with each bit representing a GPIO pin, except bit 22-31 in the second register. Setting a bit to 1 in GPCLRn will pull the pin down.
Setting a bit to 1 in GPSETn will pull the pin up. Setting 0 has no effect.
| Field Name | Physical Address |
|---|---|
GPSET0 |
0x3F20001C |
GPSET1 |
0x3F200020 |
GPCLR0 |
0x3F200028 |
GPCLR1 |
0x3F20002C |
GPCLR0 Link to heading
| Bits | Field Name | Description |
|---|---|---|
| 31-0 | CLRn (n=0..31) | 1 = Clear GPIO pin n; 0 = No effect |
GPCLR1 Link to heading
| Bits | Field Name | Description |
|---|---|---|
| 31-22 | - | Reserved |
| 21-0 | CLRn (n=32..53) | 1 = Clear GPIO pin n; 0 = No effect |
GPSET0 Link to heading
| Bits | Field Name | Description |
|---|---|---|
| 31-0 | SETn (n=0..31) | 1 = Clear GPIO pin n; 0 = No effect |
GPSET1 Link to heading
| Bits | Field Name | Description |
|---|---|---|
| 31-22 | - | Reserved |
| 21-0 | SETn (n=32..53) | 1 = Set GPIO pin n.; 0 = No effect |
Step 3: Clock Link to heading
To keep track of time the broadcom chip has a System Timer that allows us to keep track of time in micro seconds.
At 0x3F003000 we have multiple registers again that let us interact with the system timer. For now only CLO(Lower 32 bit clock) and CHI(Higher 32 bit clock) are important.
Together it gives us 64 bits of accurate time tracking. But CLO should be sufficient because it allows us to track time of up to 2147483647μs equaling 2147 seconds.
For now we can call nops while waiting for our delay to run out:
pub fn sleep_us(us: u32) {
let start = read_clo();
while read_clo() - start < us {
unsafe { core::arch::asm!("nop") }
}
}