/* Copyright 2018 Raptor Engineering, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #define GPIO_BASE 0x1e780000 #define GPIO_DATA 0x0 #define GPIO_DIR 0x4 #define GPIO_BANK_MNOP 0x78 #define GPIO_N7_MASK 0x00008000 static void *gpio_reg = NULL; static int mem_fd = 0; inline void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result) { if ((stop->tv_nsec - start->tv_nsec) < 0) { result->tv_sec = stop->tv_sec - start->tv_sec - 1; result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; } else { result->tv_sec = stop->tv_sec - start->tv_sec; result->tv_nsec = stop->tv_nsec - start->tv_nsec; } return; } void delay_for_interval(uint32_t interval) { uint32_t abort_count = 0; uint64_t delay_ns = interval * 1000; struct timespec start_time = {.tv_sec=0,.tv_nsec=0}; struct timespec current_time = {.tv_sec=0,.tv_nsec=0}; struct timespec difference_time = {.tv_sec=0,.tv_nsec=0}; abort_count = 0; while (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) < 0) { abort_count++; if (abort_count > 10) { return; } } while (1) { current_time.tv_sec = 0; current_time.tv_nsec = 0; if (clock_gettime(CLOCK_MONOTONIC_RAW, ¤t_time) < 0) { continue; } timespec_diff(&start_time, ¤t_time, &difference_time); if (difference_time.tv_nsec > delay_ns) { break; } } if (difference_time.tv_nsec > (delay_ns * 2)) { printf("OVERRAN timer (wanted %lld, got %lld, start: %lld.%lld end: %lld.%lld)\n", delay_ns, difference_time.tv_nsec, start_time.tv_sec, start_time.tv_nsec, current_time.tv_sec, current_time.tv_nsec); } } int main(void) { uint32_t run_cycles; uint32_t frequency = 1000; uint32_t period = 1000000 / frequency; uint32_t halfperiod = period / 2; uint32_t duration_ms = 100; uint32_t num_cycles = (duration_ms * frequency) / 1000; // Open physical memory device if (!mem_fd) { mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd < 0) { perror("Unable to open /dev/mem"); exit(1); } } // Map GPIO registers into virtual memory gpio_reg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE); if (gpio_reg == MAP_FAILED) { perror("Unable to map GPIO register memory"); exit(-1); } // Elevate priority if (setpriority(PRIO_PROCESS, 0, -20) < 0) { perror("Unable to set priority"); exit(-1); } // Set GPIO N7 to OUTPUT uint32_t *offset = gpio_reg + GPIO_BANK_MNOP + GPIO_DIR; *offset |= GPIO_N7_MASK; // Set up GPIO N7 access offset = gpio_reg + GPIO_BANK_MNOP + GPIO_DATA; for (run_cycles = 0; run_cycles < 100; run_cycles++) { delay_for_interval(halfperiod); *offset |= GPIO_N7_MASK; delay_for_interval(halfperiod); *offset &= ~GPIO_N7_MASK; } return 0; }