I'm trying to simulate a compound action potential for calibrating research instruments. The goal is to output a certain 10 µV signal at 250 Hz. The low voltage will be dealt with later, the main problem for me is the frequency. The picture below shows an overview of the system I'm trying to make.
By data acquisition from a live animal, and processing the data in MATLAB, I've made a low noise signal, with 789 values in 12-bit format. I then cloned the repository where I stored this in csv-format to a Raspberry Pi using Git. Below is the Python script I've written on the RPi. You can skip to def main in the script to see functionality.
#!/usr/bin/python
import spidev
from time import sleep
import RPi.GPIO as GPIO
import csv
import sys
import math
DEBUG = False
spi_max_speed = 20 * 1000000
V_Ref = 5000
Resolution = 2**12
CE = 0
spi = spidev.SpiDev()
spi.open(0,CE)
spi.max_speed_hz = spi_max_speed
LDAQ = 22
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LDAQ, GPIO.OUT)
GPIO.output(LDAQ,GPIO.LOW)
def setOutput(val):
lowByte = val & 0b11111111 #Make bytes using MCP4921 data sheet info
highByte = ((val >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4
if DEBUG :
print("Highbyte = {0:8b}".format(highByte))
print("Lowbyte = {0:8b}".format(lowByte))
spi.xfer2([highByte, lowByte])
def main():
with open('signal12bit.csv') as signal:
signal_length = float(raw_input("Please input signal length in ms: "))
delay = float(raw_input("Please input delay after signal in ms: "))
amplitude = float(raw_input("Please input signal amplitude in mV: "))
print "Starting Simulant with signal length %.1f ms, delay %.1f ms and amplitude %.1f mV." % (signal_length, delay, amplitude)
if not DEBUG : print "Press ctrl+c to close."
sleep (1) #Wait a sec before starting
read = csv.reader(signal, delimiter=' ', quotechar='|')
try:
while(True):
signal.seek(0)
for row in read: #Loop csv file rows
if DEBUG : print ', '.join(row)
setOutput(int(row)/int((V_Ref/amplitude))) #Adjust amplitude, not super necessary to do in software
sleep (signal_length/(data_points*1000) #Divide by 1000 to make into ms, divide by length of data
sleep (delay/1000)
except (KeyboardInterrupt, Exception) as e:
print(e)
print "Closing SPI channel"
setOutput(0)
GPIO.cleanup()
spi.close()
if __name__ == '__main__':
main()
This script almost works as intended. Connecting the output pin of an MCP4921 DAC to an oscilloscope shows that it reproduces the signal very well, and it outputs the subsequent delay correctly.
Unfortunately, the data points are seperated much further than I need them to be. The shortest time I can cram the signal into is about 79 ms. This is due to dividing by 789000 in the sleep function, which I know is too much to ask from Python and from the Pi, because reading the csv file takes time. However, if I try making an array manually, and putting those values out instead of reading the csv file, I can achieve a frequency over 6 kHz with no loss.
My question is this
How can I get this signal to appear at a frequency of 250 Hz, and decrease it reliably from the user's input? I've thought about manually writing the 789 values into an array in the script, and then changing the SPI speed to whatever value fits with 250 Hz. This would eliminate the slow csv reader function, but then you can't reduce the frequency from user input. In any case, eliminating the need for csv.read would help a lot. Thanks!
Figured it out earlier today, so I thought I'd post an answer here, in case someone comes upon a similar problem in the future.
The problem with the internal delay between data points cannot be solved with sleep(), for several reasons. What I ended up doing was the following
Move all math and function calling out of the critical loop
Do a linear regression analysis on the time it takes to transfer the values with no delay
Increase the number of datapoints in the CSV file to "plenty" (9600) in MATLAB
Calculate the number of points needed to meet the user's wanted signal length
Take evenly seperated entries from the now bigger CSV file to fit that number of points as closely as possible.
Calculate these values and then calculate the SPI bytes explicitly
Save the two byte lists, and output them directly in the critical loop
The new code, with a bit of input checking, is below
#!/usr/bin/python
import spidev
from time import sleep
import RPi.GPIO as GPIO
import sys
import csv
import ast
spi_max_speed = 16 * 1000000 # 16 MHz
V_Ref = 5000 # 5V in mV
Resolution = 2**12 # 12 bits for the MCP 4921
CE = 0 # CE0 or CE1, select SPI device on bus
total_data_points = 9600 #CSV file length
spi = spidev.SpiDev()
spi.open(0,CE)
spi.max_speed_hz = spi_max_speed
LDAQ=22
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LDAQ, GPIO.OUT)
GPIO.output(LDAQ,GPIO.LOW)
def main():
#User inputs and checking for digits
signalLengthU = raw_input("Input signal length in ms, minimum 4: ")
if signalLengthU.isdigit():
signalLength = signalLengthU
else:
signalLength = 4
delayU = raw_input("Input delay after signal in ms: ")
if delayU.isdigit():
delay = delayU
else:
delay = 0
amplitudeU = raw_input("Input signal amplitude in mV, between 1 and 5000: ")
if amplitudeU.isdigit():
amplitude = amplitudeU
else:
amplitude = 5000
#Calculate data points, delay, and amplitude
data_points = int((1000*float(signalLength)-24.6418)/12.3291)
signalDelay = float(delay)/1000
setAmplitude = V_Ref/float(amplitude)
#Load and save CSV file
datain = open('signal12bit.csv')
read = csv.reader(datain, delimiter=' ', quotechar='|')
signal = []
for row in read:
signal.append(ast.literal_eval(row[0]))
#Downsampling to achieve desired signal length
downsampling = int(round(total_data_points/data_points))
signalSpeed = signal[0::downsampling]
listlen = len(signalSpeed)
#Construction of SPI bytes, to avoid calling functions in critical loop
lowByte = []
highByte = []
for i in signalSpeed:
lowByte.append(int(i/setAmplitude) & 0b11111111)
highByte.append(((int(i/setAmplitude) >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4)
print "Starting Simulant with signal length %s ms, delay %s ms and amplitude %s mV." % (signalLength, delay, amplitude)
print "Press ctrl+c to stop."
sleep (1)
try:
while(True): #Main loop
for i in range(listlen):
spi.xfer2([highByte[i],lowByte[i]]) #Critical loop, no delay!
sleep (signalDelay)
except (KeyboardInterrupt, Exception) as e:
print e
print "Closing SPI channel"
lowByte = 0 & 0b11111111
highByte = ((0 >> 8) & 0xff) | 0b0 << 7 | 0b0 << 6 | 0b1 << 5 | 0b1 << 4
spi.xfer2([highByte, lowByte])
GPIO.cleanup()
spi.close()
if __name__ == '__main__':
main()
The result is exactly what I wanted. Below is seen an example from the oscilloscope with a signal length of 5 ms; 200 Hz. Thanks for your help, guys!
Related
I'm using python to read in values from a high-speed 8-bit ADC (the ADS7885 linked here) and convert them into voltages using the SPI0 ports on a Raspberry Pi 4. At this point, I do receive values from the ADC on the Raspberry Pi, but the values I am reading in are not at all accurate. I was hoping someone might be able to help me out with my code so that I can accurately read values from the ADC at a sampling rate of 48mHz and convert them into voltages?
I think the problem might have to do with the number of clock cycles it takes before the ADC can read/convert valid data? The datasheet says that this specific ADC requires 16 SCLK cycles before it is able to begin converting valid data, but I'm not sure how to enforce this in my code.
I followed sample code for a 10-bit ADC that uses the Spidev python module, but I'm open to any other code solutions. This is what I'm currently running:
spi404 = spidev.SpiDev(0, 0)
def read_adc404(adc_ch, vref = 5):
msg = 0b11
msg = ((msg << 1) + 0) << 3
msg = (msg, 0b000000)
reply = spi404.xfer2(msg)
adc = 0
for n in reply:
adc = (adc << 6) + n
adc = adc >> 2
voltage = (vref * adc) / 256
return voltage
Any tips or help would be greatly appreciated!!
my very first post - so please be gentle
Raspberry Pi Zero - Python3, AD5325 10 bit DAC
I realise I'm probably biting off more than I can chew for such a python beginner - but I do have some basic programing experience and there is nothing like trying to make something real actually work. What I'm trying to do is convert my working 'basic' uC code to Python for use on the Pi
This is the working code in basic
W_Data_DAC=W_Data_DAC*3.41 'value between 0 and 300 - scaled to 10 bits
Clear B_DAC_pnt 'clear the pointer
B_DAC_pnt.2=1 'set for DAC C
W_Data_DAC=W_Data_DAC<<2 'shift left 2 places (to fit the DAC requirements)
W_Data_DAC.12=0 'set to update all channels
W_Data_DAC.13=1 'Normal Operation
BusOut Ad5315,[B_DAC_pnt,B_Hi_DAC,B_Lo_DAC] 'update each DAC
So I start of with a word size variable between 0 - 1023 (10 bits) W_Data_DAC
set bit 2 of a pointer byte (B_DAC_pnt) - instruct to write to ch C
shift W_Data_DAC left 2 places
clear W_Data_DAC bit 12 - instruct to update all ch
set W_Data_DAC bit 13 - instruct normal operation
then write 3 bytes to the DAC via the i2c bus
This is the code I have so far in Python
import smbus
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM) # GPIO Numbers instead of board numbers
#GPIO.setwarning(False) # no warnings
Coil_1 = 17
Coil_2 = 27
Coil_3 = 22
chan_list = [Coil_1,Coil_2,Coil_3]
GPIO.setup(chan_list, GPIO.OUT)
#GPIO.setup(Coil_1, GPIO.OUT) # GPIO Assign mode
#GPIO.setup(Coil_2, GPIO.OUT) # GPIO Assign mode
#GPIO.setup(Coil_3, GPIO.OUT) # GPIO Assign mode
bus = smbus.SMBus(1)
adc_add=0x4d #ADC address
dac=0x0c #DAC address
def an_in(): #read the current analogue input
result=bus.read_i2c_block_data(adc_add, 0x00, 2)
test1=(result[0]<<8)+result[1]
v_in=test1*0.001221
return v_in
def an_out(v_out): #v_out will be a value 0 to 300 from the calling routine)
v_out=v_out*3.41 #range now 0-1023 10 bits
#convert this a 16 bit word
W_Out=int(v_out) # convert to an integer (? 16 bits)
W_out=W_out<<2 #shift left 2 places
W_out=W_out | 12288 #Logocal OR to set bit 13
bus.write_i2c_block_data(dac,W_out)
while True:
#run through the relays
GPIO.output(Coil_1, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(Coil_1, GPIO.LOW)
time.sleep(0.5)
GPIO.output(Coil_2, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(Coil_2, GPIO.LOW)
time.sleep(0.5)
GPIO.output(Coil_3, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(Coil_3, GPIO.LOW)
time.sleep(0.5)
#This reads the state of the PCF8574 Port Expander / anlg input
result=bus.read_byte(0x20)
print('Dig Input ',format(result,'08b'))
print('Anlg In = ',format(an_in(),'f'))
an_out(an_in) #call the DAC value 0-300
time.sleep(2)
as you can see - I have 3 relays, 1 ADC and a DAC - ok with the first 2 parts, but a bit stumped with the DAC.
The output I'm getting is:
Dig Input 11111111
Anlg In = 3.632475
Traceback (most recent call last):
File "i2c.py", line 67, in
an_out(an_in) #call the DAC value 0-300
File "i2c.py", line 34, in an_out
v_out=v_out*3.41 #range now 0-1023 10 bits
TypeError: unsupported operand type(s) for *: 'function' and 'float'
I suspect I'm making a number of very basic errors here - but my approach to learning is 'bite off more than you can chew - then chew like mad'
Specifically my questions are - why I can't call the function an_out(an_in)?
and why can't I multiply the variable v_out by 4.31 - I haven't specified the var as an integer anywhere?
Also - I suspect this is not the correct way to write to the DAC in this case anyway?
This question is as much me 'dipping my toe' as it it trying to solve a particular problem - my next challenge is figuring out my toolchain (vim seems very clunky - I'm after an IDE that works headlessly and has a good debugger - I get a lot of bugs :-)
Any help or advice would be much appreciated. Thanks
Resolved - posted here for future reference
import smbus
def an_out(v_out): #0 to 300 (PSI)
if v_out > 300:
v_out = 300 #max value is 300
print('Anlg Out = ', v_out)
v_out = int(v_out * 3.41) #scale to 10 bits
v_out = v_out << 2 #shift left 2 places
mask = 1 << 13 #set mask
v_out = v_out | mask #this should set bit 13
v_out_hi = v_out & 65280 #mask out the high byte
v_out_hi = v_out_hi >> 8 #shiift down to 8 bits
v_out_lo = v_out & 255 #mask out the high byte
b_pnt=1 #DAC Ch C
command = [(v_out_hi), (v_out_lo)] #load the command
bus.write_i2c_block_data(dac, b_pnt, command) #i2c (4-20ma out)
b_pnt=4 #DAC Ch A
bus.write_i2c_block_data(dac, b_pnt, command) #i2c (0-10v out)
I'd be glad if anyone can advise if I have approached this incorrectly or my coding style is not up to scratch (only just starting with python).
Kind regards
I wrote a python 3 script which tests an SPI link to an FPGA. It runs on an Raspberry Pi 3. The test works like this: after putting the FPGA in test mode (a push switch), send the first byte, which can be any value. Then further bytes are sent indefinitely. Each one increments by the first value sent, truncated to 8 bits. Thus, if the first value is 37, the FPGA expects the following sequence:
37, 74, 111, 148, 185, 222, 4, 41 ...
Some additional IO pins are used to signal between the devices - RUN (RPi output) starts the test (necessary because the FPGA times out in about 15ms if it expects a byte) and ERR (FPGA output) signals an error. Errors can thus be counted at both ends.
In addition, the RPi script writes a one line summary of bytes sent and number of erros every million bytes.
All of this works just fine. But after running for about 3 days, I get the following error on the RPi:
free(): invalid pointer: 0x00405340
I get this exact same error on two identical test setups, even the same memory address. The last report says
"4294M bytes sent, 0 errors"
I seem to have proved the SPI link, but I am concerned that this long-running program crashes for no apparent reason.
Here is the important part of my test code:
def _report(self, msg):
now = datetime.datetime.now()
os.system("echo \"{} : {}\" > spitest_last.log".format(now, msg))
def spi_test(self):
global end_loop
input("Put the FPGA board into SPI test mode (SW1) and press any key")
self._set_run(True)
self.END_LOOP = False
print("SPI test is running, CTRL-C to end.")
# first byte is sent without LOAD, this is the seed
self._send_byte(self._val)
self._next_val()
end_loop = False
err_flag = False
err_cnt = 0
byte_count = 1
while not end_loop:
mb = byte_count % 1000000
if mb == 0:
msg = "{}M bytes sent, {} errors".format(int(byte_count/1000000), err_cnt)
print("\r" + msg, end="")
self._report(msg)
err_flag = True
else:
err_flag = False
#print("sending: {}".format(self._val))
self._set_load(True)
if self._errors and err_flag:
self._send_byte(self._val + 1)
else:
self._send_byte(self._val)
if self.is_error():
err_cnt += 1
msg = "{}M bytes sent, {} errors".format(int(byte_count/1000000), err_cnt)
print("\r{}".format(msg), end="")
self._report(msg)
self._set_load(False)
# increase the value by the seed and truncate to 8 bits
self._next_val()
byte_count += 1
# test is done
input("\nSPI test ended ({} bytes sent, {} errors). Press ENTER to end.".format(byte_count, err_cnt))
self._set_run(False)
(Note for clarification : there is a command line option to artifically create an error every million bytes. Hence the " err_flag" variable.)
I've tried using python3 in console mode, and there seems to be no issue with the size of the byte_count variable (there shouldn't be, according to what I have read about python integer size limits).
Anyone have an idea as to what might cause this?
This issue is connected to spidev versions older than 3.5 only. The comments below were done under assumption that I was using the upgraded version of spidev.
#############################################################################
I can confirm this problem. It is persistent with both RPi3B and RPi4B. Using python 3.7.3 at both RPi3 and RPi4. The version of spidev which I tried were 3.3, 3.4 and the latest 3.5. I was able to reproduce this error several times by simply looping through this single line.
spidevice2.xfer2([0x00, 0x00, 0x00, 0x00])
It takes up to 11 hours depending on the RPi version. After 1073014000 calls (rounded to 1000), the script crashes because of "invalid pointer". The total amount of bytes sent is the same as in danmcb's case. It seems as if 2^32 bytes represent a limit.
I tried different approaches. For example, calling close() from time to time followed by open(). This did not help.
Then, I tried to create the spiDev object locally, so it would re-created for every batch of data.
def spiLoop():
spidevice2 = spidev.SpiDev()
spidevice2.open(0, 1)
spidevice2.max_speed_hz = 15000000
spidevice2.mode = 1 # Data is clocked in on falling edge
for j in range(100000):
spidevice2.xfer2([0x00, 0x00, 0x00, 0x00])
spidevice2.close()
It still crashed at after approx. 2^30 calls of xfer2([0x00, 0x00, 0x00, 0x00]) which corresponds to approx. 2^32 bytes.
EDIT1
To speed up the process, I was sending in blocks of 4096 bytes using the code below. And I repeatedly created the SpiDev object locally. It took 2 hours to arrive at 2^32 bytes count.
def spiLoop():
spidevice2 = spidev.SpiDev()
spidevice2.open(0, 1)
spidevice2.max_speed_hz = 25000000
spidevice2.mode = 1 # Data is clocked in on falling edge
to_send = [0x00] * 2**12 # 4096 bytes
for j in range(100):
spidevice2.xfer2(to_send)
spidevice2.close()
del spidevice2
def runSPI():
for i in range(2**31 - 1):
spiLoop()
print((2**12 * 100 * (i + 1)) / 2**20, 'Mbytes')
EDIT2
Reloading the spidev on the fly does not help either. I tried this code on both RPi3 and RPi4 with the same result:
import importlib
def spiLoop():
importlib.reload(spidev)
spidevice2 = spidev.SpiDev()
spidevice2.open(0, 1)
spidevice2.max_speed_hz = 25000000
spidevice2.mode = 1 # Data is clocked in on falling edge
to_send = [0x00] * 2**12 # 4096 bytes
for j in range(100):
spidevice2.xfer2(to_send)
spidevice2.close()
del spidevice2
def runSPI():
for i in range(2**31 - 1):
spiLoop()
print((2**12 * 100 * (i + 1)) / 2**20, 'Mbytes')
EDIT3
Executing the code snippet did not isolate the problem either. It crashed after the 4th chuck of 1Gbyte-data was sent.
program = '''
import spidev
spidevice = None
def configSPI():
global spidevice
# We only have SPI bus 0 available to us on the Pi
bus = 0
#Device is the chip select pin. Set to 0 or 1, depending on the connections
device = 1
spidevice = spidev.SpiDev()
spidevice.open(bus, device)
spidevice.max_speed_hz = 250000000
spidevice.mode = 1 # Data is clocked in on falling edge
def spiLoop():
to_send = [0xAA] * 2**12
loops = 1024
for j in range(loops):
spidevice.xfer2(to_send)
return len(to_send) * loops
configSPI()
bytes_total = 0
while True:
bytes_sent = spiLoop()
bytes_total += bytes_sent
print(int(bytes_total / 2**20), "Mbytes", int(1000 * (bytes_total / 2**30)) / 10, "% finished")
if bytes_total > 2**30:
break
'''
for i in range(100):
exec(program)
print("program executed", i + 1, "times, bytes sent > ", (i + 1) * 2**30)
I belive the original asker's issue is a reference leak. Specifically py-spidev issue 91. Said reference leak has been fixed in the 3.5 release of spidev.
Python uses a shared pool of objects to represent small integer values*, rather than re-creating them each time. So when code leaks references to small numbers the result is not a memory leak but instead a reference count that keeps increasing. The python spidev library had an issue where it leaked references to small integers in this way.
On a 32-bit system** the eventual result is that the reference count overflows. Then something decrements the overflowed reference count and the reference counting system frees the object.
What I can't explain is the other answer that claims they can still reproduce the issue with 3.5. This issue was supposed to have been fixed in that version.
* Specifically numbers in the range -3 to 256 inclusive, so anything that can be represented in an unsigned byte plus a few negative values (presumably because they are commonly used as error returns) and 256 (presumably because it's often used as a multiplier).
** On a 64-bit system the reference count will not overflow within a human lifetime.
I'm using Raspberry Pi 3 and ADS1115, my project requires me to get evenly spaced samples so as to plot and analyse. The other posts were about achieving 10k and 50k sps but I only require 500SPS and that isn't working either. Is there a way to run my code for 120 seconds with 500 sps and get 60,000 samples in the end from both A0 and A1 channel at the same time? I have attached the code for reference. Thanks in advance
from Adafruit_ADS1x15 import ADS1x15
import time
import numpy as np
pga = 2/3 # Set full-scale range of programmable gain
# amplifier (page 13 of data sheet), change
#depending on the input voltage range
ADS1115 = 0x01 # Specify that the device being used is the
# ADS1115, for the ADS1015 used 0x00
adc = Adafruit_ADS1x15.ADS1015() # Create instance of the class ADS1x15
# Function to print sampled values to the terminal
def logdata():
print "sps value should be one of: 8, 16, 32, 64, 128, 250, 475, 860,
otherwise the value will default to 250"
frequency = input("Input sampling frequency (Hz): ") # Get
#sampling frequency from user
sps = input("Input sps (Hz) : ") # Get
# ads1115 sps value from the user
time1 = input("Input sample time (seconds): ") # Get how
#long to sample for from the user
period = 1.0 / frequency # Calculate sampling period
datapoints = int(time1*frequency) # Datapoints is the total number
#of samples to take, which must be an integer
startTime=time.time() # Time of first sample
t1=startTime # T1 is last sample time
t2=t1 # T2 is current time
for x in range (0,datapoints) : # Loop in which data is sampled
while (t2-t1 < period) : # Check if t2-t1 is less then
#sample period, if it is then update t2
t2=time.time() # and check again
t1+=period # Update last sample time by the
# sampling period
print adc.read_adc(0, pga, data_rate=sps), "mV ", ("%.2f" %
(t2-startTime)) , "s" # Print sampled value and time to the terminal
# Call to logdata function
logdata()
1) Are you using the ADS1115 ???
adc = Adafruit_ADS1x15.ADS1015() # should be adc = Adafruit_ADS1x15.ADS1115()
2) you can't read two or more single-ended channels at the same time. In differential mode one can compare two channels to yield one value.
To read a value from channel 1, besides channel 0 you would have to add another call in your loop:
print adc.read_adc(0, pga, data_rate=sps) ..... # original call for channel 0
print adc.read_adc(1, pga, data_rate=sps) ..... # new call for channel 1
3) before a value can be read, the ADS must be configured with several parameters, like channel, rate, gain etc. After some time, which is needed for doing an analog/digital conversion, values can be read, once, or over and over again, when in continuous mode.
In the original ADAFruit library this time is calculated from the data rate (insecure) and in the recent port to CircuitPython this time will most often be around 0.01 s, because the conversion will most probably not have finished directly after configuration (check the _read method).
4) reading at 500SPS is about the fastest the ADS1115 can read. The reference states that conversion at 860SPS takes 1.2 ms. Adding time for configuration and reading you will not be able to read two or more values continuosly every 0.002s, even if you were receiving notifications for conversion, like I described on my homepage, instead of waiting for a fixed period of time.
5) I think the closest you can get with Python is to run 2 daisy-chained ADS1115 in continuous mode with GPIO notifications, but I have no experience with that.
I'm trying to read the temperature and humidity using a Texas Instruments HDC1008 from Adafruit, product 2635. I'm on a rasberry pi 2, using the smbus module. According to TI's PDF, when getting a reading, the number will be sent in two bytes that you put together. I found this code that does what I'm trying to do with micropython, where they have a recv function that seems to simply sends them back a list with two bytes. The SMBus module doesn't seem to have any equivalent for what I'm trying to do. Here's some of my code.
class HDC1008:
I2C_BUS = 1
#Registers
REG_TEMP = 0
REG_HUMID = 1
REG_CONFIG = 2
#Configuration bits
CFG_RST = 1<<15
CFG_MODE_SINGLE = 0 << 12
CFG_MODE_BOTH = 1 << 12
ADDRESS = 0x40
def __init__(self, bus_num=I2C_BUS):
self.bus=smbus.SMBus(bus_num)
def readTemperature(self):
#configure the HDC1008 for one reading
config = 0
config |= self.CFG_MODE_SINGLE
self.bus.write_byte_data(self.ADDRESS, self.REG_CONFIG, config)
#tell the thing to take a reading
self.bus.write_byte(self.ADDRESS, self.REG_TEMP)
time.sleep(0.015)
#get the reading back from the thing
raw = self.bus.read_byte(self.ADDRESS)
raw = (raw<<8) + self.bus.read_byte(self.ADDRESS)
#use TI's formula to turn it into people numbers
temperature = (raw/65536.0)*165.0 - 40
#convert temp to f
temperature = temperature * (9.0/5.0) + 32
return temperature
When I'm getting the value for raw from bus.read_byte, I'm able to get the first half of the temperature bits, but the second reading is just zeros, presumably because the first transaction is over. How do I get two bytes in one transaction?
tnx a lot for sharing this code. I'm happy to get it working in Python.
I do not exactly understand the problem, I can read the Temperature and Humidity with our code (the only Python code I could find and works)
I did change it a little bit (make it a Class):
import smbus
class HDC:
#Registers
REG_TEMP = 0
REG_HUMID = 1
REG_CONFIG = 2
I2C_BUS = 2 #2 for PCDuino, 1 for PI
#Configuration bits
CFG_RST = 1<<15
CFG_MODE_SINGLE = 0 << 12
CFG_MODE_BOTH = 1 << 12
ADDRESS = 0x40
def __init__(self, bus_num=I2C_BUS):
self.bus=smbus.SMBus(bus_num)
def readTemperature(self):
#configure the HDC1008 for one reading
config = 0
config |= self.CFG_MODE_SINGLE
self.bus.write_byte_data(self.ADDRESS, self.REG_CONFIG, config)
#tell the thing to take a reading
self.bus.write_byte(self.ADDRESS, self.REG_TEMP)
time.sleep(0.015)
#get the reading back from the thing
raw = self.bus.read_byte(self.ADDRESS)
raw = (raw<<8) + self.bus.read_byte(self.ADDRESS)
#use TI's formula to turn it into people numbers
temperature = (raw/65536.0)* 165 - 40
#convert temp to farenheid
#temperature = temperature * (9.0/5.0) + 32
return temperature
def readHum(self):
#configure the HDC1008 for one reading
config = 0
config |= self.CFG_MODE_SINGLE
self.bus.write_byte_data(self.ADDRESS, self.REG_CONFIG, config)
#tell the thing to take a reading
self.bus.write_byte(self.ADDRESS, self.REG_HUMID)
time.sleep(0.015)
#get the reading back from the thing
raw = self.bus.read_byte(self.ADDRESS)
raw = (raw<<8) + self.bus.read_byte(self.ADDRESS)
hum=(raw/(2.0**16))*100
return hum
In the program:
from hdc1008 import HDC
HDC1008=HDC()
print HDC1008.readTemperature()
print HDC1008.readHum()