Skip to content

slave_example

Boris Lovosevic edited this page Jul 27, 2019 · 5 revisions

In this example SPI master on ESP32 is connected to the K210 SPI Slave.
As ESP32 does not support 3-line mode, K210 Slave is configured for 4-line communication.
Sipeed Maix-bit development board was used for testing.


Spi slave initialization

import machine

# slave callback is not used, so enable debug log to see the slave operation status
machine.loglevel(machine.LOG_DEBUG)

s=machine.SPI(machine.SPI.SPI_SLAVE, mosi=15, miso=16, sck=10, cs=9, slave_buffer=8192)

buffill=b'12345678abcdefghijklmnoprstuvzABCDEFGHIJKLMNOPRSTUVZ'

s.fillbuffer(ord('@'))
s.setdata(buffill, 0)

ESP32 SPI master initialization

import machine, time, ustruct

m=machine.SPI(1,baudrate=16000000,mosi=19,miso=23,sck=18,cs=21,duplex=False)

# K210 SPI slave command codes
CMD_TEST=1
CMD_INFO=2
CMD_STATUS=3
CMD_WRITE=4
CMD_WRITE_CSUM=5
CMD_READ=6
CMD_READ_CSUM=7
# time in us to sleep between command and data
SPI_SLEEP = 5
# slave commands descriptions
slave_commands = (
    "No command",
    "Test",
    "Read info",
    "Status",
    "Write data",
    "Write data with csum",
    "Read data",
    "Read data with csum",
    "Unknown"
)
# slave error codes descriptions
slave_error = (
    "Ok",
    "Wrong command",
    "Cmd CSUM error",
    "Data CRC error",
    "Wrong address",
    "Wrong length",
    "Timeout",
    "Error",
    "Fatal Error, SLAVE reset",
    "Unknown"
)

# define some helper functions
#---------------------------
def setcmd(cmd, addr, size):
    spi_cmd = bytearray(8)
    spi_cmd[7] = 0
    spi_cmd[0] = cmd;
    spi_cmd[1] = addr & 0xff
    spi_cmd[2] = (addr >> 8) & 0xff
    spi_cmd[3] = (addr >> 16) & 0xff
    spi_cmd[4] = size & 0xff
    spi_cmd[5] = (size >> 8) & 0xff
    spi_cmd[6] = (size >> 16) & 0xff
    for i in range(7):
        spi_cmd[7] ^= spi_cmd[i]
    return spi_cmd

#------------------------------------
def spi_read(addr, size, csum=False):
    if csum is True:
        spi_cmd = setcmd(CMD_READ_CSUM, addr, size)
        rdbuf = bytearray(size+2)
    else:
        spi_cmd = setcmd(CMD_READ, addr, size)
        rdbuf = bytearray(size)
    m.write(spi_cmd)
    time.sleep_ms(SPI_SLEEP)
    time.sleep_us(400)
    m.readinto(rdbuf)
    if csum is True:
        csum1 = machine.crc16(rdbuf[:-2])
        csum2 = rdbuf[len(rdbuf)-2] | (rdbuf[len(rdbuf)-1] << 8)
        if csum1 == csum2:
            return rdbuf[:size], True
        else:
            return rdbuf, False
    else:
        return rdbuf

#-------------------------------------------------
def spi_write(addr, buf, csum=False, check=False):
    if csum is True:
        # sending data block + csum, increase length by 2
        spi_cmd = setcmd(CMD_WRITE_CSUM, addr, len(buf)+2)
        csum1 = machine.crc16(buf)
        csumaray = bytearray(2)
        csumaray[0] = csum1 & 0xff
        csumaray[1] = (csum1 >> 8) & 0xff
        bbuf = bytearray(buf) + csumaray
    else:
        spi_cmd = setcmd(CMD_WRITE, addr, len(buf))
        bbuf = bytearray(buf)
    # Write command
    m.write(spi_cmd)
    # and data
    #time.sleep_us(SPI_SLEEP)
    m.write(bbuf)
    if check is True:
        # Check by reading the data back
        time.sleep_ms(5)
        rbuf, res = spi_read(addr, len(buf), True)
        if res is not True:
            return False
        bbuf = bytearray(buf) # convert to bytearray as the input can be string
        for i in range(len(buf)):
            if rbuf[i] != bbuf[i]:
                return False
    return True

#---------------------
def spi_test(b, size):
    spi_cmd = setcmd(CMD_TEST, b, size)
    rdbuf = bytearray(size)
    m.write(spi_cmd)
    time.sleep_us(SPI_SLEEP)
    m.readinto(rdbuf)
    return rdbuf

#----------------
def spi_status():
    spi_cmd = setcmd(CMD_STATUS, 2, 3)
    rdbuf = bytearray(26)
    m.write(spi_cmd)
    time.sleep_us(SPI_SLEEP)
    m.readinto(rdbuf)
    csum1 = machine.crc16(rdbuf[:-2])
    csum2 = rdbuf[len(rdbuf)-2] | (rdbuf[len(rdbuf)-1] << 8)
    if csum1 == csum2:
        res = ustruct.unpack('IIIIQ', rdbuf[:24])
        try:
            print("Command: {}; status={}, addr={}, len={}, time={}".format(slave_commands[res[0]], slave_error[res[1]], res[2], res[3], res[4]))
        except:
            pass
        return res, True
    return rdbuf, False

