Skip to content

Commit

Permalink
64bit Cleanup
Browse files Browse the repository at this point in the history
This adds compatibility to 64Bit Linux, derived from work by @Kaiede in
PR #76.

Added a comment in the PWM section for what could be a source of issues
when configuring the DMA on 64bit systems. Need to check the official
docs for more info on this.
  • Loading branch information
uraimo committed Sep 10, 2018
1 parent f1c9b44 commit 0ea60fd
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 73 deletions.
122 changes: 61 additions & 61 deletions Sources/PWM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ public class RaspberryPWM: PWMOutput {
let BCM2708_PHY_BASE: Int = 0x7e000000
let PWM_PHY_BASE: Int

var gpioBasePointer: UnsafeMutablePointer<UInt>!
var pwmBasePointer: UnsafeMutablePointer<UInt>!
var clockBasePointer: UnsafeMutablePointer<UInt>!
var dmaBasePointer: UnsafeMutablePointer<UInt>!
var gpioBasePointer: UnsafeMutablePointer<UInt32>!
var pwmBasePointer: UnsafeMutablePointer<UInt32>!
var clockBasePointer: UnsafeMutablePointer<UInt32>!
var dmaBasePointer: UnsafeMutablePointer<UInt32>!
var dmaCallbackPointer: UnsafeMutablePointer<DMACallback>! = nil
var pwmRawPointer: UnsafeMutablePointer<UInt>! = nil
var pwmRawPointer: UnsafeMutablePointer<UInt32>! = nil
var mailbox: MailBox! = nil

var zeroPattern: Int = 0
Expand Down Expand Up @@ -148,7 +148,7 @@ public class RaspberryPWM: PWMOutput {
dma_addr -= pageOffset

let dma_map = UnsafeMutableRawPointer(memmap(from: mem_fd, at: dma_addr))
dmaBasePointer = (dma_map + pageOffset).assumingMemoryBound(to: UInt.self)
dmaBasePointer = (dma_map + pageOffset).assumingMemoryBound(to: UInt32.self)

close(mem_fd)

Expand All @@ -165,10 +165,10 @@ public class RaspberryPWM: PWMOutput {
usleep(10)

// If the required frequency is too high, this value reduces the number of samples (scale does the opposite)
let highFreqSampleReduction: UInt = (ns < 750) ? 10 : 1
let highFreqSampleReduction: UInt32 = (ns < 750) ? 10 : 1

let freq: UInt = (1_000_000_000/UInt(ns)) * 100 / highFreqSampleReduction
let (idiv, scale) = calculateDIVI(base: .PLLD, desired: freq) //Using the faster (with known freq) available clock to reduce jitter
let freq = UInt32( (1_000_000_000/UInt(ns)) * 100 / UInt(highFreqSampleReduction) )
let (idiv, scale) = calculateDIVI(base: .PLLD, desired: UInt32(freq)) //Using the faster (with known freq) available clock to reduce jitter

// Configure the clock and divisor that will be used to generate the signal
clockBasePointer.advanced(by: 41).pointee = CLKM_PASSWD | (idiv << CLKM_DIV_DIVI) //CM CTL DIV register: Set DIVI value
Expand All @@ -179,7 +179,7 @@ public class RaspberryPWM: PWMOutput {
let RNG = (channel == 0) ? 4 : 8
let DAT = (channel == 0) ? 5 : 9
pwmBasePointer.advanced(by: RNG).pointee = 100 * scale / highFreqSampleReduction //RNG1 register
pwmBasePointer.advanced(by: DAT).pointee = UInt((percent / Float(highFreqSampleReduction)) * Float(scale)) //DAT1 register
pwmBasePointer.advanced(by: DAT).pointee = UInt32((percent / Float(highFreqSampleReduction)) * Float(scale)) //DAT1 register
let PWMCTL_MSEN = (channel == 0) ? PWMCTL_MSEN1 : PWMCTL_MSEN2
let PWMCTL_PWEN = (channel == 0) ? PWMCTL_PWEN1 : PWMCTL_PWEN2
pwmBasePointer.pointee = PWMCTL_MSEN | PWMCTL_PWEN //PWM CTL register, channel enabled, M/S mode
Expand All @@ -190,7 +190,7 @@ public class RaspberryPWM: PWMOutput {
}

/// Maps a block of memory and returns the pointer
internal func memmap(from mem_fd: Int32, at offset: Int) -> UnsafeMutablePointer<UInt> {
internal func memmap(from mem_fd: Int32, at offset: Int) -> UnsafeMutablePointer<UInt32> {
let m = mmap(
nil, //Any adddress in our space will do
PAGE_SIZE, //Map length
Expand All @@ -204,17 +204,17 @@ public class RaspberryPWM: PWMOutput {
perror("mmap error")
abort()
}
let pointer = m.assumingMemoryBound(to: UInt.self)
let pointer = m.assumingMemoryBound(to: UInt32.self)

return pointer
}

/// Set the alternative function for this GPIO
internal func setAlt() {
let altid = (self.alt<=3) ? self.alt+4 : self.alt==4 ? 3 : 2
let altid = (self.alt<=3) ? UInt32(self.alt+4) : self.alt==4 ? UInt32(3) : UInt32(2)
let ptr = gpioBasePointer.advanced(by: Int(gpioId/10)) // GPFSELn 0..5
ptr.pointee &= ~(7<<((gpioId%10)*3))
ptr.pointee |= (altid<<((gpioId%10)*3))
ptr.pointee &= ~(7<<((UInt32(gpioId)%10)*3))
ptr.pointee |= (altid<<((UInt32(gpioId)%10)*3))
}

/// Calculate the DIVI value that will divide the selected base clock frequency to obtain the desired frequency.
Expand All @@ -230,9 +230,9 @@ public class RaspberryPWM: PWMOutput {
///
/// - Returns: divi divisor value, and scale value as a multiple of ten
///
internal func calculateDIVI(base: ClockSource, desired: UInt) -> (divi: UInt, scale: UInt) {
var divi: UInt = base.rawValue/desired
var scale: UInt = 1
internal func calculateDIVI(base: ClockSource, desired: UInt32) -> (divi: UInt32, scale: UInt32) {
var divi: UInt32 = base.rawValue/desired
var scale: UInt32 = 1

while divi > 0x800 {
// Divisor too high (greater then half the limit), would not be generated properly
Expand All @@ -255,8 +255,8 @@ public class RaspberryPWM: PWMOutput {
///
/// - Returns: divi divisor value
///
internal func calculateUnscaledDIVI(base: ClockSource, desired: UInt) -> UInt {
var divi: UInt = base.rawValue/desired
internal func calculateUnscaledDIVI(base: ClockSource, desired: UInt32) -> UInt32 {
var divi: UInt32 = base.rawValue/desired

if divi > 0x1000 {
// Divisor too high (greater then half the limit), would not be generated properly
Expand All @@ -278,7 +278,7 @@ extension RaspberryPWM {
dmaBasePointer.pointee = DMACS_RESET
usleep(10)
dmaBasePointer.pointee = DMACS_INT | DMACS_END
dmaBasePointer.advanced(by: 1).pointee = address //CONBLK_AD
dmaBasePointer.advanced(by: 1).pointee = UInt32(address) //CONBLK_AD //Verify this on 64bit
dmaBasePointer.advanced(by: 8).pointee = 7 //DEBUG: clear debug error flags
dmaBasePointer.pointee = DMACS_WAIT_OUTSTANDING_WRITES | (15 << DMACS_PANIC_PRIORITY) | (15 << DMACS_PRIORITY) | DMACS_ACTIVE
}
Expand Down Expand Up @@ -340,7 +340,7 @@ extension RaspberryPWM {
guard let mailbox = mailbox else {fatalError("Could allocate mailbox.")}

dmaCallbackPointer = mailbox.baseVirtualAddress.assumingMemoryBound(to: DMACallback.self)
pwmRawPointer = (mailbox.baseVirtualAddress + MemoryLayout<DMACallback>.stride).assumingMemoryBound(to: UInt.self)
pwmRawPointer = (mailbox.baseVirtualAddress + MemoryLayout<DMACallback>.stride).assumingMemoryBound(to: UInt32.self)

// Fill PWM buffer with zeros
let rows = dataSize / MemoryLayout<UInt>.stride
Expand All @@ -358,7 +358,7 @@ extension RaspberryPWM {
//while (clockBasePointer.advanced(by: 40).pointee & (1 << 7)) != 0 {}

// Configure clock
let idiv = calculateUnscaledDIVI(base: .PLLD, desired: UInt(symbolBits * patternFrequency))
let idiv = calculateUnscaledDIVI(base: .PLLD, desired: UInt32(symbolBits * patternFrequency))
clockBasePointer.advanced(by: 41).pointee = CLKM_PASSWD | (idiv << CLKM_DIV_DIVI) //Set DIVI value
clockBasePointer.advanced(by: 40).pointee = CLKM_PASSWD | CLKM_CTL_ENAB | CLKM_CTL_SRC_PLLD //Enable clock, MASH 0, source PLLD
usleep(10)
Expand Down Expand Up @@ -551,34 +551,34 @@ extension RaspberryPWM {
// MARK: - PWM Contants

// Constants for the Clock Manager General Purpose Control Register
let CLKM_PASSWD: UInt = 0x5A000000
let CLKM_CTL_KILL: UInt = (1 << 5)
let CLKM_CTL_ENAB: UInt = (1 << 4)
let CLKM_CTL_SRC_OSC: UInt = 1 // 19.2 MHz oscillator
let CLKM_CTL_SRC_PLLA: UInt = 4 // ~393.216 MHz PLLA (Audio)
let CLKM_CTL_SRC_PLLC: UInt = 5 // 1000 MHz PLLC (changes with overclock settings)
let CLKM_CTL_SRC_PLLD: UInt = 6 // 500 MHz PLLD
let CLKM_CTL_SRC_HDMI: UInt = 7 // 216 MHz HDMI auxiliary
let CLKM_PASSWD: UInt32 = 0x5A000000
let CLKM_CTL_KILL: UInt32 = (1 << 5)
let CLKM_CTL_ENAB: UInt32 = (1 << 4)
let CLKM_CTL_SRC_OSC: UInt32 = 1 // 19.2 MHz oscillator
let CLKM_CTL_SRC_PLLA: UInt32 = 4 // ~393.216 MHz PLLA (Audio)
let CLKM_CTL_SRC_PLLC: UInt32 = 5 // 1000 MHz PLLC (changes with overclock settings)
let CLKM_CTL_SRC_PLLD: UInt32 = 6 // 500 MHz PLLD
let CLKM_CTL_SRC_HDMI: UInt32 = 7 // 216 MHz HDMI auxiliary
// Constants for the Clock Manager General Purpose Divisors Register
let CLKM_DIV_DIVI: UInt = 12
let CLKM_DIV_DIVF: UInt = 0
let CLKM_DIV_DIVI: UInt32 = 12
let CLKM_DIV_DIVF: UInt32 = 0
// Constants for the PWM Control Register
let PWMCTL_MSEN2: UInt = (1 << 15)
let PWMCTL_MSEN2: UInt32 = (1 << 15)
// No PWMCTL_CLRF2, the FIFO is shared
let PWMCTL_USEF2: UInt = (1 << 13)
let PWMCTL_POLA2: UInt = (1 << 12)
let PWMCTL_SBIT2: UInt = (1 << 11)
let PWMCTL_RPTL2: UInt = (1 << 10)
let PWMCTL_MODE2: UInt = (1 << 9)
let PWMCTL_PWEN2: UInt = (1 << 8)
let PWMCTL_MSEN1: UInt = (1 << 7)
let PWMCTL_CLRF1: UInt = (1 << 6)
let PWMCTL_USEF1: UInt = (1 << 5)
let PWMCTL_POLA1: UInt = (1 << 4)
let PWMCTL_SBIT1: UInt = (1 << 3)
let PWMCTL_RPTL1: UInt = (1 << 2)
let PWMCTL_MODE1: UInt = (1 << 1)
let PWMCTL_PWEN1: UInt = (1 << 0)
let PWMCTL_USEF2: UInt32 = (1 << 13)
let PWMCTL_POLA2: UInt32 = (1 << 12)
let PWMCTL_SBIT2: UInt32 = (1 << 11)
let PWMCTL_RPTL2: UInt32 = (1 << 10)
let PWMCTL_MODE2: UInt32 = (1 << 9)
let PWMCTL_PWEN2: UInt32 = (1 << 8)
let PWMCTL_MSEN1: UInt32 = (1 << 7)
let PWMCTL_CLRF1: UInt32 = (1 << 6)
let PWMCTL_USEF1: UInt32 = (1 << 5)
let PWMCTL_POLA1: UInt32 = (1 << 4)
let PWMCTL_SBIT1: UInt32 = (1 << 3)
let PWMCTL_RPTL1: UInt32 = (1 << 2)
let PWMCTL_MODE1: UInt32 = (1 << 1)
let PWMCTL_PWEN1: UInt32 = (1 << 0)

// Clock sources
// 0 0 Hz Ground
Expand All @@ -590,7 +590,7 @@ let PWMCTL_PWEN1: UInt = (1 << 0)
// 6 500 MHz PLLD
// 7 216 MHz HDMI auxiliary
// 8-15 0 Hz Ground
enum ClockSource: UInt {
enum ClockSource: UInt32 {
case Oscillator = 19200000
case PLLA = 393216000
case PLLC = 1000000000
Expand All @@ -599,15 +599,15 @@ enum ClockSource: UInt {
}

// DMA Register
let DMACS_RESET: UInt = (1 << 31)
let DMACS_ABORT: UInt = (1 << 30)
let DMACS_WAIT_OUTSTANDING_WRITES: UInt = (1 << 28)
let DMACS_PANIC_PRIORITY: UInt = 20 // <<
let DMACS_PRIORITY: UInt = 16 // <<
let DMACS_ERROR: UInt = (1 << 8)
let DMACS_INT: UInt = (1 << 2)
let DMACS_END: UInt = (1 << 1)
let DMACS_ACTIVE: UInt = (1 << 0)
let DMACS_RESET: UInt32 = (1 << 31)
let DMACS_ABORT: UInt32 = (1 << 30)
let DMACS_WAIT_OUTSTANDING_WRITES: UInt32 = (1 << 28)
let DMACS_PANIC_PRIORITY: UInt32 = 20 // <<
let DMACS_PRIORITY: UInt32 = 16 // <<
let DMACS_ERROR: UInt32 = (1 << 8)
let DMACS_INT: UInt32 = (1 << 2)
let DMACS_END: UInt32 = (1 << 1)
let DMACS_ACTIVE: UInt32 = (1 << 0)

/*
* DMA Control Block in Main Memory
Expand All @@ -627,9 +627,9 @@ struct DMACallback {
}

// PWM DMAC Register
let PWMDMAC_ENAB: UInt = (1 << 31)
let PWMDMAC_PANIC: UInt = 8
let PWMDMAC_DREQ: UInt = 0
let PWMDMAC_ENAB: UInt32 = (1 << 31)
let PWMDMAC_PANIC: UInt32 = 8
let PWMDMAC_DREQ: UInt32 = 0

// DMA Register
let DMATI_NO_WIDE_BURSTS: UInt32 = (1 << 26)
Expand Down
24 changes: 12 additions & 12 deletions Sources/SwiftyGPIO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,20 +280,20 @@ extension GPIO: CustomStringConvertible {

public final class RaspberryGPIO: GPIO {

var setGetId: UInt = 0
var setGetId: UInt32 = 0
var baseAddr: Int = 0
var inited = false

let BCM2708_PERI_BASE: Int
let GPIO_BASE: Int

var gpioBasePointer: UnsafeMutablePointer<UInt>!
var gpioGetPointer: UnsafeMutablePointer<UInt>!
var gpioSetPointer: UnsafeMutablePointer<UInt>!
var gpioClearPointer: UnsafeMutablePointer<UInt>!
var gpioBasePointer: UnsafeMutablePointer<UInt32>!
var gpioGetPointer: UnsafeMutablePointer<UInt32>!
var gpioSetPointer: UnsafeMutablePointer<UInt32>!
var gpioClearPointer: UnsafeMutablePointer<UInt32>!

public init(name: String, id: Int, baseAddr: Int) {
self.setGetId = UInt(1<<id)
self.setGetId = UInt32(1<<id)
self.BCM2708_PERI_BASE = baseAddr
self.GPIO_BASE = BCM2708_PERI_BASE + 0x200000 /* GPIO controller */
super.init(name:name, id:id)
Expand Down Expand Up @@ -368,7 +368,7 @@ public final class RaspberryGPIO: GPIO {
perror("mmap error")
abort()
}
gpioBasePointer = gpio_map.assumingMemoryBound(to: UInt.self)
gpioBasePointer = gpio_map.assumingMemoryBound(to: UInt32.self)

gpioGetPointer = gpioBasePointer.advanced(by: 13) // GPLEV0
gpioSetPointer = gpioBasePointer.advanced(by: 7) // GPSET0
Expand All @@ -379,18 +379,18 @@ public final class RaspberryGPIO: GPIO {

private func gpioAsInput() {
let ptr = gpioBasePointer.advanced(by: id/10) // GPFSELn 0..5
ptr.pointee &= ~(7<<((UInt(id)%10)*3)) // SEL=000 input
ptr.pointee &= ~(7<<((UInt32(id)%10)*3)) // SEL=000 input
}

private func gpioAsOutput() {
let ptr = gpioBasePointer.advanced(by: id/10) // GPFSELn 0..5
ptr.pointee &= ~(7<<((UInt(id)%10)*3))
ptr.pointee |= (1<<((UInt(id)%10)*3)) // SEL=001 output
ptr.pointee &= ~(7<<((UInt32(id)%10)*3))
ptr.pointee |= (1<<((UInt32(id)%10)*3)) // SEL=001 output
}

private func gpioGetDirection() -> GPIODirection {
let ptr = gpioBasePointer.advanced(by: id/10) // GPFSELn 0..5
let d = (ptr.pointee & (7<<((UInt(id)%10)*3)))
let d = (ptr.pointee & (7<<((UInt32(id)%10)*3)))
return (d == 0) ? .IN : .OUT
}

Expand Down Expand Up @@ -521,7 +521,7 @@ public enum GPIOEdge: String {
case BOTH="both"
}

public enum GPIOPull: UInt {
public enum GPIOPull: UInt32 {
case neither = 0
case down = 1
case up = 2
Expand Down

2 comments on commit 0ea60fd

@Kaiede
Copy link

@Kaiede Kaiede commented on 0ea60fd Sep 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the DMA issue, section 4.2.1.1 covers this. If you try to write a 64-bit address into a channel's CONBLK_AD where you placed the comment, you wind up writing to the TI register for the channel as well with the high 32-bit "word" (ARM is little endian, yes?). Writing 64-bit addresses in the CB will overflow into the channel's DEBUG register in the same way.

DMA on these devices only supports 32-bit physical addresses, despite supporting 64-bit. I think because the chip doesn't expect more than 4GB of physical RAM + IO memory.

@uraimo
Copy link
Owner Author

@uraimo uraimo commented on 0ea60fd Sep 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this settles it then.

Please sign in to comment.