Created
December 13, 2016 02:13
-
-
Save keybuk/faebfde6d858eeb8472b65421e583822 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
#if os(Linux) | |
import Glibc | |
#else | |
import Darwin | |
let O_SYNC: Int32 = 0 | |
#endif | |
import Dispatch | |
let peripheralAddressBase = 0x3f000000 | |
let peripheralBlockSize = 0x1000 | |
let clockRegistersAddress = peripheralAddressBase + 0x101000 | |
let gpioRegistersAddress = peripheralAddressBase + 0x200000 | |
let pwmRegistersAddress = peripheralAddressBase + 0x20c000 | |
let pwmClockControlOffset = 0xa0 | |
let pwmClockDivOffset = 0xa4 | |
let pwmControlOffset = 0x00 | |
let pwmRange1Offset = 0x010 | |
let pwmData1Offset = 0x14 | |
let memFd = open("/dev/mem", O_RDWR | O_SYNC) | |
guard memFd > 0 else { fatalError("Couldn't open /dev/mem") } | |
defer { close(memFd) } | |
guard let clockRegisters = mmap(nil, peripheralBlockSize, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, off_t(clockRegistersAddress)) else { fatalError("Couldn't mmap clock registers") } | |
guard let gpioRegisters = mmap(nil, peripheralBlockSize, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, off_t(gpioRegistersAddress)) else { fatalError("Couldn't mmap GPIO registers") } | |
guard let pwmRegisters = mmap(nil, peripheralBlockSize, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, off_t(pwmRegistersAddress)) else { fatalError("Couldn't mmap PWM registers") } | |
// Begin by disabling the PWM while we configure it. | |
let pwmControl = pwmRegisters.advanced(by: pwmControlOffset).assumingMemoryBound(to: UInt32.self) | |
pwmControl.pointee = 0 | |
usleep(10) | |
// Configure the PWM clock. | |
let pwmClockControl = clockRegisters.advanced(by: pwmClockControlOffset).assumingMemoryBound(to: UInt32.self) | |
let pwmClockDiv = clockRegisters.advanced(by: pwmClockDivOffset).assumingMemoryBound(to: UInt32.self) | |
// Disable, and set source to PLLD (500 Mhz). | |
pwmClockControl.pointee = 0x5a000006 | |
usleep(100) | |
// Set the divisor to 500, giving us a 1MHz clock. | |
pwmClockDiv.pointee = 0x5a000000 | UInt32(500 << 12) | |
usleep(100) | |
// Enable, with the source still set to PLLD. | |
pwmClockControl.pointee = 0x5a000016 | |
usleep(100) | |
// Set the range of the clock to 1,000 giving us 1KHz "bits", and the duty cycle to 25%. | |
let pwmRange1 = pwmRegisters.advanced(by: pwmRange1Offset).assumingMemoryBound(to: UInt32.self) | |
let pwmData1 = pwmRegisters.advanced(by: pwmData1Offset).assumingMemoryBound(to: UInt32.self) | |
pwmRange1.pointee = 1000 | |
usleep(10) | |
pwmData1.pointee = 250 | |
usleep(10) | |
// GPIO 18's alternate mode 5 (0b010) uses PWM1 as a source, select it. | |
let gpioPin = 18 | |
let gpioFunctionSelect = gpioRegisters.assumingMemoryBound(to: UInt32.self).advanced(by: gpioPin / 10) | |
gpioFunctionSelect.pointee &= ~(0b111 << UInt32((gpioPin % 10) * 3)) | |
gpioFunctionSelect.pointee |= 0b010 << UInt32((gpioPin % 10) * 3) | |
// Enable PWM1 in PWM mode, using the data register as a source, and the PWM algorithm. | |
pwmControl.pointee = 0b00000001 | |
dispatchMain() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment