Commit 25d379c1 authored by Dustin Brewer's avatar Dustin Brewer

Support RPi 2 w/bcm2835.c version 1.39

parent e7deb684
...@@ -40,16 +40,23 @@ ...@@ -40,16 +40,23 @@
// By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. // By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected.
// #define I2C_V1 // #define I2C_V1
// Pointers to the hardware register bases // Physical address and size of the peripherals block
volatile uint32_t *bcm2835_gpio = (volatile uint32_t *)MAP_FAILED; // May be overridden on RPi2
volatile uint32_t *bcm2835_pwm = (volatile uint32_t *)MAP_FAILED; uint32_t *bcm2835_peripherals_base = (uint32_t *)BCM2835_PERI_BASE;
volatile uint32_t *bcm2835_clk = (volatile uint32_t *)MAP_FAILED; uint32_t bcm2835_peripherals_size = BCM2835_PERI_SIZE;
volatile uint32_t *bcm2835_pads = (volatile uint32_t *)MAP_FAILED;
volatile uint32_t *bcm2835_spi0 = (volatile uint32_t *)MAP_FAILED; // Virtual memory address of the mapped peripherals block
volatile uint32_t *bcm2835_bsc0 = (volatile uint32_t *)MAP_FAILED; void *bcm2835_peripherals = (uint32_t *)MAP_FAILED;
volatile uint32_t *bcm2835_bsc1 = (volatile uint32_t *)MAP_FAILED;
volatile uint32_t *bcm2835_st = (volatile uint32_t *)MAP_FAILED; // And the register bases within the peripherals block
uint32_t *bcm2835_gpio = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_pwm = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_clk = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_pads = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_spi0 = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_bsc0 = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_bsc1 = (uint32_t *)MAP_FAILED;
uint32_t *bcm2835_st = (uint32_t *)MAP_FAILED;
// This variable allows us to test on hardware other than RPi. // This variable allows us to test on hardware other than RPi.
// It prevents access to the kernel memory, and does not do any peripheral access // It prevents access to the kernel memory, and does not do any peripheral access
...@@ -66,13 +73,38 @@ static unsigned long long epoch ; ...@@ -66,13 +73,38 @@ static unsigned long long epoch ;
// Low level register access functions // Low level register access functions
// //
// Function to return the pointers to the hardware register bases
uint32_t* bcm2835_regbase(uint8_t regbase)
{
switch (regbase)
{
case BCM2835_REGBASE_ST:
return (uint32_t *)bcm2835_st;
case BCM2835_REGBASE_GPIO:
return (uint32_t *)bcm2835_gpio;
case BCM2835_REGBASE_PWM:
return (uint32_t *)bcm2835_pwm;
case BCM2835_REGBASE_CLK:
return (uint32_t *)bcm2835_clk;
case BCM2835_REGBASE_PADS:
return (uint32_t *)bcm2835_pads;
case BCM2835_REGBASE_SPI0:
return (uint32_t *)bcm2835_spi0;
case BCM2835_REGBASE_BSC0:
return (uint32_t *)bcm2835_bsc0;
case BCM2835_REGBASE_BSC1:
return (uint32_t *)bcm2835_st;
}
return (uint32_t *)MAP_FAILED;
}
void bcm2835_set_debug(uint8_t d) void bcm2835_set_debug(uint8_t d)
{ {
debug = d; debug = d;
} }
// safe read from peripheral // safe read from peripheral
uint32_t bcm2835_peri_read(volatile uint32_t* paddr) uint32_t bcm2835_peri_read(uint32_t* paddr)
{ {
if (debug) if (debug)
{ {
...@@ -90,7 +122,7 @@ uint32_t bcm2835_peri_read(volatile uint32_t* paddr) ...@@ -90,7 +122,7 @@ uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
} }
// read from peripheral without the read barrier // read from peripheral without the read barrier
uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) uint32_t bcm2835_peri_read_nb(uint32_t* paddr)
{ {
if (debug) if (debug)
{ {
...@@ -104,7 +136,7 @@ uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) ...@@ -104,7 +136,7 @@ uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr)
} }
// safe write to peripheral // safe write to peripheral
void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) void bcm2835_peri_write(uint32_t* paddr, uint32_t value)
{ {
if (debug) if (debug)
{ {
...@@ -120,7 +152,7 @@ void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) ...@@ -120,7 +152,7 @@ void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value)
} }
// write to peripheral without the write barrier // write to peripheral without the write barrier
void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) void bcm2835_peri_write_nb(uint32_t* paddr, uint32_t value)
{ {
if (debug) if (debug)
{ {
...@@ -134,7 +166,7 @@ void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) ...@@ -134,7 +166,7 @@ void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value)
} }
// Set/clear only the bits in value covered by the mask // Set/clear only the bits in value covered by the mask
void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) void bcm2835_peri_set_bits(uint32_t* paddr, uint32_t value, uint32_t mask)
{ {
uint32_t v = bcm2835_peri_read(paddr); uint32_t v = bcm2835_peri_read(paddr);
v = (v & ~mask) | (value & mask); v = (v & ~mask) | (value & mask);
...@@ -165,7 +197,7 @@ void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t ma ...@@ -165,7 +197,7 @@ void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t ma
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
{ {
// Function selects are 10 pins per 32 bit word, 3 bits per pin // Function selects are 10 pins per 32 bit word, 3 bits per pin
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10);
uint8_t shift = (pin % 10) * 3; uint8_t shift = (pin % 10) * 3;
uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift;
uint32_t value = mode << shift; uint32_t value = mode << shift;
...@@ -175,7 +207,7 @@ void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) ...@@ -175,7 +207,7 @@ void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
// Set output pin // Set output pin
void bcm2835_gpio_set(uint8_t pin) void bcm2835_gpio_set(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
bcm2835_peri_write(paddr, 1 << shift); bcm2835_peri_write(paddr, 1 << shift);
} }
...@@ -183,7 +215,7 @@ void bcm2835_gpio_set(uint8_t pin) ...@@ -183,7 +215,7 @@ void bcm2835_gpio_set(uint8_t pin)
// Clear output pin // Clear output pin
void bcm2835_gpio_clr(uint8_t pin) void bcm2835_gpio_clr(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
bcm2835_peri_write(paddr, 1 << shift); bcm2835_peri_write(paddr, 1 << shift);
} }
...@@ -191,21 +223,21 @@ void bcm2835_gpio_clr(uint8_t pin) ...@@ -191,21 +223,21 @@ void bcm2835_gpio_clr(uint8_t pin)
// Set all output pins in the mask // Set all output pins in the mask
void bcm2835_gpio_set_multi(uint32_t mask) void bcm2835_gpio_set_multi(uint32_t mask)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4;
bcm2835_peri_write(paddr, mask); bcm2835_peri_write(paddr, mask);
} }
// Clear all output pins in the mask // Clear all output pins in the mask
void bcm2835_gpio_clr_multi(uint32_t mask) void bcm2835_gpio_clr_multi(uint32_t mask)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4;
bcm2835_peri_write(paddr, mask); bcm2835_peri_write(paddr, mask);
} }
// Read input pin // Read input pin
uint8_t bcm2835_gpio_lev(uint8_t pin) uint8_t bcm2835_gpio_lev(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = bcm2835_peri_read(paddr); uint32_t value = bcm2835_peri_read(paddr);
return (value & (1 << shift)) ? HIGH : LOW; return (value & (1 << shift)) ? HIGH : LOW;
...@@ -215,7 +247,7 @@ uint8_t bcm2835_gpio_lev(uint8_t pin) ...@@ -215,7 +247,7 @@ uint8_t bcm2835_gpio_lev(uint8_t pin)
// Sigh cant support interrupts yet // Sigh cant support interrupts yet
uint8_t bcm2835_gpio_eds(uint8_t pin) uint8_t bcm2835_gpio_eds(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = bcm2835_peri_read(paddr); uint32_t value = bcm2835_peri_read(paddr);
return (value & (1 << shift)) ? HIGH : LOW; return (value & (1 << shift)) ? HIGH : LOW;
...@@ -224,7 +256,7 @@ uint8_t bcm2835_gpio_eds(uint8_t pin) ...@@ -224,7 +256,7 @@ uint8_t bcm2835_gpio_eds(uint8_t pin)
// Write a 1 to clear the bit in EDS // Write a 1 to clear the bit in EDS
void bcm2835_gpio_set_eds(uint8_t pin) void bcm2835_gpio_set_eds(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_write(paddr, value); bcm2835_peri_write(paddr, value);
...@@ -233,14 +265,14 @@ void bcm2835_gpio_set_eds(uint8_t pin) ...@@ -233,14 +265,14 @@ void bcm2835_gpio_set_eds(uint8_t pin)
// Rising edge detect enable // Rising edge detect enable
void bcm2835_gpio_ren(uint8_t pin) void bcm2835_gpio_ren(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_ren(uint8_t pin) void bcm2835_gpio_clr_ren(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -249,14 +281,14 @@ void bcm2835_gpio_clr_ren(uint8_t pin) ...@@ -249,14 +281,14 @@ void bcm2835_gpio_clr_ren(uint8_t pin)
// Falling edge detect enable // Falling edge detect enable
void bcm2835_gpio_fen(uint8_t pin) void bcm2835_gpio_fen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_fen(uint8_t pin) void bcm2835_gpio_clr_fen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -265,14 +297,14 @@ void bcm2835_gpio_clr_fen(uint8_t pin) ...@@ -265,14 +297,14 @@ void bcm2835_gpio_clr_fen(uint8_t pin)
// High detect enable // High detect enable
void bcm2835_gpio_hen(uint8_t pin) void bcm2835_gpio_hen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_hen(uint8_t pin) void bcm2835_gpio_clr_hen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -281,14 +313,14 @@ void bcm2835_gpio_clr_hen(uint8_t pin) ...@@ -281,14 +313,14 @@ void bcm2835_gpio_clr_hen(uint8_t pin)
// Low detect enable // Low detect enable
void bcm2835_gpio_len(uint8_t pin) void bcm2835_gpio_len(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_len(uint8_t pin) void bcm2835_gpio_clr_len(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -297,14 +329,14 @@ void bcm2835_gpio_clr_len(uint8_t pin) ...@@ -297,14 +329,14 @@ void bcm2835_gpio_clr_len(uint8_t pin)
// Async rising edge detect enable // Async rising edge detect enable
void bcm2835_gpio_aren(uint8_t pin) void bcm2835_gpio_aren(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_aren(uint8_t pin) void bcm2835_gpio_clr_aren(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -313,14 +345,14 @@ void bcm2835_gpio_clr_aren(uint8_t pin) ...@@ -313,14 +345,14 @@ void bcm2835_gpio_clr_aren(uint8_t pin)
// Async falling edge detect enable // Async falling edge detect enable
void bcm2835_gpio_afen(uint8_t pin) void bcm2835_gpio_afen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, value, value); bcm2835_peri_set_bits(paddr, value, value);
} }
void bcm2835_gpio_clr_afen(uint8_t pin) void bcm2835_gpio_clr_afen(uint8_t pin)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
uint32_t value = 1 << shift; uint32_t value = 1 << shift;
bcm2835_peri_set_bits(paddr, 0, value); bcm2835_peri_set_bits(paddr, 0, value);
...@@ -329,7 +361,7 @@ void bcm2835_gpio_clr_afen(uint8_t pin) ...@@ -329,7 +361,7 @@ void bcm2835_gpio_clr_afen(uint8_t pin)
// Set pullup/down // Set pullup/down
void bcm2835_gpio_pud(uint8_t pud) void bcm2835_gpio_pud(uint8_t pud)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4;
bcm2835_peri_write(paddr, pud); bcm2835_peri_write(paddr, pud);
} }
...@@ -337,7 +369,7 @@ void bcm2835_gpio_pud(uint8_t pud) ...@@ -337,7 +369,7 @@ void bcm2835_gpio_pud(uint8_t pud)
// Clocks the value of pud into the GPIO pin // Clocks the value of pud into the GPIO pin
void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on)
{ {
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32;
uint8_t shift = pin % 32; uint8_t shift = pin % 32;
bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); bcm2835_peri_write(paddr, (on ? 1 : 0) << shift);
} }
...@@ -345,7 +377,7 @@ void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) ...@@ -345,7 +377,7 @@ void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on)
// Read GPIO pad behaviour for groups of GPIOs // Read GPIO pad behaviour for groups of GPIOs
uint32_t bcm2835_gpio_pad(uint8_t group) uint32_t bcm2835_gpio_pad(uint8_t group)
{ {
volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group*2; uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group*2;
return bcm2835_peri_read(paddr); return bcm2835_peri_read(paddr);
} }
...@@ -354,7 +386,7 @@ uint32_t bcm2835_gpio_pad(uint8_t group) ...@@ -354,7 +386,7 @@ uint32_t bcm2835_gpio_pad(uint8_t group)
// BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA // BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA
void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) void bcm2835_gpio_set_pad(uint8_t group, uint32_t control)
{ {
volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group*2; uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group*2;
bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD);
} }
...@@ -461,18 +493,14 @@ void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud) ...@@ -461,18 +493,14 @@ void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud)
void bcm2835_spi_begin(void) void bcm2835_spi_begin(void)
{ {
// Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them // Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them
//bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1 bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1
// Enable CE0 by default, will be disabled if bcm2835_chipSelect() is called using another pin
bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0 bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0
bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); // MISO bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); // MISO
bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // MOSI bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // MOSI
bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); // CLK bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); // CLK
// Set the SPI CS register to the some sensible defaults // Set the SPI CS register to the some sensible defaults
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
bcm2835_peri_write(paddr, 0); // All 0s bcm2835_peri_write(paddr, 0); // All 0s
// Clear TX and RX fifos // Clear TX and RX fifos
...@@ -500,13 +528,13 @@ void bcm2835_spi_setBitOrder(uint8_t order) ...@@ -500,13 +528,13 @@ void bcm2835_spi_setBitOrder(uint8_t order)
// of the APB clock // of the APB clock
void bcm2835_spi_setClockDivider(uint16_t divider) void bcm2835_spi_setClockDivider(uint16_t divider)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4;
bcm2835_peri_write(paddr, divider); bcm2835_peri_write(paddr, divider);
} }
void bcm2835_spi_setDataMode(uint8_t mode) void bcm2835_spi_setDataMode(uint8_t mode)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
// Mask in the CPO and CPHA bits of CS // Mask in the CPO and CPHA bits of CS
bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA);
} }
...@@ -514,8 +542,8 @@ void bcm2835_spi_setDataMode(uint8_t mode) ...@@ -514,8 +542,8 @@ void bcm2835_spi_setDataMode(uint8_t mode)
// Writes (and reads) a single byte to SPI // Writes (and reads) a single byte to SPI
uint8_t bcm2835_spi_transfer(uint8_t value) uint8_t bcm2835_spi_transfer(uint8_t value)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
// This is Polled transfer as per section 10.6.1 // This is Polled transfer as per section 10.6.1
// BUG ALERT: what happens if we get interupted in this section, and someone else // BUG ALERT: what happens if we get interupted in this section, and someone else
...@@ -549,8 +577,8 @@ uint8_t bcm2835_spi_transfer(uint8_t value) ...@@ -549,8 +577,8 @@ uint8_t bcm2835_spi_transfer(uint8_t value)
// Writes (and reads) an number of bytes to SPI // Writes (and reads) an number of bytes to SPI
void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
uint32_t TXCnt=0; uint32_t TXCnt=0;
uint32_t RXCnt=0; uint32_t RXCnt=0;
...@@ -568,7 +596,7 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) ...@@ -568,7 +596,7 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
while((TXCnt < len)||(RXCnt < len)) while((TXCnt < len)||(RXCnt < len))
{ {
// TX fifo not full, so add some more bytes // TX fifo not full, so add some more bytes
while( (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD ) && (TXCnt < len ) && !(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXR) ) while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len ))
{ {
bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); bcm2835_peri_write_nb(fifo, tbuf[TXCnt]);
TXCnt++; TXCnt++;
...@@ -580,18 +608,19 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) ...@@ -580,18 +608,19 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
RXCnt++; RXCnt++;
} }
} }
while(! (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_DONE) ) // Wait for DONE to be set
; while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
if(TXCnt == len) bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA)
; ;
}
// Set TA = 0, and also set the barrier
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
}
// Writes an number of bytes to SPI // Writes an number of bytes to SPI
void bcm2835_spi_writenb(char* tbuf, uint32_t len) void bcm2835_spi_writenb(char* tbuf, uint32_t len)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
// This is Polled transfer as per section 10.6.1 // This is Polled transfer as per section 10.6.1
// BUG ALERT: what happens if we get interupted in this section, and someone else // BUG ALERT: what happens if we get interupted in this section, and someone else
...@@ -637,22 +666,14 @@ void bcm2835_spi_transfern(char* buf, uint32_t len) ...@@ -637,22 +666,14 @@ void bcm2835_spi_transfern(char* buf, uint32_t len)
void bcm2835_spi_chipSelect(uint8_t cs) void bcm2835_spi_chipSelect(uint8_t cs)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
if(cs){
bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1
bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); // Revert default of CE0 back to input
}else{
bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0
}
// Mask in the CS bits of CS // Mask in the CS bits of CS
bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS);
} }
void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active)
{ {
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
uint8_t shift = 21 + cs; uint8_t shift = 21 + cs;
// Mask in the appropriate CSPOLn bit // Mask in the appropriate CSPOLn bit
bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); bcm2835_peri_set_bits(paddr, active << shift, 1 << shift);
...@@ -661,12 +682,12 @@ void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) ...@@ -661,12 +682,12 @@ void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active)
void bcm2835_i2c_begin(void) void bcm2835_i2c_begin(void)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4;
// Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them // Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them
bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA
bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL
#else #else
volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4;
// Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them // Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); // SDA
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); // SCL
...@@ -697,9 +718,9 @@ void bcm2835_i2c_setSlaveAddress(uint8_t addr) ...@@ -697,9 +718,9 @@ void bcm2835_i2c_setSlaveAddress(uint8_t addr)
{ {
// Set I2C Device Address // Set I2C Device Address
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4;
#else #else
volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4;
#endif #endif
bcm2835_peri_write(paddr, addr); bcm2835_peri_write(paddr, addr);
} }
...@@ -710,9 +731,9 @@ void bcm2835_i2c_setSlaveAddress(uint8_t addr) ...@@ -710,9 +731,9 @@ void bcm2835_i2c_setSlaveAddress(uint8_t addr)
void bcm2835_i2c_setClockDivider(uint16_t divider) void bcm2835_i2c_setClockDivider(uint16_t divider)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4;
#else #else
volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4;
#endif #endif
bcm2835_peri_write(paddr, divider); bcm2835_peri_write(paddr, divider);
// Calculate time for transmitting one byte // Calculate time for transmitting one byte
...@@ -734,15 +755,15 @@ void bcm2835_i2c_set_baudrate(uint32_t baudrate) ...@@ -734,15 +755,15 @@ void bcm2835_i2c_set_baudrate(uint32_t baudrate)
uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) uint8_t bcm2835_i2c_write(const char * buf, uint32_t len)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4;
#else #else
volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
#endif #endif
uint32_t remaining = len; uint32_t remaining = len;
...@@ -805,15 +826,15 @@ uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) ...@@ -805,15 +826,15 @@ uint8_t bcm2835_i2c_write(const char * buf, uint32_t len)
uint8_t bcm2835_i2c_read(char* buf, uint32_t len) uint8_t bcm2835_i2c_read(char* buf, uint32_t len)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4;
#else #else
volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
#endif #endif
uint32_t remaining = len; uint32_t remaining = len;
...@@ -879,15 +900,15 @@ uint8_t bcm2835_i2c_read(char* buf, uint32_t len) ...@@ -879,15 +900,15 @@ uint8_t bcm2835_i2c_read(char* buf, uint32_t len)
uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4;
#else #else
volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
#endif #endif
uint32_t remaining = len; uint32_t remaining = len;
uint32_t i = 0; uint32_t i = 0;
...@@ -969,15 +990,15 @@ uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) ...@@ -969,15 +990,15 @@ uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len)
uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len)
{ {
#ifdef I2C_V1 #ifdef I2C_V1
volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4;
#else #else
volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4;
volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4;
volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4;
volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4;
#endif #endif
uint32_t remaining = cmds_len; uint32_t remaining = cmds_len;
...@@ -1070,7 +1091,7 @@ uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint ...@@ -1070,7 +1091,7 @@ uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint
// Read the System Timer Counter (64-bits) // Read the System Timer Counter (64-bits)
uint64_t bcm2835_st_read(void) uint64_t bcm2835_st_read(void)
{ {
volatile uint32_t* paddr; uint32_t* paddr;
uint32_t hi, lo; uint32_t hi, lo;
uint64_t st; uint64_t st;
paddr = bcm2835_st + BCM2835_ST_CHI/4; paddr = bcm2835_st + BCM2835_ST_CHI/4;
...@@ -1186,7 +1207,7 @@ void *malloc_aligned(size_t size) ...@@ -1186,7 +1207,7 @@ void *malloc_aligned(size_t size)
static void *mapmem(const char *msg, size_t size, int fd, off_t off) static void *mapmem(const char *msg, size_t size, int fd, off_t off)
{ {
void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off);
if (MAP_FAILED == map) if (map == MAP_FAILED)
fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
return map; return map;
} }
...@@ -1200,21 +1221,40 @@ static void unmapmem(void **pmem, size_t size) ...@@ -1200,21 +1221,40 @@ static void unmapmem(void **pmem, size_t size)
// Initialise this library. // Initialise this library.
int bcm2835_init(void) int bcm2835_init(void)
{ {
struct timeval tv ; struct timeval tv ;
if (debug)
if (debug)
{ {
bcm2835_pads = (uint32_t*)BCM2835_GPIO_PADS; bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE;
bcm2835_clk = (uint32_t*)BCM2835_CLOCK_BASE;
bcm2835_gpio = (uint32_t*)BCM2835_GPIO_BASE; bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS;
bcm2835_pwm = (uint32_t*)BCM2835_GPIO_PWM; bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE;
bcm2835_spi0 = (uint32_t*)BCM2835_SPI0_BASE; bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE;
bcm2835_bsc0 = (uint32_t*)BCM2835_BSC0_BASE; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM;
bcm2835_bsc1 = (uint32_t*)BCM2835_BSC1_BASE; bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE;
bcm2835_st = (uint32_t*)BCM2835_ST_BASE; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE;
bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE;
bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE;
return 1; // Success return 1; // Success
} }
// Figure out the base and size of the peripheral address block, based on whether we are on a RPI2 or not,
// using the device-tree
FILE *fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb");
if (fp)
{
unsigned char buf[4];
fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET);
if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0);
fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET);
if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0);
fclose(fp);
}
// else we are prob on RPi 1 with BCM2835, and use the hardwired defaults
// Now get ready to map the peripherals block
int memfd = -1; int memfd = -1;
int ok = 0; int ok = 0;
// Open the master /dev/memory device // Open the master /dev/memory device
...@@ -1225,34 +1265,19 @@ int bcm2835_init(void) ...@@ -1225,34 +1265,19 @@ int bcm2835_init(void)
goto exit; goto exit;
} }
// GPIO: // Base of the peripherals block is mapped to VM
bcm2835_gpio = (volatile uint32_t *)mapmem("gpio", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_BASE); bcm2835_peripherals = (uint32_t *)mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base);
if (bcm2835_gpio == MAP_FAILED) goto exit; if (bcm2835_peripherals == MAP_FAILED) goto exit;
// PWM // Now compute the base addresses of various peripherals, which are at fixed offsets within the mapped peripherals block
bcm2835_pwm = (volatile uint32_t *)mapmem("pwm", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PWM); bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE;
if (bcm2835_pwm == MAP_FAILED) goto exit; bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM;
bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE;
// Clock control (needed for PWM) bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS;
bcm2835_clk = (volatile uint32_t *)mapmem("clk", BCM2835_BLOCK_SIZE, memfd, BCM2835_CLOCK_BASE); bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE;
if (bcm2835_clk == MAP_FAILED) goto exit; bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE; // I2C
bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE; // I2C
bcm2835_pads = (volatile uint32_t *)mapmem("pads", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PADS); bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE;
if (bcm2835_pads == MAP_FAILED) goto exit;
bcm2835_spi0 = (volatile uint32_t *)mapmem("spi0", BCM2835_BLOCK_SIZE, memfd, BCM2835_SPI0_BASE);
if (bcm2835_spi0 == MAP_FAILED) goto exit;
// I2C
bcm2835_bsc0 = (volatile uint32_t *)mapmem("bsc0", BCM2835_BLOCK_SIZE, memfd, BCM2835_BSC0_BASE);
if (bcm2835_bsc0 == MAP_FAILED) goto exit;
bcm2835_bsc1 = (volatile uint32_t *)mapmem("bsc1", BCM2835_BLOCK_SIZE, memfd, BCM2835_BSC1_BASE);
if (bcm2835_bsc1 == MAP_FAILED) goto exit;
// ST
bcm2835_st = (volatile uint32_t *)mapmem("st", BCM2835_BLOCK_SIZE, memfd, BCM2835_ST_BASE);
if (bcm2835_st == MAP_FAILED) goto exit;
ok = 1; ok = 1;
...@@ -1273,14 +1298,17 @@ exit: ...@@ -1273,14 +1298,17 @@ exit:
int bcm2835_close(void) int bcm2835_close(void)
{ {
if (debug) return 1; // Success if (debug) return 1; // Success
unmapmem((void**) &bcm2835_gpio, BCM2835_BLOCK_SIZE);
unmapmem((void**) &bcm2835_pwm, BCM2835_BLOCK_SIZE); unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size);
unmapmem((void**) &bcm2835_clk, BCM2835_BLOCK_SIZE); bcm2835_peripherals = MAP_FAILED;
unmapmem((void**) &bcm2835_spi0, BCM2835_BLOCK_SIZE); bcm2835_gpio = MAP_FAILED;
unmapmem((void**) &bcm2835_bsc0, BCM2835_BLOCK_SIZE); bcm2835_pwm = MAP_FAILED;
unmapmem((void**) &bcm2835_bsc1, BCM2835_BLOCK_SIZE); bcm2835_clk = MAP_FAILED;
unmapmem((void**) &bcm2835_st, BCM2835_BLOCK_SIZE); bcm2835_pads = MAP_FAILED;
unmapmem((void**) &bcm2835_pads, BCM2835_BLOCK_SIZE); bcm2835_spi0 = MAP_FAILED;
bcm2835_bsc0 = MAP_FAILED;
bcm2835_bsc1 = MAP_FAILED;
bcm2835_st = MAP_FAILED;
return 1; // Success return 1; // Success
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
/// BCM 2835). /// BCM 2835).
/// ///
/// The version of the package that this documentation refers to can be downloaded /// The version of the package that this documentation refers to can be downloaded
/// from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.36.tar.gz /// from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.39.tar.gz
/// You can find the latest version at http://www.airspayce.com/mikem/bcm2835 /// You can find the latest version at http://www.airspayce.com/mikem/bcm2835
/// ///
/// Several example programs are provided. /// Several example programs are provided.
...@@ -316,6 +316,12 @@ ...@@ -316,6 +316,12 @@
/// \version 1.37 Moved confiure.in to configure.ac as receommnded by autoreconf.<br> /// \version 1.37 Moved confiure.in to configure.ac as receommnded by autoreconf.<br>
/// Improvements to bcm2835_st_read to account for possible timer overflow, contributed by 'Ed'.<br> /// Improvements to bcm2835_st_read to account for possible timer overflow, contributed by 'Ed'.<br>
/// Added definitions for Raspberry Pi B+ J8 header GPIO pins.<br> /// Added definitions for Raspberry Pi B+ J8 header GPIO pins.<br>
/// \version 1.38 Added bcm2835_regbase for the benefit of C# wrappers, patch by Frank Hommers <br>
/// \version 1.39 Beta version of RPi2 compatibility. Not tested here on RPi2 hardware.
/// Testers please confirm correct operation on RPi2.<br>
/// Unneccessary 'volatile' qualifiers removed from all variables and signatures.<br>
/// Removed unsupportable PWM dividers, based on a report from Christophe Cecillon.<br>
/// Minor improvements to spi.c example.<br>
/// ///
/// \author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS /// \author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS
...@@ -340,58 +346,92 @@ ...@@ -340,58 +346,92 @@
/// Speed of the core clock core_clk /// Speed of the core clock core_clk
#define BCM2835_CORE_CLK_HZ 250000000 ///< 250 MHz #define BCM2835_CORE_CLK_HZ 250000000 ///< 250 MHz
// Physical addresses for various peripheral register sets /// On RPi2 with BCM2836, the base of the peripherals is read from a /proc file
#define BMC2835_RPI2_DT_FILENAME "/proc/device-tree/soc/ranges"
/// On RPi2, offset into BMC2835_RPI2_DT_FILENAME for the peripherals base address
#define BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET 4
/// On RPi2, offset into BMC2835_RPI2_DT_FILENAME for the peripherals size address
#define BMC2835_RPI2_DT_PERI_SIZE_OFFSET 8
/// Physical addresses for various peripheral register sets
/// Base Physical Address of the BCM 2835 peripheral registers /// Base Physical Address of the BCM 2835 peripheral registers
/// Note this is different for the RPi2 BCM2836, where this isderived from /proc/device-tree/soc/ranges
#define BCM2835_PERI_BASE 0x20000000 #define BCM2835_PERI_BASE 0x20000000
/// Base Physical Address of the System Timer registers /// Size of the perioherals block on RPi 1
#define BCM2835_ST_BASE (BCM2835_PERI_BASE + 0x3000) #define BCM2835_PERI_SIZE 0x01000000
/// Base Physical Address of the Pads registers
#define BCM2835_GPIO_PADS (BCM2835_PERI_BASE + 0x100000) /// Offsets for the bases of various peripherals within the peripherals block
/// Base Physical Address of the Clock/timer registers /// Base Address of the System Timer registers
#define BCM2835_CLOCK_BASE (BCM2835_PERI_BASE + 0x101000) #define BCM2835_ST_BASE 0x3000
/// Base Physical Address of the GPIO registers /// Base Address of the Pads registers
#define BCM2835_GPIO_BASE (BCM2835_PERI_BASE + 0x200000) #define BCM2835_GPIO_PADS 0x100000
/// Base Physical Address of the SPI0 registers /// Base Address of the Clock/timer registers
#define BCM2835_SPI0_BASE (BCM2835_PERI_BASE + 0x204000) #define BCM2835_CLOCK_BASE 0x101000
/// Base Physical Address of the BSC0 registers /// Base Address of the GPIO registers
#define BCM2835_BSC0_BASE (BCM2835_PERI_BASE + 0x205000) #define BCM2835_GPIO_BASE 0x200000
/// Base Physical Address of the PWM registers /// Base Address of the SPI0 registers
#define BCM2835_GPIO_PWM (BCM2835_PERI_BASE + 0x20C000) #define BCM2835_SPI0_BASE 0x204000
/// Base Physical Address of the BSC1 registers /// Base Address of the BSC0 registers
#define BCM2835_BSC1_BASE (BCM2835_PERI_BASE + 0x804000) #define BCM2835_BSC0_BASE 0x205000
/// Base Address of the PWM registers
#define BCM2835_GPIO_PWM 0x20C000
/// Base Address of the BSC1 registers
#define BCM2835_BSC1_BASE 0x804000
/// Physical address and size of the peripherals block
/// May be overridden on RPi2
extern uint32_t *bcm2835_peripherals_base;
/// Size of the peripherals block to be mapped
extern uint32_t bcm2835_peripherals_size;
/// Virtual memory address of the mapped peripherals block
extern void *bcm2835_peripherals;
/// Base of the ST (System Timer) registers. /// Base of the ST (System Timer) registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_st; extern uint32_t *bcm2835_st;
/// Base of the GPIO registers. /// Base of the GPIO registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_gpio; extern uint32_t *bcm2835_gpio;
/// Base of the PWM registers. /// Base of the PWM registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_pwm; extern uint32_t *bcm2835_pwm;
/// Base of the CLK registers. /// Base of the CLK registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_clk; extern uint32_t *bcm2835_clk;
/// Base of the PADS registers. /// Base of the PADS registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_pads; extern uint32_t *bcm2835_pads;
/// Base of the SPI0 registers. /// Base of the SPI0 registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_spi0; extern uint32_t *bcm2835_spi0;
/// Base of the BSC0 registers. /// Base of the BSC0 registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_bsc0; extern uint32_t *bcm2835_bsc0;
/// Base of the BSC1 registers. /// Base of the BSC1 registers.
/// Available after bcm2835_init has been called /// Available after bcm2835_init has been called
extern volatile uint32_t *bcm2835_bsc1; extern uint32_t *bcm2835_bsc1;
/// \brief bcm2835RegisterBase
/// Register bases for bcm2835_regbase()
typedef enum
{
BCM2835_REGBASE_ST = 1, ///< Base of the ST (System Timer) registers.
BCM2835_REGBASE_GPIO = 2, ///< Base of the GPIO registers.
BCM2835_REGBASE_PWM = 3, ///< Base of the PWM registers.
BCM2835_REGBASE_CLK = 4, ///< Base of the CLK registers.
BCM2835_REGBASE_PADS = 5, ///< Base of the PADS registers.
BCM2835_REGBASE_SPI0 = 6, ///< Base of the SPI0 registers.
BCM2835_REGBASE_BSC0 = 7, ///< Base of the BSC0 registers.
BCM2835_REGBASE_BSC1 = 8 ///< Base of the BSC1 registers.
} bcm2835RegisterBase;
/// Size of memory page on RPi /// Size of memory page on RPi
#define BCM2835_PAGE_SIZE (4*1024) #define BCM2835_PAGE_SIZE (4*1024)
...@@ -437,24 +477,24 @@ extern volatile uint32_t *bcm2835_bsc1; ...@@ -437,24 +477,24 @@ extern volatile uint32_t *bcm2835_bsc1;
/// Port function select modes for bcm2835_gpio_fsel() /// Port function select modes for bcm2835_gpio_fsel()
typedef enum typedef enum
{ {
BCM2835_GPIO_FSEL_INPT = 0x00, ///< Input BCM2835_GPIO_FSEL_INPT = 0b000, ///< Input
BCM2835_GPIO_FSEL_OUTP = 0x01, ///< Output BCM2835_GPIO_FSEL_OUTP = 0b001, ///< Output
BCM2835_GPIO_FSEL_ALT0 = 0x04, ///< Alternate function 0 BCM2835_GPIO_FSEL_ALT0 = 0b100, ///< Alternate function 0
BCM2835_GPIO_FSEL_ALT1 = 0x05, ///< Alternate function 1 BCM2835_GPIO_FSEL_ALT1 = 0b101, ///< Alternate function 1
BCM2835_GPIO_FSEL_ALT2 = 0x06, ///< Alternate function 2 BCM2835_GPIO_FSEL_ALT2 = 0b110, ///< Alternate function 2
BCM2835_GPIO_FSEL_ALT3 = 0x07, ///< Alternate function 3 BCM2835_GPIO_FSEL_ALT3 = 0b111, ///< Alternate function 3
BCM2835_GPIO_FSEL_ALT4 = 0x03, ///< Alternate function 4 BCM2835_GPIO_FSEL_ALT4 = 0b011, ///< Alternate function 4
BCM2835_GPIO_FSEL_ALT5 = 0x02, ///< Alternate function 5 BCM2835_GPIO_FSEL_ALT5 = 0b010, ///< Alternate function 5
BCM2835_GPIO_FSEL_MASK = 0x07 ///< Function select bits mask BCM2835_GPIO_FSEL_MASK = 0b111 ///< Function select bits mask
} bcm2835FunctionSelect; } bcm2835FunctionSelect;
/// \brief bcm2835PUDControl /// \brief bcm2835PUDControl
/// Pullup/Pulldown defines for bcm2835_gpio_pud() /// Pullup/Pulldown defines for bcm2835_gpio_pud()
typedef enum typedef enum
{ {
BCM2835_GPIO_PUD_OFF = 0x00, ///< Off ? disable pull-up/down BCM2835_GPIO_PUD_OFF = 0b00, ///< Off ? disable pull-up/down
BCM2835_GPIO_PUD_DOWN = 0x01, ///< Enable Pull Down control BCM2835_GPIO_PUD_DOWN = 0b01, ///< Enable Pull Down control
BCM2835_GPIO_PUD_UP = 0x02 ///< Enable Pull Up control BCM2835_GPIO_PUD_UP = 0b10 ///< Enable Pull Up control
} bcm2835PUDControl; } bcm2835PUDControl;
/// Pad control register offsets from BCM2835_GPIO_PADS /// Pad control register offsets from BCM2835_GPIO_PADS
...@@ -494,7 +534,9 @@ typedef enum ...@@ -494,7 +534,9 @@ typedef enum
/// RPi B+ has yet differnet pinouts and these are defined in RPI_BPLUS_*. /// RPi B+ has yet differnet pinouts and these are defined in RPI_BPLUS_*.
/// At bootup, pins 8 and 10 are set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively /// At bootup, pins 8 and 10 are set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
/// When SPI0 is in use (ie after bcm2835_spi_begin()), SPI0 pins are dedicated to SPI /// When SPI0 is in use (ie after bcm2835_spi_begin()), SPI0 pins are dedicated to SPI
/// and cant be controlled independently /// and cant be controlled independently.
/// If you are using the RPi Compute Module, just use the GPIO number: there is no need to use one of these
/// symbolic names
typedef enum typedef enum
{ {
RPI_GPIO_P1_03 = 0, ///< Version 1, Pin P1-03 RPI_GPIO_P1_03 = 0, ///< Version 1, Pin P1-03
...@@ -629,12 +671,10 @@ typedef enum ...@@ -629,12 +671,10 @@ typedef enum
/// Specify the SPI chip select pin(s) /// Specify the SPI chip select pin(s)
typedef enum typedef enum
{ {
// Can also use non-standard pins with this lib
BCM2835_SPI_CS0 = 0, ///< Chip Select 0 BCM2835_SPI_CS0 = 0, ///< Chip Select 0
BCM2835_SPI_CS1 = 1, ///< Chip Select 1 BCM2835_SPI_CS1 = 1, ///< Chip Select 1
BCM2835_SPI_CS2 = 2, ///< Chip Select 2 (ie pins CS1 and CS2 are asserted) BCM2835_SPI_CS2 = 2, ///< Chip Select 2 (ie pins CS1 and CS2 are asserted)
BCM2835_SPI_CS_NONE = 3, ///< No CS, control it yourself BCM2835_SPI_CS_NONE = 3, ///< No CS, control it yourself
} bcm2835SPIChipSelect; } bcm2835SPIChipSelect;
/// \brief bcm2835SPIClockDivider /// \brief bcm2835SPIClockDivider
...@@ -682,6 +722,7 @@ typedef enum ...@@ -682,6 +722,7 @@ typedef enum
#define BCM2835_SPI_SPEED_16KHZ BCM2835_SPI_CLOCK_DIVIDER_16384 #define BCM2835_SPI_SPEED_16KHZ BCM2835_SPI_CLOCK_DIVIDER_16384
#define BCM2835_SPI_SPEED_8KHZ BCM2835_SPI_CLOCK_DIVIDER_32768 #define BCM2835_SPI_SPEED_8KHZ BCM2835_SPI_CLOCK_DIVIDER_32768
// Defines for I2C // Defines for I2C
// GPIO register offsets from BCM2835_BSC*_BASE. // GPIO register offsets from BCM2835_BSC*_BASE.
// Offsets into the BSC Peripheral block in bytes per 3.1 BSC Register Map // Offsets into the BSC Peripheral block in bytes per 3.1 BSC Register Map
...@@ -788,7 +829,6 @@ typedef enum ...@@ -788,7 +829,6 @@ typedef enum
#define BCM2835_PWM0_SERIAL 0x0002 ///< Run in serial mode #define BCM2835_PWM0_SERIAL 0x0002 ///< Run in serial mode
#define BCM2835_PWM0_ENABLE 0x0001 ///< Channel Enable #define BCM2835_PWM0_ENABLE 0x0001 ///< Channel Enable
/// \brief bcm2835PWMClockDivider /// \brief bcm2835PWMClockDivider
/// Specifies the divider used to generate the PWM clock from the system clock. /// Specifies the divider used to generate the PWM clock from the system clock.
/// Figures below give the divider, clock period and clock frequency. /// Figures below give the divider, clock period and clock frequency.
...@@ -796,10 +836,6 @@ typedef enum ...@@ -796,10 +836,6 @@ typedef enum
/// The frequencies shown for each divider have been confirmed by measurement /// The frequencies shown for each divider have been confirmed by measurement
typedef enum typedef enum
{ {
BCM2835_PWM_CLOCK_DIVIDER_32768 = 32768, ///< 32768 = 585Hz
BCM2835_PWM_CLOCK_DIVIDER_16384 = 16384, ///< 16384 = 1171.8Hz
BCM2835_PWM_CLOCK_DIVIDER_8192 = 8192, ///< 8192 = 2.34375kHz
BCM2835_PWM_CLOCK_DIVIDER_4096 = 4096, ///< 4096 = 4.6875kHz
BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, ///< 2048 = 9.375kHz BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, ///< 2048 = 9.375kHz
BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, ///< 1024 = 18.75kHz BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, ///< 1024 = 18.75kHz
BCM2835_PWM_CLOCK_DIVIDER_512 = 512, ///< 512 = 37.5kHz BCM2835_PWM_CLOCK_DIVIDER_512 = 512, ///< 512 = 37.5kHz
...@@ -859,13 +895,20 @@ extern "C" { ...@@ -859,13 +895,20 @@ extern "C" {
/// ///
/// @{ /// @{
/// Gets the base of a register
/// \param[in] regbase You can use one of the common values BCM2835_REGBASE_*
/// in \ref bcm2835RegisterBase
/// \return the register base
/// \sa Physical Addresses
extern uint32_t* bcm2835_regbase(uint8_t regbase);
/// Reads 32 bit value from a peripheral address /// Reads 32 bit value from a peripheral address
/// The read is done twice, and is therefore always safe in terms of /// The read is done twice, and is therefore always safe in terms of
/// manual section 1.3 Peripheral access precautions for correct memory ordering /// manual section 1.3 Peripheral access precautions for correct memory ordering
/// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. /// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc.
/// \return the value read from the 32 bit register /// \return the value read from the 32 bit register
/// \sa Physical Addresses /// \sa Physical Addresses
extern uint32_t bcm2835_peri_read(volatile uint32_t* paddr); extern uint32_t bcm2835_peri_read(uint32_t* paddr);
/// Reads 32 bit value from a peripheral address without the read barrier /// Reads 32 bit value from a peripheral address without the read barrier
...@@ -874,7 +917,7 @@ extern "C" { ...@@ -874,7 +917,7 @@ extern "C" {
/// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. /// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc.
/// \return the value read from the 32 bit register /// \return the value read from the 32 bit register
/// \sa Physical Addresses /// \sa Physical Addresses
extern uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr); extern uint32_t bcm2835_peri_read_nb(uint32_t* paddr);
/// Writes 32 bit value from a peripheral address /// Writes 32 bit value from a peripheral address
...@@ -883,7 +926,7 @@ extern "C" { ...@@ -883,7 +926,7 @@ extern "C" {
/// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. /// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc.
/// \param[in] value The 32 bit value to write /// \param[in] value The 32 bit value to write
/// \sa Physical Addresses /// \sa Physical Addresses
extern void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value); extern void bcm2835_peri_write(uint32_t* paddr, uint32_t value);
/// Writes 32 bit value from a peripheral address without the write barrier /// Writes 32 bit value from a peripheral address without the write barrier
/// You should only use this when your code has previously called bcm2835_peri_write() /// You should only use this when your code has previously called bcm2835_peri_write()
...@@ -891,7 +934,7 @@ extern "C" { ...@@ -891,7 +934,7 @@ extern "C" {
/// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. /// \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc.
/// \param[in] value The 32 bit value to write /// \param[in] value The 32 bit value to write
/// \sa Physical Addresses /// \sa Physical Addresses
extern void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value); extern void bcm2835_peri_write_nb(uint32_t* paddr, uint32_t value);
/// Alters a number of bits in a 32 peripheral regsiter. /// Alters a number of bits in a 32 peripheral regsiter.
/// It reads the current valu and then alters the bits deines as 1 in mask, /// It reads the current valu and then alters the bits deines as 1 in mask,
...@@ -904,7 +947,7 @@ extern "C" { ...@@ -904,7 +947,7 @@ extern "C" {
/// \param[in] value The 32 bit value to write, masked in by mask. /// \param[in] value The 32 bit value to write, masked in by mask.
/// \param[in] mask Bitmask that defines the bits that will be altered in the register. /// \param[in] mask Bitmask that defines the bits that will be altered in the register.
/// \sa Physical Addresses /// \sa Physical Addresses
extern void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask); extern void bcm2835_peri_set_bits(uint32_t* paddr, uint32_t value, uint32_t mask);
/// @} // end of lowlevel /// @} // end of lowlevel
/// \defgroup gpio GPIO register access /// \defgroup gpio GPIO register access
...@@ -1107,89 +1150,79 @@ extern "C" { ...@@ -1107,89 +1150,79 @@ extern "C" {
/// \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl /// \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl
extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud); extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud);
/// @} /// @}
/// \defgroup spi SPI access /// \defgroup spi SPI access
/// These functions let you use SPI0 (Serial Peripheral Interface) to /// These functions let you use SPI0 (Serial Peripheral Interface) to
/// interface with an external SPI device. /// interface with an external SPI device.
/// @{ /// @{
/// Start SPI operations. /// Start SPI operations.
/// Forces RPi SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) /// Forces RPi SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1)
/// to alternate function ALT0, which enables those pins for SPI interface. /// to alternate function ALT0, which enables those pins for SPI interface.
/// \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave. /// You should call bcm2835_spi_end() when all SPI funcitons are complete to return the pins to
/// One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect
/// or one of One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect
/// by default PI hardware driven using CE0
/// You should call bcm2835_spi_end() when all SPI funcitons are complete to return the pins to
/// their default functions /// their default functions
/// \sa bcm2835_spi_end() /// \sa bcm2835_spi_end()
extern void bcm2835_spi_begin(); extern void bcm2835_spi_begin(void);
/// End SPI operations. /// End SPI operations.
/// SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) /// SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1)
/// are returned to their default INPUT behaviour. /// are returned to their default INPUT behaviour.
extern void bcm2835_spi_end(void); extern void bcm2835_spi_end(void);
/// Sets the SPI custom Chip Select pin to correct level
/// Defaults to
/// \param[in] level The desired level, LOW or HIGH,
extern void bcm2835_spi_setChipSelect(uint8_t level);
/// Sets the SPI bit order /// Sets the SPI bit order
/// NOTE: has no effect. Not supported by SPI0. /// NOTE: has no effect. Not supported by SPI0.
/// Defaults to /// Defaults to
/// \param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*, /// \param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*,
/// see \ref bcm2835SPIBitOrder /// see \ref bcm2835SPIBitOrder
extern void bcm2835_spi_setBitOrder(uint8_t order); extern void bcm2835_spi_setBitOrder(uint8_t order);
/// Sets the SPI clock divider and therefore the /// Sets the SPI clock divider and therefore the
/// SPI clock speed. /// SPI clock speed.
/// \param[in] divider The desired SPI clock divider, one of BCM2835_SPI_CLOCK_DIVIDER_*, /// \param[in] divider The desired SPI clock divider, one of BCM2835_SPI_CLOCK_DIVIDER_*,
/// see \ref bcm2835SPIClockDivider /// see \ref bcm2835SPIClockDivider
extern void bcm2835_spi_setClockDivider(uint16_t divider); extern void bcm2835_spi_setClockDivider(uint16_t divider);
/// Sets the SPI data mode /// Sets the SPI data mode
/// Sets the clock polariy and phase /// Sets the clock polariy and phase
/// \param[in] mode The desired data mode, one of BCM2835_SPI_MODE*, /// \param[in] mode The desired data mode, one of BCM2835_SPI_MODE*,
/// see \ref bcm2835SPIMode /// see \ref bcm2835SPIMode
extern void bcm2835_spi_setDataMode(uint8_t mode); extern void bcm2835_spi_setDataMode(uint8_t mode);
/// Sets the chip select pin(s) /// Sets the chip select pin(s)
/// When an bcm2835_spi_transfer() is made, the selected pin(s) will be asserted during the /// When an bcm2835_spi_transfer() is made, the selected pin(s) will be asserted during the
/// transfer. /// transfer.
/// \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave. /// \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave.
/// One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect /// One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect
/// or one of One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect
extern void bcm2835_spi_chipSelect(uint8_t cs); extern void bcm2835_spi_chipSelect(uint8_t cs);
/// Sets the chip select pin polarity for a given pin /// Sets the chip select pin polarity for a given pin
/// When an bcm2835_spi_transfer() occurs, the currently selected chip select pin(s) /// When an bcm2835_spi_transfer() occurs, the currently selected chip select pin(s)
/// will be asserted to the /// will be asserted to the
/// value given by active. When transfers are not happening, the chip select pin(s) /// value given by active. When transfers are not happening, the chip select pin(s)
/// return to the complement (inactive) value. /// return to the complement (inactive) value.
/// \param[in] cs The chip select pin to affect /// \param[in] cs The chip select pin to affect
/// \param[in] active Whether the chip select pin is to be active HIGH /// \param[in] active Whether the chip select pin is to be active HIGH
extern void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active); extern void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active);
/// Transfers one byte to and from the currently selected SPI slave. /// Transfers one byte to and from the currently selected SPI slave.
/// Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) /// Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect)
/// during the transfer. /// during the transfer.
/// Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO. /// Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO.
/// Returns the read data byte from the slave. /// Returns the read data byte from the slave.
/// Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual /// Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual
/// \param[in] value The 8 bit data byte to write to MOSI /// \param[in] value The 8 bit data byte to write to MOSI
/// \return The 8 bit byte simultaneously read from MISO /// \return The 8 bit byte simultaneously read from MISO
/// \sa bcm2835_spi_transfern() /// \sa bcm2835_spi_transfern()
extern uint8_t bcm2835_spi_transfer(uint8_t value); extern uint8_t bcm2835_spi_transfer(uint8_t value);
/// Transfers any number of bytes to and from the currently selected SPI slave. /// Transfers any number of bytes to and from the currently selected SPI slave.
/// Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) /// Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect)
/// during the transfer. /// during the transfer.
/// Clocks the len 8 bit bytes out on MOSI, and simultaneously clocks in data from MISO. /// Clocks the len 8 bit bytes out on MOSI, and simultaneously clocks in data from MISO.
/// The data read read from the slave is placed into rbuf. rbuf must be at least len bytes long /// The data read read from the slave is placed into rbuf. rbuf must be at least len bytes long
/// Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual /// Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual
/// \param[in] tbuf Buffer of bytes to send. /// \param[in] tbuf Buffer of bytes to send.
/// \param[out] rbuf Received bytes will by put in this buffer /// \param[out] rbuf Received bytes will by put in this buffer
/// \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send/received /// \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send/received
/// \sa bcm2835_spi_transfer() /// \sa bcm2835_spi_transfer()
...@@ -1301,7 +1334,7 @@ extern "C" { ...@@ -1301,7 +1334,7 @@ extern "C" {
/// \param[in] micros Delay in microseconds /// \param[in] micros Delay in microseconds
extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros); extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros);
/// @} /// @}
/// \defgroup pwm Pulse Width Modulation /// \defgroup pwm Pulse Width Modulation
/// Allows control of 2 independent PWM channels. A limited subset of GPIO pins /// Allows control of 2 independent PWM channels. A limited subset of GPIO pins
...@@ -1310,12 +1343,12 @@ extern "C" { ...@@ -1310,12 +1343,12 @@ extern "C" {
/// documentation on the Main Page. /// documentation on the Main Page.
/// @{ /// @{
/// Sets the PWM clock divisor, /// Sets the PWM clock divisor,
/// to control the basic PWM pulse widths. /// to control the basic PWM pulse widths.
/// \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common /// \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common
/// values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider /// values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider
extern void bcm2835_pwm_set_clock(uint32_t divisor); extern void bcm2835_pwm_set_clock(uint32_t divisor);
/// Sets the mode of the given PWM channel, /// Sets the mode of the given PWM channel,
/// allowing you to control the PWM mode and enable/disable that channel /// allowing you to control the PWM mode and enable/disable that channel
/// \param[in] channel The PWM channel. 0 or 1. /// \param[in] channel The PWM channel. 0 or 1.
...@@ -1328,15 +1361,15 @@ extern "C" { ...@@ -1328,15 +1361,15 @@ extern "C" {
/// \param[in] channel The PWM channel. 0 or 1. /// \param[in] channel The PWM channel. 0 or 1.
/// \param[in] range The maximum value permitted for DATA. /// \param[in] range The maximum value permitted for DATA.
extern void bcm2835_pwm_set_range(uint8_t channel, uint32_t range); extern void bcm2835_pwm_set_range(uint8_t channel, uint32_t range);
/// Sets the PWM pulse ratio to emit to DATA/RANGE, /// Sets the PWM pulse ratio to emit to DATA/RANGE,
/// where RANGE is set by bcm2835_pwm_set_range(). /// where RANGE is set by bcm2835_pwm_set_range().
/// \param[in] channel The PWM channel. 0 or 1. /// \param[in] channel The PWM channel. 0 or 1.
/// \param[in] data Controls the PWM output ratio as a fraction of the range. /// \param[in] data Controls the PWM output ratio as a fraction of the range.
/// Can vary from 0 to RANGE. /// Can vary from 0 to RANGE.
extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data); extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data);
/// @} /// @}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
...@@ -1362,9 +1395,9 @@ extern "C" { ...@@ -1362,9 +1395,9 @@ extern "C" {
/// Shows how to use PWM to control GPIO pins /// Shows how to use PWM to control GPIO pins
/// @example i2c.c /// @example i2c.c
/// Command line utility for executing i2c commands with the /// Command line utility for executing i2c commands with the
/// Broadcom bcm2835. Contributed by Shahrooz Shahparnia. /// Broadcom bcm2835. Contributed by Shahrooz Shahparnia.
/// example gpio.c /// example gpio.c
/// Command line utility for executing gpio commands with the /// Command line utility for executing gpio commands with the
/// Broadcom bcm2835. Contributed by Shahrooz Shahparnia. /// Broadcom bcm2835. Contributed by Shahrooz Shahparnia.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment