chakokuのブログ(rev4)

日々のごった煮ブログです

ビットバンギングで、SPI 3-Wireモードを実装して加速度センサ(LSM6DSL)のレジスタを読んでみる

STEVAL-DRONE01上の加速度センサはマイコンとSPI 3-Wireモードで接続されていてMicroPython上で利用可能な標準のSPIドライバでは制御できない*1
泥臭いが、ビットバンギングでIOポートを上げ下げしてSPI 3-Wire相当のバスを作って加速度センサのレジスタを読んでみた。
結果、以下の通りで動いてそうな感じ。

>>> reg_dump()
00: 00 00 00 00 00 00 00 00 12 00 00 00 00 00 00 6a
10: 00 00 08 00 00 00 00 00 e0 00 00 00 00 00 00 c2
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 10 00 00 bb a8
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 84 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 bb 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 12 00 00 00 00 00 00 6a
90: 00 00 08 00 00 00 00 00 e0 00 00 00 00 00 00 c2
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 10 00 00 bb a8
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 84 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 bb 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

あたりまえだが、、ダンプさせるともっさり動いている。

SPI 3-Wireモードによる制御サンプルは以下

#-----------------------------------------
from pyb import Pin

# def for SPI
SPI_READ_BIT = 0x80

CTRL3_C = 0x12
CTRL6_C = 0x15
SIM_3WIRE = 0x08

lsm6d_cs = None
s2_clk = None
s2_sda = None


def reg_dump():
    for addr in range(0xff+1):
        data = spi_read_reg(addr)
        if (addr % 16) == 0:
            print(f"\n{addr:02x}: ", end="")
        print(f"{data:02x} ", end="")
    print("")

def spi_init():
    global lsm6d_cs, s2_clk, s2_sda

    lsm6d_cs = Pin(Pin.cpu.A8, mode=Pin.OUT)
    s2_clk = Pin(Pin.cpu.B13, mode=Pin.OUT)
    s2_sda = Pin(Pin.cpu.B15, mode=Pin.OUT)


def spi_write_reg(addr,data):
    global lsm6d_cs, s2_clk, s2_sda

    s2_sda = Pin(Pin.cpu.B15, mode=Pin.OUT)
    lsm6d_cs.high()
    spi_out(addr, no_ctrl_cs = True)
    spi_out(data, no_ctrl_cs = True)
    lsm6d_cs.low()

def spi_read_reg(addr):
    global lsm6d_cs, s2_clk, s2_sda

    s2_sda = Pin(Pin.cpu.B15, mode=Pin.OUT)
    lsm6d_cs.high()
    spi_out(addr | SPI_READ_BIT, no_ctrl_cs = True)
    s2_sda = Pin(Pin.cpu.B15, mode=Pin.IN)
    data = spi_in(no_ctrl_cs = True)
    #print(f"{data:02x}")
    lsm6d_cs.low()
    return data    

def spi_out(data,no_ctrl_cs = False):
    global lsm6d_cs, s2_clk, s2_sda

    # setup SPI bus
    if not no_ctrl_cs:
        lsm6d_cs.high()
    s2_clk.high()
    s2_sda.high()

    lsm6d_cs.low()

    mask = 0x80
    for i in range(8):
        s2_clk.low()
        #print("C_L ",end="")
        if data & mask:
            s2_sda.high()
            #print("D_H ",end="")
        else:
            s2_sda.low()
            #print("D_L ",end="")
        s2_clk.high()
        #print("C_H")
        mask >>= 1

    if not no_ctrl_cs:
        lsm6d_cs.high()



def spi_in(no_ctrl_cs = False):
    global lsm6d_cs, s2_clk, s2_sda
 
    # setup SPI bus
    if not no_ctrl_cs:
        lsm6d_cs.high()
    s2_clk.high()
 
    lsm6d_cs.low()
 
    data = 0
    for i in range(8):
        data <<= 1
        s2_clk.low()
        #print("C_L ",end="")
        s2_clk.high()
        #print("C_H ",end="")
        if s2_sda.value() == 1:
            #print("D_H")
            data |=1
        else:
            pass
            #print("D_L")
 
    if not no_ctrl_cs:
        lsm6d_cs.high()
 
    return data 
 
 
#---------------------------------------------- 
 
spi_init()

# set 3-wire mode
addr = CTRL3_C
data = SIM_3WIRE

spi_write_reg(addr,data)
data = spi_read_reg(addr)
print(f"{data:02x}")
reg_dump()

■追記
あらためて読み直すと、、以下のCS操作は逆ではなかろうか。

def spi_write_reg(addr,data):
    global lsm6d_cs, s2_clk, s2_sda

    s2_sda = Pin(Pin.cpu.B15, mode=Pin.OUT)
    lsm6d_cs.high()                              #  not cs.high but  cs.low ??
    spi_out(addr, no_ctrl_cs = True)
    spi_out(data, no_ctrl_cs = True)
    lsm6d_cs.low()                                #  not cs.low  but  cs.high ??

*1:SPI 4-Wireモードのみサポート