#-----------------
def spi_getinfo():
    spi_cmd = setcmd(CMD_INFO, 1, 2)
    rdbuf = bytearray(18)
    m.write(spi_cmd)
    time.sleep_us(SPI_SLEEP)
    m.readinto(rdbuf)
    csum1 = machine.crc16(rdbuf[:-2])
    csum2 = rdbuf[len(rdbuf)-2] | (rdbuf[len(rdbuf)-1] << 8)
    if csum1 == csum2:
        vers = bytes(rdbuf[:9]).decode('utf-8')
        size = rdbuf[10] | (rdbuf[11] << 8) | (rdbuf[12] << 16)
        rosize = rdbuf[13] | (rdbuf[14] << 8) | (rdbuf[15] << 16)
        return vers, size, rosize, True
    else:
        return rdbuf, False

Test various combinations of spi slave commands
black colored boxes are ESP32 (spi master), blue colored K210 (spi slave)

# Get slave version, buffer size and read only size
>>> spi_getinfo()
('K210 v1.2', 8192, 0, True)
>>> 
D (991251590) [SPI_SLAVE_DRIVER]: Transfer time: 58 us)
D (991256124) [SPI_SLAVE_DRIVER]: Prepare time: 7 us
D (991261143) [SPI_SLAVE_DRIVER]: In IDLE mode
D (991265671) [SPI_SLAVE]: cmd=2 (Read info), err=0 (Ok), addr=1, len=2, time=4613
# Test: Request 64 bytes of character 'M'
>>> spi_test(ord('M'), 64)
bytearray(b'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM')
>>> 
D (1623575304) [SPI_SLAVE_DRIVER]: Transfer time: 86 us)
D (1623579924) [SPI_SLAVE_DRIVER]: Prepare time: 1 us
D (1623585031) [SPI_SLAVE_DRIVER]: In IDLE mode
D (1623589644) [SPI_SLAVE]: cmd=1 (Test), err=0 (Ok), addr=77, len=64, time=4726
# Write: write string to slave buffer at address 100
>>> txt = "This string was sent from ESP32 to the K210 SPI slave buffer at address 100"
>>> spi_write(100, txt)
True
# check the transfer status
>>> spi_status()
Command: Write data; status=Ok, addr=100, len=75, time=4691
((4, 0, 100, 75, 4691), True)
>>> 
D (2010267104) [SPI_SLAVE]: cmd=4 (Write data), err=0 (Ok), addr=100, len=75, time=4691
D (2044830010) [SPI_SLAVE_DRIVER]: Transfer time: 68 us)
D (2044834630) [SPI_SLAVE_DRIVER]: Prepare time: 8 us
D (2044839737) [SPI_SLAVE_DRIVER]: In IDLE mode
D (2044844350) [SPI_SLAVE]: cmd=3 (Status), err=0 (Ok), addr=2, len=3, time=4712
# Read: read back previously sent string from address 100
>>> spi_read(100, len(txt))
bytearray(b'This string was sent from ESP32 to the K210 SPI slave buffer at address 100')
# check the transfer status
>>> spi_status()
Command: Read data; status=Ok, addr=100, len=75, time=11108
((6, 0, 100, 75, 11108), True)
>>> 
D (2361152798) [SPI_SLAVE]: cmd=6 (Read data), err=0 (Ok), addr=100, len=75, time=11108
D (2375163698) [SPI_SLAVE_DRIVER]: Transfer time: 59 us)
D (2375168318) [SPI_SLAVE_DRIVER]: Prepare time: 9 us
D (2375173425) [SPI_SLAVE_DRIVER]: In IDLE mode
D (2375178038) [SPI_SLAVE]: cmd=3 (Status), err=0 (Ok), addr=2, len=3, time=4703
# Write with csum: write larger block of data to slave buffer at address 1000
>>> bb = b'Y' * 2000
>>> spi_write(1000, bb, True)
True
>>> spi_status()
Command: Write data with csum; status=Ok, addr=1000, len=2002, time=6603
((5, 0, 1000, 2002, 6603), True)
>>> 
>>> 
D (4059560224) [SPI_SLAVE]: cmd=5 (Write data with csum), err=0 (Ok), addr=1000, len=2002, time=6603
D (4106841279) [SPI_SLAVE_DRIVER]: Transfer time: 57 us)
D (4106845899) [SPI_SLAVE_DRIVER]: Prepare time: 8 us
D (4106851006) [SPI_SLAVE_DRIVER]: In IDLE mode
D (4106855619) [SPI_SLAVE]: cmd=3 (Status), err=0 (Ok), addr=2, len=3, time=4702
# Read with csum: read back previously sent block from address 1000
>>> bbr = spi_read(1000, len(bb), True)
>>> bbr[0] == bb
True
>>> spi_status()
Command: Read data with csum; status=Ok, addr=1000, len=2000, time=12209
((7, 0, 1000, 2000, 12209), True)
>>> 
D (4632014040) [SPI_SLAVE]: cmd=7 (Read data with csum), err=0 (Ok), addr=1000, len=2000, time=12209
D (4764811811) [SPI_SLAVE_DRIVER]: Transfer time: 70 us)
D (4764816432) [SPI_SLAVE_DRIVER]: Prepare time: 9 us
D (4764821538) [SPI_SLAVE_DRIVER]: In IDLE mode
D (4764826151) [SPI_SLAVE]: cmd=3 (Status), err=0 (Ok), addr=2, len=3, time=4715
Clone this wiki locally