Created
January 30, 2013 12:20
-
-
Save masquaremo/4672925 to your computer and use it in GitHub Desktop.
Raspberry PiのPWM制御サンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// BCM2835 pwm lib | |
// | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <dirent.h> | |
#include <fcntl.h> | |
#include <assert.h> | |
#include <sys/mman.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#define BCM2708_PERI_BASE 0x20000000 | |
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ | |
#define PWM_BASE (BCM2708_PERI_BASE + 0x20C000) /* PWM controller */ | |
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) | |
// PWM controller offset | |
#define PWM_CONTROL 0 | |
#define PWM_STATUS 1 | |
#define PWM0_RANGE 4 | |
#define PWM0_DATA 5 | |
#define PWM1_RANGE 8 | |
#define PWM1_DATA 9 | |
// GPIO clock reg offset | |
#define PWMCLK_CNTL 40 | |
#define PWMCLK_DIV 41 | |
// BCM Magic | |
#define BCM_PASSWORD 0x5A000000 | |
#define PWM1_MS_MODE 0x8000 // Run in MS mode | |
#define PWM1_USEFIFO 0x2000 // Data from FIFO | |
#define PWM1_REVPOLAR 0x1000 // Reverse polarity | |
#define PWM1_OFFSTATE 0x0800 // Ouput Off state | |
#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty | |
#define PWM1_SERIAL 0x0200 // Run in serial mode | |
#define PWM1_ENABLE 0x0100 // Channel Enable | |
#define PWM0_MS_MODE 0x0080 // Run in MS mode | |
#define PWM0_USEFIFO 0x0020 // Data from FIFO | |
#define PWM0_REVPOLAR 0x0010 // Reverse polarity | |
#define PWM0_OFFSTATE 0x0008 // Ouput Off state | |
#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty | |
#define PWM0_SERIAL 0x0002 // Run in serial mode | |
#define PWM0_ENABLE 0x0001 // Channel Enable | |
#define PAGE_SIZE (4*1024) | |
#define BLOCK_SIZE (4*1024) | |
// 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)) | |
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 | |
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 | |
#define GPIO_GET *(gpio+13) // read bits | |
// I/O access | |
volatile unsigned *gpio; | |
volatile unsigned *pwm; | |
volatile unsigned *clk; | |
static int mem_fd = 0; | |
// | |
// Set up a memory regions to access GPIO | |
// | |
volatile unsigned * io_mapping(int base_addr) | |
{ | |
char *gpio_mem, *gpio_map; | |
/* open /dev/mem */ | |
if (!mem_fd) { | |
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { | |
printf("can't open /dev/mem \n"); | |
exit (-1); | |
} | |
} | |
/* mmap GPIO */ | |
// Allocate MAP block | |
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { | |
printf("allocation error \n"); | |
exit (-1); | |
} | |
// Make sure pointer is on 4K boundary | |
if ((unsigned long)gpio_mem % PAGE_SIZE) | |
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE); | |
// Now map it | |
gpio_map = (char *)mmap( | |
(caddr_t)gpio_mem, | |
BLOCK_SIZE, | |
PROT_READ|PROT_WRITE, | |
MAP_SHARED|MAP_FIXED, | |
mem_fd, | |
base_addr | |
); | |
if ((long)gpio_map < 0) { | |
printf("mmap error %d\n", (int)gpio_map); | |
exit (-1); | |
} | |
// Always use volatile pointer! | |
return (volatile unsigned *)gpio_map; | |
} | |
// | |
void hw_initialize() | |
{ | |
gpio = io_mapping(GPIO_BASE); | |
pwm = io_mapping(PWM_BASE); | |
clk = io_mapping(CLOCK_BASE); | |
// GPIO18をPWMに | |
SET_GPIO_ALT(18, 5); | |
*(pwm + PWM_CONTROL) = 0; // Stop PWM | |
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01; // Stop PWM Clock | |
usleep(110000); // See comments in pwmSetClockWPi | |
while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY | |
usleep(1000) ; | |
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (32 << 12); // set pwm div to 32 (19.2/32 = 600KHz) | |
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11; // enable clk | |
usleep(110000); | |
// Default range register of 1024 | |
*(pwm + PWM0_RANGE) = 1024; | |
usleep(10000); | |
*(pwm + PWM1_RANGE) = 1024; | |
usleep(10000); | |
*(pwm + PWM0_DATA) = 0; | |
usleep(10000); | |
*(pwm + PWM1_DATA) = 0; | |
usleep(10000); | |
// Enable PWMs in balanced mode (default) | |
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE; | |
usleep(100000); | |
} | |
// Range設定 | |
void set_range(int range) | |
{ | |
*(pwm + PWM0_RANGE) = range; | |
usleep(1000); | |
} | |
// Duty設定 | |
void set_duty(int duty) | |
{ | |
*(pwm + PWM0_DATA) = duty; | |
usleep(1000); | |
} | |
int main(void) | |
{ | |
int i; | |
hw_initialize(); | |
set_range(1000); | |
for(i = 0; i <= 1000; i += 100) { | |
usleep(1000000); | |
set_duty(i); | |
printf("d=%d\n", i); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment