After working on this for a while, I found someone else who was having problems getting the SPI to work in docker. Enable spi and gpio in docker? - Hardware - Home Assistant Community
They said that they successfully replaced the wiringpi calls with the corresponding pigpio calls
I went through and replaced all the wiringpi calls with pigpio calls and created my own replacement function for the wiringpi microsecond delay method.
I am trying to run the pigpio daemon in a separate container.
However, it seems I am having problems successfully starting the pigpio daemon. When it runs I get the following message.
07.04.20 11:06:39 (-0400) AD_test %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
07.04.20 11:06:39 (-0400) AD_test Can't connect to pigpio at soft(8888)
07.04.20 11:06:39 (-0400) AD_test
07.04.20 11:06:39 (-0400) AD_test Did you start the pigpio daemon? E.g. sudo pigpiod
07.04.20 11:06:39 (-0400) AD_test
07.04.20 11:06:39 (-0400) AD_test Did you specify the correct Pi host/port in the environment
07.04.20 11:06:39 (-0400) AD_test variables PIGPIO_ADDR/PIGPIO_PORT?
07.04.20 11:06:39 (-0400) AD_test E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888
07.04.20 11:06:39 (-0400) AD_test
07.04.20 11:06:39 (-0400) AD_test Did you specify the correct Pi host/port in the
07.04.20 11:06:39 (-0400) AD_test pigpio.pi() function? E.g. pigpio.pi('soft', 8888)
07.04.20 11:06:39 (-0400) AD_test %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
07.04.20 11:06:39 (-0400) AD_test Empty main loop
Thanks for your help getting pigpio to work.
Below are all my relevant settings and files
Device Configuration
pigpio uses GPU memory, so with GPU memory set at less than 64MB I got the following error:
initMboxBlock: init mbox zaps failed
Device Environment Variables
Files
docker-compose.yml
version: '2.1'
services:
pigpio:
privileged: true
restart: always
build: ./rpi-pigpio
ports:
- "8888:8888"
cap_add:
- SYS_RAWIO
devices:
- "/dev/mem"
- "/dev/vcio"
AD_test:
privileged: true
build: ./AD_test
depends_on:
- pigpio
rpi_pigpio
Dockerfile
(from https://github.com/lachatak/rpi-pigpio/blob/master/Dockerfile)
FROM resin/rpi-raspbian:jessie
MAINTAINER Krisztian Lachata <krisztian.lachata@gmail.com>
RUN apt-get update && apt-get upgrade
RUN apt-get install build-essential daemontools git -y
WORKDIR /opt
RUN git config --global http.sslVerify false
RUN git clone https://github.com/joan2937/pigpio
WORKDIR /opt/pigpio
RUN make
RUN make install
RUN ln -s /usr/local/lib/libpigpio.so /usr/lib/libpigpio.so
RUN mkdir -p /etc/svscan/pigpiod
RUN echo "#!/bin/bash\nif [ ! -f /var/run/pigpio.pid ]; then\n echo 'Starting'\n exec /opt/pigpio/pigpiod\nfi" > /etc/svscan/pigpiod/run
RUN chmod +x /etc/svscan/pigpiod/run
EXPOSE 8888
CMD ["/usr/bin/svscan", "/etc/svscan/"]
AD_test
Dockerfile.template
FROM balenalib/%%BALENA_MACHINE_NAME%%-python:3-stretch-run
# enable container init system.
ENV INITSYSTEM on
# use `install_packages` if you need to install dependencies,
# for instance if you need git, just uncomment the line below.
# RUN install_packages git
RUN pip install --upgrade pip
RUN apt-get update && apt-get install -yq --no-install-recommends build-essential rpi.gpio
RUN pip install pigpio
RUN apt-get install pigpio python-pigpio python3-pigpio
# Set our working directory
WORKDIR /usr/src/AD_test
# Copy requirements.txt first for better cache on later pushes
COPY requirements.txt requirements.txt
# pip install python deps from requirements.txt on the resin.io build server
RUN pip install -r requirements.txt
# This will copy all files in our root to the working directory in the container
COPY . ./
# Enable udevd so that plugged dynamic hardware devices show up in our container.
ENV UDEV=1
# main.py will run when container starts up on the device
CMD ["python","-u","src/AD_test_main.py"]
requirements
RPi.GPIO
pySerial
AD_test_main.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
from ADS1256_definitions import *
from pipyadc import ADS1256
def main():
print("Empty main loop")
time.sleep(10)
if __name__ == "__main__":
main()
pipyadc.py
(following is a reduced snippet with init and SPI read/write)
# -*- coding: utf-8 -*-
"""PiPyADC - Python module for interfacing Texas Instruments SPI
bus based analog-to-digital converters with the Raspberry Pi.
Currently only implemented class in this module is ADS1256 for the
ADS1255 and ADS1256 chips which are register- and command compatible.
Download: https://github.com/ul-gh/PiPyADC
Depends on WiringPi library, see:
https://github.com/WiringPi/WiringPi-Python
Uses code from: https://github.com/heathsd/PyADS1256
License: GNU LGPLv2.1, see:
https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html
Ulrich Lukas, 2017-03-03
"""
import time
#import wiringpi as wp
import pigpio
#pi_gpio = pigpio.pi()
pi_gpio = pigpio.pi('soft', 8888)
import pigpio_delay
from ADS1256_definitions import *
import ADS1256_default_config
class ADS1256(object):
"""Python class for interfacing the ADS1256 and ADS1255 analog to
digital converters with the Raspberry Pi.
This is part of module PiPyADC
Download: https://github.com/ul-gh/PiPyADC
Default pin and settings configuration is for the Open Hardware
"Waveshare High-Precision AD/DA Board"
See file ADS1256_default_config.py for
configuration settings and description.
Register read/write access is implemented via Python class/instance
properties. Commands are implemented as functions.
See help(ADS1256) for usage of the properties and functions herein.
See ADS1256_definitions.py for chip registers, flags and commands.
Documentation source: Texas Instruments ADS1255/ADS1256
datasheet SBAS288: http://www.ti.com/lit/ds/sbas288j/sbas288j.pdf
"""
.
.
.
# Constructor for the ADC object: Hardware pin configuration must be
# set up at initialization phase and can not be changed later.
# Register/Configuration Flag settings are initialized, but these
# can be changed during runtime via class properties.
# Default config is read from external file (module) import
def __init__(self, conf=ADS1256_default_config):
# Set up the wiringpi object to use physical pin numbers
#wp.wiringPiSetupPhys()
# Config and initialize the SPI and GPIO pins used by the ADC.
# The following four entries are actively used by the code:
self.SPI_CHANNEL = conf.SPI_CHANNEL
self.DRDY_PIN = conf.DRDY_PIN
self.CS_PIN = conf.CS_PIN
self.DRDY_TIMEOUT = conf.DRDY_TIMEOUT
self.DRDY_DELAY = conf.DRDY_DELAY
#DA settings
self.DA_CS_PIN = 16
# Only one GPIO input:
if conf.DRDY_PIN is not None:
self.DRDY_PIN = conf.DRDY_PIN
'''
wp.pinMode(conf.DRDY_PIN, wp.INPUT)
'''
pi_gpio.set_mode(conf.DRDY_PIN, pigpio.INPUT)
# GPIO Outputs. Only the CS_PIN is currently actively used. ~RESET and
# ~PDWN must be set to static logic HIGH level if not hardwired:
for pin in (conf.CS_PIN,
conf.RESET_PIN,
conf.PDWN_PIN):
if pin is not None:
pi_gpio.pinMode(pin, pigpio.OUTPUT)
'''
wp.pinMode(pin, wp.OUTPUT)
'''
pi_gpio.write(pin, 1)
'''
wp.digitalWrite(pin, wp.HIGH)
'''
# Initialize the wiringpi SPI setup. Return value is the Linux file
# descriptor for the SPI bus device:
self.spi_handle = pi_gpio.spi_open(conf.SPI_CHANNEL, conf.SPI_FREQUENCY, conf.SPI_MODE)
'''
fd = wp.wiringPiSPISetupMode(
conf.SPI_CHANNEL, conf.SPI_FREQUENCY, conf.SPI_MODE)
if fd == -1:
'''
if (self.spi_handle == -1):
raise IOError("ERROR: Could not access SPI device file")
return False
# ADS1255/ADS1256 command timing specifications. Do not change.
# Delay between requesting data and reading the bus for
# RDATA, RDATAC and RREG commands (datasheet: t_6 >= 50*CLKIN period).
self._DATA_TIMEOUT_US = 1 + (50*1000000)/conf.CLKIN_FREQUENCY
# Command-to-command timeout after SYNC and RDATAC
# commands (datasheet: t11)
self._SYNC_TIMEOUT_US = 1 + (24*1000000)/conf.CLKIN_FREQUENCY
# See datasheet ADS1256: CS needs to remain low
# for t_10 = 8*T_CLKIN after last SCLK falling edge of a command.
# Because this delay is longer than timeout t_11 for the
# RREG, WREG and RDATA commands of 4*T_CLKIN, we do not need
# the extra t_11 timeout for these commands when using software
# chip select selection and the _CS_TIMEOUT_US.
self._CS_TIMEOUT_US = 1 + (8*1000000)/conf.CLKIN_FREQUENCY
# When using hardware/hard-wired chip select, still a command-
# to command timeout of t_11 is needed as a minimum for the
# RREG, WREG and RDATA commands.
self._T_11_TIMEOUT_US = 1 + (4*1000000)/conf.CLKIN_FREQUENCY
# Initialise class properties
self.v_ref = conf.v_ref
# At hardware initialisation, a settling time for the oscillator
# is necessary before doing any register access.
# This is approx. 30ms, according to the datasheet.
time.sleep(0.03)
self.wait_DRDY()
print('Before ADS1256 device reset')
# Device reset for defined initial state
self.reset()
# Configure ADC registers:
# Status register not yet set, only variable written to avoid multiple
# triggering of the AUTOCAL procedure by changing other register flags
self._status = conf.status
# Class properties now configure registers via their setter functions
self.mux = conf.mux
self.adcon = conf.adcon
self.drate = conf.drate
self.gpio = conf.gpio
self.status = conf.status
#configure DA cs pin mode
pi_gpio.set_mode(self.DA_CS_PIN, pigpio.OUTPUT)
'''
wp.pinMode(self.DA_CS_PIN, wp.OUTPUT)
'''
.
.
.
def _send_byte(self, mybyte):
# Sends a byte via the SPI bus
# Workaround for single-byte transfers due to mutation of immutable
# function argument. Thanks @JKR
# wiringPiSPIDataRW() returns a Linux ioctl() error code.
# We ignore that since we already checked for presence of the file
# descriptor of the SPI device during initialisation.
'''
wp.wiringPiSPIDataRW(self.SPI_CHANNEL, "%s" % chr(mybyte&0xFF))
'''
pi_gpio.spi_write(self.spi_handle, "%s" % chr(mybyte&0xFF))
def _read_byte(self):
# Returns a byte read via the SPI bus
(nBytes, MISObyte) = pi_gpio.spi_read(self.spi_handle, 1)
if (nBytes < 0):
print('Error: _read_byte failed and gave error code %d', nBytes)
'''
MISObyte = wp.wiringPiSPIDataRW(self.SPI_CHANNEL, chr(0xFF))
'''
return ord(MISObyte[1])
PDFs of full files for reference.
pipyadc.py.pdf (70.3 KB) ADS1256_default_config.py.pdf (52.9 KB) ADS1256_definitions.py.pdf (21.6 KB) pigpio_delay.py.pdf (17.8 KB)