79424011

Date: 2025-02-08 22:29:18
Score: 4.5
Natty:
Report link

Any suggestions for improvement would be greatly appreciated!

The RP1 DataSheet https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf

Here’s an example of how to accomplish this:

//The RP1 DataSheet https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf
#include <iostream>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cstdint>
#include <chrono>
#include <cstdio>

// Base address for GPIO memory mapping (Datasheet: 0x400d0000; Chapter 3.1.4)
constexpr off_t kGpioBank = 0x00000;

// Offset of 32 Bit inside the pins register (status register)
// |-- Pin 1 - 64 bit --|-- Pin 2 --|-- Pin 3 --| ... |...
// |- Status - Control -| - S - C - | - S - C - | ... |...
// |- 32 bit - 32 bit  -|...
constexpr off_t kGpioCtrlOffset = 0x1;

// Function select value for RIO mode (Chapter 3.1.1 & 3.3)
constexpr int kGpioFunSelectRio = 0x5;

// Base address for RIO bank (Datasheet: 0x400e0000, relative to 0x400d0000; Chapter 3.3.2. )
constexpr off_t kRioBankOffset = 0x10000;

// Offset for RIO output enable register (Chapter 3.3)
constexpr off_t kRioOutputEnable = 0x4;
constexpr off_t kRioInput = 0x8; // no sync input

// Offsets for atomic read/write/xor operations (Chapter 2.4 and 3.3)
constexpr off_t kRioClear = 0x3000; // normal Reads
constexpr off_t kRioSet = 0x2000; // normal Reads
constexpr off_t kRioXor = 0x1000; // Reads have no side effect

// Base address for Pad bank (Datasheet: 0x400f0000, relative to 0x400d0000; Chapter 3.1.4)
constexpr off_t kPadBank = 0x20000 + 0x04; // 0x00 is voltage select. Chapter 3.3 Table 19

// GPIO configuration constants
constexpr int kGpioPin = 12;                      // GPIO pin to toggle
constexpr int kToggleCount = 1000;                     // Number of toggles
constexpr int kGpioToggleMask = (1 << kGpioPin); // Bitmask for selected GPIO pin

// Maps GPIO memory for direct register access
static void* MmapGpioMemRegister()
{
  int mem_fd;
  if ((mem_fd = open("/dev/gpiomem0", O_RDWR | O_SYNC)) < 0)
  {
    perror("Can't open /dev/gpiomem0");
    std::cerr << "You need GPIO access permissions.\n";
    return nullptr;
  }

  uint32_t* result = static_cast<uint32_t*>(mmap(
      nullptr, 0x30000, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0));

  close(mem_fd);

  if (result == MAP_FAILED)
  {
    std::cerr << "mmap error\n";
    return nullptr;
  }
  return result;
}

// Returns a high-resolution timestamp in nanoseconds
uint64_t GetTimestampNs()
{
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts); // Get time since boot
  return static_cast<uint64_t>(ts.tv_sec)*  1000000000ULL + ts.tv_nsec;
}

// Implements a precise delay in nanoseconds
void PreciseDelayNs(uint32_t delayNs)
{
  auto start_time_ns = std::chrono::high_resolution_clock::now();
  auto end_time_ns = start_time_ns + std::chrono::nanoseconds(delayNs);
  while (std::chrono::high_resolution_clock::now() < end_time_ns)
  {
  };
}

