#########################################################################################
# Package HiPi::BCM2835
# Description : Wrapper for bcm2835 C library - Access to /dev/mem
# Created Fri Nov 23 13:55:49 2012
# Copyright : Copyright (c) 2013-2019 Mark Dootson
# License : This work is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or any later
# version.
#########################################################################################
package HiPi::BCM2835;
#########################################################################################
use strict;
use warnings;
use threads::shared;
use parent qw( HiPi::Device );
use XSLoader;
use Carp;
use HiPi qw( :rpi :i2c );
use HiPi::RaspberryPi;
our $VERSION ='0.66';
XSLoader::load('HiPi::BCM2835', $VERSION) if HiPi::is_raspberry_pi();
our $_memmapped : shared;
{
lock $_memmapped;
$_memmapped = 0;
}
my $altnames = HiPi::RaspberryPi::get_alt_function_names();
sub bcm2835_init {
lock $_memmapped;
unless( $_memmapped ) {
_hipi_bcm2835_init() or croak 'Failed to initialise libbcm2835';
$_memmapped = 1;
}
}
sub bcm2835_close {
# only close in main thread which has tid of zero
return if( $threads::threads && threads->tid );
lock $_memmapped;
if( $_memmapped ) {
_hipi_bcm2835_close();
$_memmapped = 0;
}
}
END{
bcm2835_close();
}
sub CLONE_SKIP {
return 1;
}
require HiPi::BCM2835::Pin;
# Constants for libbcm2835
our @EXPORT_OK = ();
our %EXPORT_TAGS = ( all => \@EXPORT_OK );
sub _register_exported_constants {
my( $tag, @constants ) = @_;
$EXPORT_TAGS{$tag} = \@constants;
push( @EXPORT_OK, @constants);
}
# define HIGH / LOW at MyPi level as RPI_HIGH / RPI_LOW
use constant {
BCM2835_CORE_CLK_HZ => 250000000,
BCM2835_ST_CS => 0x0000,
BCM2835_ST_CLO => 0x0004,
BCM2835_ST_CHI => 0x0008,
};
_register_exported_constants( qw(
clock
BCM2835_CORE_CLK_HZ
BCM2835_ST_CS
BCM2835_ST_CLO
BCM2835_ST_CHI
) );
#-------------------------------------------------------
# Physical addresses for various peripheral regiser sets
#-------------------------------------------------------
sub BCM2835_GPIO_BASE { bcm2835_gpio(); }
sub BCM2835_GPIO_PWM { bcm2835_pwm(); }
sub BCM2835_CLOCK_BASE { bcm2835_clk(); }
sub BCM2835_GPIO_PADS { bcm2835_pads(); }
sub BCM2835_SPI0_BASE { bcm2835_spi0(); }
sub BCM2835_BSC0_BASE { bcm2835_bsc0(); }
sub BCM2835_BSC1_BASE { bcm2835_bsc1(); }
sub BCM2835_ST_BASE { bcm2835_st(); }
_register_exported_constants( qw(
registers
BCM2835_ST_BASE
BCM2835_GPIO_PADS
BCM2835_CLOCK_BASE
BCM2835_GPIO_BASE
BCM2835_SPI0_BASE
BCM2835_BSC0_BASE
BCM2835_GPIO_PWM
BCM2835_BSC1_BASE
) );
#-------------------------------------------------------
# Memory
#-------------------------------------------------------
use constant {
BCM2835_PAGE_SIZE => 4*1024,
BCM2835_BLOCK_SIZE => 4*1024,
};
_register_exported_constants( qw(
memory
BCM2835_PAGE_SIZE
BCM2835_BLOCK_SIZE
) );
#-----------------------------------------------------
# Defines for GPIO
# The BCM2835 has 54 GPIO pins.
# BCM2835 data sheet, Page 90 onwards.
# GPIO register offsets from BCM2835_GPIO_BASE. Offsets into the GPIO Peripheral block in bytes per 6.1 Register View
#-----------------------------------------------------
use constant {
BCM2835_GPFSEL0 => 0x0000, # GPIO Function Select 0
BCM2835_GPFSEL1 => 0x0004, # GPIO Function Select 1
BCM2835_GPFSEL2 => 0x0008, # GPIO Function Select 2
BCM2835_GPFSEL3 => 0x000c, # GPIO Function Select 3
BCM2835_GPFSEL4 => 0x0010, # GPIO Function Select 4
BCM2835_GPFSEL5 => 0x0014, # GPIO Function Select 5
BCM2835_GPSET0 => 0x001c, # GPIO Pin Output Set 0
BCM2835_GPSET1 => 0x0020, # GPIO Pin Output Set 1
BCM2835_GPCLR0 => 0x0028, # GPIO Pin Output Clear 0
BCM2835_GPCLR1 => 0x002c, # GPIO Pin Output Clear 1
BCM2835_GPLEV0 => 0x0034, # GPIO Pin Level 0
BCM2835_GPLEV1 => 0x0038, # GPIO Pin Level 1
BCM2835_GPEDS0 => 0x0040, # GPIO Pin Event Detect Status 0
BCM2835_GPEDS1 => 0x0044, # GPIO Pin Event Detect Status 1
BCM2835_GPREN0 => 0x004c, # GPIO Pin Rising Edge Detect Enable 0
BCM2835_GPREN1 => 0x0050, # GPIO Pin Rising Edge Detect Enable 1
BCM2835_GPFEN0 => 0x0058, # GPIO Pin Falling Edge Detect Enable 0
BCM2835_GPFEN1 => 0x005c, # GPIO Pin Falling Edge Detect Enable 1
BCM2835_GPHEN0 => 0x0064, # GPIO Pin High Detect Enable 0
BCM2835_GPHEN1 => 0x0068, # GPIO Pin High Detect Enable 1
BCM2835_GPLEN0 => 0x0070, # GPIO Pin Low Detect Enable 0
BCM2835_GPLEN1 => 0x0074, # GPIO Pin Low Detect Enable 1
BCM2835_GPAREN0 => 0x007c, # GPIO Pin Async. Rising Edge Detect 0
BCM2835_GPAREN1 => 0x0080, # GPIO Pin Async. Rising Edge Detect 1
BCM2835_GPAFEN0 => 0x0088, # GPIO Pin Async. Falling Edge Detect 0
BCM2835_GPAFEN1 => 0x008c, # GPIO Pin Async. Falling Edge Detect 1
BCM2835_GPPUD => 0x0094, # GPIO Pin Pull-up/down Enable
BCM2835_GPPUDCLK0 => 0x0098, # GPIO Pin Pull-up/down Enable Clock 0
BCM2835_GPPUDCLK1 => 0x009c, # GPIO Pin Pull-up/down Enable Clock 1
#-------------------------------------------------------
# Port function select modes for bcm2845_gpio_fsel()
#-------------------------------------------------------
BCM2835_GPIO_FSEL_INPT => 0, # Input
BCM2835_GPIO_FSEL_OUTP => 1, # Output
BCM2835_GPIO_FSEL_ALT0 => 4, # Alternate function 0
BCM2835_GPIO_FSEL_ALT1 => 5, # Alternate function 1
BCM2835_GPIO_FSEL_ALT2 => 6, # Alternate function 2
BCM2835_GPIO_FSEL_ALT3 => 7, # Alternate function 3
BCM2835_GPIO_FSEL_ALT4 => 3, # Alternate function 4
BCM2835_GPIO_FSEL_ALT5 => 2, # Alternate function 5
BCM2835_GPIO_FSEL_MASK => 7 # Function select bits mask
};
_register_exported_constants( qw(
function
BCM2835_GPFSEL0
BCM2835_GPFSEL1
BCM2835_GPFSEL2
BCM2835_GPFSEL3
BCM2835_GPFSEL4
BCM2835_GPFSEL5
BCM2835_GPSET0
BCM2835_GPSET1
BCM2835_GPCLR0
BCM2835_GPCLR1
BCM2835_GPLEV0
BCM2835_GPLEV1
BCM2835_GPEDS0
BCM2835_GPEDS1
BCM2835_GPREN0
BCM2835_GPREN1
BCM2835_GPFEN0
BCM2835_GPFEN1
BCM2835_GPHEN0
BCM2835_GPHEN1
BCM2835_GPLEN0
BCM2835_GPLEN1
BCM2835_GPAREN0
BCM2835_GPAREN1
BCM2835_GPAFEN0
BCM2835_GPAFEN1
BCM2835_GPPUD
BCM2835_GPPUDCLK0
BCM2835_GPPUDCLK1
BCM2835_GPIO_FSEL_INPT
BCM2835_GPIO_FSEL_OUTP
BCM2835_GPIO_FSEL_ALT0
BCM2835_GPIO_FSEL_ALT1
BCM2835_GPIO_FSEL_ALT2
BCM2835_GPIO_FSEL_ALT3
BCM2835_GPIO_FSEL_ALT4
BCM2835_GPIO_FSEL_ALT5
BCM2835_GPIO_FSEL_MASK
) );
#----------------------------------------------------------
# Pullup/Pulldown defines for bcm2845_gpio_pud()
#----------------------------------------------------------
use constant {
BCM2835_GPIO_PUD_OFF => 0, # < Off ? disable pull-up/down
BCM2835_GPIO_PUD_DOWN => 1, # < Enable Pull Down control
BCM2835_GPIO_PUD_UP => 2, # < Enable Pull Up control
BCM2835_GPIO_PUD_ERROR => 0x100,
};
_register_exported_constants( qw(
pud
BCM2835_GPIO_PUD_OFF
BCM2835_GPIO_PUD_DOWN
BCM2835_GPIO_PUD_UP
BCM2835_GPIO_PUD_ERROR
) );
#----------------------------------------------------------
# Pad control register offsets from BCM2835_GPIO_PADS,
# control masks and groups
#----------------------------------------------------------
use constant {
BCM2835_PADS_GPIO_0_27 => 0x002c, #< Pad control register for pads 0 to 27
BCM2835_PADS_GPIO_28_45 => 0x0030, #< Pad control register for pads 28 to 45
BCM2835_PADS_GPIO_46_53 => 0x0034, #< Pad control register for pads 46 to 53
BCM2835_PAD_PASSWRD => (0x5A << 24), #< Password to enable setting pad mask
BCM2835_PAD_SLEW_RATE_UNLIMITED => 0x10, #< Slew rate unlimited
BCM2835_PAD_HYSTERESIS_ENABLED => 0x08, #< Hysteresis enabled
BCM2835_PAD_DRIVE_2mA => 0x00, #< 2mA drive current
BCM2835_PAD_DRIVE_4mA => 0x01, #< 4mA drive current
BCM2835_PAD_DRIVE_6mA => 0x02, #< 6mA drive current
BCM2835_PAD_DRIVE_8mA => 0x03, #< 8mA drive current
BCM2835_PAD_DRIVE_10mA => 0x04, #< 10mA drive current
BCM2835_PAD_DRIVE_12mA => 0x05, #< 12mA drive current
BCM2835_PAD_DRIVE_14mA => 0x06, #< 14mA drive current
BCM2835_PAD_DRIVE_16mA => 0x07, #< 16mA drive current
BCM2835_PAD_GROUP_GPIO_0_27 => 0, #< Pad group for GPIO pads 0 to 27
BCM2835_PAD_GROUP_GPIO_28_45 => 1, #< Pad group for GPIO pads 28 to 45
BCM2835_PAD_GROUP_GPIO_46_53 => 2, #< Pad group for GPIO pads 46 to 53
};
_register_exported_constants( qw(
pads
BCM2835_PADS_GPIO_0_27
BCM2835_PADS_GPIO_28_45
BCM2835_PADS_GPIO_46_53
BCM2835_PAD_PASSWRD
BCM2835_PAD_SLEW_RATE_UNLIMITED
BCM2835_PAD_HYSTERESIS_ENABLED
BCM2835_PAD_DRIVE_2mA
BCM2835_PAD_DRIVE_4mA
BCM2835_PAD_DRIVE_6mA
BCM2835_PAD_DRIVE_8mA
BCM2835_PAD_DRIVE_10mA
BCM2835_PAD_DRIVE_12mA
BCM2835_PAD_DRIVE_14mA
BCM2835_PAD_DRIVE_16mA
BCM2835_PAD_GROUP_GPIO_0_27
BCM2835_PAD_GROUP_GPIO_28_45
BCM2835_PAD_GROUP_GPIO_46_53
) );
#------------------------------------------------------------------------------------------------
# Here we define Raspberry Pin GPIO pins on P1 in terms of the underlying BCM GPIO pin numbers.
# These can be passed as a pin number to any function requiring a pin.
# Not all pins on the RPi 26 bin IDE plug are connected to GPIO pins
# and some can adopt an alternate function.
# RPi version 2 has some slightly different pinouts, and these are values RPI_V2_*.
# 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()), pins 19, 21, 23, 24, 26 are dedicated to SPI
# and cant be controlled independently
#-------------------------------------------------------------------------------------------------
use constant {
RPI_GPIO_P1_03 => 0, # Version 1, Pin P1-03
RPI_GPIO_P1_05 => 1, # Version 1, Pin P1-05
RPI_GPIO_P1_07 => 4, # Version 1, Pin P1-07
RPI_GPIO_P1_08 => 14, # Version 1, Pin P1-08, defaults to alt function 0 UART0_TXD
RPI_GPIO_P1_10 => 15, # Version 1, Pin P1-10, defaults to alt function 0 UART0_RXD
RPI_GPIO_P1_11 => 17, # Version 1, Pin P1-11
RPI_GPIO_P1_12 => 18, # Version 1, Pin P1-12
RPI_GPIO_P1_13 => 21, # Version 1, Pin P1-13
RPI_GPIO_P1_15 => 22, # Version 1, Pin P1-15
RPI_GPIO_P1_16 => 23, # Version 1, Pin P1-16
RPI_GPIO_P1_18 => 24, # Version 1, Pin P1-18
RPI_GPIO_P1_19 => 10, # Version 1, Pin P1-19, MOSI when SPI0 in use
RPI_GPIO_P1_21 => 9, # Version 1, Pin P1-21, MISO when SPI0 in use
RPI_GPIO_P1_22 => 25, # Version 1, Pin P1-22
RPI_GPIO_P1_23 => 11, # Version 1, Pin P1-23, CLK when SPI0 in use
RPI_GPIO_P1_24 => 8, # Version 1, Pin P1-24, CE0 when SPI0 in use
RPI_GPIO_P1_26 => 7, # Version 1, Pin P1-26, CE1 when SPI0 in use
RPI_V2_GPIO_P1_03 => 2, # Version 2, Pin P1-03
RPI_V2_GPIO_P1_05 => 3, # Version 2, Pin P1-05
RPI_V2_GPIO_P1_07 => 4, # Version 2, Pin P1-07
RPI_V2_GPIO_P1_08 => 14, # Version 2, Pin P1-08, defaults to alt function 0 UART0_TXD
RPI_V2_GPIO_P1_10 => 15, # Version 2, Pin P1-10, defaults to alt function 0 UART0_RXD
RPI_V2_GPIO_P1_11 => 17, # Version 2, Pin P1-11
RPI_V2_GPIO_P1_12 => 18, # Version 2, Pin P1-12
RPI_V2_GPIO_P1_13 => 27, # Version 2, Pin P1-13
RPI_V2_GPIO_P1_15 => 22, # Version 2, Pin P1-15
RPI_V2_GPIO_P1_16 => 23, # Version 2, Pin P1-16
RPI_V2_GPIO_P1_18 => 24, # Version 2, Pin P1-18
RPI_V2_GPIO_P1_19 => 10, # Version 2, Pin P1-19, MOSI when SPI0 in use
RPI_V2_GPIO_P1_21 => 9, # Version 2, Pin P1-21, MISO when SPI0 in use
RPI_V2_GPIO_P1_22 => 25, # Version 2, Pin P1-22
RPI_V2_GPIO_P1_23 => 11, # Version 2, Pin P1-23, CLK when SPI0 in use
RPI_V2_GPIO_P1_24 => 8, # Version 2, Pin P1-24, CE0 when SPI0 in use
RPI_V2_GPIO_P1_26 => 7, # Version 2, Pin P1-26, CE1 when SPI0 in use
RPI_V2_GPIO_P5_03 => 28, # Version 2, Pin P5-03
RPI_V2_GPIO_P5_04 => 29, # Version 2, Pin P5-04
RPI_V2_GPIO_P5_05 => 30, # Version 2, Pin P5-05
RPI_V2_GPIO_P5_06 => 31, # Version 2, Pin P5-06
RPI_BPLUS_GPIO_J8_03 => 2, # /*!< B+, Pin J8-03 */
RPI_BPLUS_GPIO_J8_05 => 3, # /*!< B+, Pin J8-05 */
RPI_BPLUS_GPIO_J8_07 => 4, # /*!< B+, Pin J8-07 */
RPI_BPLUS_GPIO_J8_08 => 14, # /*!< B+, Pin J8-08, defaults to alt function 0 UART0_TXD */
RPI_BPLUS_GPIO_J8_10 => 15, # /*!< B+, Pin J8-10, defaults to alt function 0 UART0_RXD */
RPI_BPLUS_GPIO_J8_11 => 17, # /*!< B+, Pin J8-11 */
RPI_BPLUS_GPIO_J8_12 => 18, # /*!< B+, Pin J8-12, can be PWM channel 0 in ALT FUN 5 */
RPI_BPLUS_GPIO_J8_13 => 27, # /*!< B+, Pin J8-13 */
RPI_BPLUS_GPIO_J8_15 => 22, # /*!< B+, Pin J8-15 */
RPI_BPLUS_GPIO_J8_16 => 23, # /*!< B+, Pin J8-16 */
RPI_BPLUS_GPIO_J8_18 => 24, # /*!< B+, Pin J8-18 */
RPI_BPLUS_GPIO_J8_19 => 10, # /*!< B+, Pin J8-19, MOSI when SPI0 in use */
RPI_BPLUS_GPIO_J8_21 => 9, # /*!< B+, Pin J8-21, MISO when SPI0 in use */
RPI_BPLUS_GPIO_J8_22 => 25, # /*!< B+, Pin J8-22 */
RPI_BPLUS_GPIO_J8_23 => 11, # /*!< B+, Pin J8-23, CLK when SPI0 in use */
RPI_BPLUS_GPIO_J8_24 => 8, # /*!< B+, Pin J8-24, CE0 when SPI0 in use */
RPI_BPLUS_GPIO_J8_26 => 7, # /*!< B+, Pin J8-26, CE1 when SPI0 in use */
RPI_BPLUS_GPIO_J8_29 => 5, #/*!< B+, Pin J8-29, */
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_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,
};
_register_exported_constants( qw(
pins
RPI_GPIO_P1_03
RPI_GPIO_P1_05
RPI_GPIO_P1_07
RPI_GPIO_P1_08
RPI_GPIO_P1_10
RPI_GPIO_P1_11
RPI_GPIO_P1_12
RPI_GPIO_P1_13
RPI_GPIO_P1_15
RPI_GPIO_P1_16
RPI_GPIO_P1_18
RPI_GPIO_P1_19
RPI_GPIO_P1_21
RPI_GPIO_P1_22
RPI_GPIO_P1_23
RPI_GPIO_P1_24
RPI_GPIO_P1_26
RPI_V2_GPIO_P1_03
RPI_V2_GPIO_P1_05
RPI_V2_GPIO_P1_07
RPI_V2_GPIO_P1_08
RPI_V2_GPIO_P1_10
RPI_V2_GPIO_P1_11
RPI_V2_GPIO_P1_12
RPI_V2_GPIO_P1_13
RPI_V2_GPIO_P1_15
RPI_V2_GPIO_P1_16
RPI_V2_GPIO_P1_18
RPI_V2_GPIO_P1_19
RPI_V2_GPIO_P1_21
RPI_V2_GPIO_P1_22
RPI_V2_GPIO_P1_23
RPI_V2_GPIO_P1_24
RPI_V2_GPIO_P1_26
RPI_V2_GPIO_P5_03
RPI_V2_GPIO_P5_04
RPI_V2_GPIO_P5_05
RPI_V2_GPIO_P5_06
RPI_BPLUS_GPIO_J8_03
RPI_BPLUS_GPIO_J8_05
RPI_BPLUS_GPIO_J8_07
RPI_BPLUS_GPIO_J8_08
RPI_BPLUS_GPIO_J8_10
RPI_BPLUS_GPIO_J8_11
RPI_BPLUS_GPIO_J8_12
RPI_BPLUS_GPIO_J8_13
RPI_BPLUS_GPIO_J8_15
RPI_BPLUS_GPIO_J8_16
RPI_BPLUS_GPIO_J8_18
RPI_BPLUS_GPIO_J8_19
RPI_BPLUS_GPIO_J8_21
RPI_BPLUS_GPIO_J8_22
RPI_BPLUS_GPIO_J8_23
RPI_BPLUS_GPIO_J8_24
RPI_BPLUS_GPIO_J8_26
RPI_BPLUS_GPIO_J8_29
RPI_BPLUS_GPIO_J8_31
RPI_BPLUS_GPIO_J8_32
RPI_BPLUS_GPIO_J8_33
RPI_BPLUS_GPIO_J8_35
RPI_BPLUS_GPIO_J8_36
RPI_BPLUS_GPIO_J8_37
RPI_BPLUS_GPIO_J8_38
RPI_BPLUS_GPIO_J8_40
) );
#---------------------------------------------------------------------------
# Defines for SPI
#---------------------------------------------------------------------------
use constant {
# GPIO register offsets from BCM2835_SPI0_BASE.
# Offsets into the SPI Peripheral block in bytes per 10.5 SPI Register Map
BCM2835_SPI0_CS => 0x0000, # SPI Master Control and Status
BCM2835_SPI0_FIFO => 0x0004, # SPI Master TX and RX FIFOs
BCM2835_SPI0_CLK => 0x0008, # SPI Master Clock Divider
BCM2835_SPI0_DLEN => 0x000c, # SPI Master Data Length
BCM2835_SPI0_LTOH => 0x0010, # SPI LOSSI mode TOH
BCM2835_SPI0_DC => 0x0014, # SPI DMA DREQ Controls
# Register masks for SPI0_CS
BCM2835_SPI0_CS_LEN_LONG => 0x02000000, # Enable Long data word in Lossi mode if DMA_LEN is set
BCM2835_SPI0_CS_DMA_LEN => 0x01000000, # Enable DMA mode in Lossi mode
BCM2835_SPI0_CS_CSPOL2 => 0x00800000, # Chip Select 2 Polarity
BCM2835_SPI0_CS_CSPOL1 => 0x00400000, # Chip Select 1 Polarity
BCM2835_SPI0_CS_CSPOL0 => 0x00200000, # Chip Select 0 Polarity
BCM2835_SPI0_CS_RXF => 0x00100000, # RXF - RX FIFO Full
BCM2835_SPI0_CS_RXR => 0x00080000, # RXR RX FIFO needs Reading ( full)
BCM2835_SPI0_CS_TXD => 0x00040000, # TXD TX FIFO can accept Data
BCM2835_SPI0_CS_RXD => 0x00020000, # RXD RX FIFO contains Data
BCM2835_SPI0_CS_DONE => 0x00010000, # Done transfer Done
BCM2835_SPI0_CS_TE_EN => 0x00008000, # Unused
BCM2835_SPI0_CS_LMONO => 0x00004000, # Unused
BCM2835_SPI0_CS_LEN => 0x00002000, # LEN LoSSI enable
BCM2835_SPI0_CS_REN => 0x00001000, # REN Read Enable
BCM2835_SPI0_CS_ADCS => 0x00000800, # ADCS Automatically Deassert Chip Select
BCM2835_SPI0_CS_INTR => 0x00000400, # INTR Interrupt on RXR
BCM2835_SPI0_CS_INTD => 0x00000200, # INTD Interrupt on Done
BCM2835_SPI0_CS_DMAEN => 0x00000100, # DMAEN DMA Enable
BCM2835_SPI0_CS_TA => 0x00000080, # Transfer Active
BCM2835_SPI0_CS_CSPOL => 0x00000040, # Chip Select Polarity
BCM2835_SPI0_CS_CLEAR => 0x00000030, # Clear FIFO Clear RX and TX
BCM2835_SPI0_CS_CLEAR_RX => 0x00000020, # Clear FIFO Clear RX
BCM2835_SPI0_CS_CLEAR_TX => 0x00000010, # Clear FIFO Clear TX
BCM2835_SPI0_CS_CPOL => 0x00000008, # Clock Polarity
BCM2835_SPI0_CS_CPHA => 0x00000004, # Clock Phase
BCM2835_SPI0_CS_CS => 0x00000003, # Chip Select
# Specifies the SPI data bit ordering
BCM2835_SPI_BIT_ORDER_LSBFIRST => 0, # LSB First
BCM2835_SPI_BIT_ORDER_MSBFIRST => 1, # MSB First
# Specify the SPI data mode
BCM2835_SPI_MODE0 => 0, # CPOL = 0, CPHA = 0
BCM2835_SPI_MODE1 => 1, # CPOL = 0, CPHA = 1
BCM2835_SPI_MODE2 => 2, # CPOL = 1, CPHA = 0
BCM2835_SPI_MODE3 => 3, # CPOL = 1, CPHA = 1
# Specify the SPI chip select pin(s)
BCM2835_SPI_CS0 => 0, # Chip Select 0
BCM2835_SPI_CS1 => 1, # Chip Select 1
BCM2835_SPI_CS2 => 2, # Chip Select 2 (ie pins CS1 and CS2 are asserted)
BCM2835_SPI_CS_NONE => 3, # No CS, control it yourself
# Specifies the divider used to generate the SPI clock from the system clock.
# Figures below give the divider, clock period and clock frequency.
BCM2835_SPI_CLOCK_DIVIDER_65536 => 0, # 65536 = 256us = 4kHz
BCM2835_SPI_CLOCK_DIVIDER_32768 => 32768, # 32768 = 126us = 8kHz
BCM2835_SPI_CLOCK_DIVIDER_16384 => 16384, # 16384 = 64us = 15.625kHz
BCM2835_SPI_CLOCK_DIVIDER_8192 => 8192, # 8192 = 32us = 31.25kHz
BCM2835_SPI_CLOCK_DIVIDER_4096 => 4096, # 4096 = 16us = 62.5kHz
BCM2835_SPI_CLOCK_DIVIDER_2048 => 2048, # 2048 = 8us = 125kHz
BCM2835_SPI_CLOCK_DIVIDER_1024 => 1024, # 1024 = 4us = 250kHz
BCM2835_SPI_CLOCK_DIVIDER_512 => 512, # 512 = 2us = 500kHz
BCM2835_SPI_CLOCK_DIVIDER_256 => 256, # 256 = 1us = 1MHz
BCM2835_SPI_CLOCK_DIVIDER_128 => 128, # 128 = 500ns = = 2MHz
BCM2835_SPI_CLOCK_DIVIDER_64 => 64, # 64 = 250ns = 4MHz
BCM2835_SPI_CLOCK_DIVIDER_32 => 32, # 32 = 125ns = 8MHz
BCM2835_SPI_CLOCK_DIVIDER_16 => 16, # 16 = 50ns = 20MHz
BCM2835_SPI_CLOCK_DIVIDER_8 => 8, # 8 = 25ns = 40MHz
BCM2835_SPI_CLOCK_DIVIDER_4 => 4, # 4 = 12.5ns 80MHz
BCM2835_SPI_CLOCK_DIVIDER_2 => 2, # 2 = 6.25ns = 160MHz
BCM2835_SPI_CLOCK_DIVIDER_1 => 1, # 0 = 256us = 4kHz
};
_register_exported_constants( qw(
spi
BCM2835_SPI0_CS
BCM2835_SPI0_FIFO
BCM2835_SPI0_CLK
BCM2835_SPI0_DLEN
BCM2835_SPI0_LTOH
BCM2835_SPI0_DC
BCM2835_SPI0_CS_LEN_LONG
BCM2835_SPI0_CS_DMA_LEN
BCM2835_SPI0_CS_CSPOL2
BCM2835_SPI0_CS_CSPOL1
BCM2835_SPI0_CS_CSPOL0
BCM2835_SPI0_CS_RXF
BCM2835_SPI0_CS_RXR
BCM2835_SPI0_CS_TXD
BCM2835_SPI0_CS_RXD
BCM2835_SPI0_CS_DONE
BCM2835_SPI0_CS_TE_EN
BCM2835_SPI0_CS_LMONO
BCM2835_SPI0_CS_LEN
BCM2835_SPI0_CS_REN
BCM2835_SPI0_CS_ADCS
BCM2835_SPI0_CS_INTR
BCM2835_SPI0_CS_INTD
BCM2835_SPI0_CS_DMAEN
BCM2835_SPI0_CS_TA
BCM2835_SPI0_CS_CSPOL
BCM2835_SPI0_CS_CLEAR
BCM2835_SPI0_CS_CLEAR_RX
BCM2835_SPI0_CS_CLEAR_TX
BCM2835_SPI0_CS_CPOL
BCM2835_SPI0_CS_CPHA
BCM2835_SPI0_CS_CS
BCM2835_SPI_BIT_ORDER_LSBFIRST
BCM2835_SPI_BIT_ORDER_MSBFIRST
BCM2835_SPI_MODE0
BCM2835_SPI_MODE1
BCM2835_SPI_MODE2
BCM2835_SPI_MODE3
BCM2835_SPI_CS0
BCM2835_SPI_CS1
BCM2835_SPI_CS2
BCM2835_SPI_CS_NONE
BCM2835_SPI_CLOCK_DIVIDER_65536
BCM2835_SPI_CLOCK_DIVIDER_32768
BCM2835_SPI_CLOCK_DIVIDER_16384
BCM2835_SPI_CLOCK_DIVIDER_8192
BCM2835_SPI_CLOCK_DIVIDER_4096
BCM2835_SPI_CLOCK_DIVIDER_2048
BCM2835_SPI_CLOCK_DIVIDER_1024
BCM2835_SPI_CLOCK_DIVIDER_512
BCM2835_SPI_CLOCK_DIVIDER_256
BCM2835_SPI_CLOCK_DIVIDER_128
BCM2835_SPI_CLOCK_DIVIDER_64
BCM2835_SPI_CLOCK_DIVIDER_32
BCM2835_SPI_CLOCK_DIVIDER_16
BCM2835_SPI_CLOCK_DIVIDER_8
BCM2835_SPI_CLOCK_DIVIDER_4
BCM2835_SPI_CLOCK_DIVIDER_2
BCM2835_SPI_CLOCK_DIVIDER_1
) );
#------------------------------------------------------------
# Defines for PWM
#------------------------------------------------------------
use constant {
BCM2835_PWM_CONTROL => 0,
BCM2835_PWM_STATUS => 1,
BCM2835_PWM_DMAC => 2,
BCM2835_PWM0_RANGE => 4,
BCM2835_PWM0_DATA => 5,
BCM2835_PWM_FIF1 => 6,
BCM2835_PWM1_RANGE => 8,
BCM2835_PWM1_DATA => 9,
BCM2835_PWMCLK_CNTL => 40,
BCM2835_PWMCLK_DIV => 41,
BCM2835_PWM_PASSWRD => (0x5A << 24),
BCM2835_PWM1_MS_MODE => 0x8000, # Run in MS mode
BCM2835_PWM1_USEFIFO => 0x2000, # Data from FIFO
BCM2835_PWM1_REVPOLAR => 0x1000, # Reverse polarity
BCM2835_PWM1_OFFSTATE => 0x0800, # Ouput Off state
BCM2835_PWM1_REPEATFF => 0x0400, # Repeat last value if FIFO empty
BCM2835_PWM1_SERIAL => 0x0200, # Run in serial mode
BCM2835_PWM1_ENABLE => 0x0100, # Channel Enable
BCM2835_PWM0_MS_MODE => 0x0080, # Run in MS mode
BCM2835_PWM0_USEFIFO => 0x0020, # Data from FIFO
BCM2835_PWM0_REVPOLAR => 0x0010, # Reverse polarity
BCM2835_PWM0_OFFSTATE => 0x0008, # Ouput Off state
BCM2835_PWM0_REPEATFF => 0x0004, # Repeat last value if FIFO empty
BCM2835_PWM0_SERIAL => 0x0002, # Run in serial mode
BCM2835_PWM0_ENABLE => 0x0001, # Channel Enable
BCM2835_PWM_CLOCK_DIVIDER_2048 => 2048, # /*!< 2048 = 9.375kHz */
BCM2835_PWM_CLOCK_DIVIDER_1024 => 1024, # /*!< 1024 = 18.75kHz */
BCM2835_PWM_CLOCK_DIVIDER_512 => 512, # /*!< 512 = 37.5kHz */
BCM2835_PWM_CLOCK_DIVIDER_256 => 256, # /*!< 256 = 75kHz */
BCM2835_PWM_CLOCK_DIVIDER_128 => 128, # /*!< 128 = 150kHz */
BCM2835_PWM_CLOCK_DIVIDER_64 => 64, # /*!< 64 = 300kHz */
BCM2835_PWM_CLOCK_DIVIDER_32 => 32, # /*!< 32 = 600.0kHz */
BCM2835_PWM_CLOCK_DIVIDER_16 => 16, # /*!< 16 = 1.2MHz */
BCM2835_PWM_CLOCK_DIVIDER_8 => 8, # /*!< 8 = 2.4MHz */
BCM2835_PWM_CLOCK_DIVIDER_4 => 4, # /*!< 4 = 4.8MHz */
BCM2835_PWM_CLOCK_DIVIDER_2 => 2, # /*!< 2 = 9.6MHz, fastest you can get */
BCM2835_PWM_CLOCK_DIVIDER_1 => 1, # /*!< 1 = 4.6875kHz, same as divider 4096 */
};
_register_exported_constants( qw(
pwm
BCM2835_PWM_CONTROL
BCM2835_PWM_STATUS
BCM2835_PWM_DMAC
BCM2835_PWM0_RANGE
BCM2835_PWM0_DATA
BCM2835_PWM_FIF1
BCM2835_PWM1_RANGE
BCM2835_PWM1_DATA
BCM2835_PWMCLK_CNTL
BCM2835_PWMCLK_DIV
BCM2835_PWM_PASSWRD
BCM2835_PWM1_MS_MODE
BCM2835_PWM1_USEFIFO
BCM2835_PWM1_REVPOLAR
BCM2835_PWM1_OFFSTATE
BCM2835_PWM1_REPEATFF
BCM2835_PWM1_SERIAL
BCM2835_PWM1_ENABLE
BCM2835_PWM0_MS_MODE
BCM2835_PWM0_USEFIFO
BCM2835_PWM0_REVPOLAR
BCM2835_PWM0_OFFSTATE
BCM2835_PWM0_REPEATFF
BCM2835_PWM0_SERIAL
BCM2835_PWM0_ENABLE
BCM2835_PWM_CLOCK_DIVIDER_2048
BCM2835_PWM_CLOCK_DIVIDER_1024
BCM2835_PWM_CLOCK_DIVIDER_512
BCM2835_PWM_CLOCK_DIVIDER_256
BCM2835_PWM_CLOCK_DIVIDER_128
BCM2835_PWM_CLOCK_DIVIDER_64
BCM2835_PWM_CLOCK_DIVIDER_32
BCM2835_PWM_CLOCK_DIVIDER_16
BCM2835_PWM_CLOCK_DIVIDER_8
BCM2835_PWM_CLOCK_DIVIDER_4
BCM2835_PWM_CLOCK_DIVIDER_2
BCM2835_PWM_CLOCK_DIVIDER_1
) );
#-------------------------------------------------------------
# Defines for I2C
#-------------------------------------------------------------
use constant {
BCM2835_BSC_C => 0x0000, # BSC Master Control
BCM2835_BSC_S => 0x0004, # BSC Master Status
BCM2835_BSC_DLEN => 0x0008, # BSC Master Data Length
BCM2835_BSC_A => 0x000c, # BSC Master Slave Address
BCM2835_BSC_FIFO => 0x0010, # BSC Master Data FIFO
BCM2835_BSC_DIV => 0x0014, # BSC Master Clock Divider
BCM2835_BSC_DEL => 0x0018, # BSC Master Data Delay
BCM2835_BSC_CLKT => 0x001c, # BSC Master Clock Stretch Timeout
BCM2835_BSC_C_I2CEN => 0x00008000, # I2C Enable, 0 = disabled, 1 = enabled
BCM2835_BSC_C_INTR => 0x00000400, # Interrupt on RX
BCM2835_BSC_C_INTT => 0x00000200, # Interrupt on TX
BCM2835_BSC_C_INTD => 0x00000100, # Interrupt on DONE
BCM2835_BSC_C_ST => 0x00000080, # Start transfer, 1 = Start a new transfer
BCM2835_BSC_C_CLEAR_1 => 0x00000020, # Clear FIFO Clear
BCM2835_BSC_C_CLEAR_2 => 0x00000010, # Clear FIFO Clear
BCM2835_BSC_C_READ => 0x00000001, # Read transfer
BCM2835_BSC_S_CLKT => 0x00000200, # Clock stretch timeout
BCM2835_BSC_S_ERR => 0x00000100, # ACK error
BCM2835_BSC_S_RXF => 0x00000080, # RXF FIFO full, 0 = FIFO is not full, 1 = FIFO is full
BCM2835_BSC_S_TXE => 0x00000040, # TXE FIFO full, 0 = FIFO is not full, 1 = FIFO is full
BCM2835_BSC_S_RXD => 0x00000020, # RXD FIFO contains data
BCM2835_BSC_S_TXD => 0x00000010, # TXD FIFO can accept data
BCM2835_BSC_S_RXR => 0x00000008, # RXR FIFO needs reading (full)
BCM2835_BSC_S_TXW => 0x00000004, # TXW FIFO needs writing (full)
BCM2835_BSC_S_DONE => 0x00000002, # Transfer DONE
BCM2835_BSC_S_TA => 0x00000001, # Transfer Active
BCM2835_BSC_FIFO_SIZE => 16, # BSC FIFO size
BCM2835_I2C_CLOCK_DIVIDER_2500 => 2500, # 2500 = 10us = 100 kHz
BCM2835_I2C_CLOCK_DIVIDER_626 => 626, # 622 = 2.504us = 399.3610 kHz
BCM2835_I2C_CLOCK_DIVIDER_150 => 150, # 150 = 60ns = 1.666 MHz (default at reset)
BCM2835_I2C_CLOCK_DIVIDER_148 => 148, # 148 = 59ns = 1.689 MHz
BCM2835_I2C_REASON_OK => 0x00, # Success
BCM2835_I2C_REASON_ERROR_NACK => 0x01, # Received a NACK
BCM2835_I2C_REASON_ERROR_CLKT => 0x02, # Received Clock Stretch Timeout
BCM2835_I2C_REASON_ERROR_DATA => 0x04, # Not all data is sent / received
};
_register_exported_constants( qw(
i2c
BCM2835_BSC_C
BCM2835_BSC_S
BCM2835_BSC_DLEN
BCM2835_BSC_A
BCM2835_BSC_FIFO
BCM2835_BSC_DIV
BCM2835_BSC_DEL
BCM2835_BSC_CLKT
BCM2835_BSC_C_I2CEN
BCM2835_BSC_C_INTR
BCM2835_BSC_C_INTT
BCM2835_BSC_C_INTD
BCM2835_BSC_C_ST
BCM2835_BSC_C_CLEAR_1
BCM2835_BSC_C_CLEAR_2
BCM2835_BSC_C_READ
BCM2835_BSC_S_CLKT
BCM2835_BSC_S_ERR
BCM2835_BSC_S_RXF
BCM2835_BSC_S_TXE
BCM2835_BSC_S_RXD
BCM2835_BSC_S_TXD
BCM2835_BSC_S_RXR
BCM2835_BSC_S_TXW
BCM2835_BSC_S_DONE
BCM2835_BSC_S_TA
BCM2835_BSC_FIFO_SIZE
BCM2835_I2C_CLOCK_DIVIDER_2500
BCM2835_I2C_CLOCK_DIVIDER_626
BCM2835_I2C_CLOCK_DIVIDER_150
BCM2835_I2C_CLOCK_DIVIDER_148
BCM2835_I2C_REASON_OK
BCM2835_I2C_REASON_ERROR_NACK
BCM2835_I2C_REASON_ERROR_CLKT
BCM2835_I2C_REASON_ERROR_DATA
) );
#-----------------------------------------
# create OO method wrappers
#-----------------------------------------
{
for my $method( qw(
gpio_fget
gpio_get_eds
get_pin
gpio_fget_name
set_SPI0
set_I2C0
set_I2C1
set_UART0
set_UART1
set_CTS0
set_CTS1
set_PWM0
spi_transfern
spi_transfernb
spi_writenb
) ) {
no strict 'refs';
my $subkey = __PACKAGE__ . qq(::$method);
my $funckey = qq(hipi_$method);
*{$subkey} = sub { shift; &$funckey( @_ ); };
}
for my $method( qw(
peri_read
peri_read_nb
peri_write
peri_write_nb
peri_set_bits
gpio_fsel
gpio_set
gpio_clr
gpio_set_multi
gpio_clr_multi
gpio_lev
gpio_eds
gpio_set_eds
gpio_eds_multi
gpio_set_eds_multi
gpio_ren
gpio_clr_ren
gpio_fen
gpio_clr_fen
gpio_hen
gpio_clr_hen
gpio_len
gpio_clr_len
gpio_aren
gpio_clr_aren
gpio_afen
gpio_clr_afen
gpio_pud
gpio_pudclk
gpio_pad
gpio_set_pad
delay
delayMicroseconds
gpio_write
gpio_write_multi
gpio_write_mask
gpio_set_pud
gpio_get_pud
spi_begin
spi_end
spi_setBitOrder
spi_setClockDivider
spi_setDataMode
spi_chipSelect
spi_setChipSelectPolarity
spi_transfer
st_read
st_delay
peripherals
gpio
pwm
clk
pads
spi0
bsc0
bsc1
st
peripherals_base
uses_dmb
) ) {
no strict 'refs';
my $subkey = __PACKAGE__ . qq(::$method);
my $funckey = qq(bcm2835_$method);
*{$subkey} = sub { shift; &$funckey( @_ ); };
}
}
sub i2c_read {
my($self, $numbytes) = @_;
$numbytes ||= 1;
my $buffer = chr(0) x $numbytes;
bcm2835_i2c_read( $buffer, $numbytes );
return $buffer;
}
sub hipi_get_pin {
HiPi::BCM2835::Pin->_open( pinid => $_[0] );
}
sub hipi_gpio_fget_name {
my($pinid) = @_;
return 'UNKNOWN' if $pinid < 0 || $pinid > 53;
my $checkval = hipi_gpio_fget( $pinid );
if ( $checkval == BCM2835_GPIO_FSEL_INPT()) {
return 'INPUT';
} elsif ( $checkval == BCM2835_GPIO_FSEL_OUTP()) {
return 'OUTPUT';
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT0()) {
return $altnames->[$pinid]->[0];
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT1()) {
return $altnames->[$pinid]->[1];
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT2()) {
return $altnames->[$pinid]->[2];
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT3()) {
return $altnames->[$pinid]->[3];
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT4()) {
return $altnames->[$pinid]->[4];
} elsif ( $checkval == BCM2835_GPIO_FSEL_ALT5()) {
return $altnames->[$pinid]->[5];
} else {
return 'UNKNOWN';
}
}
sub new {
my($class, %params) = @_;
$params{devicename} = '/dev/mem';
my $self = $class->SUPER::new(%params);
bcm2835_init();
return $self;
}
sub hipi_set_SPI0 {
if($_[0]) {
bcm2835_spi_begin();
} else {
bcm2835_spi_end();
}
}
sub hipi_set_I2C0 {
my($on) = @_;
my $retval = 0;
my @pins = ( I2C1_SDA, I2C1_SCL );
if( $on ) {
if(RPI_BOARD_REVISION > 1) {
# we must disable the S5 pin 0 & 1 ALT0 function
for my $gpio ( 0, 1 ) {
my $currentmode = hipi_gpio_fget($gpio);
if( $currentmode != BCM2835_GPIO_FSEL_INPT()) {
bcm2835_gpio_fsel($gpio, BCM2835_GPIO_FSEL_INPT());
}
}
}
$retval = bcm2835_hipi_i2c_begin( RPI_BOARD_REVISION );
} else {
if( RPI_BOARD_REVISION > 1) {
# we must enable the S5 pin 0 & 1 ALT0 function
for my $gpio ( 0, 1 ) {
my $currentmode = hipi_gpio_fget($gpio);
if( $currentmode != BCM2835_GPIO_FSEL_ALT0()) {
bcm2835_gpio_fsel($gpio, BCM2835_GPIO_FSEL_ALT0());
}
}
}
$retval = bcm2835_hipi_i2c_end( RPI_BOARD_REVISION );
}
return $retval;
}
sub hipi_set_I2C1 {
my($on) = @_;
my $retval = 0;
return $retval if RPI_BOARD_REVISION == 1;
if( $on ) {
$retval = bcm2835_hipi_i2c_begin( RPI_BOARD_REVISION );
} else {
$retval = bcm2835_hipi_i2c_end( RPI_BOARD_REVISION );
}
return $retval;
}
sub hipi_set_UART0 {
my($on) = @_;
my @pins = ( RPI_V2_GPIO_P1_08(), RPI_V2_GPIO_P1_10() );
if( $on ) {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_ALT0());
}
} else {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_INPT());
}
}
}
sub hipi_set_CTS0 {
my($on) = @_;
my @pins = ( RPI_V2_GPIO_P5_05(), RPI_V2_GPIO_P5_06() );
if( $on ) {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_ALT3());
}
} else {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_INPT());
}
}
}
sub hipi_set_UART1 {
my($on) = @_;
my @pins = ( RPI_V2_GPIO_P1_08(), RPI_V2_GPIO_P1_10() );
if( $on ) {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_ALT5());
}
} else {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_INPT());
}
}
}
sub hipi_set_CTS1 {
my($on) = @_;
my @pins = ( RPI_V2_GPIO_P5_05(), RPI_V2_GPIO_P5_06() );
if( $on ) {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_ALT5());
}
} else {
for my $pin ( @pins ) {
bcm2835_gpio_fsel($pin, BCM2835_GPIO_FSEL_INPT());
}
}
}
sub hipi_set_PWM0 {
my($on) = @_;
if( $on ) {
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_12(), BCM2835_GPIO_FSEL_ALT5());
} else {
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_12(), BCM2835_GPIO_FSEL_INPT());
}
}
1;
=pod
=encoding UTF-8
=head1 NAME
HiPi::BCM2835 - Modules for Raspberry Pi GPIO
=head1 DESCRIPTION
This module provides access to the gpio and I2C functions of the bcm2835 library for HiPi Perl modules.
Documentation and details are available at
L<http://hipi.znix.com/archive/bcm2835.html>
=head1 AUTHOR
Mark Dootson, C<< mdootson@cpan.org >>.
=head1 COPYRIGHT
Copyright (c) 2013 - 2019 Mark Dootson
=cut
__END__