I'm attempting to generate a clock signal to drive external device. However I'm unable to see a signal with the below given code after several hours of trying different changes. Would someone be able to do a sanity check to see if I'm missing something obvious?
rpi4.hppmain.cppOutput:
file descriptor: 13
frequency will be 50000 Hz
clock 0: 1509949457
clock 0: 1509949440
clock 0: 1509949440
clock 0: 1509949441
clock 0: 1509949457
mode: 4
clock initialized
but no clock signal on my OScope.
Any help would be appreciated. I've check and double checked my register values for BCM2711, but that's all I can figure is I have an incorrect address maybe?
rpi4.hpp
Code:
/** * NOTE: PI4 ONLY!!!! (BCM2711) * convience methods for setting RPI 4 registers that are not exposed in the generic linux gpiod library * * influence for clocks taken from below link, modified for pi4 * https://forums.raspberrypi.com/viewtopic.php?t=22274&sid=86e37b8b410e76419751ebaa1879d719 */#pragma once#include <cmath>#include <fcntl.h>#include <stdexcept>#include <stdint.h>#include <sys/mman.h>#include <unistd.h>class Rpi4 {public: enum class GP_CLOCK { GPC_CLOCK0 = 0x70, GPC_CLOCK1 = 0x78, GPC_CLOCK2 = 0x80 }; enum class CLOCK_SOURCE { CS_OSCILLATOR = 1, // 54 MHz CS_PLLC = 5, // 1000 MHz CS_PLLD = 6, // 750 MHz CS_HDMI_AUX = 7 // 216 MHz }; enum class GPIO_MODE { GM_INPUT = 0, GM_OUTPUT = 1, GM_ALT0 = 4, GM_ALT1 = 5, GM_ALT2 = 6, GM_ALT3 = 7, GM_ALT4 = 3, GM_ALT5 = 2 }; enum class GPIO_LEVEL { GL_OFF = 0, GL_ON = 1 }; Rpi4() { this->initialize(); } void gpioSetLevel(const uint8_t gpio, const GPIO_LEVEL level) { if (level == GPIO_LEVEL::GL_OFF) { *(this->_gpioRegisters + GPCLR0 + (gpio >> 5)) = (1 << (gpio & 0x1F)); } else { *(this->_gpioRegisters + GPSET0 + (gpio >> 5)) = (1 << (gpio & 0x1F)); } } void gpioSetMode(const uint8_t gpio, const GPIO_MODE mode) { uint32_t reg = gpio / 10; // each sel register covers 10 pins each w/ 3 bits (32 bits total) uint32_t shift = (gpio % 10) * 3; // we will shift to appropriate location for this gpio in register (3 bit values) uint32_t value = *(this->_gpioRegisters + reg); uint32_t shftdMode = ((uint32_t)mode) << shift; uint32_t registerClr = ~(7 << shift); *(this->_gpioRegisters + reg) = (*(this->_gpioRegisters + reg) & registerClr) | shftdMode; } GPIO_MODE gpioGetMode(const uint8_t gpio) { uint32_t reg = gpio / 10; uint32_t shift = (gpio % 10) * 3; uint32_t value = (*(this->_gpioRegisters + reg) >> shift) & 7; return static_cast<GPIO_MODE>(value); } /** * this method attempts to get the clock as close to the target frequency as possible. Please NOTE that it doesn't attempt to utilize mash divider to get * fractional clock divider (TODO: add feature in future), and therefore the clock rate will be as close as possible using whole number dividers. */ int startClock(const GP_CLOCK clock, const uint32_t targetFrequencyHz) { // since lowest divI value allowed is 2 and highest is 4095, we need to restrict the requested frequencies if (targetFrequencyHz < 13187 || targetFrequencyHz > 125e6) { throw std::runtime_error("target frequency requires fractional dividers that have not been implemented. Please select a frequency between 13187 Hz and 125 MHz"); } // TODO: improve as this will not always select the best clock for getting the desired target frequency // determine best clock source CLOCK_SOURCE clkSrc = CLOCK_SOURCE::CS_OSCILLATOR; CLOCK_SOURCE clkSrcMap[4] = { CLOCK_SOURCE::CS_OSCILLATOR, CLOCK_SOURCE::CS_PLLC, CLOCK_SOURCE::CS_PLLD, CLOCK_SOURCE::CS_HDMI_AUX }; uint32_t clkIdx = 0; for (clkIdx = 0; clkIdx < 4; clkIdx++) { if (targetFrequencyHz < CLOCK_SOURCE_FREQUENCIES[clkIdx]) { clkSrc = clkSrcMap[clkIdx]; break; } } // calculate divider required to get closest to target frequency uint32_t divI = std::ceil(CLOCK_SOURCE_FREQUENCIES[clkIdx] / targetFrequencyHz); uint32_t freq = CLOCK_SOURCE_FREQUENCIES[clkIdx] / divI; std::cout << "frequency will be " << std::to_string(freq) << " Hz" << std::endl; if (divI < 2 || divI > 4095) { throw std::runtime_error("invalid clock divI value provided (2-4095)"); } // TODO: implement uint32_t divF = 0; uint32_t mash = 0; if (divF < 0 || divF > 4095) { throw std::runtime_error("invlaid clock divF value provided (0-4095)"); } if (mash < 0 || mash > 3) { throw std::runtime_error("invalid clock mash value provided (0-3)"); } uint32_t clkCtl = (int)clock; uint32_t clkDiv = clkCtl + 4; // div is 4 more than the ctl address this->printClockCtlValue(); this->_clkRegisters[clkCtl] = CLK_PASSWD & CLK_CTL_DISABLE; this->printClockCtlValue(); while (this->_clkRegisters[clkCtl] & CLK_CTL_BUSY) { usleep(10); } uint32_t divValue = Rpi4::getClockDivIntValue(divI); divValue |= Rpi4::getClockDivFractionalValue(divF); divValue |= CLK_PASSWD; this->_clkRegisters[clkDiv] = divValue; usleep(10); this->printClockCtlValue(); uint32_t ctlValue = Rpi4::getClockMashValue(mash); ctlValue |= Rpi4::getClockSourceValue(static_cast<uint32_t>(clkSrc)); ctlValue |= CLK_PASSWD; this->_clkRegisters[clkCtl] = ctlValue; this->printClockCtlValue(); usleep(10); this->_clkRegisters[clkCtl] |= (CLK_PASSWD | CLK_CTL_ENABLE); this->printClockCtlValue(); } void printClockCtlValue() { uint32_t value = this->_clkRegisters[112]; std::cout << "clock 0: " << std::to_string(value) << std::endl; } int stopClock(const GP_CLOCK clock) { uint32_t clkCtl = (int)clock; this->_clkRegisters[clkCtl] = CLK_PASSWD | CLK_CTL_KILL; while (this->_clkRegisters[clkCtl] & CLK_CTL_BUSY) { usleep(10); } }private: static constexpr uint32_t CLOCK_BASE_ADDRESS = 0x7E101000; static constexpr uint32_t GPIO_BASE_ADDRESS = 0x7E200000; static constexpr uint32_t CLOCK_MEMORY_LENGTH = 0xA8; static constexpr uint32_t GPIO_MEMORY_LENGTH = 0xB4; static constexpr uint32_t CLOCK_SOURCE_FREQUENCIES[4] = { // frequency index must align with above clock source enum index 54e6, // oscillator 1000e6, // PLLC 750e6, // PLLD 216e6 // HDMI AUX }; static constexpr uint8_t CLK_GP0_CTL = 0x70; static constexpr uint8_t CLK_GP0_DIV = 0x74; static constexpr uint8_t CLK_GP1_CTL = 0x78; static constexpr uint8_t CLK_GP1_DIV = 0x7C; static constexpr uint8_t CLK_GP2_CTL = 0x80; static constexpr uint8_t CLK_GP2_DIV = 0x84; static constexpr uint32_t CLK_PASSWD = 0x5A << 24; static constexpr uint32_t CLK_CTL_BUSY = 0x01 << 7; static constexpr uint32_t CLK_CTL_KILL = 0x01 << 5; static constexpr uint32_t CLK_CTL_ENABLE = 0x01 << 4; static constexpr uint32_t CLK_CTL_DISABLE = ~(0x01 << 4); static constexpr uint8_t GPCLR0 = 10; static constexpr uint8_t GPSET0 = 7; uint32_t* _gpioRegisters = (uint32_t*)MAP_FAILED; uint32_t* _clkRegisters = (uint32_t*)MAP_FAILED; static uint32_t getClockMashValue(uint32_t mash) { return mash << 9; } static uint32_t getClockSourceValue(uint32_t src) { return src << 0; } static uint32_t getClockDivIntValue(uint32_t divI) { return divI << 12; } static uint32_t getClockDivFractionalValue(uint32_t divF) { return divF << 0; } static uint32_t* initializeMemoryMap(const uint32_t fd, const uint32_t address, const uint32_t length) { return (uint32_t*)mmap(0, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_LOCKED, fd, address); } uint32_t initialize() { int fd = open("/dev/gpiomem", O_RDWR | O_SYNC); // /dev/gpiomem doesn't require root whereas /dev/mem does (just be member of gpio group) if (fd < 0) { throw std::runtime_error("failed to access gpio memory map"); } this->_gpioRegisters = Rpi4::initializeMemoryMap(fd, GPIO_BASE_ADDRESS, GPIO_MEMORY_LENGTH); close(fd); int genMemFd = open("/dev/mem", O_RDWR | O_SYNC); // unfortunately requires run as sudo if (fd < 0) { throw std::runtime_error("failed to access memory map"); } this->_clkRegisters = Rpi4::initializeMemoryMap(genMemFd, CLOCK_BASE_ADDRESS, CLOCK_MEMORY_LENGTH); close(genMemFd); if (this->_gpioRegisters == MAP_FAILED || this->_clkRegisters == MAP_FAILED) { throw std::runtime_error("register memory map failed"); } return 0; }};
Code:
#include <iostream>#include <unistd.h>#include "./rpi4.hpp"int main(int argc, const char** argv) { // rpi clock Rpi4 rpi4; rpi4.startClock(Rpi4::GP_CLOCK::GPC_CLOCK0, 50000); rpi4.gpioSetMode(4, Rpi4::GPIO_MODE::GM_ALT0); // pin 4 as gp clock std::cout << "mode: " << std::to_string((uint32_t)rpi4.gpioGetMode(4)) << std::endl; std::cout << "clock initialized" << std::endl; // rpi4.gpioSetMode(4, Rpi4::GPIO_MODE::GM_OUTPUT); // pin 4 as gp clock while (true) { // rpi4.gpioSetLevel(4, Rpi4::GPIO_LEVEL::GL_ON); // usleep(10); // rpi4.gpioSetLevel(4, Rpi4::GPIO_LEVEL::GL_OFF); // usleep(10); usleep(100); }}
file descriptor: 13
frequency will be 50000 Hz
clock 0: 1509949457
clock 0: 1509949440
clock 0: 1509949440
clock 0: 1509949441
clock 0: 1509949457
mode: 4
clock initialized
but no clock signal on my OScope.
Any help would be appreciated. I've check and double checked my register values for BCM2711, but that's all I can figure is I have an incorrect address maybe?
Statistics: Posted by weagle08 — Tue Nov 19, 2024 4:08 am — Replies 0 — Views 18