-
-
Notifications
You must be signed in to change notification settings - Fork 24
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
- Maix-M1 schematic
- Maix-Bit schematic
- Maix-Go schematic
- Kendryte K210 datasheet
- RISC-V ISA Design
- RISC-V ISA Manual
- Forum
- MicroPython documentation
If you find this project useful, you can contribute by making a donation