Also known as the CPU family in Raspberry Pi computers (early ones at least) - working on a π0w, not bare metal as a learning process of how to interact with hardware in a hosted environment. Turns out to be fairly simple on this platform as the entire memory space is kindly presented to the operator through a block device.
I don’t know how many of these includes I needed:
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// GPIO modes - datasheet table 6.2
#define GPIO_IN 0
#define GPIO_OUT 1
#define GPIO_ALT0 4
#define GPIO_ALT1 5
#define GPIO_ALT2 6
#define GPIO_ALT3 7
#define GPIO_ALT4 3
#define GPIO_ALT5 2
// GPIO register; GPCLK register
static volatile uint32_t *reg = NULL;
static volatile uint32_t *mem = NULL;
void setup(void) {
// technically these are redundant since I could use /dev/mem for both
int fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
reg = (uint32_t *)mmap(NULL, 0xB4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
fd = open("/dev/mem", O_RDWR | O_SYNC);
mem = (uint32_t *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
0x20101000);
close(fd);
}
void set_mode(int gpio, int mode) {
int off = gpio / 10;
int shift = 3 * (gpio % 10);
reg[off] = (reg[off] & ~(0b111 << shift)) | (mode << shift);
}
int main() {
setup();
set_mode(4, GPIO_ALT0);
uint32_t pass = 0x5a << 24;
uint32_t div = 1920 << 12;
mem[0x70 / 4] = 0;
mem[0x74 / 4] = pass | div;
mem[0x70 / 4] = pass | 0x10 | 0x1;
return 0;
}
Essentially this swithces the GPIO4 pin to be connected to CM_GP0
general purpose clock, here internally connected to the 19.2 MHz crystal oscillator, through a divider to give 10 kHz output. On the scope this gives the right pulse sequence.
Racing against a pico however with
from machine import mem32
IO_BANK_BASE = 0x40014000
CLK_BASE = 0x40008000
GPIO21_CTRL = IO_BANK_BASE | 0xac
mem32[GPIO21_CTRL] = 8 # GPCLK0
mem32[CLK_BASE] = 1 << 11
mem32[CLK_BASE | 4] = 12500 << 8
Shows that clocks drift slightly: