Skip to content

Instantly share code, notes, and snippets.

@Gadgetoid
Last active September 5, 2024 12:39
Show Gist options
  • Save Gadgetoid/a7227b56f7d34277b3616225c5884976 to your computer and use it in GitHub Desktop.
Save Gadgetoid/a7227b56f7d34277b3616225c5884976 to your computer and use it in GitHub Desktop.
MicroPython library for the AS7343
import time
import struct
from micropython import const
# Bank 1
AUXID = 0x58 # AUXID = 0b00001111
REVID = 0x59 # REVID = 0b00000111
ID = 0x5A # ID = 0b11111111
CFG12 = 0x66 # SP_TH_CH = 0b00000111
# Bank 0
ENABLE = 0x80 # FDEN = 0b01000000
# SMUXEN = 0b00010000
# WEN = 0b00001000
# SP_EN = 0b00000010
# PON = 0b00000001
ATIME = 0x81 # ATIME = 0b11111111
# Integration Time Step Size
# 0 = 2.87us
# n 2.87us x (n + 1)
ASTEP = 0xD4 # STEP = 0xFFFF
# Spectral Measurement Wait Time
# 0 = 1 cycle = 2.78ms
# n = 2.78ms x (n + 1)
WTIME = 0x83 # WTIME = 0b11111111
SP_TH = 0x84 # SP_TH_L = 0xFFFF0000 Spectral Low Threshold
# SP_TH_H = 0x0000FFFF Spectral High Threshold
STATUS = 0x93 # ASAT = 0b10000000 Spectral Saturation (if ASIEN set)
# AINT = 0b00001000 Spectral Channel Interrupt (if SP_IEN set)
# FINT = 0b00000100 FIFO Buffer Interrupt
# SINT = 0b00000001 System Interrupt
ASTATUS = 0x94 # ASAT = 0b10000000 Saturation Status
# AGAIN = 0b00000111 Gain Status
DATA = 0x95 # 36 bytes, fields 0 to 17 (2 bytes eac)
STATUS2 = 0x90 # AVALID = 0b01000000 Spectral Data Valid
# ASAT_DIG = 0b00010000 Digital Saturation
# ASAT_ANA = 0b00001000 Analog Saturation
# FDSAT_ANA= 0b00000010 Flicker Analog Saturation
# FDSAT_DIG= 0b00000001 Flicker Digital Saturation
STATUS3 = 0x91 # INT_SP_H = 0b00100000 Spectral Above High Threshold
# INT_SP_L = 0b00010000 Spectral Below Low Threshold
STATUS5 = 0xBB # SINT_FD = 0b00001000 Flicker Detect Interrupt (if SIEN_FD set)
# SINT_SMUX= 0b00000100 SMUS Operation Interrupt (SMUX exec finished)
STATUS4 = 0xBC # FIFO_OV = 0b10000000 FIFO Buffer Overflow
# OVTEMP = 0b00100000 Over Temperature
# FD_TRIG = 0b00010000 Flicker Detect Trigger Error
# SD_TRIG = 0b00000100 Spectral Trigger Error
# SAI_ACT = 0b00000010 Sleep After Interrupt Active
# INT_BUSY = 0b00000001 Initialization busy (1 for ~300us after power on)
CFG0 = 0xBF # LOW_POWER= 0b00100000
# REG_BANK = 0b00010000 0 - Register 0x80 and above
# 1 - Register 0x20 to 0x7f
# WLONG = 0b00000100 Increase WTIME by factor of 16
# Spectral Engines Gain Setting
# 0 = 0.5x, # 1 = 1x, 2 = 2x, 12 = 2048x
# GAINx = 1 << (n - 1)
CFG1 = 0xC6
CFG3 = 0xC7 # SAI = 0b00100000 Sleep after interrupt
CFG6 = 0xF5 # SMUS_CMD = 0b00011000 0 - ROM_init
# 1 - Read_SMUX
# 2 - Write_SMUX
CFG8 = 0xC9 # FIFO_TH = 0b11000000 0b00, 0b01, 0b10, 0b11
CFG9 = 0xCA # SIEN_FD = 0b01000000 System Interrupt Flicker Detection
# SIEN_SMUX= 0b00010000 System Interrupt SMUX Operation
CFG10 = 0x65 # FD_PERS = 0b00000111 Flicker Detect Persistence
# Number of results that must differ before status change
PERS = 0xCF # APERS = 0b00001111
GPIO = 0x6B # GPIO_INV = 0b00001000 Invert GPIO output
# GPIO_IN_EN=0b00000100 Enable GPIO input
# GPIO_OUT = 0b00000010 GPIO Output
# GPIO_IN = 0b00000001 GPIO Input
CFG20 = 0xD6 # FD_FIFO_8b=0b10000000 Enable 8bit FIFO mode for Flicker Detect (FD_TIME < 256)
# auto_SMUX= 0b01100000 Auto channel read-out
LED = 0xCD # LED_ACT = 0b10000000 External LED (LDR) Control
# LED_DRIVE= 0b01111111 External LED drive strength (N - 4) >> 1
# Flicker Detection AGC Gain Max
# Max = 2^N (0 = 0.5x)
AGC_GAIN_MAX = 0xD7 # ADC_FD_GAIN_MAX = 0b11110000
AZ_CONFIG = 0xDE # AT_NTH_ITERATION = 0b11111111 Auto-zero Frequency
# 0 - Never (Not Recommended)
# n - Every n integration cycles
# 255 - only before first measurement cycle
FD_TIME_1 = 0xE0 # FD_TIME=0b11111111 Flicker Detection Integration Time (Do not change if FDEN = 1 & PON = 1)
FD_TIME_2 = 0xE2 # FD_GAIN=0b11111000 Flicker Detection Gain (0 = 0.5x, 1 = 1x, 2 = 2x, 12 = 2048x)
# FD_TIME=0b00000111 Flicker Detection Time (Do not change if FDEN = 1 & PON = 1)
FD_CFG0 = 0xDF # FIFO_WRITE_FD = 0b10000000 Write flicker raw data to FIFO (1 byte per sample)
FD_STATUS = 0xE3 # FD_VALID=0b00100000
# FD_SAT = 0b00010000
# FD_120HZ_VALID = 0b00001000
# FD_100HZ_VALID = 0b00000100
# FD_120HZ = 0b00000010
# FD_100HZ = 0b00000001
INTERNAB = 0xF9 # ASIEN = 0b10000000 Saturation Interrupt Enable
# SP_IEN = 0b00001000 Spectral Interrupt Enable
# FIEN = 0b00000100 FIFO Buffer Interrupt Enable
# SIEN = 0b00000001 System Interrupt Enable
CONTROL = 0xFA # SW_RESET = 0b00001000 Software Reset
# SP_MAN_AZ= 0b00000100 Spectral Manual Auto-zero
# FIFO_CLR = 0b00000010 FIFO Buffer Clear
# CLEAR_SAI_ACT = 0b00000001 Clear sleep-after-interrupt
FIFO_MAP = 0xFC # CH5 = 0b01000000
# CH4 = 0b00100000
# CH3 = 0b00010000
# CH2 = 0b00001000
# CH1 = 0b00000100
# CH0 = 0b00000010
# ASTATUS = 0b00000001
FIFO_LVL = 0xFD
FDATA = 0xFE # 0xFFFF
HARDWARE_ID = const(0b10000001)
CFG0_LOW_POWER = const(0b00100000)
CFG0_BANK = const(0b00010000)
CFG0_WLONG = const(0b00000100)
CFG20_6_CH = const(0b00000000)
CFG20_12_CH = const(0b01000000)
CFG20_18_CH = const(0b01100000)
ENABLE_FDEN = const(0b01000000)
ENABLE_SMUXEN = const(0b00010000)
ENABLE_WEN = const(0b00001000)
ENABLE_SP_EN = const(0b00000010)
ENABLE_PON = const(0b00000001)
FD_CFG0_FIFO_WRITE = const(0b10000000)
FD_VALID = const(0b00100000)
FD_SAT = const(0b00010000)
FD_120HZ_VALID = const(0b00001000)
FD_100HZ_VALID = const(0b00000100)
FD_120HZ = const(0b00000010)
FD_100HZ = const(0b00000001)
INTERNAB_ASIEN = const(0b10000000)
INTERNAB_SP_IEN = const(0b00001000)
INTERNAB_FIEN = const(0b00000100)
INTERNAB_SIEN = const(0b00000001)
CONTROL_SW_RESET = const(0b00001000)
CONTROL_SP_MAN_AZ = const(0b00000100)
CONTROL_FIFO_CLR = const(0b00000010)
CONTROL_CLEAR_SAI_ACT = const(0b00000001)
FIFO_MAP_CH5 = const(0b01000000)
FIFO_MAP_CH4 = const(0b00100000)
FIFO_MAP_CH3 = const(0b00010000)
FIFO_MAP_CH2 = const(0b00001000)
FIFO_MAP_CH1 = const(0b00000100)
FIFO_MAP_CH0 = const(0b00000010)
FIFO_MAP_ASTATUS = const(0b00000001)
AZ_NEVER = const(0)
AZ_BEFORE_FIRST_CYCLE = const(255)
class BreakoutAS7343:
def __init__(self, i2c):
self.address = 0x39
self.i2c = i2c
self.num_channels = 18
self.active = False
# Soft reset
self.w_uint8(CONTROL, CONTROL_SW_RESET)
time.sleep(0.5)
# Bank 0
self.w_uint8(CFG0, 0)
# Set default AGAIN
self.w_uint8(CFG1, 9)
# Set default sensor settings
self.set_gain(256)
self.set_measurement_time(33) # Roughly 30fps at 16ms/measurement
self.set_integration_time(27800)
self.set_channels(18)
# Auto zero on measurement start
self.w_uint8(AZ_CONFIG, AZ_BEFORE_FIRST_CYCLE)
# Set the FIFO map
self.w_uint8(0xFC, FIFO_MAP_CH5 | FIFO_MAP_CH4 | FIFO_MAP_CH3 | FIFO_MAP_CH2 | FIFO_MAP_CH1 | FIFO_MAP_CH0 | FIFO_MAP_ASTATUS)
def set_gain(self, gain):
if gain == 0.5:
bitlength = 0
else:
igain = int(gain)
bitlength = 0
while igain > 0:
bitlength += 1
igain >>= 1
self.w_uint8(CFG1, bitlength)
def set_measurement_time(self, measurement_time_ms):
resolution = 2.78
self.w_uint8(WTIME, int((measurement_time_ms - resolution) / resolution))
def set_integration_time(self, integration_time_us, repeat=1):
resolution = 2.78
max_astep = (65534 + 1) * resolution
if integration_time_us > max_astep:
raise ValueError("Integration time out of range!")
self.w_uint8(ATIME, repeat - 1)
self.w_uint16(ASTEP, int((integration_time_us - resolution) / resolution) & 0xfffe)
def set_illumination_current(self, current):
current = int((current - 4) / 2.0)
temp = self.r_uint8(LED) & 0b10000000 # Preserve on/off state
temp |= (current & 0b01111111)
self.w_uint8(LED, temp)
def set_illumination_led(self, state):
temp = self.r_uint8(LED) & ~0b10000000 # Preserve current
if state:
temp |= 0b10000000
self.w_uint8(LED, temp)
def start_measurement(self):
if self.active:
return
self.active = True
# Enable things
self.w_uint8(ENABLE, ENABLE_WEN | ENABLE_SMUXEN | ENABLE_SP_EN | ENABLE_PON)
def stop_measurement(self):
self.w_uint8(ENABLE, ENABLE_PON)
self.w_uint8(CONTROL, CONTROL_FIFO_CLR)
def force_autorange(self):
self.w_uint8(CONTROL, CONTROL_SP_MAN_AZ)
time.sleep(0.1)
def set_channels(self, c):
self.num_channels = c
temp = self.r_uint8(0xD6)
def read_fifo(self):
expected_results = (self.num_channels // 6) * 7
results = []
while self.r_uint8(0xFD) < expected_results:
time.sleep(0.01)
while self.r_uint8(0xFD) > 0 and expected_results > 0:
results.append(self.r_uint16(0xFE))
expected_results -= 1
return results
def read(self):
self.start_measurement()
result = self.read_fifo()
return (
result[0], # FZ
result[1], # FY
result[2], # FZL
result[3], # NIR
result[7], # F2
result[8], # F3
result[9], # F4
result[10], # F6
result[14], # F1
result[15], # F5
result[16], # F7
result[17], # F8
)
def r_uint8(self, reg):
self.i2c.writeto(self.address, bytes([reg]))
return struct.unpack("<B", self.i2c.readfrom(self.address, 1))[0]
def w_uint8(self, reg, value):
self.i2c.writeto(self.address, bytes([reg, value]))
def r_uint16(self, reg):
self.i2c.writeto(self.address, bytes([reg]))
return struct.unpack("<H", self.i2c.readfrom(self.address, 2))[0]
def w_uint16(self, reg, value):
self.i2c.writeto(self.address, struct.pack("<BH", reg, value))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment