如何使用Raspberry Pi 5上的内存映射寄存器读写gpio引脚? 我正在尝试使用直接内存映射寄存器和RIO功能在Raspberry Pi 5上读取GPIO引脚。如何映射GPIO内存,设置PIN模式并访问寄存器进行阅读和

问题描述 投票:0回答:1
任何改进的建议将不胜感激!

c++ raspberry-pi raspberry-pi5
1个回答
-1
投票
https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf

在这里是如何实现这一目标的一个例子:

通过使用

/dev/gpiomem0

,我们可以访问GPIO存储器而无需根特权。这允许从用户空间访问GPIO寄存器。
    为了有效的GPIO操作,我们可以使用原子读/写入说明。
  • //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;
    }
    
    我使用的一些帮助:
https://github.com/hzeller/rpi-gpio-dma-demo

https://github.com/praktronics/rpi5-rp1-gpio/tree/main
  • https://www.i-programmer.info/programming/148-hardware/16887-raspberry-pi-iot-in-c-pi--in-c-pi--pi-5-memory-memory-mapp.-gpio.html?start =2
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.