Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: create documentation [#2] #3

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 277 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,285 @@
# Python communication with COINES firmware

`python3` communication with COINES app-board 3.0 and app-board 3.1 firmware.
[![Static analysis and Unit tests](https://github.com/umrx-sw/umrx-v3-py/actions/workflows/python-lint-and-test.yml/badge.svg)](https://github.com/umrx-sw/umrx-v3-py/actions/workflows/python-lint-and-test.yml)

## Development
`python3` communication with COINES firmware on
[Application Board 3.1](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-1/) or
[3.0](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-0/) hardware.

- Run `poetry add {package}` to add a runtime dependency.
- Run `poetry update` from within the development environment to upgrade all dependencies to the latest versions
defined in `pyproject.toml` and it's lock file.
Install the latest version from [pypi](https://pypi.org/):
```bash
pip install umrx-v3-py
```

The `umrx-v3-py` project implements in `python3` COINES communication protocol
to control the micro-controller (MCU) and read the sensor data from the
[Application Board 3.1](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-1/) and
[3.0](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-0/) when
board is programmed with BST default firmware.

Unlike python bindings from [COINES SDK](https://github.com/boschsensortec/COINES_SDK)
which load pre-compiled OS-dependent C library,
this project is built entirely in python and requires only
[`pyserial`](https://pypi.org/project/pyserial/)
and
[`pyusb`](https://pypi.org/project/pyusb/) dependencies.

## Maintainer
## Features

[Dr. Konstantin Selyunin](https://selyunin.github.io/),
for suggestions / questions / comments
please contact:
selyunin [dot] k [dot] v [at] gmail [dot] com
* Support [Application Board 3.1](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-1/)
and
[Application Board 3.0](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-0/);
* Configure shuttle pins, set pin levels;
* Switch ON/OFF `VDD` and `VDDIO` of the shuttle board to power the sensor;
* Read / write the sensor registers using the I2C protocol;
* Read / write the sensor registers using the SPI protocol;
* Configure and receive streaming packets:
* **Polling** streaming: sensor registers are read in bulk at regular intervals;
* **Interrupt** streaming: sensor registers are read in bulk when sensor reports data ready over interrupt pin.
* Switch application to
[DFU](https://www.usb.org/document-library/device-firmware-upgrade-11-new-version-31-aug-2004) or
[MTP](https://en.wikipedia.org/wiki/Media_Transfer_Protocol)
* Enable MCU time stamp (works only with Application Board 3.0).


## Installation

Communication with firmware happens either via USB (for Application Board 3.0)
or serial port over USB (for Application Board 3.1).
Reading / writing USB (or serial) devices is often a privileged operation.
Below we describe OS-specific setup steps to be able to use the package.

### OS prerequisites

#### Linux

To access USB device on Linux as a regular user, one needs to install the `udev`-rules.
Create the file `/etc/udev/rules.d/application_board.rules` with the following content:

```bash
# Application Board 3.0
SUBSYSTEM=="usb", ATTRS{idVendor}=="152a", ATTRS{idProduct}=="80c0", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3d", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3f", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"

# Application Board 3.1
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab38", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab39", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3a", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
```

The file can be created with the following command:
```bash
sudo bash -c 'cat <<EOF >>/etc/udev/rules.d/application_board.rules
# Application Board 3.0
SUBSYSTEM=="usb", ATTRS{idVendor}=="152a", ATTRS{idProduct}=="80c0", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3d", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3f", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"

# Application Board 3.1
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab38", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab39", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ATTRS{idVendor}=="108c", ATTRS{idProduct}=="ab3a", ACTION=="add", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
EOF'
```

Reload the udev-rules:

```bash
sudo udevadm control --reload-rules && sudo udevadm trigger
```

To access serial devices on Linux as a regular user, one needs to be a member of the `dialout` group.

```bash
sudo usermod -a -G dialout <your-user-name>
```

#### Windows

Install [libusb-1](https://github.com/libusb/libusb) via `vcpkg` by following
these [instructions](https://github.com/libusb/libusb/wiki/Windows#user-content-vcpkg_port).

Add the path where the `*.DLL` libraries are located to the `PATH` environment variable.

Use [`zadig`](https://zadig.akeo.ie/) to install the drivers for the boards:

* For Application Board 3.1 install CDC serial driver:

* For Application Board 3.0 install WinUSB:



#### Mac OS

Install [Homebrew](https://brew.sh/).

Install [libusb](https://formulae.brew.sh/formula/libusb):
```bash
brew install libusb
```


Execute the python scripts with `sudo` to read/write USB device.

### Install using pip

```bash
pip install umrx-v3-py
```


### Install from source

To install the package from source:
1. clone the repository, and
2. run in the repo root:
```bash
pip install poetry
poetry install
poetry shell
```

## Supported python version

The project was developed with `python-3.12` although it might work earlier python versions `>=3.9`.

## Quick start

The examples below are self-contained and can be copy-pasted as is.

### Terminology

Bosch offers two hardware revisions:
* [Application Board 3.1](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-1/), **3.1** HW
* [Application Board 3.0](https://www.bosch-sensortec.com/software-tools/tools/application-board-3-0/), **3.0** HW

Although both boards use [`nRF52840`](https://www.nordicsemi.com/Products/nRF52840)
(and are based on [`NINA-B30*`](https://www.u-blox.com/en/product/nina-b30-series-open-cpu-0) modules),
they differ in hardware and firmware.

In `umrx-v3-py` code to differentiate the boards we use
`v3_rev1` (for _v3, revision 1_) suffix for **3.1** HW
and
`v3_rev0` (for _v3, revision 0_) suffix for **3.0** HW.

### Create the board object

Create the board object and initialize (connect to board and open communication):

```python
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1

board = ApplicationBoardV3Rev1()
# initialize board communication
board.initialize()
```

### Configure shuttle pins

```python
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1
from umrx_app_v3.mcu_board.bst_protocol_constants import MultiIOPin, PinDirection, PinValue

board = ApplicationBoardV3Rev1()
board.initialize()
# configure shuttle pin P2.6 as output and set to high
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_6, PinDirection.OUTPUT, PinValue.HIGH)
```

### Supply power to shuttle

```python
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1

board = ApplicationBoardV3Rev1()
board.initialize()
# set VDD to 3.3 V, VDDIO to 3.3 V
board.set_vdd_vddio(3.3, 3.3)
```

### Configure communication interface

#### I2C

```python
import time
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1
from umrx_app_v3.mcu_board.bst_protocol_constants import MultiIOPin, PinDirection, PinValue

board = ApplicationBoardV3Rev1()
board.initialize()
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_6, PinDirection.OUTPUT, PinValue.HIGH)
board.set_vdd_vddio(3.3, 3.3)
time.sleep(0.01)
board.configure_i2c()
```

#### SPI

```python
import time
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1
from umrx_app_v3.mcu_board.bst_protocol_constants import MultiIOPin, PinDirection, PinValue, SPIBus
from umrx_app_v3.mcu_board.commands.spi import SPIConfigureCmd

board = ApplicationBoardV3Rev1()
board.initialize()
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_1, PinDirection.OUTPUT, PinValue.HIGH)
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_5, PinDirection.OUTPUT, PinValue.HIGH)
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_6, PinDirection.OUTPUT, PinValue.LOW)
board.set_vdd_vddio(3.3, 3.3)
time.sleep(0.01)
SPIConfigureCmd.set_bus(SPIBus.BUS_1)
board.configure_spi()
```

### Read / write registers

#### I2C
```python
import time
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1
from umrx_app_v3.mcu_board.bst_protocol_constants import MultiIOPin, PinDirection, PinValue

board = ApplicationBoardV3Rev1()
board.initialize()
board.start_communication()
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_6, PinDirection.OUTPUT, PinValue.HIGH)
board.set_vdd_vddio(3.3, 3.3)
time.sleep(0.1)
board.configure_i2c()
result = board.read_i2c(i2c_address=0x68, register_address=0x0, bytes_to_read=1)
print(result)
```
#### SPI

```python
import time
from umrx_app_v3.mcu_board.app_board_v3_rev1 import ApplicationBoardV3Rev1
from umrx_app_v3.mcu_board.bst_protocol_constants import MultiIOPin, PinDirection, PinValue, SPIBus
from umrx_app_v3.mcu_board.commands.spi import SPIConfigureCmd

board = ApplicationBoardV3Rev1()
board.initialize()
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_1, PinDirection.OUTPUT, PinValue.HIGH)
board.set_pin_config(MultiIOPin.MINI_SHUTTLE_PIN_2_6, PinDirection.OUTPUT, PinValue.LOW)
board.set_vdd_vddio(3.3, 3.3)
time.sleep(0.01)
SPIConfigureCmd.set_bus(SPIBus.BUS_1)
board.configure_spi()
result = board.read_spi(cs_pin=MultiIOPin.MINI_SHUTTLE_PIN_2_5, register_address=0x0, bytes_to_read=1)
print(result)
```

### Examples

Take a look at the additional [examples](./examples).

## Default firmware

The code was developed and tested with the _default_ firmware the **3.0** and **3.1** boards
were pre-programmed with.

If you want to program you board with the same firmware, follow instructions from this
[repo](https://github.com/umrx-sw/bst-default-firmware).
23 changes: 23 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Examples

These are self-contained examples for using the `umrx-v3-py` with Application Board 3.1.

* [`switch_app_dfu.py`](./switch_app_dfu.py)
* [`switch_app_mtp.py`](./switch_app_mtp.py)

The examples in the [`bmi088`](./bmi088) folder
show different communication features for the
[BMI088 shuttle](https://www.bosch-sensortec.com/media/boschsensortec/downloads/shuttle_board_flyer/application_board_3_1/bst-bmi088-sf000.pdf)
board:

* [`bmi088/bmi088_i2c_read_write.py`](./bmi088/bmi088_i2c_read_write.py)
* [`bmi088/bmi088_i2c_polling_streaming.py`](./bmi088/bmi088_i2c_polling_streaming.py)
* [`bmi088/bmi088_i2c_interrupt_streaming.py`](./bmi088/bmi088_i2c_interrupt_streaming.py)
* [`bmi088/bmi088_spi_read_write.py`](./bmi088/bmi088_spi_read_write.py)
* [`bmi088/bmi088_spi_polling_streaming.py`](./bmi088/bmi088_spi_polling_streaming.py)
* [`bmi088/bmi088_spi_interrupt_streaming.py`](./bmi088/bmi088_spi_interrupt_streaming.py)


## Need a specific example or do not know how to read data from your sensor?

Let us know, we are happy to help and offer our development expertise.
Loading