Giter VIP home page Giter VIP logo

Comments (8)

dmazzella avatar dmazzella commented on May 26, 2024

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.

from uble.

dmazzella avatar dmazzella commented on May 26, 2024

Close for no, reopen it if you need help.

from uble.

waleckaw avatar waleckaw commented on May 26, 2024

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.

from uble.

dmazzella avatar dmazzella commented on May 26, 2024

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.

from uble.

waleckaw avatar waleckaw commented on May 26, 2024

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')

from uble.

dmazzella avatar dmazzella commented on May 26, 2024

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.

from uble.

waleckaw avatar waleckaw commented on May 26, 2024

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!

from uble.

dmazzella avatar dmazzella commented on May 26, 2024

I'm glad that everything works.

Best regards,
D.

from uble.

Related Issues (7)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.