2013-06-20 16:32:51 +00:00
|
|
|
|
//
|
|
|
|
|
// Modified from:
|
|
|
|
|
// How to access GPIO registers from C-code on the Raspberry-Pi
|
|
|
|
|
// Example program
|
|
|
|
|
// 15-January-2012
|
|
|
|
|
// Dom and Gert
|
|
|
|
|
// Revised: 15-Feb-2013
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
// Access from ARM Running Linux
|
2015-02-22 21:05:34 +00:00
|
|
|
|
#define ARMv6_PERI_BASE 0x20000000
|
|
|
|
|
#define ARMv7_PERI_BASE 0x3F000000
|
2013-06-20 16:32:51 +00:00
|
|
|
|
#define GPIO_OFFSET 0x00200000
|
|
|
|
|
#define CMGP_OFFSET 0x00101000
|
|
|
|
|
|
|
|
|
|
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
|
|
|
|
|
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
|
|
|
|
|
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
|
|
|
|
|
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
|
|
|
|
|
|
2015-02-22 21:05:34 +00:00
|
|
|
|
#define GPIO_REG(reg) (gpio[(reg)/4])
|
|
|
|
|
#define CMGP_REG(reg) (cmgp[(reg)/4])
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2015-02-22 21:05:34 +00:00
|
|
|
|
#define GPFSEL0 0x000
|
|
|
|
|
#define CM_GP0CTL 0x070
|
|
|
|
|
#define CM_GP0DIV 0x074
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2013-09-20 03:44:18 +00:00
|
|
|
|
#define IOMAP_LEN 4096
|
2013-06-20 16:32:51 +00:00
|
|
|
|
//
|
|
|
|
|
// Set up a memory regions to access GPIO
|
|
|
|
|
//
|
2013-09-20 03:44:18 +00:00
|
|
|
|
volatile unsigned int *setup_io(int reg_base)
|
2013-06-20 16:32:51 +00:00
|
|
|
|
{
|
|
|
|
|
int mem_fd;
|
|
|
|
|
void *io_map;
|
|
|
|
|
|
|
|
|
|
// open /dev/mem
|
|
|
|
|
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
|
|
|
|
|
{
|
2015-02-27 16:08:42 +00:00
|
|
|
|
printf("can't open /dev/mem \n");
|
|
|
|
|
exit(-1);
|
2013-06-20 16:32:51 +00:00
|
|
|
|
}
|
|
|
|
|
// mmap IO
|
|
|
|
|
io_map = mmap(NULL, //Any adddress in our space will do
|
2013-09-20 03:44:18 +00:00
|
|
|
|
IOMAP_LEN, //Map length
|
2013-06-20 16:32:51 +00:00
|
|
|
|
PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
|
|
|
|
|
MAP_SHARED, //Shared with other processes
|
|
|
|
|
mem_fd, //File to map
|
|
|
|
|
reg_base); //Offset to peripheral
|
|
|
|
|
close(mem_fd); //No need to keep mem_fd open after mmap
|
|
|
|
|
if (io_map == MAP_FAILED)
|
|
|
|
|
{
|
2015-02-27 16:08:42 +00:00
|
|
|
|
printf("mmap error<6F>%d\n", (int)io_map);//errno also set!
|
|
|
|
|
exit(-1);
|
2013-06-20 16:32:51 +00:00
|
|
|
|
}
|
|
|
|
|
return (volatile unsigned *)io_map;
|
2013-09-20 03:44:18 +00:00
|
|
|
|
}
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2013-09-20 03:44:18 +00:00
|
|
|
|
void release_io(volatile unsigned int *io_map)
|
|
|
|
|
{
|
|
|
|
|
munmap((void *)io_map, IOMAP_LEN);
|
|
|
|
|
}
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2013-09-20 04:03:28 +00:00
|
|
|
|
void gpclk(int idiv)
|
2013-06-20 16:32:51 +00:00
|
|
|
|
{
|
2013-09-20 03:44:18 +00:00
|
|
|
|
// I/O access
|
|
|
|
|
volatile unsigned *gpio, *cmgp;
|
2013-06-20 16:32:51 +00:00
|
|
|
|
int g,rep;
|
2015-02-22 21:05:34 +00:00
|
|
|
|
unsigned int arm_base = ARMv6_PERI_BASE; // Default to ARMv6 peripheral base
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2015-02-22 21:05:34 +00:00
|
|
|
|
FILE *cpuinfo;
|
2017-05-16 19:26:22 +00:00
|
|
|
|
char rasstr[1024], pistr[128];
|
|
|
|
|
int version;
|
2015-02-22 21:05:34 +00:00
|
|
|
|
|
2017-05-16 19:26:22 +00:00
|
|
|
|
if ((cpuinfo = fopen("/proc/device-tree/model", "r") ) == NULL)
|
2015-02-22 21:05:34 +00:00
|
|
|
|
{
|
2017-05-16 19:26:22 +00:00
|
|
|
|
printf("can't open /proc/device-tree/model\n");
|
2015-02-27 16:08:42 +00:00
|
|
|
|
exit(-1);
|
2015-02-22 21:05:34 +00:00
|
|
|
|
}
|
2017-05-16 19:26:22 +00:00
|
|
|
|
if (fscanf(cpuinfo, "%s %s %d", rasstr, pistr, &version) == 3)
|
2015-02-22 21:05:34 +00:00
|
|
|
|
{
|
2017-05-16 19:26:22 +00:00
|
|
|
|
if (strcmp(rasstr, "Raspberry") == 0 && strcmp(pistr, "Pi") == 0)
|
2015-02-22 21:05:34 +00:00
|
|
|
|
{
|
2017-05-16 19:26:22 +00:00
|
|
|
|
//printf("Found %s %s version %d\n", rasstr, pistr, version);
|
|
|
|
|
switch (version)
|
2015-02-22 21:05:34 +00:00
|
|
|
|
{
|
2017-05-16 19:26:22 +00:00
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
arm_base = ARMv6_PERI_BASE; // Pi version 1 (ARMv6)
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
arm_base = ARMv7_PERI_BASE; // Pi version 2 and 3 (ARMv7)
|
|
|
|
|
break;
|
2015-02-22 21:05:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-16 19:26:22 +00:00
|
|
|
|
}
|
2015-02-22 21:05:34 +00:00
|
|
|
|
fclose(cpuinfo);
|
2013-06-20 16:32:51 +00:00
|
|
|
|
// Set up gpi pointer for direct register access
|
2015-02-22 21:05:34 +00:00
|
|
|
|
cmgp = setup_io(arm_base + CMGP_OFFSET);
|
|
|
|
|
gpio = setup_io(arm_base + GPIO_OFFSET);
|
2013-06-20 16:32:51 +00:00
|
|
|
|
|
2013-09-20 04:03:28 +00:00
|
|
|
|
// Set Clock Manager to 500 MHz source (PLLD)
|
2013-06-20 16:32:51 +00:00
|
|
|
|
CMGP_REG(CM_GP0CTL) = (0x5A << 24) // Password
|
|
|
|
|
// Disable
|
|
|
|
|
| (1); // Src = oscillator
|
|
|
|
|
usleep(1000);
|
|
|
|
|
CMGP_REG(CM_GP0CTL) = (0x5A << 24) // Password
|
|
|
|
|
// Disable
|
|
|
|
|
| (6); // Src = PLLD
|
|
|
|
|
CMGP_REG(CM_GP0DIV) = (0x5A << 24) // Password
|
2013-09-20 04:03:28 +00:00
|
|
|
|
| ((idiv) << 12); // IDIV
|
2013-06-20 16:32:51 +00:00
|
|
|
|
usleep(1000);
|
|
|
|
|
CMGP_REG(CM_GP0CTL) = (0x5A << 24) // Password
|
|
|
|
|
| (1 << 4) // Enable
|
|
|
|
|
| (6); // Src = PLLD
|
|
|
|
|
usleep(1000);
|
|
|
|
|
// Set GCLK function (ALT0) for GPIO 4 (header pin #7)
|
|
|
|
|
INP_GPIO(4);
|
|
|
|
|
SET_GPIO_ALT(4, 0x00);
|
2013-09-20 03:44:18 +00:00
|
|
|
|
// Release I/O space
|
|
|
|
|
release_io(gpio);
|
|
|
|
|
release_io(cmgp);
|
2013-06-20 16:32:51 +00:00
|
|
|
|
}
|
2014-02-04 23:28:36 +00:00
|
|
|
|
#ifndef SETSERCLK
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Initialize ACIA clock for Apple II Pi card
|
|
|
|
|
*/
|
|
|
|
|
gpclk(271); /* divisor for ~1.8 MHz => (500/271) MHz */
|
|
|
|
|
}
|
|
|
|
|
#endif
|