// Toggles GPIO using direct register access
void Blink()
{
  // Map GPIO memory
  volatile void* gpio_mem = MmapGpioMemRegister();
  if (!gpio_mem)
  {
    exit(EXIT_FAILURE);
  }

  // Configure GPIO for RIO mode (function select 5)
  volatile uint32_t* const gpio_bank = (volatile uint32_t*)(gpio_mem + kGpioBank);
  volatile uint32_t* pin_register = gpio_bank + (2 * kGpioPin + kGpioCtrlOffset); // 2 * kGpioPin --> 64 for each pin in the Bank
  *pin_register = kGpioFunSelectRio;

  // Configure GPIO pads (disable output disable & input enable)
  volatile uint32_t* const pad_bank = (volatile uint32_t*)(gpio_mem + kPadBank);
  volatile uint32_t* pad_register = pad_bank + kGpioPin; // pad_bank is only 32 bit per pin (gpio_bank is 64 - Status and Control each 32 bit)
  *pad_register = (0b00 << 6); // Chapter 3.3 Table 21 --> Output disabled bit 7 (default 0x1), Input enabled bit 6 (default 0x0) 

  // Enable output in RIO
  *((volatile uint32_t*)(gpio_mem + kRioBankOffset + kRioOutputEnable)) = kGpioToggleMask;

  // Get direct register access pointers for toggling
  volatile uint32_t* const rio_out_set = (volatile uint32_t*)(gpio_mem + kRioBankOffset + kRioSet);
  volatile uint32_t* const rio_out_clear = (volatile uint32_t*)(gpio_mem + kRioBankOffset + kRioClear);

  printf("2) CPU: Writing to GPIO %d directly %d times\n", kGpioPin, kToggleCount);

  uint64_t start_time_ns = GetTimestampNs();

  // Perform the toggling operation
  for (int i = 0; i < kToggleCount; i++)
  {
    *rio_out_set = kGpioToggleMask; // using the kRioXor we could also toggle here
    //PreciseDelayNs(100000000);
    *rio_out_clear = kGpioToggleMask;
    //PreciseDelayNs(100000000);
  }

  uint64_t end_time_ns = GetTimestampNs();

  // Calculate and display timing results
  uint64_t elapsed_time_ns = end_time_ns - start_time_ns;
  printf("Elapsed time: %lu ns\n", elapsed_time_ns);

  uint64_t elapsed_time_per_rep_ns = elapsed_time_ns / kToggleCount;
  printf("Elapsed per repetition: %lu ns\n", elapsed_time_per_rep_ns);

  uint64_t frequency_hz = kToggleCount / (elapsed_time_ns / 1e9);
  printf("Toggle frequency: %lu Hz\n", frequency_hz);
}

void Read()
{
  // Map GPIO memory
  volatile void* gpio_mem = MmapGpioMemRegister();
  if (!gpio_mem)
  {
    exit(EXIT_FAILURE);
  }

  // Configure GPIO for RIO mode (function select 5)
  volatile uint32_t* const gpio_bank = (volatile uint32_t*)(gpio_mem + kGpioBank);
  volatile uint32_t* pin_register = gpio_bank + (2 * kGpioPin + kGpioCtrlOffset); // 2 * kGpioPin --> 64 for each pin in the Bank
  *pin_register = kGpioFunSelectRio;

  // Configure GPIO pads (enable output disable & input enable)
  volatile uint32_t* const pad_bank = (volatile uint32_t*)(gpio_mem + kPadBank);
  volatile uint32_t* pad_register = pad_bank + kGpioPin; // pad_bank is only 32 bit per pin (gpio_bank is 64 - Status and Control each 32 bit)
  *pad_register = (0b01 << 6); // Chapter 3.3 Table 21 --> Output disabled bit 7 (default 0x1), Input enabled bit 6 (default 0x0)

  // Disable output in RIO
  *((volatile uint32_t*)(gpio_mem + kRioBankOffset + kRioOutputEnable)) = 0x0 << kGpioPin;

  // Get direct register access pointer for reading
  volatile uint32_t* const rio_input = (volatile uint32_t*)(gpio_mem + kRioBankOffset + kRioInput);

  volatile uint32_t val;
  while (true)
  {
    val = (*rio_input & kGpioToggleMask) ? 1 : 0; //  ">> kGpioPin" instead ???
    
    printf("Value is: %u\n", val);
    PreciseDelayNs(100000000);
  }
}

int main()
{
  //Blink();
  Read();

  // munmap()

  return 0;
}

Some help I used:

Reasons:
  • Blacklisted phrase (1): appreciated
  • Blacklisted phrase (1): ???
  • RegEx Blacklisted phrase (2): Any suggestions
  • Probably link only (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Doku