mirror of
https://github.com/mysensors/MySensors.git
synced 2026-02-19 17:11:28 +01:00
RPI: Add support for RPI4 (#1364)
This commit is contained in:
2
Makefile
2
Makefile
@@ -26,7 +26,7 @@ GATEWAY_OBJECTS=$(patsubst %.c,$(BUILDDIR)/%.o,$(GATEWAY_C_SOURCES)) $(patsubst
|
||||
|
||||
INCLUDES=-I. -I./core -I./hal/architecture/Linux/drivers/core
|
||||
|
||||
ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836 BCM2837))
|
||||
ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836 BCM2837 BCM2711))
|
||||
BCM_C_SOURCES=$(wildcard hal/architecture/Linux/drivers/BCM/*.c)
|
||||
BCM_CPP_SOURCES=$(wildcard hal/architecture/Linux/drivers/BCM/*.cpp)
|
||||
GATEWAY_OBJECTS+=$(patsubst %.c,$(BUILDDIR)/%.o,$(BCM_C_SOURCES)) $(patsubst %.cpp,$(BUILDDIR)/%.o,$(BCM_CPP_SOURCES))
|
||||
|
||||
17
configure
vendored
17
configure
vendored
@@ -17,7 +17,7 @@ SPI driver options:
|
||||
Device path. [/dev/spidev0.0]
|
||||
|
||||
Building options:
|
||||
--soc=[BCM2835|BCM2836|BCM2837|AM33XX|A10|A13|A20|H3]
|
||||
--soc=[BCM2711|BCM2835|BCM2836|BCM2837|AM33XX|A10|A13|A20|H3]
|
||||
SoC type to be used. [configure autodetected]
|
||||
--cpu-flags=<CPUFLAGS> CPU defining/optimizing flags to be used. [configure autodetected]
|
||||
--extra-cflags=<CFLAGS> Extra C flags passed to C compilation. []
|
||||
@@ -183,6 +183,10 @@ function detect_machine {
|
||||
soc="BCM2837"
|
||||
tp="rpi3"
|
||||
;;
|
||||
3)
|
||||
soc="BCM2711"
|
||||
tp="rpi4"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
elif [[ $hardware == "BCM2708"* ]]; then
|
||||
@@ -261,6 +265,9 @@ function gcc_cpu_flags {
|
||||
BCM2837)
|
||||
flags="-march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard"
|
||||
;;
|
||||
BCM2711)
|
||||
flags="-march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard"
|
||||
;;
|
||||
AM33XX)
|
||||
flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard"
|
||||
;;
|
||||
@@ -557,7 +564,7 @@ if [ -z "${CPUFLAGS}" ]; then
|
||||
CPUFLAGS=$(gcc_cpu_flags $SOC)
|
||||
fi
|
||||
|
||||
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then
|
||||
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" || $SOC == "BCM2711" ]]; then
|
||||
CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS"
|
||||
else
|
||||
printf "${SECTION} Checking GPIO Sysfs.\n"
|
||||
@@ -570,7 +577,7 @@ fi
|
||||
|
||||
if [ -z "${SPI_DRIVER}" ]; then
|
||||
printf "${SECTION} Detecting SPI driver.\n"
|
||||
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then
|
||||
if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" || $SOC == "BCM2711" ]]; then
|
||||
SPI_DRIVER=BCM
|
||||
elif [[ $(eval 'ls /dev/spidev* 2>/dev/null') ]]; then
|
||||
SPI_DRIVER=SPIDEV
|
||||
@@ -585,8 +592,8 @@ fi
|
||||
if [ -n "${SPI_DRIVER}" ]; then
|
||||
case ${SPI_DRIVER} in
|
||||
BCM)
|
||||
if [[ $SOC != "BCM2835" && $SOC != "BCM2836" && $SOC != "BCM2837" ]]; then
|
||||
die "BCM SPI driver is only supported for SOCs BCM2835, BCM2836 or BCM2837" 5
|
||||
if [[ $SOC != "BCM2835" && $SOC != "BCM2836" && $SOC != "BCM2837" && $SOC != "BCM2711" ]]; then
|
||||
die "BCM SPI driver is only supported for SOCs BCM2835, BCM2836, BCM2837 or BCM2711" 5
|
||||
fi
|
||||
CPPFLAGS="-DLINUX_SPI_BCM $CPPFLAGS"
|
||||
;;
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
//
|
||||
// Author: Mike McCauley
|
||||
// Copyright (C) 2011-2013 Mike McCauley
|
||||
// $Id: bcm2835.c,v 1.23 2015/03/31 04:55:41 mikem Exp mikem $
|
||||
//
|
||||
// Modified September 2016 by Marcelo Aquino <marceloaqno@gmail.org>
|
||||
// $Id: bcm2835.c,v 1.27 2019/07/22 23:04:24 mikem Exp mikem $
|
||||
*/
|
||||
|
||||
|
||||
@@ -20,8 +18,6 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h> // For PRIu64
|
||||
#include "log.h"
|
||||
|
||||
#define BCK2835_LIBRARY_BUILD
|
||||
#include "bcm2835.h"
|
||||
@@ -59,18 +55,77 @@ volatile uint32_t *bcm2835_spi0 = (uint32_t *)MAP_FAILED;
|
||||
volatile uint32_t *bcm2835_bsc0 = (uint32_t *)MAP_FAILED;
|
||||
volatile uint32_t *bcm2835_bsc1 = (uint32_t *)MAP_FAILED;
|
||||
volatile uint32_t *bcm2835_st = (uint32_t *)MAP_FAILED;
|
||||
volatile uint32_t *bcm2835_aux = (uint32_t *)MAP_FAILED;
|
||||
volatile uint32_t *bcm2835_spi1 = (uint32_t *)MAP_FAILED;
|
||||
|
||||
|
||||
|
||||
/* 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
|
||||
// Instead it prints out what it _would_ do if debug were 0
|
||||
*/
|
||||
*/
|
||||
static uint8_t debug = 0;
|
||||
|
||||
/* RPI 4 has different pullup registers - we need to know if we have that type */
|
||||
|
||||
static uint8_t pud_type_rpi4 = 0;
|
||||
|
||||
/* RPI 4 has different pullup operation - make backwards compat */
|
||||
|
||||
static uint8_t pud_compat_setting = BCM2835_GPIO_PUD_OFF;
|
||||
|
||||
/* I2C The time needed to transmit one byte. In microseconds.
|
||||
*/
|
||||
static int i2c_byte_wait_us = 0;
|
||||
|
||||
/* SPI bit order. BCM2835 SPI0 only supports MSBFIRST, so we instead
|
||||
* have a software based bit reversal, based on a contribution by Damiano Benedetti
|
||||
*/
|
||||
static uint8_t bcm2835_spi_bit_order = BCM2835_SPI_BIT_ORDER_MSBFIRST;
|
||||
static uint8_t bcm2835_byte_reverse_table[] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
static uint8_t bcm2835_correct_order(uint8_t b)
|
||||
{
|
||||
if (bcm2835_spi_bit_order == BCM2835_SPI_BIT_ORDER_LSBFIRST) {
|
||||
return bcm2835_byte_reverse_table[b];
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Low level register access functions
|
||||
*/
|
||||
@@ -95,6 +150,11 @@ uint32_t* bcm2835_regbase(uint8_t regbase)
|
||||
return (uint32_t *)bcm2835_bsc0;
|
||||
case BCM2835_REGBASE_BSC1:
|
||||
return (uint32_t *)bcm2835_st;
|
||||
case BCM2835_REGBASE_AUX:
|
||||
return (uint32_t *)bcm2835_aux;
|
||||
case BCM2835_REGBASE_SPI1:
|
||||
return (uint32_t *)bcm2835_spi1;
|
||||
|
||||
}
|
||||
return (uint32_t *)MAP_FAILED;
|
||||
}
|
||||
@@ -114,11 +174,11 @@ unsigned int bcm2835_version(void)
|
||||
*/
|
||||
uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
|
||||
{
|
||||
uint32_t ret;
|
||||
if (debug) {
|
||||
printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr);
|
||||
printf("bcm2835_peri_read paddr %p\n", (void *) paddr);
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t ret;
|
||||
__sync_synchronize();
|
||||
ret = *paddr;
|
||||
__sync_synchronize();
|
||||
@@ -135,7 +195,7 @@ uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
|
||||
uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr)
|
||||
{
|
||||
if (debug) {
|
||||
printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr);
|
||||
printf("bcm2835_peri_read_nb paddr %p\n", paddr);
|
||||
return 0;
|
||||
} else {
|
||||
return *paddr;
|
||||
@@ -148,7 +208,7 @@ uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr)
|
||||
void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value)
|
||||
{
|
||||
if (debug) {
|
||||
printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value);
|
||||
printf("bcm2835_peri_write paddr %p, value %08X\n", paddr, value);
|
||||
} else {
|
||||
__sync_synchronize();
|
||||
*paddr = value;
|
||||
@@ -160,8 +220,8 @@ void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value)
|
||||
void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value)
|
||||
{
|
||||
if (debug) {
|
||||
printf("bcm2835_peri_write_nb paddr %08X, value %08X\n",
|
||||
(unsigned) paddr, value);
|
||||
printf("bcm2835_peri_write_nb paddr %p, value %08X\n",
|
||||
paddr, value);
|
||||
} else {
|
||||
*paddr = value;
|
||||
}
|
||||
@@ -380,8 +440,12 @@ void bcm2835_gpio_clr_afen(uint8_t pin)
|
||||
/* Set pullup/down */
|
||||
void bcm2835_gpio_pud(uint8_t pud)
|
||||
{
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4;
|
||||
bcm2835_peri_write(paddr, pud);
|
||||
if( pud_type_rpi4 ) {
|
||||
pud_compat_setting = pud;
|
||||
} else {
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4;
|
||||
bcm2835_peri_write(paddr, pud);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pullup/down clock
|
||||
@@ -389,9 +453,15 @@ void bcm2835_gpio_pud(uint8_t pud)
|
||||
*/
|
||||
void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on)
|
||||
{
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32;
|
||||
uint8_t shift = pin % 32;
|
||||
bcm2835_peri_write(paddr, (on ? 1 : 0) << shift);
|
||||
if( pud_type_rpi4 ) {
|
||||
if( on ) {
|
||||
bcm2835_gpio_set_pud( pin, pud_compat_setting);
|
||||
}
|
||||
} else {
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32;
|
||||
uint8_t shift = pin % 32;
|
||||
bcm2835_peri_write(paddr, (on ? 1 : 0) << shift);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read GPIO pad behaviour for groups of GPIOs */
|
||||
@@ -439,7 +509,7 @@ void bcm2835_delayMicroseconds(uint64_t micros)
|
||||
|
||||
if (debug) {
|
||||
/* Cant access sytem timers in debug mode */
|
||||
printf("bcm2835_delayMicroseconds %" PRIu64 "\n", micros);
|
||||
printf("bcm2835_delayMicroseconds %lld\n", (long long int) micros);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -448,6 +518,14 @@ void bcm2835_delayMicroseconds(uint64_t micros)
|
||||
*/
|
||||
start = bcm2835_st_read();
|
||||
|
||||
/* Not allowed to access timer registers (result is not as precise)*/
|
||||
if (start==0) {
|
||||
t1.tv_sec = 0;
|
||||
t1.tv_nsec = 1000 * (long)(micros);
|
||||
nanosleep(&t1, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (micros > 450) {
|
||||
t1.tv_sec = 0;
|
||||
t1.tv_nsec = 1000 * (long)(micros - 200);
|
||||
@@ -505,17 +583,79 @@ void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask)
|
||||
// 6. Write to GPPUDCLK0/1 to remove the clock
|
||||
//
|
||||
// RPi has P1-03 and P1-05 with 1k8 pullup resistor
|
||||
//
|
||||
// RPI 4 uses a different PUD method - no clock
|
||||
|
||||
*/
|
||||
void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud)
|
||||
{
|
||||
bcm2835_gpio_pud(pud);
|
||||
delayMicroseconds(10);
|
||||
bcm2835_gpio_pudclk(pin, 1);
|
||||
delayMicroseconds(10);
|
||||
bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF);
|
||||
bcm2835_gpio_pudclk(pin, 0);
|
||||
if( pud_type_rpi4 ) {
|
||||
int shiftbits = (pin & 0xf) << 1;
|
||||
uint32_t bits;
|
||||
uint32_t pull;
|
||||
|
||||
switch (pud) {
|
||||
case BCM2835_GPIO_PUD_OFF:
|
||||
pull = 0;
|
||||
break;
|
||||
case BCM2835_GPIO_PUD_UP:
|
||||
pull = 1;
|
||||
break;
|
||||
case BCM2835_GPIO_PUD_DOWN:
|
||||
pull = 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUPPDN0/4 + (pin >> 4);
|
||||
|
||||
bits = bcm2835_peri_read_nb( paddr );
|
||||
bits &= ~(3 << shiftbits);
|
||||
bits |= (pull << shiftbits);
|
||||
|
||||
bcm2835_peri_write_nb( paddr, bits );
|
||||
|
||||
} else {
|
||||
bcm2835_gpio_pud(pud);
|
||||
delayMicroseconds(10);
|
||||
bcm2835_gpio_pudclk(pin, 1);
|
||||
delayMicroseconds(10);
|
||||
bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF);
|
||||
bcm2835_gpio_pudclk(pin, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint8_t bcm2835_gpio_get_pud(uint8_t pin)
|
||||
{
|
||||
uint8_t ret = BCM2835_GPIO_PUD_ERROR;
|
||||
|
||||
if( pud_type_rpi4 ) {
|
||||
uint32_t bits;
|
||||
volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUPPDN0/4 + (pin >> 4);
|
||||
bits = (bcm2835_peri_read_nb( paddr ) >> ((pin & 0xf)<<1)) & 0x3;
|
||||
|
||||
switch (bits) {
|
||||
case 0:
|
||||
ret = BCM2835_GPIO_PUD_OFF;
|
||||
break;
|
||||
case 1:
|
||||
ret = BCM2835_GPIO_PUD_UP;
|
||||
break;
|
||||
case 2:
|
||||
ret = BCM2835_GPIO_PUD_DOWN;
|
||||
break;
|
||||
default:
|
||||
ret = BCM2835_GPIO_PUD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int bcm2835_spi_begin(void)
|
||||
{
|
||||
volatile uint32_t* paddr;
|
||||
@@ -551,9 +691,9 @@ void bcm2835_spi_end(void)
|
||||
bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */
|
||||
}
|
||||
|
||||
void bcm2835_spi_setBitOrder(uint8_t __attribute__((unused)) order)
|
||||
void bcm2835_spi_setBitOrder(uint8_t order)
|
||||
{
|
||||
/* BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one supported by SPI0 */
|
||||
bcm2835_spi_bit_order = order;
|
||||
}
|
||||
|
||||
/* defaults to 0, which means a divider of 65536.
|
||||
@@ -567,6 +707,13 @@ void bcm2835_spi_setClockDivider(uint16_t divider)
|
||||
bcm2835_peri_write(paddr, divider);
|
||||
}
|
||||
|
||||
void bcm2835_spi_set_speed_hz(uint32_t speed_hz)
|
||||
{
|
||||
uint16_t divider = (uint16_t) ((uint32_t) BCM2835_CORE_CLK_HZ / speed_hz);
|
||||
divider &= 0xFFFE;
|
||||
bcm2835_spi_setClockDivider(divider);
|
||||
}
|
||||
|
||||
void bcm2835_spi_setDataMode(uint8_t mode)
|
||||
{
|
||||
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
|
||||
@@ -596,14 +743,14 @@ uint8_t bcm2835_spi_transfer(uint8_t value)
|
||||
;
|
||||
|
||||
/* Write to FIFO, no barrier */
|
||||
bcm2835_peri_write_nb(fifo, value);
|
||||
bcm2835_peri_write_nb(fifo, bcm2835_correct_order(value));
|
||||
|
||||
/* Wait for DONE to be set */
|
||||
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
|
||||
;
|
||||
|
||||
/* Read any byte that was sent back by the slave while we sere sending to it */
|
||||
ret = bcm2835_peri_read_nb(fifo);
|
||||
ret = bcm2835_correct_order(bcm2835_peri_read_nb(fifo));
|
||||
|
||||
/* Set TA = 0, and also set the barrier */
|
||||
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
|
||||
@@ -634,12 +781,12 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
while((TXCnt < len)||(RXCnt < len)) {
|
||||
/* TX fifo not full, so add some more bytes */
|
||||
while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) {
|
||||
bcm2835_peri_write_nb(fifo, tbuf[TXCnt]);
|
||||
bcm2835_peri_write_nb(fifo, bcm2835_correct_order(tbuf[TXCnt]));
|
||||
TXCnt++;
|
||||
}
|
||||
/* Rx fifo not empty, so get the next received bytes */
|
||||
while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) {
|
||||
rbuf[RXCnt] = bcm2835_peri_read_nb(fifo);
|
||||
rbuf[RXCnt] = bcm2835_correct_order(bcm2835_peri_read_nb(fifo));
|
||||
RXCnt++;
|
||||
}
|
||||
}
|
||||
@@ -652,7 +799,7 @@ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
}
|
||||
|
||||
/* Writes an number of bytes to SPI */
|
||||
void bcm2835_spi_writenb(char* tbuf, uint32_t len)
|
||||
void bcm2835_spi_writenb(const char* tbuf, uint32_t len)
|
||||
{
|
||||
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
|
||||
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
|
||||
@@ -676,7 +823,7 @@ void bcm2835_spi_writenb(char* tbuf, uint32_t len)
|
||||
;
|
||||
|
||||
/* Write to FIFO, no barrier */
|
||||
bcm2835_peri_write_nb(fifo, tbuf[i]);
|
||||
bcm2835_peri_write_nb(fifo, bcm2835_correct_order(tbuf[i]));
|
||||
|
||||
/* Read from FIFO to prevent stalling */
|
||||
while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) {
|
||||
@@ -718,6 +865,279 @@ void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active)
|
||||
bcm2835_peri_set_bits(paddr, active << shift, 1 << shift);
|
||||
}
|
||||
|
||||
void bcm2835_spi_write(uint16_t data)
|
||||
{
|
||||
#if 0
|
||||
char buf[2];
|
||||
|
||||
buf[0] = data >> 8;
|
||||
buf[1] = data & 0xFF;
|
||||
|
||||
bcm2835_spi_transfern(buf, 2);
|
||||
#else
|
||||
volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4;
|
||||
volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4;
|
||||
|
||||
/* Clear TX and RX fifos */
|
||||
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
|
||||
|
||||
/* Set TA = 1 */
|
||||
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
|
||||
|
||||
/* Maybe wait for TXD */
|
||||
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
|
||||
;
|
||||
|
||||
/* Write to FIFO */
|
||||
bcm2835_peri_write_nb(fifo, (uint32_t) data >> 8);
|
||||
bcm2835_peri_write_nb(fifo, data & 0xFF);
|
||||
|
||||
|
||||
/* Wait for DONE to be set */
|
||||
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
|
||||
;
|
||||
|
||||
/* Set TA = 0, and also set the barrier */
|
||||
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
|
||||
#endif
|
||||
}
|
||||
|
||||
int bcm2835_aux_spi_begin(void)
|
||||
{
|
||||
volatile uint32_t* enable = bcm2835_aux + BCM2835_AUX_ENABLE/4;
|
||||
volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4;
|
||||
volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4;
|
||||
|
||||
if (bcm2835_spi1 == MAP_FAILED) {
|
||||
return 0; /* bcm2835_init() failed, or not root */
|
||||
}
|
||||
|
||||
/* Set the SPI pins to the Alt 4 function to enable SPI1 access on them */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_36, BCM2835_GPIO_FSEL_ALT4); /* SPI1_CE2_N */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_35, BCM2835_GPIO_FSEL_ALT4); /* SPI1_MISO */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_38, BCM2835_GPIO_FSEL_ALT4); /* SPI1_MOSI */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_40, BCM2835_GPIO_FSEL_ALT4); /* SPI1_SCLK */
|
||||
|
||||
bcm2835_aux_spi_setClockDivider(bcm2835_aux_spi_CalcClockDivider(1000000)); // Default 1MHz SPI
|
||||
|
||||
bcm2835_peri_write(enable, BCM2835_AUX_ENABLE_SPI0);
|
||||
bcm2835_peri_write(cntl1, 0);
|
||||
bcm2835_peri_write(cntl0, BCM2835_AUX_SPI_CNTL0_CLEARFIFO);
|
||||
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
void bcm2835_aux_spi_end(void)
|
||||
{
|
||||
/* Set all the SPI1 pins back to input */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_36, BCM2835_GPIO_FSEL_INPT); /* SPI1_CE2_N */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_35, BCM2835_GPIO_FSEL_INPT); /* SPI1_MISO */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_38, BCM2835_GPIO_FSEL_INPT); /* SPI1_MOSI */
|
||||
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_40, BCM2835_GPIO_FSEL_INPT); /* SPI1_SCLK */
|
||||
}
|
||||
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
|
||||
uint16_t bcm2835_aux_spi_CalcClockDivider(uint32_t speed_hz)
|
||||
{
|
||||
uint16_t divider;
|
||||
|
||||
if (speed_hz < (uint32_t) BCM2835_AUX_SPI_CLOCK_MIN) {
|
||||
speed_hz = (uint32_t) BCM2835_AUX_SPI_CLOCK_MIN;
|
||||
} else if (speed_hz > (uint32_t) BCM2835_AUX_SPI_CLOCK_MAX) {
|
||||
speed_hz = (uint32_t) BCM2835_AUX_SPI_CLOCK_MAX;
|
||||
}
|
||||
|
||||
divider = (uint16_t) DIV_ROUND_UP(BCM2835_CORE_CLK_HZ, 2 * speed_hz) - 1;
|
||||
|
||||
if (divider > (uint16_t) BCM2835_AUX_SPI_CNTL0_SPEED_MAX) {
|
||||
return (uint16_t) BCM2835_AUX_SPI_CNTL0_SPEED_MAX;
|
||||
}
|
||||
|
||||
return divider;
|
||||
}
|
||||
|
||||
static uint32_t spi1_speed;
|
||||
|
||||
void bcm2835_aux_spi_setClockDivider(uint16_t divider)
|
||||
{
|
||||
spi1_speed = (uint32_t) divider;
|
||||
}
|
||||
|
||||
void bcm2835_aux_spi_write(uint16_t data)
|
||||
{
|
||||
volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4;
|
||||
volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4;
|
||||
volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4;
|
||||
volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4;
|
||||
|
||||
uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT);
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
|
||||
_cntl0 |= 16; // Shift length
|
||||
|
||||
bcm2835_peri_write(cntl0, _cntl0);
|
||||
bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN);
|
||||
|
||||
while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL)
|
||||
;
|
||||
|
||||
bcm2835_peri_write(io, (uint32_t) data << 16);
|
||||
}
|
||||
|
||||
void bcm2835_aux_spi_writenb(const char *tbuf, uint32_t len)
|
||||
{
|
||||
volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4;
|
||||
volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4;
|
||||
volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4;
|
||||
volatile uint32_t* txhold = bcm2835_spi1 + BCM2835_AUX_SPI_TXHOLD/4;
|
||||
volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4;
|
||||
|
||||
char *tx = (char *) tbuf;
|
||||
uint32_t tx_len = len;
|
||||
uint32_t count;
|
||||
uint32_t data;
|
||||
uint32_t i;
|
||||
uint8_t byte;
|
||||
|
||||
uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT);
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_VAR_WIDTH;
|
||||
|
||||
bcm2835_peri_write(cntl0, _cntl0);
|
||||
bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN);
|
||||
|
||||
while (tx_len > 0) {
|
||||
|
||||
while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL)
|
||||
;
|
||||
|
||||
count = MIN(tx_len, 3);
|
||||
data = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
byte = (tx != NULL) ? (uint8_t) *tx++ : (uint8_t) 0;
|
||||
data |= byte << (8 * (2 - i));
|
||||
}
|
||||
|
||||
data |= (count * 8) << 24;
|
||||
tx_len -= count;
|
||||
|
||||
if (tx_len != 0) {
|
||||
bcm2835_peri_write(txhold, data);
|
||||
} else {
|
||||
bcm2835_peri_write(io, data);
|
||||
}
|
||||
|
||||
while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_BUSY)
|
||||
;
|
||||
|
||||
(void) bcm2835_peri_read(io);
|
||||
}
|
||||
}
|
||||
|
||||
void bcm2835_aux_spi_transfernb(const char *tbuf, char *rbuf, uint32_t len)
|
||||
{
|
||||
volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4;
|
||||
volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4;
|
||||
volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4;
|
||||
volatile uint32_t* txhold = bcm2835_spi1 + BCM2835_AUX_SPI_TXHOLD/4;
|
||||
volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4;
|
||||
|
||||
char *tx = (char *)tbuf;
|
||||
char *rx = (char *)rbuf;
|
||||
uint32_t tx_len = len;
|
||||
uint32_t rx_len = len;
|
||||
uint32_t count;
|
||||
uint32_t data;
|
||||
uint32_t i;
|
||||
uint8_t byte;
|
||||
|
||||
uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT);
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
|
||||
_cntl0 |= BCM2835_AUX_SPI_CNTL0_VAR_WIDTH;
|
||||
|
||||
bcm2835_peri_write(cntl0, _cntl0);
|
||||
bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN);
|
||||
|
||||
while ((tx_len > 0) || (rx_len > 0)) {
|
||||
|
||||
while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL) && (tx_len > 0)) {
|
||||
count = MIN(tx_len, 3);
|
||||
data = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
byte = (tx != NULL) ? (uint8_t) *tx++ : (uint8_t) 0;
|
||||
data |= byte << (8 * (2 - i));
|
||||
}
|
||||
|
||||
data |= (count * 8) << 24;
|
||||
tx_len -= count;
|
||||
|
||||
if (tx_len != 0) {
|
||||
bcm2835_peri_write(txhold, data);
|
||||
} else {
|
||||
bcm2835_peri_write(io, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_RX_EMPTY) && (rx_len > 0)) {
|
||||
count = MIN(rx_len, 3);
|
||||
data = bcm2835_peri_read(io);
|
||||
|
||||
if (rbuf != NULL) {
|
||||
switch (count) {
|
||||
case 3:
|
||||
*rx++ = (char)((data >> 16) & 0xFF);
|
||||
/*@fallthrough@*/
|
||||
/* no break */
|
||||
case 2:
|
||||
*rx++ = (char)((data >> 8) & 0xFF);
|
||||
/*@fallthrough@*/
|
||||
/* no break */
|
||||
case 1:
|
||||
*rx++ = (char)((data >> 0) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
rx_len -= count;
|
||||
}
|
||||
|
||||
while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_BUSY) && (rx_len > 0)) {
|
||||
count = MIN(rx_len, 3);
|
||||
data = bcm2835_peri_read(io);
|
||||
|
||||
if (rbuf != NULL) {
|
||||
switch (count) {
|
||||
case 3:
|
||||
*rx++ = (char)((data >> 16) & 0xFF);
|
||||
/*@fallthrough@*/
|
||||
/* no break */
|
||||
case 2:
|
||||
*rx++ = (char)((data >> 8) & 0xFF);
|
||||
/*@fallthrough@*/
|
||||
/* no break */
|
||||
case 1:
|
||||
*rx++ = (char)((data >> 0) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
rx_len -= count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bcm2835_aux_spi_transfern(char *buf, uint32_t len)
|
||||
{
|
||||
bcm2835_aux_spi_transfernb(buf, buf, len);
|
||||
}
|
||||
|
||||
int bcm2835_i2c_begin(void)
|
||||
{
|
||||
uint16_t cdiv;
|
||||
@@ -898,7 +1318,7 @@ uint8_t bcm2835_i2c_read(char* buf, uint32_t len)
|
||||
/* wait for transfer to complete */
|
||||
while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) {
|
||||
/* we must empty the FIFO as it is populated and not use any delay */
|
||||
while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) {
|
||||
while (remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) {
|
||||
/* Read from FIFO, no barrier */
|
||||
buf[i] = bcm2835_peri_read_nb(fifo);
|
||||
i++;
|
||||
@@ -1122,6 +1542,11 @@ uint64_t bcm2835_st_read(void)
|
||||
volatile uint32_t* paddr;
|
||||
uint32_t hi, lo;
|
||||
uint64_t st;
|
||||
|
||||
if (bcm2835_st==MAP_FAILED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
paddr = bcm2835_st + BCM2835_ST_CHI/4;
|
||||
hi = bcm2835_peri_read(paddr);
|
||||
|
||||
@@ -1259,7 +1684,7 @@ 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);
|
||||
if (map == MAP_FAILED) {
|
||||
logError("bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
|
||||
fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -1291,22 +1716,58 @@ int bcm2835_init(void)
|
||||
bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4;
|
||||
bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4;
|
||||
bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4;
|
||||
bcm2835_aux = bcm2835_peripherals + BCM2835_AUX_BASE/4;
|
||||
bcm2835_spi1 = bcm2835_peripherals + BCM2835_SPI1_BASE/4;
|
||||
|
||||
return 1; /* Success */
|
||||
}
|
||||
|
||||
/* Figure out the base and size of the peripheral address block
|
||||
// using the device-tree. Required for RPi2, optional for RPi 1
|
||||
// using the device-tree. Required for RPi2/3/4, optional for RPi 1
|
||||
*/
|
||||
if ((fp = fopen(BMC2835_RPI2_DT_FILENAME, "rb"))) {
|
||||
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);
|
||||
unsigned char buf[16];
|
||||
uint32_t base_address;
|
||||
uint32_t peri_size;
|
||||
if (fread(buf, 1, sizeof(buf), fp) >= 8) {
|
||||
base_address = (buf[4] << 24) |
|
||||
(buf[5] << 16) |
|
||||
(buf[6] << 8) |
|
||||
(buf[7] << 0);
|
||||
|
||||
peri_size = (buf[8] << 24) |
|
||||
(buf[9] << 16) |
|
||||
(buf[10] << 8) |
|
||||
(buf[11] << 0);
|
||||
|
||||
if (!base_address) {
|
||||
/* looks like RPI 4 */
|
||||
base_address = (buf[8] << 24) |
|
||||
(buf[9] << 16) |
|
||||
(buf[10] << 8) |
|
||||
(buf[11] << 0);
|
||||
|
||||
peri_size = (buf[12] << 24) |
|
||||
(buf[13] << 16) |
|
||||
(buf[14] << 8) |
|
||||
(buf[15] << 0);
|
||||
}
|
||||
/* check for valid known range formats */
|
||||
if ((buf[0] == 0x7e) &&
|
||||
(buf[1] == 0x00) &&
|
||||
(buf[2] == 0x00) &&
|
||||
(buf[3] == 0x00) &&
|
||||
((base_address == BCM2835_PERI_BASE) || (base_address == BCM2835_RPI2_PERI_BASE) ||
|
||||
(base_address == BCM2835_RPI4_PERI_BASE))) {
|
||||
bcm2835_peripherals_base = (uint32_t *)base_address;
|
||||
bcm2835_peripherals_size = peri_size;
|
||||
if( base_address == BCM2835_RPI4_PERI_BASE ) {
|
||||
pud_type_rpi4 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
/* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */
|
||||
@@ -1321,14 +1782,14 @@ int bcm2835_init(void)
|
||||
if (geteuid() == 0) {
|
||||
/* Open the master /dev/mem device */
|
||||
if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
|
||||
logError("bcm2835_init: Unable to open /dev/mem: %s\n",
|
||||
strerror(errno)) ;
|
||||
fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n",
|
||||
strerror(errno)) ;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Base of the peripherals block is mapped to VM */
|
||||
bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd,
|
||||
(uint32_t)bcm2835_peripherals_base);
|
||||
(off_t)bcm2835_peripherals_base);
|
||||
if (bcm2835_peripherals == MAP_FAILED) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -1345,21 +1806,23 @@ int bcm2835_init(void)
|
||||
bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */
|
||||
bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */
|
||||
bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4;
|
||||
bcm2835_aux = bcm2835_peripherals + BCM2835_AUX_BASE/4;
|
||||
bcm2835_spi1 = bcm2835_peripherals + BCM2835_SPI1_BASE/4;
|
||||
|
||||
ok = 1;
|
||||
} else {
|
||||
/* Not root, try /dev/gpiomem */
|
||||
/* Open the master /dev/mem device */
|
||||
if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) {
|
||||
logError("bcm2835_init: Unable to open /dev/gpiomem: %s\n",
|
||||
strerror(errno)) ;
|
||||
fprintf(stderr, "bcm2835_init: Unable to open /dev/gpiomem: %s\n",
|
||||
strerror(errno)) ;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Base of the peripherals block is mapped to VM */
|
||||
bcm2835_peripherals_base = 0;
|
||||
bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd,
|
||||
(uint32_t)bcm2835_peripherals_base);
|
||||
(off_t)bcm2835_peripherals_base);
|
||||
if (bcm2835_peripherals == MAP_FAILED) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -1396,6 +1859,8 @@ int bcm2835_close(void)
|
||||
bcm2835_bsc0 = MAP_FAILED;
|
||||
bcm2835_bsc1 = MAP_FAILED;
|
||||
bcm2835_st = MAP_FAILED;
|
||||
bcm2835_aux = MAP_FAILED;
|
||||
bcm2835_spi1 = MAP_FAILED;
|
||||
return 1; /* Success */
|
||||
}
|
||||
|
||||
@@ -1478,3 +1943,6 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
|
||||
Author: Mike McCauley
|
||||
Copyright (C) 2011-2013 Mike McCauley
|
||||
$Id: bcm2835.h,v 1.20 2015/03/31 04:55:41 mikem Exp mikem $
|
||||
$Id: bcm2835.h,v 1.25 2019/07/22 23:04:13 mikem Exp $
|
||||
*/
|
||||
|
||||
/*! \defgroup BCM2835grp C library for Broadcom BCM 2835 as used in Raspberry Pi
|
||||
\ingroup internals
|
||||
|
||||
This is a C library for Raspberry Pi (RPi). It provides access to
|
||||
GPIO and other IO functions on the Broadcom BCM 2835 chip,
|
||||
GPIO and other IO functions on the Broadcom BCM 2835 chip, as used in the RaspberryPi,
|
||||
allowing access to the GPIO pins on the
|
||||
26 pin IDE plug on the RPi board so you can control and interface with various external devices.
|
||||
|
||||
@@ -19,12 +18,15 @@
|
||||
and for accessing the system timers.
|
||||
Pin event detection is supported by polling (interrupts are not supported).
|
||||
|
||||
Works on all versions upt to and including RPI 4.
|
||||
Works with all versions of Debian up to and including Debian Buster 10.
|
||||
|
||||
It is C++ compatible, and installs as a header file and non-shared library on
|
||||
any Linux-based distro (but clearly is no use except on Raspberry Pi or another board with
|
||||
BCM 2835).
|
||||
|
||||
The version of the package that this documentation refers to can be downloaded
|
||||
from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz
|
||||
from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.60.tar.gz
|
||||
You can find the latest version at http://www.airspayce.com/mikem/bcm2835
|
||||
|
||||
Several example programs are provided.
|
||||
@@ -36,7 +38,10 @@
|
||||
You can also find online help and discussion at http://groups.google.com/group/bcm2835
|
||||
Please use that group for all questions and discussions on this topic.
|
||||
Do not contact the author directly, unless it is to discuss commercial licensing.
|
||||
Before asking a question or reporting a bug, please read http://www.catb.org/esr/faqs/smart-questions.html
|
||||
Before asking a question or reporting a bug, please read
|
||||
- http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/How_to_ask_a_software_question
|
||||
- http://www.catb.org/esr/faqs/smart-questions.html
|
||||
- http://www.chiark.greenend.org.uk/~shgtatham/bugs.html
|
||||
|
||||
Tested on debian6-19-04-2012, 2012-07-15-wheezy-raspbian, 2013-07-26-wheezy-raspbian
|
||||
and Occidentalisv01, 2016-02-09 Raspbian Jessie.
|
||||
@@ -107,6 +112,8 @@
|
||||
bcm2835_st
|
||||
bcm2835_bsc0
|
||||
bcm2835_bsc1
|
||||
bcm2835_aux
|
||||
bcm2835_spi1
|
||||
|
||||
\par Raspberry Pi 2 (RPI2)
|
||||
|
||||
@@ -161,6 +168,22 @@
|
||||
- P1-24 (CE0)
|
||||
- P1-26 (CE1)
|
||||
|
||||
Although it is possible to select high speeds for the SPI interface, up to 125MHz (see bcm2835_spi_setClockDivider())
|
||||
you should not expect to actually achieve those sorts of speeds with the RPi wiring. Our tests on RPi 2 show that the
|
||||
SPI CLK line when unloaded has a resonant frequency of about 40MHz, and when loaded, the MOSI and MISO lines
|
||||
ring at an even lower frequency. Measurements show that SPI waveforms are very poor and unusable at 62 and 125MHz.
|
||||
Dont expect any speed faster than 31MHz to work reliably.
|
||||
|
||||
The bcm2835_aux_spi_* functions allow you to control the BCM 2835 SPI1 interface,
|
||||
allowing you to send and received data by SPI (Serial Peripheral Interface).
|
||||
|
||||
The Raspberry Pi GPIO pins used for AUX SPI (SPI1) are:
|
||||
|
||||
- P1-38 (MOSI)
|
||||
- P1-35 (MISO)
|
||||
- P1-40 (CLK)
|
||||
- P1-36 (CE2)
|
||||
|
||||
\par I2C Pins
|
||||
|
||||
The bcm2835_i2c_* functions allow you to control the BCM 2835 BSC interface,
|
||||
@@ -216,7 +239,7 @@
|
||||
clock divider to be 16, and the RANGE to 1024. The pulse repetition frequency will be
|
||||
1.2MHz/1024 = 1171.875Hz.
|
||||
|
||||
\par SPI
|
||||
\par Interactions with other systems
|
||||
|
||||
In order for bcm2835 library SPI to work, you may need to disable the SPI kernel module using:
|
||||
|
||||
@@ -227,6 +250,20 @@
|
||||
Reboot.
|
||||
\endcode
|
||||
|
||||
Since bcm2835 accesses the lowest level hardware interfaces (in eh intererests of speed and flexibility)
|
||||
there can be intercations with other low level software trying to do similar things.
|
||||
|
||||
It seems that with "latest" 8.0 Jessie 4.9.24-v7+ kernel PWM just won't
|
||||
work unless you disable audio. There's a line
|
||||
\code
|
||||
dtparam=audio=on
|
||||
\endcode
|
||||
in the /boot/config.txt.
|
||||
Comment it out like this:
|
||||
\code
|
||||
#dtparam=audio=on
|
||||
\endcode
|
||||
|
||||
\par Real Time performance constraints
|
||||
|
||||
The bcm2835 is a library for user programs (i.e. they run in 'userland').
|
||||
@@ -241,6 +278,9 @@
|
||||
Arjan reports that you can prevent swapping on Linux with the following code fragment:
|
||||
|
||||
\code
|
||||
#define <sched.h>
|
||||
#define <sys/mman.h>
|
||||
|
||||
struct sched_param sp;
|
||||
memset(&sp, 0, sizeof(sp));
|
||||
sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
@@ -248,6 +288,15 @@
|
||||
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
\endcode
|
||||
|
||||
\par Crashing on some versions of Raspbian
|
||||
Some people have reported that various versions of Rasbian will crash or hang
|
||||
if certain GPIO pins are toggled: https://github.com/raspberrypi/linux/issues/2550
|
||||
when using bcm2835.
|
||||
A workaround is to add this line to your /boot/config.txt:
|
||||
\code
|
||||
dtoverlay=gpio-no-irq
|
||||
\endcode
|
||||
|
||||
\par Bindings to other languages
|
||||
|
||||
mikem has made Perl bindings available at CPAN:
|
||||
@@ -266,7 +315,13 @@
|
||||
the right to share who uses it. If you wish to use this software under Open
|
||||
Source Licensing, you must contribute all your source code to the open source
|
||||
community in accordance with the GPL Version 2 when your application is
|
||||
distributed. See http://www.gnu.org/copyleft/gpl.html and COPYING
|
||||
distributed. See https://www.gnu.org/licenses/gpl-2.0.html and COPYING
|
||||
|
||||
\par Commercial Licensing
|
||||
|
||||
This is the appropriate option if you are creating proprietary applications
|
||||
and you are not prepared to distribute and share the source code of your
|
||||
application. To purchase a commercial license, contact info@airspayce.com
|
||||
|
||||
\par Acknowledgements
|
||||
|
||||
@@ -368,7 +423,7 @@
|
||||
|
||||
\version 1.27 bcm2835_gpio_set_pad() no longer needs BCM2835_PAD_PASSWRD: it is
|
||||
now automatically included.
|
||||
Added suport for PWM mode with bcm2835_pwm_* functions.
|
||||
Added support for PWM mode with bcm2835_pwm_* functions.
|
||||
|
||||
\version 1.28 Fixed a problem where bcm2835_spi_writenb() would have problems with transfers of more than
|
||||
64 bytes dues to read buffer filling. Patched by Peter Würtz.
|
||||
@@ -403,7 +458,7 @@
|
||||
|
||||
\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>
|
||||
Unnecessary '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>
|
||||
|
||||
@@ -425,13 +480,13 @@
|
||||
Testing on RPI 2, with ArchLinuxARM-rpi-2-latest and 2015-02-16-raspbian-wheezy.<br>
|
||||
|
||||
\version 1.44 Added documention about the need for device tree to be enabled on RPI2.<br>
|
||||
Improvements to detection of availablity of DMB instruction based on value of __ARM_ARCH macro.<br>
|
||||
Improvements to detection of availability of DMB instruction based on value of __ARM_ARCH macro.<br>
|
||||
|
||||
\version 1.45 Fixed an error in the pad group offsets that would prevent bcm2835_gpio_set_pad()
|
||||
and bcm2835_gpio_pad() working correctly with non-0 pad groups. Reported by Guido.
|
||||
|
||||
\version 1.46 2015-09-18
|
||||
Added symbolic definitions for remaining pins on 40 pin GPIO header on RPi 2. <br>
|
||||
Added symbolic definitions for remaining pins on 40 pin GPIO header on RPi 2. <br>
|
||||
|
||||
\version 1.47 2015-11-18
|
||||
Fixed possibly incorrect reads in bcm2835_i2c_read_register_rs, patch from Eckhardt Ulrich.<br>
|
||||
@@ -449,10 +504,45 @@
|
||||
(which prevents access to the SPI and I2C peripherals, amongst others).
|
||||
Testing on Raspbian Jessie.
|
||||
|
||||
\version 1.51 2016-11-03
|
||||
Added documentation about SPI clock divider and resulting SPI speeds on RPi3.
|
||||
Fixed a problem where seg fault could occur in bcm2835_delayMicroseconds() if not running as root. Patch from Pok.
|
||||
|
||||
\version 1.52 2017-02-03
|
||||
Added link to commercial license purchasing.
|
||||
|
||||
\version 1.53 2018-01-14
|
||||
Added support for AUX SPI (SPI1)
|
||||
Contributed by Arjan van Vught (http://www.raspberrypi-dmx.org/)
|
||||
|
||||
\version 1.54 2018-01-17
|
||||
Fixed compile errors in new AUX spi code under some circumstances.
|
||||
|
||||
\version 1.55 2018-01-20
|
||||
Fixed version numbers.
|
||||
Fixed some warnings.
|
||||
|
||||
\version 1.56 2018-06-10
|
||||
Supports bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST), after which SPI bytes are reversed on read or write.
|
||||
Based on a suggestion by Damiano Benedetti.
|
||||
|
||||
\version 1.57 2018-08-28
|
||||
Added SPI function bcm2835_spi_set_speed_hz(uint32_t speed_hz);
|
||||
Contributed by Arjan van Vught (http://www.raspberrypi-dmx.org/)
|
||||
|
||||
\version 1.58 2018-11-29
|
||||
Added examples/spiram, which shows how to use the included little library (spiram.c and spiram.h)
|
||||
to read and write SPI RAM chips such as 23K256-I/P
|
||||
|
||||
\version 1.59 2019-05-22
|
||||
Fixed a bug in bcm2835_i2c_read reported by Charles Hayward where a noisy I2C line cold cause a seg fault by
|
||||
reading too many characters.
|
||||
|
||||
\version 1.60 2019-07-23
|
||||
Applied patch from Mark Dootson for RPi 4 compatibility. Thanks Mark. Not tested here on RPi4, but others report it works.
|
||||
Tested as still working correctly on earlier RPi models. Tested with Debian Buster on earlier models
|
||||
|
||||
\author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS
|
||||
|
||||
|
||||
Modified September 2016 by Marcelo Aquino <marceloaqno@gmail.org>
|
||||
*/
|
||||
|
||||
|
||||
@@ -462,7 +552,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BCM2835_VERSION 10050 /* Version 1.50 */
|
||||
#define BCM2835_VERSION 10060 /* Version 1.60 */
|
||||
|
||||
/* RPi 2 is ARM v7, and has DMB instruction for memory barriers.
|
||||
Older RPis are ARM v6 and don't, so a coprocessor instruction must be used instead.
|
||||
@@ -473,8 +563,7 @@
|
||||
#define BCM2835_HAVE_DMB
|
||||
#endif
|
||||
|
||||
/*! \defgroup BCM2835constantsgrp Constants for passing to and from library functions
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup constants Constants for passing to and from library functions
|
||||
The values here are designed to be passed to various functions in the bcm2835 library.
|
||||
@{
|
||||
*/
|
||||
@@ -484,15 +573,16 @@
|
||||
/*! This means pin LOW, false, 0volts on a pin. */
|
||||
#define LOW 0x0
|
||||
|
||||
/*! Return the minimum of 2 numbers */
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#endif
|
||||
|
||||
/*! Speed of the core clock core_clk */
|
||||
#define BCM2835_CORE_CLK_HZ 250000000 /*!< 250 MHz */
|
||||
|
||||
/*! On RPi2 with BCM2836, and all recent OSs, the base of the peripherals is read from a /proc file */
|
||||
/*! On all recent OSs, the base of the peripherals is read from a /proc file */
|
||||
#define BMC2835_RPI2_DT_FILENAME "/proc/device-tree/soc/ranges"
|
||||
/*! Offset into BMC2835_RPI2_DT_FILENAME for the peripherals base address */
|
||||
#define BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET 4
|
||||
/*! 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
|
||||
@@ -504,11 +594,17 @@
|
||||
#define BCM2835_PERI_BASE 0x20000000
|
||||
/*! Size of the peripherals block on RPi 1 */
|
||||
#define BCM2835_PERI_SIZE 0x01000000
|
||||
/*! Alternate base address for RPI 2 / 3 */
|
||||
#define BCM2835_RPI2_PERI_BASE 0x3F000000
|
||||
/*! Alternate base address for RPI 4 */
|
||||
#define BCM2835_RPI4_PERI_BASE 0xFE000000
|
||||
/*! Alternate size for RPI 4 */
|
||||
#define BCM2835_RPI4_PERI_SIZE 0x01800000
|
||||
|
||||
/*! Offsets for the bases of various peripherals within the peripherals block
|
||||
/ Base Address of the System Timer registers
|
||||
*/
|
||||
#define BCM2835_ST_BASE 0x3000
|
||||
#define BCM2835_ST_BASE 0x3000
|
||||
/*! Base Address of the Pads registers */
|
||||
#define BCM2835_GPIO_PADS 0x100000
|
||||
/*! Base Address of the Clock/timer registers */
|
||||
@@ -518,11 +614,18 @@
|
||||
/*! Base Address of the SPI0 registers */
|
||||
#define BCM2835_SPI0_BASE 0x204000
|
||||
/*! Base Address of the BSC0 registers */
|
||||
#define BCM2835_BSC0_BASE 0x205000
|
||||
#define BCM2835_BSC0_BASE 0x205000
|
||||
/*! Base Address of the PWM registers */
|
||||
#define BCM2835_GPIO_PWM 0x20C000
|
||||
/*! Base Address of the AUX registers */
|
||||
#define BCM2835_AUX_BASE 0x215000
|
||||
/*! Base Address of the AUX_SPI1 registers */
|
||||
#define BCM2835_SPI1_BASE 0x215080
|
||||
/*! Base Address of the AUX_SPI2 registers */
|
||||
#define BCM2835_SPI2_BASE 0x2150C0
|
||||
/*! Base Address of the BSC1 registers */
|
||||
#define BCM2835_BSC1_BASE 0x804000
|
||||
#define BCM2835_BSC1_BASE 0x804000
|
||||
|
||||
|
||||
/*! Physical address and size of the peripherals block
|
||||
May be overridden on RPi2
|
||||
@@ -574,6 +677,17 @@ extern volatile uint32_t *bcm2835_bsc0;
|
||||
*/
|
||||
extern volatile uint32_t *bcm2835_bsc1;
|
||||
|
||||
/*! Base of the AUX registers.
|
||||
Available after bcm2835_init has been called (as root)
|
||||
*/
|
||||
extern volatile uint32_t *bcm2835_aux;
|
||||
|
||||
/*! Base of the SPI1 registers.
|
||||
Available after bcm2835_init has been called (as root)
|
||||
*/
|
||||
extern volatile uint32_t *bcm2835_spi1;
|
||||
|
||||
|
||||
/*! \brief bcm2835RegisterBase
|
||||
Register bases for bcm2835_regbase()
|
||||
*/
|
||||
@@ -585,7 +699,9 @@ typedef enum {
|
||||
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. */
|
||||
BCM2835_REGBASE_BSC1 = 8, /*!< Base of the BSC1 registers. */
|
||||
BCM2835_REGBASE_AUX = 9, /*!< Base of the AUX registers. */
|
||||
BCM2835_REGBASE_SPI1 = 10 /*!< Base of the SPI1 registers. */
|
||||
} bcm2835RegisterBase;
|
||||
|
||||
/*! Size of memory page on RPi */
|
||||
@@ -631,6 +747,12 @@ typedef enum {
|
||||
#define BCM2835_GPPUDCLK0 0x0098 /*!< GPIO Pin Pull-up/down Enable Clock 0 */
|
||||
#define BCM2835_GPPUDCLK1 0x009c /*!< GPIO Pin Pull-up/down Enable Clock 1 */
|
||||
|
||||
/* 2711 has a different method for pin pull-up/down/enable */
|
||||
#define BCM2835_GPPUPPDN0 0x00e4 /* Pin pull-up/down for pins 15:0 */
|
||||
#define BCM2835_GPPUPPDN1 0x00e8 /* Pin pull-up/down for pins 31:16 */
|
||||
#define BCM2835_GPPUPPDN2 0x00ec /* Pin pull-up/down for pins 47:32 */
|
||||
#define BCM2835_GPPUPPDN3 0x00f0 /* Pin pull-up/down for pins 57:48 */
|
||||
|
||||
/*! \brief bcm2835PortFunction
|
||||
Port function select modes for bcm2835_gpio_fsel()
|
||||
*/
|
||||
@@ -655,6 +777,9 @@ typedef enum {
|
||||
BCM2835_GPIO_PUD_UP = 0x02 /*!< Enable Pull Up control 0b10 */
|
||||
} bcm2835PUDControl;
|
||||
|
||||
/* need a value for pud functions that can't work unless RPI 4 */
|
||||
#define BCM2835_GPIO_PUD_ERROR 0x08
|
||||
|
||||
/*! Pad control register offsets from BCM2835_GPIO_PADS */
|
||||
#define BCM2835_PADS_GPIO_0_27 0x002c /*!< Pad control register for pads 0 to 27 */
|
||||
#define BCM2835_PADS_GPIO_28_45 0x0030 /*!< Pad control register for pads 28 to 45 */
|
||||
@@ -737,7 +862,7 @@ typedef enum {
|
||||
RPI_V2_GPIO_P1_31 = 6, /*!< Version 2, Pin P1-31 */
|
||||
RPI_V2_GPIO_P1_32 = 12, /*!< Version 2, Pin P1-32 */
|
||||
RPI_V2_GPIO_P1_33 = 13, /*!< Version 2, Pin P1-33 */
|
||||
RPI_V2_GPIO_P1_35 = 19, /*!< Version 2, Pin P1-35 */
|
||||
RPI_V2_GPIO_P1_35 = 19, /*!< Version 2, Pin P1-35, can be PWM channel 1 in ALT FUN 5 */
|
||||
RPI_V2_GPIO_P1_36 = 16, /*!< Version 2, Pin P1-36 */
|
||||
RPI_V2_GPIO_P1_37 = 26, /*!< Version 2, Pin P1-37 */
|
||||
RPI_V2_GPIO_P1_38 = 20, /*!< Version 2, Pin P1-38 */
|
||||
@@ -771,13 +896,69 @@ typedef enum {
|
||||
RPI_BPLUS_GPIO_J8_31 = 6, /*!< B+, Pin J8-31, */
|
||||
RPI_BPLUS_GPIO_J8_32 = 12, /*!< B+, Pin J8-32, */
|
||||
RPI_BPLUS_GPIO_J8_33 = 13, /*!< B+, Pin J8-33, */
|
||||
RPI_BPLUS_GPIO_J8_35 = 19, /*!< B+, Pin J8-35, */
|
||||
RPI_BPLUS_GPIO_J8_35 = 19, /*!< B+, Pin J8-35, can be PWM channel 1 in ALT FUN 5 */
|
||||
RPI_BPLUS_GPIO_J8_36 = 16, /*!< B+, Pin J8-36, */
|
||||
RPI_BPLUS_GPIO_J8_37 = 26, /*!< B+, Pin J8-37, */
|
||||
RPI_BPLUS_GPIO_J8_38 = 20, /*!< B+, Pin J8-38, */
|
||||
RPI_BPLUS_GPIO_J8_40 = 21 /*!< B+, Pin J8-40, */
|
||||
} RPiGPIOPin;
|
||||
|
||||
/* Defines for AUX
|
||||
GPIO register offsets from BCM2835_AUX_BASE.
|
||||
*/
|
||||
#define BCM2835_AUX_IRQ 0x0000 /*!< xxx */
|
||||
#define BCM2835_AUX_ENABLE 0x0004 /*!< */
|
||||
|
||||
#define BCM2835_AUX_ENABLE_UART1 0x01 /*!< */
|
||||
#define BCM2835_AUX_ENABLE_SPI0 0x02 /*!< SPI0 (SPI1 in the device) */
|
||||
#define BCM2835_AUX_ENABLE_SPI1 0x04 /*!< SPI1 (SPI2 in the device) */
|
||||
|
||||
|
||||
#define BCM2835_AUX_SPI_CNTL0 0x0000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL1 0x0004 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT 0x0008 /*!< */
|
||||
#define BCM2835_AUX_SPI_PEEK 0x000C /*!< Read but do not take from FF */
|
||||
#define BCM2835_AUX_SPI_IO 0x0020 /*!< Write = TX, read=RX */
|
||||
#define BCM2835_AUX_SPI_TXHOLD 0x0030 /*!< Write = TX keep CS, read=RX */
|
||||
|
||||
#define BCM2835_AUX_SPI_CLOCK_MIN 30500 /*!< 30,5kHz */
|
||||
#define BCM2835_AUX_SPI_CLOCK_MAX 125000000 /*!< 125Mhz */
|
||||
|
||||
#define BCM2835_AUX_SPI_CNTL0_SPEED 0xFFF00000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_SPEED_MAX 0xFFF /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT 20 /*!< */
|
||||
|
||||
#define BCM2835_AUX_SPI_CNTL0_CS0_N 0x000C0000 /*!< CS 0 low */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CS1_N 0x000A0000 /*!< CS 1 low */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CS2_N 0x00060000 /*!< CS 2 low */
|
||||
|
||||
#define BCM2835_AUX_SPI_CNTL0_POSTINPUT 0x00010000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_VAR_CS 0x00008000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_VAR_WIDTH 0x00004000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_DOUTHOLD 0x00003000 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_ENABLE 0x00000800 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CPHA_IN 0x00000400 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CLEARFIFO 0x00000200 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CPHA_OUT 0x00000100 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_CPOL 0x00000080 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_MSBF_OUT 0x00000040 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL0_SHIFTLEN 0x0000003F /*!< */
|
||||
|
||||
#define BCM2835_AUX_SPI_CNTL1_CSHIGH 0x00000700 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL1_IDLE 0x00000080 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL1_TXEMPTY 0x00000040 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL1_MSBF_IN 0x00000002 /*!< */
|
||||
#define BCM2835_AUX_SPI_CNTL1_KEEP_IN 0x00000001 /*!< */
|
||||
|
||||
#define BCM2835_AUX_SPI_STAT_TX_LVL 0xFF000000 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_RX_LVL 0x00FF0000 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_TX_FULL 0x00000400 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_TX_EMPTY 0x00000200 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_RX_FULL 0x00000100 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_RX_EMPTY 0x00000080 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_BUSY 0x00000040 /*!< */
|
||||
#define BCM2835_AUX_SPI_STAT_BITCOUNT 0x0000003F /*!< */
|
||||
|
||||
/* Defines for SPI
|
||||
GPIO register offsets from BCM2835_SPI0_BASE.
|
||||
Offsets into the SPI Peripheral block in bytes per 10.5 SPI Register Map
|
||||
@@ -848,28 +1029,35 @@ typedef enum {
|
||||
/*! \brief bcm2835SPIClockDivider
|
||||
Specifies the divider used to generate the SPI clock from the system clock.
|
||||
Figures below give the divider, clock period and clock frequency.
|
||||
Clock divided is based on nominal base clock rate of 250MHz
|
||||
Clock divided is based on nominal core clock rate of 250MHz on RPi1 and RPi2, and 400MHz on RPi3.
|
||||
It is reported that (contrary to the documentation) any even divider may used.
|
||||
The frequencies shown for each divider have been confirmed by measurement.
|
||||
The frequencies shown for each divider have been confirmed by measurement on RPi1 and RPi2.
|
||||
The system clock frequency on RPi3 is different, so the frequency you get from a given divider will be different.
|
||||
See comments in 'SPI Pins' for information about reliable SPI speeds.
|
||||
Note: it is possible to change the core clock rate of the RPi 3 back to 250MHz, by putting
|
||||
\code
|
||||
core_freq=250
|
||||
\endcode
|
||||
in the config.txt
|
||||
*/
|
||||
typedef enum {
|
||||
BCM2835_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 262.144us = 3.814697260kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 131.072us = 7.629394531kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 65.536us = 15.25878906kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 32.768us = 30/51757813kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 16.384us = 61.03515625kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 8.192us = 122.0703125kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 4.096us = 244.140625kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 2.048us = 488.28125kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 1.024us = 976.5625kHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 512ns = = 1.953125MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 256ns = 3.90625MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 128ns = 7.8125MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 64ns = 15.625MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 32ns = 31.25MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 16ns = 62.5MHz */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 8ns = 125MHz, fastest you can get */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 262.144us = 3.814697260kHz, same as 0/65536 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 3.814697260kHz on Rpi2, 6.1035156kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 7.629394531kHz on Rpi2, 12.20703125kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 15.25878906kHz on Rpi2, 24.4140625kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 30.51757813kHz on Rpi2, 48.828125kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 61.03515625kHz on Rpi2, 97.65625kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 122.0703125kHz on Rpi2, 195.3125kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 244.140625kHz on Rpi2, 390.625kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 488.28125kHz on Rpi2, 781.25kHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 976.5625kHz on Rpi2, 1.5625MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 1.953125MHz on Rpi2, 3.125MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 3.90625MHz on Rpi2, 6.250MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 7.8125MHz on Rpi2, 12.5MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 15.625MHz on Rpi2, 25MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 31.25MHz on Rpi2, 50MHz on RPI3 */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 62.5MHz on Rpi2, 100MHz on RPI3. Dont expect this speed to work reliably. */
|
||||
BCM2835_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 125MHz on Rpi2, 200MHz on RPI3, fastest you can get. Dont expect this speed to work reliably.*/
|
||||
BCM2835_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 3.814697260kHz on Rpi2, 6.1035156kHz on RPI3, same as 0/65536 */
|
||||
} bcm2835SPIClockDivider;
|
||||
|
||||
/* Defines for I2C
|
||||
@@ -945,19 +1133,22 @@ typedef enum {
|
||||
#define BCM2835_ST_CLO 0x0004 /*!< System Timer Counter Lower 32 bits */
|
||||
#define BCM2835_ST_CHI 0x0008 /*!< System Timer Counter Upper 32 bits */
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
/* Defines for PWM, word offsets (ie 4 byte multiples) */
|
||||
#define BCM2835_PWM_CONTROL 0 /*!< PWM Control register */
|
||||
#define BCM2835_PWM_STATUS 1 /*!< PWM Status register */
|
||||
#define BCM2835_PWM_DMAC 2 /*!< PWM DMA Configuration */
|
||||
#define BCM2835_PWM0_RANGE 4 /*!< PWM Channel 0 Range */
|
||||
#define BCM2835_PWM0_DATA 5 /*!< PWM Channel 0 Data */
|
||||
#define BCM2835_PWM_FIF1 6 /*!< PWM FIFO Input */
|
||||
#define BCM2835_PWM1_RANGE 8 /*!< PWM Channel 1 Range */
|
||||
#define BCM2835_PWM1_DATA 9 /*!< PWM Channel 1 Data */
|
||||
#define BCM2835_PWM_CONTROL 0
|
||||
#define BCM2835_PWM_STATUS 1
|
||||
#define BCM2835_PWM_DMAC 2
|
||||
#define BCM2835_PWM0_RANGE 4
|
||||
#define BCM2835_PWM0_DATA 5
|
||||
#define BCM2835_PWM_FIF1 6
|
||||
#define BCM2835_PWM1_RANGE 8
|
||||
#define BCM2835_PWM1_DATA 9
|
||||
|
||||
/* Defines for PWM Clock, word offsets (ie 4 byte multiples) */
|
||||
#define BCM2835_PWMCLK_CNTL 40 /*!< PWM Clock Control */
|
||||
#define BCM2835_PWMCLK_DIV 41 /*!< PWM Clock Divider */
|
||||
#define BCM2835_PWMCLK_CNTL 40
|
||||
#define BCM2835_PWMCLK_DIV 41
|
||||
#define BCM2835_PWM_PASSWRD (0x5A << 24) /*!< Password to enable setting PWM clock */
|
||||
|
||||
#define BCM2835_PWM1_MS_MODE 0x8000 /*!< Run in Mark/Space mode */
|
||||
@@ -998,8 +1189,6 @@ typedef enum {
|
||||
BCM2835_PWM_CLOCK_DIVIDER_1 = 1 /*!< 1 = 4.6875kHz, same as divider 4096 */
|
||||
} bcm2835PWMClockDivider;
|
||||
|
||||
/*! @} */
|
||||
|
||||
/* Historical name compatibility */
|
||||
#ifndef BCM2835_NO_DELAY_COMPATIBILITY
|
||||
#define delay(x) bcm2835_delay(x)
|
||||
@@ -1010,8 +1199,7 @@ typedef enum {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \defgroup BCM2835initgrp Library initialisation and management
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup init Library initialisation and management
|
||||
These functions allow you to intialise and control the bcm2835 library
|
||||
@{
|
||||
*/
|
||||
@@ -1052,8 +1240,7 @@ extern unsigned int bcm2835_version(void);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! \defgroup BCM2835lowlevelgrp Low level register access
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup lowlevel Low level register access
|
||||
These functions provide low level register access, and should not generally
|
||||
need to be used
|
||||
|
||||
@@ -1133,8 +1320,7 @@ extern void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value);
|
||||
extern void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask);
|
||||
/*! @} end of lowlevel */
|
||||
|
||||
/*! \defgroup BCM2835gpiogrp GPIO register access
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup gpio GPIO register access
|
||||
These functions allow you to control the GPIO interface. You can set the
|
||||
function of each GPIO pin, read the input state and set the output state.
|
||||
@{
|
||||
@@ -1295,6 +1481,8 @@ extern void bcm2835_gpio_clr_afen(uint8_t pin);
|
||||
used with bcm2835_gpio_pudclk() to set the Pull-up/down resistor for the given pin.
|
||||
However, it is usually more convenient to use bcm2835_gpio_set_pud().
|
||||
\param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl
|
||||
On the RPI 4, although this function and bcm2835_gpio_pudclk() are supported for backward
|
||||
compatibility, new code should always use bcm2835_gpio_set_pud().
|
||||
\sa bcm2835_gpio_set_pud()
|
||||
*/
|
||||
extern void bcm2835_gpio_pud(uint8_t pud);
|
||||
@@ -1303,17 +1491,23 @@ extern void bcm2835_gpio_pud(uint8_t pud);
|
||||
\param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin.
|
||||
\param[in] on HIGH to clock the value from bcm2835_gpio_pud() into the pin.
|
||||
LOW to remove the clock.
|
||||
|
||||
On the RPI 4, although this function and bcm2835_gpio_pud() are supported for backward
|
||||
compatibility, new code should always use bcm2835_gpio_set_pud().
|
||||
|
||||
\sa bcm2835_gpio_set_pud()
|
||||
*/
|
||||
extern void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on);
|
||||
|
||||
/*! Reads and returns the Pad Control for the given GPIO group.
|
||||
Caution: requires root access.
|
||||
\param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_*
|
||||
\return Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup
|
||||
*/
|
||||
extern uint32_t bcm2835_gpio_pad(uint8_t group);
|
||||
|
||||
/*! Sets the Pad Control for the given GPIO group.
|
||||
Caution: requires root access.
|
||||
\param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_*
|
||||
\param[in] control Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup. Note
|
||||
that it is not necessary to include BCM2835_PAD_PASSWRD in the mask as this
|
||||
@@ -1373,10 +1567,17 @@ extern void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask);
|
||||
*/
|
||||
extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud);
|
||||
|
||||
/*! On the BCM2711 based RPI 4, gets the current Pull-up/down mode for the specified pin.
|
||||
Returns one of BCM2835_GPIO_PUD_* from bcm2835PUDControl.
|
||||
On earlier RPI versions not based on the BCM2711, returns BCM2835_GPIO_PUD_ERROR
|
||||
\param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin.
|
||||
*/
|
||||
|
||||
extern uint8_t bcm2835_gpio_get_pud(uint8_t pin);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! \defgroup BCM2835spigrp SPI access
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup spi SPI access
|
||||
These functions let you use SPI0 (Serial Peripheral Interface) to
|
||||
interface with an external SPI device.
|
||||
@{
|
||||
@@ -1399,8 +1600,9 @@ extern int bcm2835_spi_begin(void);
|
||||
extern void bcm2835_spi_end(void);
|
||||
|
||||
/*! Sets the SPI bit order
|
||||
NOTE: has no effect. Not supported by SPI0.
|
||||
Defaults to
|
||||
Set the bit order to be used for transmit and receive. The bcm2835 SPI0 only supports BCM2835_SPI_BIT_ORDER_MSB,
|
||||
so if you select BCM2835_SPI_BIT_ORDER_LSB, the bytes will be reversed in software.
|
||||
The library defaults to BCM2835_SPI_BIT_ORDER_MSB.
|
||||
\param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*,
|
||||
see \ref bcm2835SPIBitOrder
|
||||
*/
|
||||
@@ -1413,6 +1615,12 @@ extern void bcm2835_spi_setBitOrder(uint8_t order);
|
||||
*/
|
||||
extern void bcm2835_spi_setClockDivider(uint16_t divider);
|
||||
|
||||
/*! Sets the SPI clock divider by converting the speed parameter to
|
||||
the equivalent SPI clock divider. ( see \sa bcm2835_spi_setClockDivider)
|
||||
\param[in] speed_hz The desired SPI clock speed in Hz
|
||||
*/
|
||||
extern void bcm2835_spi_set_speed_hz(uint32_t speed_hz);
|
||||
|
||||
/*! Sets the SPI data mode
|
||||
Sets the clock polariy and phase
|
||||
\param[in] mode The desired data mode, one of BCM2835_SPI_MODE*,
|
||||
@@ -1476,14 +1684,83 @@ extern void bcm2835_spi_transfern(char* buf, uint32_t len);
|
||||
Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect)
|
||||
during the transfer.
|
||||
\param[in] buf Buffer of bytes to send.
|
||||
\param[in] len Number of bytes in the buf buffer, and the number of bytes to send
|
||||
*/
|
||||
extern void bcm2835_spi_writenb(const char* buf, uint32_t len);
|
||||
|
||||
/*! Transfers half-word to and from the currently selected SPI slave.
|
||||
Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect)
|
||||
during the transfer.
|
||||
Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO.
|
||||
Returns the read data byte from the slave.
|
||||
Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual
|
||||
\param[in] data The 8 bit data byte to write to MOSI
|
||||
\sa bcm2835_spi_writenb()
|
||||
*/
|
||||
extern void bcm2835_spi_write(uint16_t data);
|
||||
|
||||
/*! Start AUX SPI operations.
|
||||
Forces RPi AUX SPI pins P1-36 (MOSI), P1-38 (MISO), P1-40 (CLK) and P1-36 (CE2)
|
||||
to alternate function ALT4, which enables those pins for SPI interface.
|
||||
\return 1 if successful, 0 otherwise (perhaps because you are not running as root)
|
||||
*/
|
||||
extern int bcm2835_aux_spi_begin(void);
|
||||
|
||||
/*! End AUX SPI operations.
|
||||
SPI1 pins P1-36 (MOSI), P1-38 (MISO), P1-40 (CLK) and P1-36 (CE2)
|
||||
are returned to their default INPUT behaviour.
|
||||
*/
|
||||
extern void bcm2835_aux_spi_end(void);
|
||||
|
||||
/*! Sets the AUX SPI clock divider and therefore the AUX SPI clock speed.
|
||||
\param[in] divider The desired AUX SPI clock divider.
|
||||
*/
|
||||
extern void bcm2835_aux_spi_setClockDivider(uint16_t divider);
|
||||
|
||||
/*!
|
||||
* Calculates the input for \sa bcm2835_aux_spi_setClockDivider
|
||||
* @param speed_hz A value between \sa BCM2835_AUX_SPI_CLOCK_MIN and \sa BCM2835_AUX_SPI_CLOCK_MAX
|
||||
* @return Input for \sa bcm2835_aux_spi_setClockDivider
|
||||
*/
|
||||
extern uint16_t bcm2835_aux_spi_CalcClockDivider(uint32_t speed_hz);
|
||||
|
||||
/*! Transfers half-word to and from the AUX SPI slave.
|
||||
Asserts the currently selected CS pins during the transfer.
|
||||
\param[in] data The 8 bit data byte to write to MOSI
|
||||
\return The 8 bit byte simultaneously read from MISO
|
||||
\sa bcm2835_spi_transfern()
|
||||
*/
|
||||
extern void bcm2835_aux_spi_write(uint16_t data);
|
||||
|
||||
/*! Transfers any number of bytes to the AUX SPI slave.
|
||||
Asserts the CE2 pin during the transfer.
|
||||
\param[in] buf Buffer of bytes to send.
|
||||
\param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send
|
||||
*/
|
||||
extern void bcm2835_spi_writenb(char* buf, uint32_t len);
|
||||
extern void bcm2835_aux_spi_writenb(const char *buf, uint32_t len);
|
||||
|
||||
/*! Transfers any number of bytes to and from the AUX SPI slave
|
||||
using bcm2835_aux_spi_transfernb.
|
||||
The returned data from the slave replaces the transmitted data in the buffer.
|
||||
\param[in,out] buf Buffer of bytes to send. Received bytes will replace the contents
|
||||
\param[in] len Number of bytes int eh buffer, and the number of bytes to send/received
|
||||
\sa bcm2835_aux_spi_transfer()
|
||||
*/
|
||||
extern void bcm2835_aux_spi_transfern(char *buf, uint32_t len);
|
||||
|
||||
/*! Transfers any number of bytes to and from the AUX SPI slave.
|
||||
Asserts the CE2 pin during the transfer.
|
||||
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
|
||||
\param[in] tbuf Buffer of bytes to send.
|
||||
\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
|
||||
*/
|
||||
extern void bcm2835_aux_spi_transfernb(const char *tbuf, char *rbuf, uint32_t len);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! \defgroup BCM2835i2cgrp I2C access
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup i2c I2C access
|
||||
These functions let you use I2C (The Broadcom Serial Control bus with the Philips
|
||||
I2C bus/interface version 2.1 January 2000.) to interface with an external I2C device.
|
||||
@{
|
||||
@@ -1571,8 +1848,7 @@ extern uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* bu
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! \defgroup BCM2835stgrp System Timer access
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup st System Timer access
|
||||
Allows access to and delays using the System Timer Counter.
|
||||
@{
|
||||
*/
|
||||
@@ -1590,8 +1866,7 @@ extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! \defgroup BCM2835pwmgrp Pulse Width Modulation
|
||||
\ingroup BCM2835grp
|
||||
/*! \defgroup pwm Pulse Width Modulation
|
||||
Allows control of 2 independent PWM channels. A limited subset of GPIO pins
|
||||
can be connected to one of these 2 channels, allowing PWM control of GPIO pins.
|
||||
You have to set the desired pin into a particular Alt Fun to PWM output. See the PWM
|
||||
@@ -1635,3 +1910,42 @@ extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data);
|
||||
#endif
|
||||
|
||||
#endif /* BCM2835_H */
|
||||
|
||||
/*! @example blink.c
|
||||
Blinks RPi GPIO pin 11 on and off
|
||||
*/
|
||||
|
||||
/*! @example input.c
|
||||
Reads the state of an RPi input pin
|
||||
*/
|
||||
|
||||
/*! @example event.c
|
||||
Shows how to use event detection on an input pin
|
||||
*/
|
||||
|
||||
/*! @example spi.c
|
||||
Shows how to use SPI interface to transfer a byte to and from an SPI device
|
||||
*/
|
||||
|
||||
/*! @example spin.c
|
||||
Shows how to use SPI interface to transfer a number of bytes to and from an SPI device
|
||||
*/
|
||||
|
||||
/*! @example pwm.c
|
||||
Shows how to use PWM to control GPIO pins
|
||||
*/
|
||||
|
||||
/*! @example i2c.c
|
||||
Command line utility for executing i2c commands with the
|
||||
Broadcom bcm2835. Contributed by Shahrooz Shahparnia.
|
||||
*/
|
||||
|
||||
/*! example gpio.c
|
||||
Command line utility for executing gpio commands with the
|
||||
Broadcom bcm2835. Contributed by Shahrooz Shahparnia.
|
||||
*/
|
||||
|
||||
/*! example spimem_test.c
|
||||
Shows how to use the included little library (spiram.c and spiram.h)
|
||||
to read and write SPI RAM chips such as 23K256-I/P
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user