Closed waleckaw closed 4 years ago
Hi, can you give me an example of code that I can verify?
P.S. I'm sorry if I answer with such delays, but I keep this library in my spare time and lately it's been less and less.
Close for no, reopen it if you need help.
Apologies, I am not sure how I missed your response!
dmazella_imitation_BLESPItest.txt
In the file I attached (which I ran from the REPL), I attempted to copy your SPI code almost line-for-line, and was met with the same issue I described above. As you can see, I did have to port my code to fit the microcontroller I was using, the STM32 B-L475E-IOT01A, which contains an SPBTLE-RF on board.
no problem, I just tried your code and the problem is in not sending the reset command. As you can see without the reset, the result of the script is identical to yours:
➜ micropython (master) ✗ python3 -B tools/pyboard.py --device /dev/tty.usbmodem3167398C35352 /Users/damianomazzella/Downloads/ww.py
bytearray(b'\x04\x10\x01\x00')
➜ micropython (master) ✗
Adding the reset, the behavior is correct:
➜ micropython (master) ✗ python3 -B tools/pyboard.py --device /dev/tty.usbmodem3167398C35352 /Users/damianomazzella/Downloads/ww.py
bytearray(b'\x04\xff\x03\x01\x00\x01')
➜ micropython (master) ✗
This is the code I tried:
# hail mary BLE SPI test
import machine
import pyb
import utime
import micropython
from micropython import const
from machine import Pin
# spi = machine.SPI(3, baudrate=8000000, polarity=0, phase=0,
# bits=8, firstbit=machine.SPI.MSB)
spi = machine.SPI(2, baudrate=8000000, polarity=0)
#CS = Pin('D13', Pin.OUT_PP, pull=Pin.PULL_NONE)
CS = machine.Pin('B12', machine.Pin.OUT_PP)
CS.on()
#RS = Pin('A8', Pin.OUT_PP, pull=Pin.PULL_NONE)
RS = machine.Pin('B9', machine.Pin.OUT_PP)
RS.on()
_READ_HEADER_MASTER = b'\x0B\x00\x00\x00\x00'
_WRITE_HEADER_MASTER = b'\x0A\x00\x00\x00\x00'
HCI_READ_PACKET_SIZE = const(128)
# IR = Pin('E6', Pin.IN, pull=Pin.PULL_DOWN)
IR = machine.Pin('B8', machine.Pin.IN, machine.Pin.PULL_DOWN)
class CSContext(object):
def __init__(self, pin):
self._pin = pin
def __enter__(self):
# Assert CS line
self._pin.off()
def __exit__(self, exc_type, exc_value, traceback):
# Release CS line
self._pin.on()
# return all(map(lambda x: x is None, [exc_type, exc_value, traceback]))
def write(retry=5, header=b'\x10\x03', param=0):
"""
Write packet to BlueNRG-MS module
"""
_rw_header_slave = bytearray(len(_WRITE_HEADER_MASTER))
result = None
while retry:
with CSContext(CS):
# Exchange header
spi.write_readinto(
_WRITE_HEADER_MASTER,
_rw_header_slave
)
rx_write_bytes = _rw_header_slave[1]
rx_read_bytes = (
_rw_header_slave[4] << 8
) | _rw_header_slave[3]
if _rw_header_slave[0] == 0x02 and (
rx_write_bytes > 0 or rx_read_bytes > 0):
# SPI is ready
if header:
# avoid to write more data that size of the buffer
if rx_write_bytes >= len(header):
result = bytearray(len(header))
spi.write_readinto(header, result)
if param:
rx_write_bytes -= len(header)
# avoid to read more data that size of the
# buffer
if len(param) > rx_write_bytes:
tx_bytes = rx_write_bytes
else:
tx_bytes = len(param)
result = bytearray(tx_bytes)
spi.write_readinto(param, result)
break
else:
break
else:
break
else:
break
else:
utime.sleep_us(50)
retry -= 1
return result
def read(size=HCI_READ_PACKET_SIZE, retry=5):
"""
Read packet from BlueNRG-MS module
"""
result = None
_rw_header_slave = bytearray(len(_WRITE_HEADER_MASTER))
while retry:
with CSContext(CS):
# Exchange header
spi.write_readinto(
_READ_HEADER_MASTER,
_rw_header_slave
)
rx_read_bytes = (
_rw_header_slave[4] << 8
) | _rw_header_slave[3]
if _rw_header_slave[0] == 0x02 and rx_read_bytes > 0:
# SPI is ready
# avoid to read more data that size of the buffer
if rx_read_bytes > size:
rx_read_bytes = size
data = b'\xFF' * rx_read_bytes
result = bytearray(rx_read_bytes)
spi.write_readinto(data, result)
break
else:
utime.sleep_us(50)
retry -= 1
# Add a small delay to give time to the BlueNRG to set the IRQ pin low
# to avoid a useless SPI read at the end of the transaction
utime.sleep_us(150)
return result
def run():
# reset
RS.off()
utime.sleep_us(5)
RS.on()
utime.sleep_us(5)
write() # retry=5, header=b'\x10\x03', param=0)
while True:
utime.sleep_us(12)
if (IR.value() == 1):
hi = read(size=HCI_READ_PACKET_SIZE, retry=5)
print(hi)
break
utime.sleep_us(25)
run()
Let me know how it goes. best regards, D.
Ok, I probably should have mentioned in my previous post that I always reset the BlueNRG-MS module before running the code. My mistake.
When I run the code you posted, I get the correct initialization response like you did, but all of my following commands are met with the 0x04 0x10 0x01 0x00 error code. Below is an example with a few further modifications I added to continuously send commands to the chip. As you can see, I am trying to send the HCI_Read_Local_Supported_Features command. I get the same response if I send HCI_Read_Local_Supported_Commands, HCI_Read_Remote_Version_Information, or HCI_Read_Local_Version_Information as defined on page 7 in the blueNRG-MS document found here: [https://www.st.com/content/ccc/resource/technical/document/user_manual/6d/a1/5b/6c/dc/ab/48/76/DM00162667.pdf/files/DM00162667.pdf/jcr:content/translations/en.DM00162667.pdf]. I have tried many other commands, but those are 4 that I believe should work without any initialization other than a reset.
code:
def run():
RS.off()
utime.sleep_us(5)
RS.on()
utime.sleep_us(5)
write() # HCI_Read_Local_Supported_Features
while True:
utime.sleep_us(12)
if (IR.value() == 1):
hi = read(size=HCI_READ_PACKET_SIZE, retry=5)
print(hi)
utime.sleep(2)
write() # HCI_Read_Local_Supported_Features
run()
and here is the output from the REPL:
from BLEProj.test import dmzBLESPI
bytearray(b'\x04\xff\x03\x01\x00\x01')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
bytearray(b'\x04\x10\x01\x00')
with your example:
# hail mary BLE SPI test
import machine
import pyb
import ustruct
import utime
import micropython
from micropython import const
from machine import Pin
# spi = machine.SPI(3, baudrate=8000000, polarity=0, phase=0,
# bits=8, firstbit=machine.SPI.MSB)
spi = machine.SPI(2, baudrate=8000000, polarity=0)
#CS = Pin('D13', Pin.OUT_PP, pull=Pin.PULL_NONE)
CS = machine.Pin('B12', machine.Pin.OUT_PP)
CS.on()
#RS = Pin('A8', Pin.OUT_PP, pull=Pin.PULL_NONE)
RS = machine.Pin('B9', machine.Pin.OUT_PP)
RS.on()
_READ_HEADER_MASTER = b'\x0B\x00\x00\x00\x00'
_WRITE_HEADER_MASTER = b'\x0A\x00\x00\x00\x00'
HCI_READ_PACKET_SIZE = const(128)
# IR = Pin('E6', Pin.IN, pull=Pin.PULL_DOWN)
IR = machine.Pin('B8', machine.Pin.IN, machine.Pin.PULL_DOWN)
class CSContext(object):
def __init__(self, pin):
self._pin = pin
def __enter__(self):
# Assert CS line
self._pin.off()
def __exit__(self, exc_type, exc_value, traceback):
# Release CS line
self._pin.on()
# return all(map(lambda x: x is None, [exc_type, exc_value, traceback]))
def write(retry=5, header=b'', param=0):
"""
Write packet to BlueNRG-MS module
"""
_rw_header_slave = bytearray(len(_WRITE_HEADER_MASTER))
result = None
while retry:
with CSContext(CS):
# Exchange header
spi.write_readinto(
_WRITE_HEADER_MASTER,
_rw_header_slave
)
rx_write_bytes = _rw_header_slave[1]
rx_read_bytes = (
_rw_header_slave[4] << 8
) | _rw_header_slave[3]
if _rw_header_slave[0] == 0x02 and (
rx_write_bytes > 0 or rx_read_bytes > 0):
# SPI is ready
if header:
# avoid to write more data that size of the buffer
if rx_write_bytes >= len(header):
result = bytearray(len(header))
spi.write_readinto(header, result)
if param:
rx_write_bytes -= len(header)
# avoid to read more data that size of the
# buffer
if len(param) > rx_write_bytes:
tx_bytes = rx_write_bytes
else:
tx_bytes = len(param)
result = bytearray(tx_bytes)
spi.write_readinto(param, result)
break
else:
break
else:
break
else:
break
else:
utime.sleep_us(50)
retry -= 1
return result
def read(size=HCI_READ_PACKET_SIZE, retry=5):
"""
Read packet from BlueNRG-MS module
"""
result = None
_rw_header_slave = bytearray(len(_WRITE_HEADER_MASTER))
while retry:
with CSContext(CS):
# Exchange header
spi.write_readinto(
_READ_HEADER_MASTER,
_rw_header_slave
)
rx_read_bytes = (
_rw_header_slave[4] << 8
) | _rw_header_slave[3]
if _rw_header_slave[0] == 0x02 and rx_read_bytes > 0:
# SPI is ready
# avoid to read more data that size of the buffer
if rx_read_bytes > size:
rx_read_bytes = size
data = b'\xFF' * rx_read_bytes
result = bytearray(rx_read_bytes)
spi.write_readinto(data, result)
break
else:
utime.sleep_us(50)
retry -= 1
# Add a small delay to give time to the BlueNRG to set the IRQ pin low
# to avoid a useless SPI read at the end of the transaction
utime.sleep_us(150)
return result
def run():
# reset
RS.off()
utime.sleep_us(5)
RS.on()
utime.sleep_us(5)
# wait event "device ready"
while True:
if IR.value() and read() == b'\x04\xff\x03\x01\x00\x01':
break
# HCI_Read_Local_Version_Information: OGF: 0x04 OCF: 0x01 OPCODE: 0x1001
param = b''
ogf = 0x04
ocf = 0x01
opcode = ustruct.pack("<H", (ocf & 0x03ff) | (ogf << 10)) # OPCODE
header = ustruct.pack("<B3s", 0x01, opcode)
print(header, param)
write(header=header, param=param)
while True:
if IR.value():
hi = read()
print("-------", hi)
break
# HCI_Read_Local_Supported_Features: OGF: 0x04 OCF: 0x03 OPCODE: 0x1003
param = b''
ogf = 0x04
ocf = 0x03
opcode = ustruct.pack("<H", (ocf & 0x03ff) | (ogf << 10)) # OPCODE
header = ustruct.pack("<B3s", 0x01, opcode)
print(header, param)
write(header=header, param=param)
while True:
if IR.value():
hi = read()
print("-------", hi)
break
run()
expected output:
➜ micropython (master) ✗ python3 -B tools/pyboard.py --device /dev/tty.usbmodem3167398C35352 /Users/damianomazzella/Downloads/test_uble.py
b'\x01\x01\x10\x00' b''
------- bytearray(b'\x04\x0e\x0c\x01\x01\x10\x00\x07\x071\x070\x00#\x00')
b'\x01\x03\x10\x00' b''
------- bytearray(b'\x04\x0e\x0c\x01\x03\x10\x00\x00\x00\x00\x00`\x00\x00\x00')
➜ micropython (master) ✗
Please try it and give me feedback.
It worked! I can't believe it. The issue was definitely the header format. For example, when I told you I sent the HCI_Read_Local_Supported_Features command, I was sending the header in a simple bytearray as it was given in the spec: OpCode = 0x1003. I can see now that, when the header gets packed into a ustruct, its formatting changes and it becomes 0x0103. I am not sure where or if that ever gets clarified in the BlueNRG-MS spec I linked above.
I can't thank you enough, especially because you mentioned this is an old project. Without your help I doubt I ever would have ever solved this problem. I am a relative newcomer when it comes to embedded python, and never would have thought to use a struct. Many thanks!
I'm glad that everything works.
Best regards, D.
Apologies, this is not an issue with your library
I am writing an application the STM32 B-L475E-IOT01A discovery board that uses the SPBTLE-RF BlueNRG chip as well.
I have been dealing with the following issue for a few days now. If you ever encountered a similar issue, I am wondering what you did to fix it.
The Issue:
I am having trouble interfacing with the B-L475E-IOT01A's on-board SPBTLE-RF bluetooth chip.
I am able to send header packets inquiring about the the bluetooth chip's write and read buffers. I have confirmed that I am doing this correctly, because I get responses in the correct format: 0x02 0x?? 0x00 0x?? 0x00. The ?? bytes always give me the correct number of available writable bytes and bytes to be read, respectively.
I am also able to read messages from the bluetooth chip, as I always receive the expected packet when I perform a chip reset: 0x04 0xff 0x03 0x01 0x00 0x01, and after sending an HCI command packet I am able to poll for and read the responses described below.
The issue that I am having is that, whenever I check that the write buffer is available and attempt to send a full write message such as ...
header = 0x0A 0x00 0x00 0x00 0x00 (check write buffer... only sends rest of message if write buffer > 0) HCI command packet = 0x1003 (example: Read_Local_Supported_Features) param total length = 0x00 (i have also tried not including this byte at all and raising the chip select one byte sooner instead) params: none
... I always receive the same HCI event packet in response, no matter the contents of my HCI command packet's body:
response: 0x04 0x10 0x01 0x00
This implies that I am having a hardware framing error with my SPI, and I have no idea what may be causing that. As I just described, the rest of the processes work fine, so the SPI bus seems to be functional in most cases.
Note: My send an receive methods are almost identical in structure to yours
If you can offer me any advice, I would appreciate it immensely. Otherwise, thank you for the awesome library!