import rp2
from machine import Pin, PWM
import utime
import math
# Define key and LED pins
KEY1 = Pin(0, Pin.IN, Pin.PULL_UP) # KEY1 for changing the brightness
KEY2 = Pin(1, Pin.IN, Pin.PULL_UP) # KEY2 for turning backlight ON/OFF
KEY3 = Pin(6, Pin.IN, Pin.PULL_UP) # KEY3 for LHD/RHD
led_pin = Pin(25, mode=Pin.OUT, value=0)
status_led = Pin(18, mode=Pin.OUT, value=0)
alert_led = Pin(20, mode=Pin.OUT, value=0)
Vddio = Pin( 4, mode=Pin.OUT, value=0)
Vled = Pin( 5, mode=Pin.OUT, value=0)
cs_pin = Pin(13, mode=Pin.OUT, value=0)
#pwm = Pin( 9, mode=Pin.OUT, value=0)
status = 0 # Initialize status to 0
t1_us = 50 # 100 us; make sure all sclk are sent before SCS is set High level
# The time from VLED low to VDD low is t2_s(VLED low to CS low,1ms) + t3_s(CS low to VDD low,50ms), it's setted 51ms
t2_ms = 1 # 1ms
t3_ms = 50 # The time from the discharge of vled to vddio
t4_ms = 500 # Lighting durations for each of the four BIST modes (Odd/Even-numbered LEDs at 2.5V & Odd/Even-numbered LEDs at 2.0V):
# adjust data from 8 bit to 32 bit, if you want the data to be sent in units of 8 bits, the number here should be changed to 8.
# 8 bit → 8; 16 bit → 16; 24 bit → 24; 32 bit → 32;
# The reason for sending data in 32-bit units is that it is easier to understand and the most efficient way to send the total write_blocking data.
# On the other hand, if data is sent in 8-bit/6-bit/24-bit units, there will be losses in the SCK waveform.
get_threshold = 32 # 32-bit transfer
# Shift the data ___bit to the left, if you want the data to be sent in units of 8 bits, the number here should be changed to 24.
# 32 bit → 0; 24 bit → 8; 16 bit → 16; 8 bit → 24;
get_shift_value = 0
chunk_size = 4 # 8 bit → 1; 16 bit → 2; 24 bit → 3; 32 bit → 4;
# Driver IC (MAX25503) Device Resion code check
OSC_freq = 8000000 # oscillator frequency → PWM period→125ns
DEVID = 0x65 # 要確認
REVID = 0 # 要確認
R00hL = REVID << 5
Multiplexing_Ratio = 4
MUX = Multiplexing_Ratio & 3 # R24[5:4]
PSEUDO_VSYNC = 1 # R24h[11] if==1 Internal VSYNC
VSYNC_PERIOD = 33333
vsy_freq = OSC_freq / VSYNC_PERIOD / Multiplexing_Ratio # 60.000600006 Dead_Time含むか確認必要
num_of_scans = 64
SCAN = int(math.log2(num_of_scans)) # R24h[3:0]
Scale_Factor = 3 # Current Range:35mA to 53mA
SCALE_SEL = Scale_Factor - 1 # R29h[5:4]
COMP_SEL = 3 # R29h[3:2]:SNK_出力の周波数補正を制御します。 SRC_からSNK_へのLEDループが大きい設計では、より高い値を選択してください。
VLED_OV_LVL = 16 # R22h[15:11]
DYN_ILED_DELAY = 7 # R22h[10:8]
Dead_Time = 6 # 125ns単位
TDEAD = Dead_Time - 2 # R22h[7:4]
R_Iset = 9.1 # KΩ
I_LED = 125 * Scale_Factor / R_Iset # 41.2087mA
attILED = 100 # Individual ILED current attenuat: 100% of maximum (range: 38%~100%, adjustable in 2% steps)
Driver_IC_count = 11 # number of MAX25503 on LG38.9: 5 + 6
R22hH = (VLED_OV_LVL << 3) + DYN_ILED_DELAY # [7:3]VLED_OV_LVL=10h(12.5V),[2:0]DYN_ILED_DELAY=7(7clock)
R22hL = (TDEAD << 4) + 15 # [7:4]TDEAD,[3]SFT_CSB_PU,[2]SFT_SCLK_PD,[1]SFT_SDI_PD,[0]SFT_VSYNC_PD
R23hH = Driver_IC_count - 1 # [4]GHOSTSNK_DIS=0,[3:0]DEV_COUNT=10
R23hL = 0x48 # [7]DITHER_ON=0,[6]FPSFT_ENABLE=1,[5:4]FPSFT_SET=0,[3]FB_DAC_DIS=1,[2]VSYNC_POL=0,[1]DIS_OLED=0,[0]DIS_SLED
R24hH = (PSEUDO_VSYNC << 1) # [7]SW_RESET=0(normal),[6]GHOSTSRC_DIS=0,[5:2]VLED_UV_LVL,[1]PSEUDO_VSYNC=1,[0]VSYNC_TIMEOUT_DIS=0
R24hL = (MUX << 4) + SCAN # [7:6]DELAT_OPTION=0,[5:4]MUX=0,[3:0]SCAN=6
R27hH = (VSYNC_PERIOD >> 8) # [7:0]VSYNC_PRE_LW[15:8]
R27hL = (VSYNC_PERIOD & 255) # [7:0]VSYNC_PRE_LW[7:0]
R29hH = 0x00 # [7:6]SLDET=0,[5:4]FB_OPTION=0,[3:2]NLED=0,[1:0]PREREG_STEP=0
R29hL = (SCALE_SEL << 4)+(COMP_SEL << 2) # [7:6]COMPL=0,[5:4]SCALE_SEL=3,[3:2]COMP_SEL=3
# Average current = peak current x PWM duty
#PWM duty setting
duty_value_1 = 2 # Initial brightness mode: set to 2% PWM duty cycle. 【0.17mA/LED】
duty_value_2 = 5.952 # Second brightness mode: set to 5.952% PWM duty cycle. 【0.5mA/LED】 (0.5/8.4=5.95238・・・・・)
duty_value_3 = 8.3 # This duty value is used to set the 8.3% PWM duty cycle for the 【cross_pattern_lighting】.
# LED Blinking Frequency and Period Setting
blink_freq = 8 # blinking frequency: 8Hz
period = 1 / blink_freq # 各サイクルの合計時間
# 点灯:消灯 = 7:3の比率で時間を分ける
on_time = period * 0.7 # 点灯時間を計算する。サイクル全体の70%。
off_time = period * 0.3 # 消灯時間を計算する。サイクル全体の30%。
def calculate_duty2pwm(duty):
pwm_dec = math.ceil(duty / 100 * OSC_freq / vsy_freq / Multiplexing_Ratio) # 切り上げ
pwmdata = [pwm_dec >> 8, pwm_dec & 255]
# print(pwmdata)
return pwmdata # 結合された値のリストを返す
def combine_hex_elements(lst, chunk_size): # for PIO
add_len = chunk_size - (len(lst) % chunk_size) # リストの長さをchunk_sizeで割った余りを計算し、必要なパディングバイト数を求める。例:リスト長15, chunk_size=4 → 15%4=3 → 4-3=1(1バイトのパディングが必要)
lst.extend([0] * add_len) # 元のリストの末尾に、計算された数のゼロバイト(0)を追加、これによりリスト長がchunk_sizeの倍数になる
result = [] # 結果を格納するための空リストを初期化
for i in range(0, len(lst), chunk_size): # パディング済みのリストをchunk_sizeごとに処理、例:chunk_size=4の場合、毎回4バイトずつ処理する
combined = 0 # 現在の結合値を0で初期化
for byte in lst[i:i + chunk_size]: # 現在のchunk内のバイトを順番に処理
combined = (combined << 8) | byte # 現在のcombined値を8ビット左シフト(次のバイトのためのスペースを確保)、その後、ビットOR演算で新しいバイトを追加
result.append(combined) # 結合された値を結果リストに追加
return result # 結合された値のリストを返す
def split_rd_data(raw_data): # from PIO
# 各32ビットのデータを読み出し、4つの8ビットに分解し、1次元配列として展開します。
rd_data = [] # 空のリストを用意して、デコードしたデータをここに格納します。
for data in raw_data:# Bist_RD_data の各データ(1つずつ)に対して処理します。
rd_data.extend([
(data >> 24) & 255, # data を24ビット右シフト、最上位の8ビットを取り出す
(data >> 16) & 255, # data を16ビット右シフトして、第2バイトを取り出す
(data >> 8) & 255, # data を8ビット右シフトして、第1バイトを取り出す
data & 255 # シフトなしで、そのまま最下位バイトを取り出す
])
return rd_data # 最終処理後の1次元配列を返します。その配列には、すべての8ビット値が格納されています。
def iLED(att3,att2,att1): # 5bitの引数を16bitワードに並べ替え MAX25503 datasheet参照
att3 = int((att3 - 38)/2) if att3 > 38 else 0 # 引数att3が38より大きい場合に、38を引いてから2で割り、その結果を整数に変換,もし引数が38以下であれば、0を代入。この処理でMAX25503のpeak電流調整範囲に収める。
att2 = int((att2 - 38)/2) if att2 > 38 else 0 # 引数att2を同様に処理
att1 = int((att1 - 38)/2) if att1 > 38 else 0 # 引数att1を同様に処理
att = ((((att3 << 5) + att2) << 5) + att1) # 処理後の3つの値を15ビットの設定データとして結合:a)att3を5ビット左シフト(att2の分のスペースを確保); b) att2を加算後、さらに5ビット左シフト(att1の分のスペースを確保); c)最後にatt1を加算
iLEDnH = att >> 8 # 設定データの上位バイトを取得:8ビット右シフトして上位8ビットを取り出す
iLEDnL = att & 255 # 設定データの下位バイトを取得:ビットAND演算で下位8ビットを取り出す(0xFF = 255)
return [iLEDnH, iLEDnL] # 上位・下位バイトのリストを返す
# Define PIO program
@rp2.asm_pio(
out_shiftdir=0, # out_shiftdir is the default direction in which the OSR shifts. 0 is the default, data is shifted out from the most significant bit
autopull=True, # output from Raspberry Pico's GPIO to LED board (Enable MOSI), use write function
pull_thresh = get_threshold,
autopush=True, # input from LED board to Raspberry Pico's GPIO (Enable MISO) , use read function
push_thresh = get_threshold,
sideset_init=(rp2.PIO.OUT_LOW),
out_init=rp2.PIO.OUT_LOW # MOSI default setting
) # erase [set_init=rp2.PIO.OUT_LOW]
def spi_cpha0():
set(x, 6) # Initialize the X register to 6 (for loop counting, which loops 7 times)
wrap_target() # Marks the start of the loop(It forms a loop with wrap() at the end.)
pull(ifempty) .side(0x0) [1] # Pull data from FIFO (when not empty), set sidelobe pin to 0x0 (e.g. SCK = low), delay 1 cycle; 0x0/0x1→default value of sck is setted by low, 0x2→default value of sck is setted by high
label("bitloop") # Define the label “bitloop”.
out(pins, 1) .side(0x0) [1] # 0x0→0x1, Output 1 bit from OSR to MOSI pin, set sideset pin to 0x0 (SCK held low), delay 1 cycle
in_(pins, 1) .side(0x1) # 0x2→0x0, Read 1-bit data from MISO, set sideset pin to 0x2 (SCK=high)
jmp(x_dec, "bitloop") .side(0x1) # 0x2→0x0, Decrements X and jumps back to "bitloop" until X reaches 0; 0x0 → Keep SCK low
out(pins, 1) .side(0x0) # Sends another 1 bit of data to MOSI and set SCK high.
set(x, 6) .side(0x0) # 0x0→0x1, Reset X register to 6, set sideset pin to 0x1 (SCK = High)
in_(pins, 1) .side(0x1) # Input 1 bit of data from MISO pin to ISR, set sideset pin to 0x0 (SCK = low)
jmp(not_osre, "bitloop") .side(0x1) # If OSR is not empty (not_osre), jump to “bitloop”, then the loop continues, set sideset pin to 0x0 (SCK=low)
wrap() # Jump back to `wrap_target()`, forming a loop
class PIOSPI:
def __init__(self, sm_id, pin_mosi, pin_miso, pin_sck, cpha=False, cpol=False, freq=2000000): # 2000000→SCK Freq
assert(not(cpol or cpha))
self._sm = rp2.StateMachine(sm_id, spi_cpha0, freq=4*freq,
sideset_base=Pin(pin_sck), # cs_pin → sck_pin
out_base=Pin(pin_mosi),
in_base=Pin(pin_miso)
) # set_base=Pin(pin_mosi)
self._cs = Pin(cs_pin, Pin.OUT)
self._cs.value(0) # Initialize CS to low level(or else vsync level will occur one suspicious signal)
self._sm.active(1)
def write_blocking(self, wdata):
cs_pin.value(0)
for b in wdata:
self._sm.put(b << get_shift_value)
self._sm.get()
utime.sleep_us(t1_us)
cs_pin.value(1)
utime.sleep_ms(1)
def read_blocking(self, n):
self.start()
data = []
for i in range(n):
data.append(self._sm.get() & 0xFF)
self.close()
return data
def write_read_blocking(self, wdata):
cs_pin.value(0)
rdata = []
for b in wdata:
self._sm.put(b << get_shift_value)
rdata.append(self._sm.get())
cs_pin.value(1)
return rdata
# Initialize PIO SPI
pio_spi = PIOSPI(0, 11, 12, 10) # 0→sm_id,11→MOSI,12→MISO,10→SCK,9→CS(Not used)
# filler Data
filler = [0x00] * Driver_IC_count # filler byte:Write>=(devices-1),Read>=devices
# DEV_COUNT (R23h[11:8])
DEV_COUNT = [0x1E, 0x01, 0x23,
R23hH,0x00] #
DEV_COUNT.extend(filler)
DEV_COUNT = combine_hex_elements(DEV_COUNT, chunk_size)
# SW_RESET (R24h[15])
SW_RESET = [0x1E, 0x01, 0x24, # Broadcast(Write with Same data) 1 address from 0x24(SW_RESET)
0x80, 0x00] #
SW_RESET.extend(filler)
SW_RESET = combine_hex_elements(SW_RESET, chunk_size)
# CNFG_xxx (R22h to R25h)
CNFG = [0x1E, 0x04, 0x22, # Broadcast(Write with Same data) 4 address from 0x22 to 0x25
R22hH,R22hL, # R22h:CNFG_OV [15:11]VLED_OV_LVL=10h(12.5V),[10:8]DYN_ILED_DELAY=7(7clock),[7:4]TDEAD,[3]SFT_CSB_PU,[2]SFT_SCLK_PD,[1]SFT_SDI_PD,[0]SFT_VSYNC_PD
R23hH,R23hL, # R23h:CNFG_SYS1=0x00D8, FPSFT_ENABLE(bit 6) in 0xD8 should be enable(set bit 6→1) first, FPSFT_SET(bit 5:4) should be set 0x1 (7 pwm clocks)
R24hH,R24hL, # R24h:CNFG_SYS2=0x0013 in the right side means change to 8 scan 【SCAN(3:0)→0x3(8 SCAN)】;SNK_ delay settings in page 51 & 52 of datasheet, DELAY OPTION(1:0)→0x0: 8μs per LSb; TIME_RES(4)0x1: Minimum pulse width 500ns
0x00, 0x00] # R25h:CNFG_MASK=0x00C7→enable all the functions in page 52 of the datasheet.
CNFG.extend(filler)
R22h_25h = combine_hex_elements(CNFG, chunk_size)
# VSYNC_PERIOD(R27h,R28h)
VSYNC_PER = [0x1E, 0x02, 0x27, # Broadcast(Write with Same data) 2 address from 0x22 to 0x25
R27hH,R27hL, # R27:VSYNC_PERIOD_LW =0x00D8, FPSFT_ENABLE(bit 6) in 0xD8 should be enable(set bit 6→1) first, FPSFT_SET(bit 5:4) should be set 0x1 (7 pwm clocks)
0x00, 0x00] # R28:VSYNC_PERIOD_HB =0x0013 in the right side means change to 8 scan 【SCAN(3:0)→0x3(8 SCAN)】;SNK_ delay settings in page 51 & 52 of datasheet, DELAY OPTION(1:0)→0x0: 8μs per LSb; TIME_RES(4)0x1: Minimum pulse width 500ns
VSYNC_PER.extend(filler)
R27h_28h = combine_hex_elements(VSYNC_PER, chunk_size)
# SINKSET1(R29h)
SINKSET1 = [0x1E, 0x01, 0x29, # Broadcast(Write with Same data) 1 address from 0x29(SNKSET)
R29hH,R29hL] #
SINKSET1.extend(filler)
SINKSET1 = combine_hex_elements(SINKSET1, chunk_size)
#Min→38%, Max→100%
ILED_com = [0x1E, 0x20, 0x2B] # Broadcast(Write with Same data) 32 address from 0x2B to 0x4A
ILED_com.extend(iLED(attILED,attILED,attILED) * 32) # 0x2B~4A
ILED_com.extend(filler)
ILED_com = combine_hex_elements(ILED_com, chunk_size)
ILED_1 = [0x01, 0x19, 0x2B] # Unicast(Write data) 25 address from 0x2B to 0x43
ILED_1.extend(iLED(0 ,0 ,0 )) # 0x2B
ILED_1.extend(iLED(attILED,attILED,attILED) * 7) # 0x2C~32
ILED_1.extend(iLED(0 ,0 ,0 )) # 0x33
ILED_1.extend(iLED(attILED,attILED,attILED) * 7) # 0x34~3A
ILED_1.extend(iLED(0 ,0 ,0 )) # 0x3B
ILED_1.extend(iLED(attILED,attILED,attILED) * 7) # 0x3C~42
ILED_1.extend(iLED(0 ,0 ,0 )) # 0x43
ILED_1.extend(filler)
ILED_1 = combine_hex_elements(ILED_1, chunk_size)
if KEY3.value() == 0: # LHD
ILED_B = [0x0B, 0x1A, 0x31] # Unicast (Write data) 26 address from 0x31 to 0x4A
ILED_B.extend(iLED(0 ,attILED,attILED)) # 0x31
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x32
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x33~38
ILED_B.extend(iLED(0 ,attILED,attILED)) # 0x39
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x3A
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x3B~40
ILED_B.extend(iLED(0 ,attILED,attILED)) # 0x41
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x42
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x43~48
ILED_B.extend(iLED(0 ,attILED,attILED)) # 0x49
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x4A
else:
ILED_B = [0x0B, 0x1A, 0x2B] # Unicast (Write data) 26 address from 0x2B to 0x44
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x2B
ILED_B.extend(iLED(attILED,attILED,0 )) # 0x2C
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x2D~31
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x33
ILED_B.extend(iLED(attILED,attILED,0 )) # 0x34
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x35~3A
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x3B
ILED_B.extend(iLED(attILED,attILED,0 )) # 0x3C
ILED_B.extend(iLED(attILED,attILED,attILED) * 7) # 0x3D~42
ILED_B.extend(iLED(0 ,0 ,0 )) # 0x43
ILED_B.extend(iLED(0 ,attILED,attILED)) # 0x44
ILED_B.extend(filler)
ILED_B = combine_hex_elements(ILED_B, chunk_size)
#enable this if you want to realize the lighting of a single LED or an LED controlled by a certain IC
GBL_PWM0 = [0x1E, 0x01, 0xFE, # Broadast(Write with Same data) 1 address from 0x74(GBL_PWM_LOW16_VWDPORT)
0x00, 0x00] # 0% (change 0x1388(default) to 0x0000)
GBL_PWM0.extend(filler)
GBL_PWM0 = combine_hex_elements(GBL_PWM0, chunk_size)
DELAY = [0x1E, 0x08, 0xB1, # Broadast(Write with Same data) 13 address from 0x66~0x72(DELAY)
0x08, 0x20, # 0xB1:DELAY030201 0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x14, 0x83, # 0xB2:DELAY060504=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x20, 0xE6, # 0xB3:DELAY090807=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x2D, 0x49, # 0xB4:DELAY121110=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x39, 0xAC, # 0xB5:DELAY151413=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x46, 0x0F, # 0xB6:DELAY181716=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x04, 0x12, # 0xB7:DELAY212019=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
0x10, 0x62] # 0xB8:DELAY242322=0x0000 = 0(hex, delay 0:0us) ; 0x20 = 1(hex, delay 1:8us) ;
DELAY.extend(filler)
DELAY = combine_hex_elements(DELAY, chunk_size)
#Identify Driver IC Version
DEV_ID = [0x9F, 0x01, 0x00, # Broadcast(Read data) 1 address from 0x00(Dev_ID)
DEVID,R00hL+1, #
DEVID,R00hL+2, #
DEVID,R00hL+3, #
DEVID,R00hL+4, #
DEVID,R00hL+5, #
DEVID,R00hL+6, #
DEVID,R00hL+7, #
DEVID,R00hL+8, #
DEVID,R00hL+9, #
DEVID,R00hL+10, #
DEVID,R00hL+11] #
ExDevID = filler + DEV_ID + [0x00,0x00,0x00,0x00] # SPI check for Read Expected value
DEV_ID.extend(filler)
DEV_ID = combine_hex_elements(DEV_ID, chunk_size)
#Identify STATUS2 SG
STATUS2 = [0x9F, 0x01, 0x03]
STATUS2.extend([0x80, 0x00] * 1 * Driver_IC_count)
STATUS2.extend(filler)
STATUS2 = combine_hex_elements(STATUS2, chunk_size)
#Identify Diag SNK SG1~24
Diag_SNK_SG = [0x9F, 0x02, 0x16]
Diag_SNK_SG.extend([0x00, 0x00] * 2 * Driver_IC_count)
Diag_SNK_SG.extend(filler)
Diag_SG = combine_hex_elements(Diag_SNK_SG, chunk_size)
#EN 1(Switch Go)
EN_1 = [0x1E, 0x01, 0x26, # Broadcast(Write with Same data) 1 address from 0x26(Switch Go)
0x80, 0x00] # EN=1
EN_1.extend(filler)
EN_1 = combine_hex_elements(EN_1, chunk_size)
EN_0 = [0x1E, 0x01, 0x26, # Broadast(Write with Same data) 13 address from 0x26(Switch Go)
0x00, 0x00] # EN=0; reset/default = 0
EN_0.extend(filler)
EN_0 = combine_hex_elements(EN_0, chunk_size)
def Power_Up():
Vddio.value(1)
utime.sleep_ms(10)
cs_pin.value(1)
utime.sleep_ms(1)
pio_spi.write_blocking(DEV_COUNT) # Set number of devices in system (DEV_COUNT)
pio_spi.write_blocking(SW_RESET) # Perform SW_RESET / Leave 2 ms delay after the sw_reset
utime.sleep_ms(10)
def Configuration():
pio_spi.write_blocking(R22h_25h) # CNFG_OV,CNFG_SYS1,CNFG_SYS1,CNFG_MASK
pio_spi.write_blocking(R27h_28h) # VSYNC_PRE
pio_spi.write_blocking(SINKSET1) # SINKSET1
pio_spi.write_blocking(ILED_1) # IC1:By modifying the value of attILED above, you can change the percentage setting of the Configure ILEDn register.
pio_spi.write_blocking(ILED_com) # IC2~10:By modifying the value of attILED above, you can change the percentage setting of the Configure ILEDn register.
pio_spi.write_blocking(ILED_B) # IC11:By modifying the value of attILED above, you can change the percentage setting of the Configure ILEDn register.
pio_spi.write_blocking(DELAY) # RB1h~B8h
pio_spi.write_blocking(GBL_PWM0) # duty 0%
def change_pwm_all_leds(duty):
pwmdata = calculate_duty2pwm(duty)
PWM1Solid = [0x01, 0x90, 0x4B] # Unicast Write data 144 address from 0x4B
PWM1Solid.extend([0x00,0x00] * 3) # SRC1_PWM1~PWM3: Unused SNK_ Channels
PWM1Solid.extend(pwmdata * 21) # SRC1_PWM4~PWM24:
PWM1Solid.extend([0x00,0x00] * 3) # SRC2_PWM1~PWM3: Unused SNK_ Channels
PWM1Solid.extend(pwmdata * 21) # SRC2_PWM4~PWM24:
PWM1Solid.extend([0x00,0x00] * 3) # SRC12_PWM_MSB:
PWM1Solid.extend([0x00,0x00] * 3) # SRC3_PWM1~PWM3: Unused SNK_ Channels
PWM1Solid.extend(pwmdata * 21) # SRC3_PWM4~PWM24:
PWM1Solid.extend([0x00,0x00] * 3) # SRC4_PWM1~PWM3: Unused SNK_ Channels
PWM1Solid.extend(pwmdata * 21) # SRC4_PWM4~PWM24:
PWM1Solid.extend(filler)
PWM1Solid = combine_hex_elements(PWM1Solid, chunk_size)
pio_spi.write_blocking(PWM1Solid) # IC1
print(PWM1Solid)
utime.sleep_ms(32) # interval is 32ms.
for ic in range(0x02, 0x0B): # It generates from IC No.2(0x02) to IC No.10(0x0A) (that is, decimal 2 to 10).
PWM_Solid = [ic, 0x90, 0x4B] # Unicast Write data 144 address from 0x4B
PWM_Solid.extend(pwmdata * 48) # SRC1_PWM1~PWM24,SRC2_PWM1~PWM24:
PWM_Solid.extend([0x00,0x00] * 3) # SRC12_PWM_MSB:
PWM_Solid.extend(pwmdata * 48) # SRC3_PWM1~PWM24,SRC4_PWM1~PWM24:
PWM_Solid.extend(filler)
PWM_Solid = combine_hex_elements(PWM_Solid, chunk_size)
pio_spi.write_blocking(PWM_Solid) # IC2
print(ic)
print(PWM_Solid)
utime.sleep_ms(32) # interval is 32ms.
PWMbSolid = [0x0B, 0x90, 0x4B] # Unicast Write data 144 address from 0x4B
if KEY3.value() == 0: # LHD
PWMbSolid.extend(pwmdata * 20) # SRC1_PWM1~PWM20:
PWMbSolid.extend([0x00,0x00] * 4) # SRC1_PWM21~PWM24: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC2_PWM1~PWM20:
PWMbSolid.extend([0x00,0x00] * 4) # SRC2_PWM21~PWM24: Unused SNK_ Channels
PWMbSolid.extend([0x00,0x00] * 3) # SRC12_PWM_MSB:
PWMbSolid.extend(pwmdata * 20) # SRC3_PWM1~PWM20:
PWMbSolid.extend([0x00,0x00] * 4) # SRC3_PWM21~PWM24: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC4_PWM1~PWM20:
PWMbSolid.extend([0x00,0x00] * 4) # SRC4_PWM21~PWM24: Unused SNK_ Channels
else: # RHD
PWMbSolid.extend([0x00,0x00] * 4) # SRC1_PWM1~PWM4: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC1_PWM5~PWM24:
PWMbSolid.extend([0x00,0x00] * 4) # SRC2_PWM1~PWM4: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC2_PWM5~PWM24:
PWMbSolid.extend([0x00,0x00] * 3) # SRC12_PWM_MSB:
PWMbSolid.extend([0x00,0x00] * 4) # SRC3_PWM1~PWM4: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC3_PWM5~PWM24:
PWMbSolid.extend([0x00,0x00] * 4) # SRC4_PWM1~PWM4: Unused SNK_ Channels
PWMbSolid.extend(pwmdata * 20) # SRC4_PWM5~PWM24:
PWMbSolid.extend(filler)
PWMbSolid = combine_hex_elements(PWMbSolid, chunk_size)
pio_spi.write_blocking(PWMbSolid) # IC11
print(PWMbSolid)
def Power_Down():
Vled.value(0)
utime.sleep_ms(t2_ms) # 1ms
cs_pin.value(0)
utime.sleep_ms(t3_ms) # 50ms the time from VLED low to VDD low (50ms)
Vddio.value(0) # Set Vddio low
led_pin.value(0)
alert_led.value(0)
def judge_LED_board(): # Detect LED driver IC version by reading device ID registers
test_passed = False
print(">> judge_LED_board() START")
raw_data = pio_spi.write_read_blocking(DEV_ID)
split_data = split_rd_data(raw_data)
if split_data == ExDevID:
test_pass = True
else:
test_passed = False
return test_passed
def check_sg():
test_failed = False
#print(">> check_sg() START")
raw_data = pio_spi.write_read_blocking(STATUS2)
split_data = split_rd_data(raw_data)
useful_data = split_data[14:] # skip the useless 14 bytes datas in the front
first_bytes = useful_data[0:Driver_IC_count*2:2]
for byte in first_bytes:
SG = (byte >> 7) & 1 # check bit15 = 1 → SG
if SG == 1:
#print("Detected SG fault on LED board")
test_failed = True
break
else:
test_failed = False
#print("No SG fault detected for this IC")
return test_failed
def check_diag_snk_sg():
# DIAG_SNK_SGレジスタを確認し、詳細な故障情報を返す
print(">> check_diag_snk_sg() START")
fault_detected = False #初期値はFalseを設置し、故障がまだ検出されていないことを示す
fault_details = [] #空のリストfault_detailsを作成し、検出された障害の詳細情報を格納するために使用します。
raw_data = pio_spi.write_read_blocking(Diag_SG)
split_data = split_rd_data(raw_data)
useful_data = split_data[25:] # skip the useless 25 bytes datas in the front
print(useful_data)
print("Waiting for KEY2 to be released...")
# After the program starts, if KEY2 is in the “pressed state,” it will wait until it is “released.”
# The 「While True」 function can only be executed correctly after KEY2 is released 【KEY2.value() == 1】
while KEY2.value() == 0:
utime.sleep_ms(100)
while True:
if KEY2.value() == 0 and status == 0:
status = 1
print(status)
led_pin.value(status & 1)
status_led.value(1)
# 0. First, check the Driver IC's Device revision code
Power_Up() # Vddio up ~~~~~ SW_RESET with Leave delay after the sw_reset(2ms→10ms)
# 1. First/check SPI, check the Driver IC's Device revision code
# RevID_passed = judge_LED_board() # for debugging LED driver Board
RevID_passed = True
if not RevID_passed: # If RevID Checck failed
print("MISO data invalid, entering error loop")
cs_pin.value(0)
Vddio.value(0) # Set Vddio low
while KEY2.value() == 0:
for _ in range(2): # 赤LEDを2回点滅させる
alert_led.value(1)
utime.sleep_ms(200)
alert_led.value(0)
utime.sleep_ms(200)
utime.sleep_ms(500)
# 退出错误循环后,执行Power_Down并重置状态
Power_Down()
status_led.value(0)
led_pin.value(0)
status = 0
print('Exited due to MISO error')
continue # 跳过本轮循环的剩余部分
# 2. Secand/check SNK to GND short
# If there is any SG fault, stop execution and wait for KEY2 to be pressed to exit.
sg_fault_detected = check_sg()
if sg_fault_detected:
print("SG fault detected! Program stopped. Press KEY2 to exit.")
# check_diag_snk_sg()
cs_pin.value(0)
Vddio.value(0) # Set Vddio low
while KEY2.value() == 0: # KEY2が押し続けられている間(==0)、点滅が実行され続ける。 KEY2を離したとき(KEY2.value() == 1)、このループは終了します。
alert_led.value(1)
utime.sleep(on_time)
alert_led.value(0)
utime.sleep(off_time)
# KEY2を離すと、ループが終了し、プログラムはPower_Down()などの後続動作を実行します。
# もしsg_fault_detectedの検出結果に異常がなければ、Power Downの処理の中でもe0が送信されます(余計な時間がかかる)。しかし、最終的再度KEY2を押すだけでプログラムを終了できるため、e0にかかる時間は全体のタイミングに影響しません。
Power_Down()
status = 0 # reset status
print('all LEDs off')
continue
# # 2. Second, Run BIST (True = passed, False = failed)
# bist_passed = Bist_start()
# 3. Preparation before lighting the LEDs
Vled.value(1)
utime.sleep_ms(27) # 27:VLEDからBISTまでの時間であり、BIST機能を意図通りに動作させるための起動条件です。VLEDが立ち上がってからBISTが動作するまでには必ず遅延があるため、過去の履歴を基に27msとしています。
#pwm.duty_u16(int(65535 * 0.01)) # 点灯のためのPWM基準信号VSYNCを有効化
#utime.sleep_ms(20)
Configuration()
pio_spi.write_blocking(EN_1) # 点灯開始(duty 0%なので非点灯)
# # 4. Disp Check pattern
# if not bist_passed:
# cross_pattern_lighting(RevID_passed, bist_passed, duty_value_3) # cross pattern点灯#
#
# 5. all LEDs lighting Mode1 brightness
# else:
# print("BIST passed and board is P2 - Starting normal operation")
utime.sleep_ms(10)
change_pwm_all_leds(duty_value_1) # 全点灯(duty変更)
print('Mode 1: all LEDs on with 2% PWM duty')
# 6. all LEDs lighting Mode2 brightness
# Wait for KEY1 to be pressed to switch to Mode 2
while KEY2.value() == 0:
utime.sleep_ms(10)
if KEY1.value() == 0:
while KEY1.value() == 0:
utime.sleep_ms(10)
status += 1
if status == 2:
# pio_spi.write_blocking(EN_1)
change_pwm_all_leds(duty_value_2)
print('Mode 2: all LEDs on with 5.592% PWM duty')
break
elif KEY2.value() == 1 and status != 0:
pio_spi.write_blocking(EN_0)
utime.sleep_ms(100)
Power_Down()
status = 0
print('all LEDs off')
utime.sleep_ms(10)