This document describes the steps that need to be undertaken to setup a running python environment (at the moment limited to Windows systems), with which sensors from Bosch Sensortec can be read out using the Application Board APP2.0 and the shuttle boards.
The Application Board APP2.0 runs a firmware that allows connecting to it via USB and interface to a host PC. APP2.0 mainly serves as a protocol translator (like usb to i2c/spi) and has a dedicated streaming functionality for accurate sensor readout using the real-time capabilities of the MCU on the APP2.0.
On PC side, Bosch Sensortec provides a library for convenient access of the board using C# or python.
Assumption: the computer has a recent firefox web browser installed and has direct access to the internet. Furthermore, admin rights are required.
Create virtual environment (this is to prevent any issues with anaconda python and non-conda installed packages. For example name your virtual environment "my35env" with the command:
conda create -n my35env anaconda python=3.5
Note: the script should also work with other 3.x versions of python. However, using version 3.5 enables to add guiqwt to a later moment, which may be a required module for displaying sensor data in a GUI format.
The board can also be interfaced using libusb, the required software is currently under development.
Based on the instructions and if the anaconda package is used, the following steps should be taken to run the script:
# -*- coding: utf-8 -*- """ **************************************************************************** * Copyright (C) 2018 Bosch Sensortec GmbH * * Created 15.12.2017 * * This script is intended to be used to check BMI085 using GenericAPI and * shuttle board on APP2.0. * * Version changelog * ================= * 0.9 (15.12.2017) * - Initial version based on previous sample scripts * 1.0 (18.12.2017) * - Released after testing, small code modifications * - Test signal function does not work, reason unknown * **************************************************************************** * Disclaimer * * Common: * Bosch Sensortec products are developed for the consumer goods industry. * They may only be used within the parameters of the respective valid * product data sheet. Bosch Sensortec products are provided with the * express understanding that there is no warranty of fitness for a * particular purpose.They are not fit for use in life-sustaining, * safety or security sensitive systems or any system or device * that may lead to bodily harm or property damage if the system * or device malfunctions. In addition,Bosch Sensortec products are * not fit for use in products which interact with motor vehicle systems. * The resale and or use of products are at the purchasers own risk and * his own responsibility. The examination of fitness for the intended use * is the sole responsibility of the Purchaser. * * The purchaser shall indemnify Bosch Sensortec from all third party * claims, including any claims for incidental, or consequential damages, * arising from any product use not covered by the parameters of * the respective valid product data sheet or not approved by * Bosch Sensortec and reimburse Bosch Sensortec for all costs in * connection with such claims. * * The purchaser must monitor the market for the purchased products, * particularly with regard to product safety and inform Bosch Sensortec * without delay of all security relevant incidents. * * Engineering Samples are marked with an asterisk (*) or (e). * Samples may vary from the valid technical specifications of the product * series. They are therefore not intended or fit for resale to third * parties or for use in end products. Their sole purpose is internal * client testing. The testing of an engineering sample may in no way * replace the testing of a product series. Bosch Sensortec assumes * no liability for the use of engineering samples. * By accepting the engineering samples, the Purchaser agrees to indemnify * Bosch Sensortec from all claims arising from the use of engineering * samples. * * Special: * This software module (hereinafter called "Software") and any information * on application-sheets (hereinafter called "Information") is provided * free of charge for the sole purpose to support your application work. * The Software and Information is subject to the following * terms and conditions: * * The Software is specifically designed for the exclusive use for * Bosch Sensortec products by personnel who have special experience * and training. Do not use this Software if you do not have the * proper experience or training. * * This Software package is provided `` as is `` and without any expressed * or implied warranties,including without limitation, the implied warranties * of merchantability and fitness for a particular purpose. * * Bosch Sensortec and their representatives and agents deny any liability * for the functional impairment * of this Software in terms of fitness, performance and safety. * Bosch Sensortec and their representatives and agents shall not be liable * for any direct or indirect damages or injury, except as * otherwise stipulated in mandatory applicable law. * * The Information provided is believed to be accurate and reliable. * Bosch Sensortec assumes no responsibility for the consequences of use * of such Information nor for any infringement of patents or * other rights of third parties which may result from its use. * No license is granted by implication or otherwise under any patent or * patent rights of Bosch. Specifications mentioned in the Information are * subject to change without notice. **************************************************************************/ """ import sys import clr from time import sleep sys.path.append(r"C:\Program Files\Bosch Sensortec\Development Desktop 2.0\UserpApplicationBoard") # path of dll clr.AddReference("UserApplicationBoard") from System import Byte from System import UInt16 clr.AddReference('System.Collections') import numpy as np import BST # Pin descriptions and other constants PS_Gyro = 9 SCX = 6 SDX = 5 SDO = 4 BMI085_ShuttleID = 70 ACCEL_RANGE = 2 # BMI085: smallest Accel range is 2G (for BMI088 here would be 3G) GYRO_RANGE = 2000 # BMI08x: "standard" gyro range board = '' # This class contains the relevant information about the sensor. # In case of BMI08x, there are 2 class initializations neeeded, one # for accelerometer, the other one for the gyroscope. class Sensor: def __init__(self, sensor_ID, i2c_addr, interface, CSB, asic): self.sensor_ID = sensor_ID self.i2c_addr = i2c_addr self.interface = interface self.CSB = CSB self.asic = asic self.firstdatareg = 0 self.rangereg = 0 self.fullrange = 0 if asic == 'baa450': self.firstdatareg = 0x12 self.rangereg = 0x41 self.fullrange = ACCEL_RANGE if asic == 'bag160': self.firstdatareg = 0x02 self.rangereg = 0x0F self.fullrange = GYRO_RANGE def get_if_detail(self): if self.interface == 'spi': return self.CSB elif self.interface == 'i2c': return self.i2c_addr else: return -1 def set_if(self, interface): self.interface = interface # create single board instance over USB connection def bst_init_brd_app20(): global board board = BST.UserApplicationBoard() board.PCInterfaceConfig( BST.PCINTERFACE.USB ) # print board info bi = board.GetBoardInfo() print('BoardInfo: HW/SW ID: ' + str(bi.HardwareId) + '/' + \ str(bi.SoftwareId) + ', ShuttleID: ' + str(bi.ShuttleID)) if bi.HardwareId == 0: print('Seems like there is no board commincation. Stop') board.ClosePCInterface() sys.exit() # if bi.ShuttleID != BMI085_ShuttleID: # print('Seems like you are not using BMI085 shuttle board. Stop') # board.ClosePCInterface() # sys.exit() # Set SPI bus def brd_set_spi_if(sensor): board.PinConfig(SCX, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.HIGH) board.PinConfig(SDX, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.HIGH) board.PinConfig(SDO, BST.EONOFF.ON, BST.PINMODE.INPUT, BST.PINLEVEL.HIGH) board.SensorSPIConfig( Byte(sensor.sensor_ID), sensor.CSB, \ BST.SPISPEED.SPI1000KBIT, BST.SPIMODE.MODE0 ) board.PinConfig(sensor.CSB, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.HIGH) if sensor.asic == 'bag160': board.PinConfig(PS_Gyro, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.LOW) # ic2 select # Set I2C bus def brd_set_i2c_if(sensor): # selecz ic2 addr board.PinConfig(SDO, BST.EONOFF.ON, BST.PINMODE.OUTPUT, BST.PINLEVEL.LOW) board.PinConfig(sensor.CSB, BST.EONOFF.OFF, BST.PINMODE.INPUT, \ BST.PINLEVEL.LOW) if sensor.asic == 'bag160': # selecz ic2 mode board.PinConfig(PS_Gyro, BST.EONOFF.ON, BST.PINMODE.OUTPUT, \ BST.PINLEVEL.HIGH) board.SensorI2CConfig( Byte(sensor.sensor_ID), UInt16(sensor.i2c_addr), \ BST.I2CSPEED.STANDARDMODE) # Power up sequence fo the sensors def power_up(sensor): if sensor.asic == 'baa450': # Wait times according to datasheet sleep(.001) board.Write(0x7D, 4, sensor.get_if_detail()) # write 4 to ACC_PWR_CTRL board.Write(0x7C, 0, sensor.get_if_detail()) # Clear ACC_PWR_CONF sleep(.05) if sensor.asic == 'bag160': brd_write(sensor, 0x11, ) pwr = brd_read(sensor, 0x11, 1) print(pwr) # Function to read from the previous selected bus def brd_read(sensor, reg, range): # Consider the dummy byte if (sensor.asic == 'baa450') and (sensor.get_if_detail() == sensor.CSB): range += 1 data = board.Read(reg & 0x7F, UInt16(range), sensor.get_if_detail()) data = [int(i) for i in data] # data is in Int32 format if (sensor.asic == 'baa450') and (sensor.get_if_detail() == sensor.CSB): data.pop(0) return data # Function to write on the previous selected bus def brd_write(sensor, reg, data): return board.Write(reg & 0x7F, data, sensor.get_if_detail()) # Calculate 2's complement out of given uint value def twos_comp(val, bits): """compute the 2's complement of int value val""" if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255 val = val - (1 << bits) # compute negative value return val # return positive value as is # This function reads a number of samples, calculates the average and the # standard deviation and outputs the result to the user def read_sensor_values_3D(sensor, num_of_samples = 25, delay_in_ms = 0): x =  y =  z =  # Read in number of samples while(num_of_samples > 0): data = brd_read(sensor, sensor.firstdatareg, 6) x.append(twos_comp(data * 256 + data, 16)) y.append(twos_comp(data * 256 + data, 16)) z.append(twos_comp(data * 256 + data, 16)) sleep(delay_in_ms) num_of_samples -= 1 return ([np.mean(x), np.mean(y), np.mean(z), np.std(x), np.std(y), np.std(z)]) # This function converts LSB to pyhsical measure (e.g G for accel or # dps for gyro) def convert_lsb_2_phys(sensor, data): sensrange = brd_read(sensor, sensor.rangereg, 1) print('Range is set to : ' + str(sensrange)) result =  for d in data: result.append(d/32768. * sensor.fullrange * 2 ** (sensrange)) return result def read_temp_sensor_baa450(sensor): if sensor.asic == 'baa450': data = brd_read(sensor, 0x22, 2) return(twos_comp(data * 8 + (data >> 5), 11) * 0.125 + 23) # This function is not yet working reliably at the moment! (refers to V1.0) def trigger_selftest(sensor): if sensor.asic == 'baa450': # Set 16G measurement range brd_write(sensor, 0x41, 3) # Set ODR 1.6kHz, normal mode: brd_write(sensor, 0x40, 0xA7) # Wait 2ms (see datasheet) sleep(.003) print('-> Enabling positive selftest signal') brd_write(sensor, 0x6D, 0x0D) # Wait >50ms (see datasheet) sleep(0.051) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print(data) print('-> Enabling negative selftest signal') brd_write(sensor, 0x6D, 0x09) sleep(.1) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print(data) brd_write(sensor, 0x6D, 0x00) sleep(.1) # ############################################################################ # Main routine. if __name__ == "__main__": bst_init_brd_app20() try: # ##### SPI section ##### myif = 'spi' print('\n +++ Interface: ' + myif + ' +++') bmi08x_accel = Sensor(0x1F, 0x18, myif, 8, 'baa450') bmi08x_gyro = Sensor(0x0F, 0x68, myif, 14, 'bag160') board.SetVDD(0) board.SetVDDIO(0) brd_set_spi_if(bmi08x_gyro) brd_set_spi_if(bmi08x_accel) board.SetVDD(3.3) board.SetVDDIO(3.3) # Read chip-ID 2x for accelerometer to switch to spi mode chipid = brd_read(bmi08x_accel, 0, 1) # Read chip id chipid = brd_read(bmi08x_accel, 0, 1) print ('Chip ID accel: ' + str(chipid)) chipid = brd_read(bmi08x_gyro, 0, 1) print ('Chip ID gyro: ' + str(chipid)) board.SetVDD(0) board.SetVDDIO(0) # ##### I2C section ##### myif = 'i2c' print('\n +++ Interface: ' + myif + ' +++') bmi08x_accel = Sensor(0x1F, 0x18, myif, 8, 'baa450') bmi08x_gyro = Sensor(0x0F, 0x68, myif, 14, 'bag160') brd_set_i2c_if(bmi08x_accel) brd_set_i2c_if(bmi08x_gyro) board.SetVDD(3.3) board.SetVDDIO(3.3) # Read chip id chipid = brd_read(bmi08x_accel, 0, 1) print ('Chip ID accel: ' + str(chipid)) chipid = brd_read(bmi08x_gyro, 0, 1) print ('Chip ID gyro: ' + str(chipid)) # Read accel data power_up(bmi08x_accel) data = read_sensor_values_3D(bmi08x_accel) data = convert_lsb_2_phys(bmi08x_accel, data) print ('Accel x [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data * 1000, data * 1000)) print ('Accel y [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data * 1000, data * 1000)) print ('Accel z [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data * 1000, data * 1000)) # Read gyro data data = read_sensor_values_3D(bmi08x_gyro) data = convert_lsb_2_phys(bmi08x_gyro, data) print ('Gyro x [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data, data)) print ('Gyro y [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data, data)) print ('Gyro z [mg]: %.2f\t(Noise RMS: %.2f)' % \ (data, data)) # Read temperature data data = read_temp_sensor_baa450(bmi08x_accel) print ('Temperature [degC]: %.2f' % data) # Trigger selftest not yet working for unknown reason, not a sensor, # but obvious a python/toolchain issue #trigger_selftest(bmi08x_accel) except Exception as e: print('Fehler: ' + str(e)) board.SetVDD(0) board.SetVDDIO(0) board.ClosePCInterface(