/dev/gpiomem0
//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;
}
我使用的一些帮助: