The Raspberry PI has a number of peripheral devices that are accessible over MMIO. To demonstrate how MMIO works, our application will access the system timer:
- In your working ~/test directory, create a subdirectory called timer.
- Use your favorite text editor to create a file named timer.cpp in the timer subdirectory.
- Put the required headers, constants, and declarations of types into timer.cpp:
#include <iostream>
#include <chrono>
#include <system_error>
#include <thread>
#include <fcntl.h>
#include <sys/mman.h>
constexpr uint32_t kTimerBase = 0x3F003000;
struct SystemTimer {
uint32_t CS;
uint32_t counter_lo;
uint32_t counter_hi;
};
- Add the main function, which contains all the logic of the program:
int main() {
int memfd = open("/dev/mem", O_RDWR | O_SYNC);
if (memfd < 0) {
throw std::system_error(errno, std::generic_category(),
"Failed to open /dev/mem. Make sure you run as root.");
}
SystemTimer *timer = (SystemTimer*)mmap(NULL, sizeof(SystemTimer),
PROT_READ|PROT_WRITE, MAP_SHARED,
memfd, kTimerBase);
if (timer == MAP_FAILED) {
throw std::system_error(errno, std::generic_category(),
"Memory mapping failed");
}
uint64_t prev = 0;
for (int i = 0; i < 10; i++) {
uint64_t time = ((uint64_t)timer->counter_hi << 32) + timer->counter_lo;
std::cout << "System timer: " << time;
if (i > 0) {
std::cout << ", diff " << time - prev;
}
prev = time;
std::cout << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return 0;
}
- Create a file called CMakeLists.txt in the timer subdirectory with the following content:
cmake_minimum_required(VERSION 3.5.1)
project(timer)
add_executable(timer timer.cpp)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_CXX_FLAGS "--std=c++11")
set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++)
- You can now build and run the application.
Please note that it should be run under root on a real Raspberry PI 3 device.