Reputation: 11
I am trying to control GPIO pins of a Raspberry Pi 3/4 running FreeBSD, using direct access to the BCM2835 registers. My code is based on Mike McCauley's C library.
It works fine on Linux (Raspberry Pi OS, hence Debian bookworm), but I fail to get the same code working on FreeBSD (latest FreeBSD 14.2 image for RPI (3/4) armv7). My C code builds fine on both OS'es, but on FreeBSD it the executable runs but does not actually control the GPIO pins.
Here is a simple piece of code to show what I'm doing. For simplicity with hardcoded addresses for the Raspberry Pi 3:
/*
Program to test direct access to bcm2835 registers to blink a LED
Build as follows: gcc -Wall -o gpio gpio.c
Run as root
*/
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
// GPIO pin to which a LED is connected:
#define GPIO_PIN (23)
int main() {
int mem_fd;
uint32_t *periph_base;;
uint32_t *periph_gpio;
uint32_t *gpio_function_register;
uint32_t gpio_function_register_pin_mask;
uint32_t function_register_value;
volatile uint32_t *gpio_set_lower_register;
volatile uint32_t *gpio_clear_lower_register;
uint32_t gpio_pin_mask;
mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
if (!mem_fd) return 1;
periph_base = (uint32_t *)mmap(
NULL, // Any adddress in our space will do
0x01000000, // Map length on the Raspberry Pi 3
PROT_READ|PROT_WRITE, // Enable reading & writting to mapped memory
MAP_SHARED, // Shared with other processes
mem_fd, // File to map
0x3F000000 // Offset to BCM peripherals on the Raspberry Pi 3
);
close(mem_fd); // No need to keep mem_fd open after mmap
if (periph_base == (void *)-1) return 2;
/********* calculate addresses to all registers we need *********/
// calculate address to gpio registers
periph_gpio = periph_base + 0x200000/4;
// address of pin function select for pin GPIO_PIN
gpio_function_register = periph_gpio + GPIO_PIN/10;
// bit mask for the 3 bits within the function select register for pin GPIO_PIN
gpio_function_register_pin_mask = (7 << ((GPIO_PIN%10)*3));
// address of gpio set register for the first 32 pins
gpio_set_lower_register = periph_gpio + 7;
// address of gpio clear register for the first 32 pins
gpio_clear_lower_register = periph_gpio + 10;
// bit position in register for pin GPIO_PIN
gpio_pin_mask = (uint32_t)1 << GPIO_PIN;
/********* set the function of pin GPIO_PIN to "output" *********/
// get current value of function register
function_register_value = *gpio_function_register;
// reset function select bits for this pin (this selects the "input" function)
function_register_value &= ~gpio_function_register_pin_mask;
// set function select bits for this pin to function "1" ("output")
function_register_value |= (((uint32_t)1) << ((GPIO_PIN%10)*3));
// update function register
*gpio_function_register = function_register_value;
/********* set and clear the gpio pin to make the LED blink *********/
for (;;) {
*gpio_set_lower_register = gpio_pin_mask;
sleep(1);
*gpio_clear_lower_register = gpio_pin_mask;
sleep(1);
}
return 0;
}
How do I get this working on FreeBSD?
Thanks a lot for your help!
Upvotes: 1
Views: 63