forked from vrano714/max30102-tutorial-raspberrypi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
max30102.py
165 lines (132 loc) · 5.05 KB
/
max30102.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# -*-coding:utf-8-*-
# this code is currently for python 2.7
from __future__ import print_function
from time import sleep
import Adafruit_BBIO.GPIO as GPIO
import smbus
# i2c address-es
# not required?
I2C_WRITE_ADDR = 0xAE
I2C_READ_ADDR = 0xAF
# register address-es
REG_INTR_STATUS_1 = 0x00
REG_INTR_STATUS_2 = 0x01
REG_INTR_ENABLE_1 = 0x02
REG_INTR_ENABLE_2 = 0x03
REG_FIFO_WR_PTR = 0x04
REG_OVF_COUNTER = 0x05
REG_FIFO_RD_PTR = 0x06
REG_FIFO_DATA = 0x07
REG_FIFO_CONFIG = 0x08
REG_MODE_CONFIG = 0x09
REG_SPO2_CONFIG = 0x0A
REG_LED1_PA = 0x0C
REG_LED2_PA = 0x0D
REG_PILOT_PA = 0x10
REG_MULTI_LED_CTRL1 = 0x11
REG_MULTI_LED_CTRL2 = 0x12
REG_TEMP_INTR = 0x1F
REG_TEMP_FRAC = 0x20
REG_TEMP_CONFIG = 0x21
REG_PROX_INT_THRESH = 0x30
REG_REV_ID = 0xFE
REG_PART_ID = 0xFF
# currently not used
MAX_BRIGHTNESS = 255
class MAX30102():
# by default, this assumes that pin P9_16 is used as interrupt
# by default, this assumes that the device is at 0x57 on channel 1
def __init__(self, channel=1, address=0x57, gpio_pin='P9_16'):
print("Channel: {0}, address: 0x{1:x}".format(channel, address))
self.address = address
self.channel = channel
self.bus = smbus.SMBus(self.channel)
self.interrupt = gpio_pin
# set gpio mode
GPIO.setup(self.interrupt, GPIO.IN)
self.reset()
sleep(1) # wait 1 sec
# read & clear interrupt register (read 1 byte)
reg_data = self.bus.read_i2c_block_data(
self.address, REG_INTR_STATUS_1, 1)
# print("[SETUP] reset complete with interrupt register0: {0}".format(reg_data))
self.setup()
# print("[SETUP] setup complete")
def shutdown(self):
"""
Shutdown the device.
"""
self.bus.write_i2c_block_data(self.address, REG_MODE_CONFIG, [0x80])
def reset(self):
"""
Reset the device, this will clear all settings,
so after running this, run setup() again.
"""
self.bus.write_i2c_block_data(self.address, REG_MODE_CONFIG, [0x40])
def setup(self, led_mode=0x03):
"""
This will setup the device with the values written in sample Arduino code.
"""
# INTR setting
# 0xc0 : A_FULL_EN and PPG_RDY_EN = Interrupt will be triggered when
# fifo almost full & new fifo data ready
self.bus.write_i2c_block_data(self.address, REG_INTR_ENABLE_1, [0xc0])
self.bus.write_i2c_block_data(self.address, REG_INTR_ENABLE_2, [0x00])
# FIFO_WR_PTR[4:0]
self.bus.write_i2c_block_data(self.address, REG_FIFO_WR_PTR, [0x00])
# OVF_COUNTER[4:0]
self.bus.write_i2c_block_data(self.address, REG_OVF_COUNTER, [0x00])
# FIFO_RD_PTR[4:0]
self.bus.write_i2c_block_data(self.address, REG_FIFO_RD_PTR, [0x00])
# 0b 0100 1111
# sample avg = 4, fifo rollover = false, fifo almost full = 17
self.bus.write_i2c_block_data(self.address, REG_FIFO_CONFIG, [0x4f])
# 0x02 for read-only, 0x03 for SpO2 mode, 0x07 multimode LED
self.bus.write_i2c_block_data(
self.address, REG_MODE_CONFIG, [led_mode])
# 0b 0010 0111
# SPO2_ADC range = 4096nA, SPO2 sample rate = 100Hz, LED pulse-width = 411uS
self.bus.write_i2c_block_data(self.address, REG_SPO2_CONFIG, [0x27])
# choose value for ~7mA for LED1
self.bus.write_i2c_block_data(self.address, REG_LED1_PA, [0x24])
# choose value for ~7mA for LED2
self.bus.write_i2c_block_data(self.address, REG_LED2_PA, [0x24])
# choose value fro ~25mA for Pilot LED
self.bus.write_i2c_block_data(self.address, REG_PILOT_PA, [0x7f])
# this won't validate the arguments!
# use when changing the values from default
def set_config(self, reg, value):
self.bus.write_i2c_block_data(self.address, reg, value)
def read_fifo(self):
"""
This function will read the data register.
"""
red_led = None
ir_led = None
# read 1 byte from registers (values are discarded)
reg_INTR1 = self.bus.read_i2c_block_data(
self.address, REG_INTR_STATUS_1, 1)
reg_INTR2 = self.bus.read_i2c_block_data(
self.address, REG_INTR_STATUS_2, 1)
# read 6-byte data from the device
d = self.bus.read_i2c_block_data(self.address, REG_FIFO_DATA, 6)
# mask MSB [23:18]
red_led = (d[0] << 16 | d[1] << 8 | d[2]) & 0x03FFFF
ir_led = (d[3] << 16 | d[4] << 8 | d[5]) & 0x03FFFF
return red_led, ir_led
def read_sequential(self, amount=100):
"""
This function will read the red-led and ir-led `amount` times.
This works as blocking function.
"""
red_buf = []
ir_buf = []
for i in range(amount):
while(GPIO.input(self.interrupt) == 1):
# wait for interrupt signal, which means the data is available
# do nothing here
pass
red, ir = self.read_fifo()
red_buf.append(red)
ir_buf.append(ir)
return red_buf, ir_buf