diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..bdd97ae --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,23 @@ +COPYRIGHT(c) 2017 STMicroelectronics + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + 3. Neither the name of STMicroelectronics nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index c17e640..807e425 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,62 @@ # FP_Examples -Function Pack software: Examples that combine the usage of multiple X-NUCLEO boards + +This library provides several Function Packs that combine the usage of several X-NUCLEO boards together with a NUCLEO board. + +## Examples + +There are several examples with the FP_Examples library. +* NucleoCar: This application provides a funny example of usage of a NUCLEO board (it was tested with NUCLEO-F401RE) with +X-NUCLEO-IDB05A1, X-NUCLEO-IHM02A1 and X-NUCLEO-6180XA1 Expansion Boards. The application implements two operative modes. With the +first mode the car can move using the main VL6180X sensor; the closer we put the hand on the sensor, the higher is the speed of the car. +The VL6180X satellites instead are used to avoid the obstacles. With the second mode the car can be controlled via BTLE using a dedicated +Android App. Also in this case the VL6180X satellites try to avoid the obstacles. In order to change the car mode, you can push the User +Button of the Nucleo board. +* GestureDirSwipeLed_53L0A1_LED61A1: This application provides a simple example of usage of a NUCLEO board (it was tested with NUCLEO-L476RG) +with X-NUCLEO-53L0A1 and X-NUCLEO-LED61A1 Expansion Boards. The application allows to switch on/off a strip of LEDs keeping the hand on the 3 +proximity sensors at least for 3 seconds. When the LEDs are switched on, the user can increase or decrease the intensity of the LEDs performing +a swipe movement respectively from left to right and from right to left. +* MemsMotorControl_IKS01A2_IHM02A1: This application provides a simple example of usage of a NUCLEO board (it was tested with NUCLEO-F401RE) +with X-NUCLEO-IKS01A2 and X-NUCLEO-IHM02A1 Expansion Boards. The application allows to run a motor clockwise or counter-clockwise rotating the +stack of boards accordingly; the speed of motor increases when the angle of rotation increases as well. + + +## Dependencies + +The FP_Examples library requires the following STM32duino libraries: + +* STM32duino LSM6DSL: https://github.com/stm32duino/LSM6DSL +* STM32duino Proximity_Gesture: https://github.com/stm32duino/Proximity_Gesture +* STM32duino VL6180X: https://github.com/stm32duino/VL6180X +* STM32duino VL53L0X: https://github.com/stm32duino/VL53L0X +* STM32duino SPBTLE-RF: https://github.com/stm32duino/SPBTLE-RF +* STM32duino X-NUCLEO-6180XA1: https://github.com/stm32duino/X-NUCLEO-6180XA1 +* STM32duino X-NUCLEO-53L0A1: https://github.com/stm32duino/X-NUCLEO-53L0A1 +* STM32duino X-NUCLEO-IHM02A1: https://github.com/stm32duino/X-NUCLEO-IHM02A1 +* STM32duino X-NUCLEO-LED61A1: https://github.com/stm32duino/X-NUCLEO-LED61A1 + + +## Documentation + +You can find the source files at +https://github.com/stm32duino/LSM6DSL +https://github.com/stm32duino/Proximity_Gesture +https://github.com/stm32duino/VL6180X +https://github.com/stm32duino/VL53L0X +https://github.com/stm32duino/SPBTLE-RF +https://github.com/stm32duino/X-NUCLEO-6180XA1 +https://github.com/stm32duino/X-NUCLEO-53L0A1 +https://github.com/stm32duino/X-NUCLEO-IHM02A1 +https://github.com/stm32duino/X-NUCLEO-LED61A1 + +The datasheets of the several components are available at +http://www.st.com/content/st_com/en/products/mems-and-sensors/inemo-inertial-modules/lsm6dsl.html +http://www.st.com/content/st_com/en/products/imaging-and-photonics-solutions/proximity-sensors/vl6180x.html +http://www.st.com/content/st_com/en/products/imaging-and-photonics-solutions/proximity-sensors/vl53l0x.html +http://www.st.com/content/st_com/en/products/wireless-connectivity/bluetooth-bluetooth-low-energy/spbtle-rf.html +http://www.st.com/content/st_com/en/products/motor-drivers/stepper-motor-drivers/l6470.html +http://www.st.com/content/st_com/en/products/power-management/led-drivers/boost-current-regulators-for-led/led6001.html + + + + + diff --git a/examples/GestureDirSwipeLed_53L0A1_LED61A1/GestureDirSwipeLed_53L0A1_LED61A1.ino b/examples/GestureDirSwipeLed_53L0A1_LED61A1/GestureDirSwipeLed_53L0A1_LED61A1.ino new file mode 100644 index 0000000..d54a696 --- /dev/null +++ b/examples/GestureDirSwipeLed_53L0A1_LED61A1/GestureDirSwipeLed_53L0A1_LED61A1.ino @@ -0,0 +1,554 @@ +/** + ****************************************************************************** + * @file GestureDirSwipeLed_53L0A1_LED61A1.ino + * @author STMicroelectronics + * @version V1.0.0 + * @date 27 November 2017 + * @brief Arduino test application based on X-NUCLEO-53L0A1 proximity sensor + * expansion board and X-NUCLEO-LED61A1 expansion board. + * This application makes use of C++ classes obtained from the C + * components' drivers. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Components. +STMPE1600DigiOut *xshutdown_top; +STMPE1600DigiOut *xshutdown_left; +STMPE1600DigiOut *xshutdown_right; +VL53L0X_X_NUCLEO_53L0A1 *sensor_vl53l0x_top; +VL53L0X_X_NUCLEO_53L0A1 *sensor_vl53l0x_left; +VL53L0X_X_NUCLEO_53L0A1 *sensor_vl53l0x_right; +// I2C dev. +#define DEV_I2C Wire +#define SerialPort Serial +// Gesture structure. +Gesture_DIRSWIPE_1_Data_t gestureDirSwipeData; + +// Range values +uint32_t distance_top, distance_left, distance_right; + +/* LED Control Component. */ +Led6001 *led; + +/* LED dimming */ +float dimming = 0.0f; + +/* Interrupt flags. */ +static volatile bool xfault_irq_triggered = false; +bool verbose = false; + +int current_channel = 0; +int intensity = 0; +int current_state = 0; +int timestamp_start = -1; + +void switchOffLed(); +void switchOnLed(); +int check_onoff(int r_top, int r_left, int r_right); +void changeColor(); +void changeColor(); + +/** + * Setup all sensors for single shot mode + */ +void SetupSingleShot(void) { + int status; + uint8_t VhvSettings; + uint8_t PhaseCal; + uint32_t refSpadCount; + uint8_t isApertureSpads; + + status = sensor_vl53l0x_top->StaticInit(); + if( status ) { + if(verbose) { + SerialPort.println("StaticInit top sensor failed"); + } + } + + status = sensor_vl53l0x_top->PerformRefCalibration(&VhvSettings, &PhaseCal); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefCalibration top sensor failed"); + } + } + + status = sensor_vl53l0x_top->PerformRefSpadManagement(&refSpadCount, &isApertureSpads); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefSpadManagement top sensor failed"); + } + } + + status = sensor_vl53l0x_top->SetDeviceMode(VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode + if( status ) { + if(verbose) { + SerialPort.println("SetDeviceMode top sensor failed"); + } + } + + status = sensor_vl53l0x_top->SetMeasurementTimingBudgetMicroSeconds(20*1000); + if( status ) { + if(verbose) { + SerialPort.println("SetMeasurementTimingBudgetMicroSeconds top sensor failed"); + } + } + + status = sensor_vl53l0x_left->StaticInit(); + if( status ) { + if(verbose) { + SerialPort.println("StaticInit left sensor failed"); + } + } + + status = sensor_vl53l0x_left->PerformRefCalibration(&VhvSettings, &PhaseCal); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefCalibration left sensor failed"); + } + } + + status = sensor_vl53l0x_left->PerformRefSpadManagement(&refSpadCount, &isApertureSpads); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefSpadManagement left sensor failed"); + } + } + + status = sensor_vl53l0x_left->SetDeviceMode(VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode + if( status ) { + if(verbose) { + SerialPort.println("SetDeviceMode left sensor failed"); + } + } + + status = sensor_vl53l0x_left->SetMeasurementTimingBudgetMicroSeconds(20*1000); + if( status ) { + if(verbose) { + SerialPort.println("SetMeasurementTimingBudgetMicroSeconds left sensor failed"); + } + } + + status = sensor_vl53l0x_right->StaticInit(); + if( status ) { + if(verbose) { + SerialPort.println("StaticInit right sensor failed"); + } + } + + status = sensor_vl53l0x_right->PerformRefCalibration(&VhvSettings, &PhaseCal); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefCalibration right sensor failed"); + } + } + + status = sensor_vl53l0x_right->PerformRefSpadManagement(&refSpadCount, &isApertureSpads); + if( status ) { + if(verbose) { + SerialPort.println("PerformRefSpadManagement right sensor failed"); + } + } + + status = sensor_vl53l0x_right->SetDeviceMode(VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode + if( status ) { + if(verbose) { + SerialPort.println("SetDeviceMode right sensor failed"); + } + } + + status = sensor_vl53l0x_right->SetMeasurementTimingBudgetMicroSeconds(20*1000); + if( status ) { + if(verbose) { + SerialPort.println("SetMeasurementTimingBudgetMicroSeconds right sensor failed"); + } + } +} + +/** + * @brief Interrupt Request for the component's XFAULT interrupt. + * @param None. + * @retval None. + */ +void xfault_irq(void) { + xfault_irq_triggered = true; +} + +/** + * @brief Interrupt Handler for the component's XFAULT interrupt. + * @param None. + * @retval None. + */ +void xfault_handler(void) { + /* Printing to the console. */ + if(verbose) { + SerialPort.print("XFAULT Interrupt detected! Re-initializing LED driver..."); + } + + /* Re-starting-up LED Control Component. */ + led->start_up(); + + /* Printing to the console. */ + if(verbose) { + SerialPort.println("Done."); + } +} + + +/* Setup ---------------------------------------------------------------------*/ + +void setup() { + int status; + + // Initialize serial for output. + if(verbose) { + SerialPort.begin(115200); + } + + // Initialize I2C bus. + DEV_I2C.begin(); + DEV_I2C.setClock(400000); + + /* Initializing LED Control Component. */ + led = new Led6001(D4, A3, D6, D5); + if (led->init() != COMPONENT_OK) { + if(verbose) { + SerialPort.println("Led init failed..."); + } + exit(EXIT_FAILURE); + } + + /* Attaching interrupt request functions. */ + led->attach_xfault_irq(&xfault_irq); + + switchOffLed(); + + // Create VL53L0X top component. + xshutdown_top = new STMPE1600DigiOut(&DEV_I2C, GPIO_15, (0x42 * 2)); + sensor_vl53l0x_top = new VL53L0X_X_NUCLEO_53L0A1(&DEV_I2C, xshutdown_top, A2); + + // Switch off VL53L0X top component. + sensor_vl53l0x_top->VL53L0X_Off(); + + // Create VL53L0X left component. + xshutdown_left = new STMPE1600DigiOut(&DEV_I2C, GPIO_14, (0x43 * 2)); + sensor_vl53l0x_left = new VL53L0X_X_NUCLEO_53L0A1(&DEV_I2C, xshutdown_left, D8); + + // Switch off VL53L0X left component. + sensor_vl53l0x_left->VL53L0X_Off(); + + // Create VL53L0X right component. + xshutdown_right = new STMPE1600DigiOut(&DEV_I2C, GPIO_15, (0x43 * 2)); + sensor_vl53l0x_right = new VL53L0X_X_NUCLEO_53L0A1(&DEV_I2C, xshutdown_right, D2); + + // Switch off VL53L0X right component. + sensor_vl53l0x_right->VL53L0X_Off(); + + // Initialize VL53L0X top component. + status = sensor_vl53l0x_top->InitSensor(0x10); + if(status) { + if(verbose) { + SerialPort.println("Init sensor_vl53l0x_top failed..."); + } + } + + // Initialize VL53L0X left component. + status = sensor_vl53l0x_left->InitSensor(0x12); + if(status) { + if(verbose) { + SerialPort.println("Init sensor_vl53l0x_left failed..."); + } + } + + // Initialize VL53L0X right component. + status = sensor_vl53l0x_right->InitSensor(0x14); + if(status) { + if(verbose) { + SerialPort.println("Init sensor_vl53l0x_right failed..."); + } + } + + // Initialize VL6180X gesture library. + tof_gestures_initDIRSWIPE_1(190, 0, 2000, &gestureDirSwipeData); + + SetupSingleShot(); +} + + +/* Loop ----------------------------------------------------------------------*/ + +void loop() { + int gesture_code; + // Read Range. + + sensor_vl53l0x_top->StartMeasurement(); + sensor_vl53l0x_left->StartMeasurement(); + sensor_vl53l0x_right->StartMeasurement(); + + int top_done = 0; + int left_done = 0; + int right_done = 0; + uint8_t NewDataReady=0; + VL53L0X_RangingMeasurementData_t pRangingMeasurementData; + + if (xfault_irq_triggered) { + xfault_irq_triggered = false; + xfault_handler(); + } + + do { + if(top_done == 0) { + NewDataReady = 0; + int status = sensor_vl53l0x_top->GetMeasurementDataReady(&NewDataReady); + + if( status ) { + if(verbose) { + SerialPort.println("GetMeasurementDataReady top sensor failed"); + } + } + + if(NewDataReady) { + status = sensor_vl53l0x_top->ClearInterruptMask(0); + if( status ) { + if(verbose) { + SerialPort.println("ClearInterruptMask top sensor failed"); + } + } + + status = sensor_vl53l0x_top->GetRangingMeasurementData(&pRangingMeasurementData); + if( status ) { + if(verbose) { + SerialPort.println("GetRangingMeasurementData top sensor failed"); + } + } + + if (pRangingMeasurementData.RangeStatus == 0) { + // we have a valid range. + distance_top = pRangingMeasurementData.RangeMilliMeter; + }else { + distance_top = 1200; + } + + top_done = 1; + } + } + + if(left_done == 0) { + NewDataReady = 0; + int status = sensor_vl53l0x_left->GetMeasurementDataReady(&NewDataReady); + + if( status ) { + if(verbose) { + SerialPort.println("GetMeasurementDataReady left sensor failed"); + } + } + + if(NewDataReady) { + status = sensor_vl53l0x_left->ClearInterruptMask(0); + if( status ) { + if(verbose) { + SerialPort.println("ClearInterruptMask left sensor failed"); + } + } + + status = sensor_vl53l0x_left->GetRangingMeasurementData(&pRangingMeasurementData); + if( status ) { + if(verbose) { + SerialPort.println("GetRangingMeasurementData left sensor failed"); + } + } + + if (pRangingMeasurementData.RangeStatus == 0) { + // we have a valid range. + distance_left = pRangingMeasurementData.RangeMilliMeter; + }else { + distance_left = 1200; + } + + left_done = 1; + } + } + + if(right_done == 0) { + NewDataReady = 0; + int status = sensor_vl53l0x_right->GetMeasurementDataReady(&NewDataReady); + + if( status ) { + if(verbose) { + SerialPort.println("GetMeasurementDataReady right sensor failed"); + } + } + + if(NewDataReady) { + status = sensor_vl53l0x_right->ClearInterruptMask(0); + if( status ) { + if(verbose) { + SerialPort.println("ClearInterruptMask right sensor failed"); + } + } + + status = sensor_vl53l0x_right->GetRangingMeasurementData(&pRangingMeasurementData); + if( status ) { + if(verbose) { + SerialPort.println("GetRangingMeasurementData right sensor failed"); + } + } + + if (pRangingMeasurementData.RangeStatus == 0) { + // we have a valid range. + distance_right = pRangingMeasurementData.RangeMilliMeter; + }else { + distance_right = 1200; + } + + right_done = 1; + } + } + } while(top_done == 0 || left_done == 0 || right_done == 0); + + if(check_onoff(distance_top, distance_left, distance_right) == 1) { + if(current_state == 1) { + switchOffLed(); + current_state = 0; + }else { + switchOnLed(); + current_state = 1; + delay(1000); + } + } + + // Launch gesture detection algorithm. + gesture_code = tof_gestures_detectDIRSWIPE_1(distance_left, distance_right, &gestureDirSwipeData); + + // Check the result of the gesture detection algorithm. + switch(gesture_code) { + case GESTURES_SWIPE_LEFT_RIGHT: + if(verbose) { + SerialPort.println("From Left To Right"); + } + + if(current_state == 1) { + increaseIntensity(); + } + break; + case GESTURES_SWIPE_RIGHT_LEFT: + if(verbose) { + SerialPort.println("From Right To Left"); + } + + if(current_state == 1) { + decreaseIntensity(); + } + break; + default: + // Do nothing + break; + } +} + +void increaseIntensity() { + dimming = dimming + 0.2f; + if(dimming > 1.0f) { + dimming = 1.0f; + } + + if(verbose) { + SerialPort.print("increaseIntensity -> set_pwm_dimming: "); + SerialPort.println(dimming); + } + + led->set_pwm_dimming(dimming); +} + +void decreaseIntensity() { + dimming = dimming - 0.2f; + if(dimming < 0.2f) { + dimming = 0.2f; + } + + if(verbose) { + SerialPort.print("decreaseIntensity -> set_pwm_dimming: "); + SerialPort.println(dimming); + } + + led->set_pwm_dimming(dimming); +} + +void switchOffLed() { + led->power_off(); +} + +void switchOnLed() { + dimming = 0.2f; /* default dimming value */ + led->power_on(); + led->set_pwm_dimming(dimming); +} + +int check_onoff(int r_top, int r_left, int r_right) { + int ret_val = 0; + + if(r_top < 190 && r_left < 190 && r_right < 190) { + if(timestamp_start != -1) { + int timestamp_final = millis(); + + if((timestamp_final - timestamp_start) > 3000) { + ret_val = 1; + timestamp_start = -1; + } + }else { + timestamp_start = millis(); + } + }else { + timestamp_start = -1; + } + + if(ret_val) { + if(verbose) { + SerialPort.println("ON/OFF"); + } + } + + return ret_val; +} + diff --git a/examples/MemsMotorControl_IKS01A2_IHM02A1/MemsMotorControl_IKS01A2_IHM02A1.ino b/examples/MemsMotorControl_IKS01A2_IHM02A1/MemsMotorControl_IKS01A2_IHM02A1.ino new file mode 100644 index 0000000..b0e4464 --- /dev/null +++ b/examples/MemsMotorControl_IKS01A2_IHM02A1/MemsMotorControl_IKS01A2_IHM02A1.ino @@ -0,0 +1,224 @@ +/* + ****************************************************************************** + * @file MemsMotorControl_IKS01A2_IHM02A1.ino + * @author STMicroelectronics + * @version V1.0.0 + * @date 27 November 2017 + * @brief Arduino vertical application using the STMicroelectronics + * X-NUCLEO-IKS01A2 MEMS Inertial and Environmental Sensors Expansion + * Board and the X-NUCLEO-IHM02A1 Motor Control Expansion Board to get + * a MEMS-based motor control (direction and speed). + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ + +/* mbed specific header files. */ +#include "Arduino.h" +#include "SPI.h" +#include "Wire.h" + +/* Components and expansion boards specific header files. */ +#include "LSM6DSLSensor.h" +#include "XNucleoIHM02A1.h" + + +/* Definitions ---------------------------------------------------------------*/ + +/* Preferred acceleration axis. */ +#define ACCELERATION_AXIS 1 + +/* Absolute value of the threshold on the preferred axis' acceleration. */ +#define ACCELERATION_TH 50 + +/* Rotation gain. */ +#define ROTATION_SPEED_GAIN 1 + + +/* Variables -----------------------------------------------------------------*/ + +/* Accelerometer-Gyroscope Component. */ +#define DEV_I2C Wire +#define SerialPort Serial +LSM6DSLSensor *acc_gyr; + +/* Motor Control Expansion Board. */ +SPIClass *dev_spi; +XNucleoIHM02A1 *x_nucleo_ihm02a1; +L6470 **motors; + +/* Initialization parameters of the motors connected to the expansion board. */ +L6470_init_t L6470_init[L6470DAISYCHAINSIZE] = { + /* First Motor. */ + { + 9.0, /* Motor supply voltage in V. */ + 400, /* Min number of steps per revolution for the motor. */ + 1.7, /* Max motor phase voltage in A. */ + 3.06, /* Max motor phase voltage in V. */ + 300.0, /* Motor initial speed [step/s]. */ + 500.0, /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */ + 500.0, /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */ + 1000.0, /* Motor maximum speed [step/s]. */ + 0.0, /* Motor minimum speed [step/s]. */ + 602.7, /* Motor full-step speed threshold [step/s]. */ + 3.06, /* Holding kval [V]. */ + 3.06, /* Constant speed kval [V]. */ + 3.06, /* Acceleration starting kval [V]. */ + 3.06, /* Deceleration starting kval [V]. */ + 61.52, /* Intersect speed for bemf compensation curve slope changing [step/s]. */ + 392.1569e-6, /* Start slope [s/step]. */ + 643.1372e-6, /* Acceleration final slope [s/step]. */ + 643.1372e-6, /* Deceleration final slope [s/step]. */ + 0, /* Thermal compensation factor (range [0, 15]). */ + 3.06 * 1000 * 1.10, /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */ + 3.06 * 1000 * 1.00, /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */ + StepperMotor::STEP_MODE_1_128, /* Step mode selection. */ + 0xFF, /* Alarm conditions enable. */ + 0x2E88 /* Ic configuration. */ + }, + + /* Second Motor. */ + { + 9.0, /* Motor supply voltage in V. */ + 400, /* Min number of steps per revolution for the motor. */ + 1.7, /* Max motor phase voltage in A. */ + 3.06, /* Max motor phase voltage in V. */ + 300.0, /* Motor initial speed [step/s]. */ + 500.0, /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */ + 500.0, /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */ + 1000.0, /* Motor maximum speed [step/s]. */ + 0.0, /* Motor minimum speed [step/s]. */ + 602.7, /* Motor full-step speed threshold [step/s]. */ + 3.06, /* Holding kval [V]. */ + 3.06, /* Constant speed kval [V]. */ + 3.06, /* Acceleration starting kval [V]. */ + 3.06, /* Deceleration starting kval [V]. */ + 61.52, /* Intersect speed for bemf compensation curve slope changing [step/s]. */ + 392.1569e-6, /* Start slope [s/step]. */ + 643.1372e-6, /* Acceleration final slope [s/step]. */ + 643.1372e-6, /* Deceleration final slope [s/step]. */ + 0, /* Thermal compensation factor (range [0, 15]). */ + 3.06 * 1000 * 1.10, /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */ + 3.06 * 1000 * 1.00, /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */ + StepperMotor::STEP_MODE_1_128, /* Step mode selection. */ + 0xFF, /* Alarm conditions enable. */ + 0x2E88 /* Ic configuration. */ + } +}; + +/* Defaults. */ +int status; +int speed; + + +/* Functions -----------------------------------------------------------------*/ + +/** + * @brief Initialization. + * @param None. + * @retval None. + */ +void setup() { + /* Printing to the console. */ + SerialPort.begin(115200); + SerialPort.print("Motor Control with MEMS\r\n\n"); + + /* Aliveness. */ + pinMode(D13, OUTPUT); + + // Initialize I2C bus. + DEV_I2C.begin(); + + /* Initializing Accelerometer-Gyroscope component. */ + acc_gyr = new LSM6DSLSensor(&DEV_I2C); + acc_gyr->Enable_X(); + + /* Initializing SPI bus. */ + dev_spi = new SPIClass(D11, D12, D3); + + /* Initializing Motor Control Expansion Board. */ + x_nucleo_ihm02a1 = new XNucleoIHM02A1(&L6470_init[0], &L6470_init[1], A4, A5, D4, A2, dev_spi); + + /* Building a list of motor control components. */ + motors = x_nucleo_ihm02a1->get_components(); + + /* Set defaults. */ + status = 0; + speed = 0; +} + +/** + * @brief Main loop. + * @param None. + * @retval None. + */ +void loop() { + /* Aliveness. */ + digitalWrite(D13, HIGH); + delay(250); + digitalWrite(D13, LOW); + delay(250); + + /* Main Loop. */ + while(true) { + /* Reading Accelerometer. */ + int32_t accelerometer_data[3]; + acc_gyr->Get_X_Axes(accelerometer_data); + + /* Motor Control. */ + int module = abs(accelerometer_data[ACCELERATION_AXIS]); + if (module > ACCELERATION_TH) { + int sign = accelerometer_data[ACCELERATION_AXIS] < 0 ? -1 : 1; + speed = module * ROTATION_SPEED_GAIN; + + /* Requesting to run. */ + motors[0]->run(sign == -1 ? StepperMotor::BWD : StepperMotor::FWD, speed); + status = sign; + + /* Printing to the console. */ + SerialPort.print("Speed: "); + SerialPort.print(sign == -1 ? '-' : '+'); + SerialPort.print(motors[0]->get_speed()); + SerialPort.print("\r\n"); + } else if (status != 0) { + /* Requesting to stop. */ + motors[0]->soft_stop(); + status = 0; + speed = 0; + + /* Printing to the console. */ + SerialPort.print("Stop.\r\n"); + } + + /* Waiting. */ + delay(50); + } +} diff --git a/examples/NucleoCar/NucleoCar.ino b/examples/NucleoCar/NucleoCar.ino new file mode 100644 index 0000000..be959f0 --- /dev/null +++ b/examples/NucleoCar/NucleoCar.ino @@ -0,0 +1,875 @@ +/** + ****************************************************************************** + * @file NucleoCar.ino + * @author STMicroelectronics + * @version V1.2.0 + * @date 27 November 2017 + * @brief Arduino demo application for the STMicrolectronics + * X-NUCLEO-IHM02A1, X-NUCLEO-6180XA1 and X-NUCLEO-IDB0XA1 + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEV_I2C Wire +#define SerialPort Serial + +/* ---------------- */ +/* X-NUCLEO-IHM02A1 */ +/* ---------------- */ + +#include + +/* ---------------- */ +/* X-NUCLEO-6180XA1 */ +/* ---------------- */ + +#include +#include + +STMPE1600DigiOut *gpio0_top; +STMPE1600DigiOut *gpio0_left; +STMPE1600DigiOut *gpio0_right; +VL6180X_X_NUCLEO_6180XA1 *sensor_vl6180x_top; +VL6180X_X_NUCLEO_6180XA1 *sensor_vl6180x_left; +VL6180X_X_NUCLEO_6180XA1 *sensor_vl6180x_right; + +/* ---------------- */ +/* X-NUCLEO-IDB0XA1 */ +/* ---------------- */ + +#include "hal_types.h" +#include "bluenrg_gatt_server.h" +#include "bluenrg_gap.h" +#include "string.h" +#include "bluenrg_gap_aci.h" +#include "bluenrg_gatt_aci.h" +#include "hci_const.h" +#include "gp_timer.h" +#include "bluenrg_hal_aci.h" +#include "bluenrg_aci_const.h" +#include "hci.h" +#include "hci_le.h" +#include "hal.h" +#include "sm.h" +#include "debug.h" +#include +#include +#include "bluenrg_hal_aci.h" +#include "hci.h" +#include "hci_le.h" +#include "bluenrg_utils.h" +#include "stm32_bluenrg_ble.h" +#include "osal.h" +#include "bluenrg_gap_aci.h" +#include "bluenrg_gatt_aci.h" +#include "gp_timer.h" +#include "Arduino.h" + +#define IDB0XA1_PIN_SPI_MOSI (11) +#define IDB0XA1_PIN_SPI_MISO (12) +#define IDB0XA1_PIN_SPI_SCK (3) + +SPIClass BTLE_SPI(IDB0XA1_PIN_SPI_MOSI, IDB0XA1_PIN_SPI_MISO, IDB0XA1_PIN_SPI_SCK); + +#define IDB0XA1_PIN_SPI_nCS (A1) +#define IDB0XA1_PIN_SPI_RESET (7) +#define IDB0XA1_PIN_SPI_IRQ (A0) + +SPBTLERFClass BTLE(&BTLE_SPI, IDB0XA1_PIN_SPI_nCS, IDB0XA1_PIN_SPI_IRQ, IDB0XA1_PIN_SPI_RESET); + +const char *name = "BlueCar"; // Max 7 chars otherwise error +uint8_t SERVER_BDADDR[] = {0xab, 0xb0, 0x01, 0xE1, 0x80, 0x02}; + +typedef enum +{ + CSTS_DISCONNECTED, + CSTS_CONNECTED, + CSTS_DISCONNECTED_BY_USER +}Connection_status_t; + +/* Public variables ----------------------------------------------------------*/ +extern uint8_t bnrg_expansion_board; + +/* Private macros ------------------------------------------------------------*/ +#define COPY_UUID_128(uuid_struct, uuid_15, uuid_14, uuid_13, uuid_12, uuid_11, uuid_10, uuid_9, uuid_8, uuid_7, uuid_6, uuid_5, uuid_4, uuid_3, uuid_2, uuid_1, uuid_0) \ + do {\ + uuid_struct.uuid128[0] = uuid_0; uuid_struct.uuid128[1] = uuid_1; uuid_struct.uuid128[2] = uuid_2; uuid_struct.uuid128[3] = uuid_3; \ + uuid_struct.uuid128[4] = uuid_4; uuid_struct.uuid128[5] = uuid_5; uuid_struct.uuid128[6] = uuid_6; uuid_struct.uuid128[7] = uuid_7; \ + uuid_struct.uuid128[8] = uuid_8; uuid_struct.uuid128[9] = uuid_9; uuid_struct.uuid128[10] = uuid_10; uuid_struct.uuid128[11] = uuid_11; \ + uuid_struct.uuid128[12] = uuid_12; uuid_struct.uuid128[13] = uuid_13; uuid_struct.uuid128[14] = uuid_14; uuid_struct.uuid128[15] = uuid_15; \ + }while(0) + +/* Private Prototypes --------------------------------------------------------*/ +void NucleoCar_HCI_Event_CB(void *pckt); + +class NucleoCarServiceClass +{ + public: + NucleoCarServiceClass(void) + { + BTLEArrivedDataLength = 0; + DEVICE_CONNECTION_STATUS = CSTS_DISCONNECTED; + DEVICE_CONNECTION_AUTHORIZED = FALSE; + connection_handle = 0; + connected = FALSE; + set_connectable = TRUE; + } + + tBleStatus begin(const char *name, uint8_t addr[BDADDR_SIZE]) { + uint8_t bdaddr[BDADDR_SIZE]; + uint16_t service_handle, dev_name_char_handle, appearance_char_handle; + + uint8_t hwVersion; + uint16_t fwVersion; + + int ret; + + if((name == NULL) || (addr == NULL)) { + return BLE_STATUS_NULL_PARAM; + } + + attach_HCI_CB(NucleoCar_HCI_Event_CB); + + /* get the BlueNRG HW and FW versions */ + ret = getBlueNRGVersion(&hwVersion, &fwVersion); + if(ret) { + PRINTF("Reading Version failed.\n"); + return ret; + } + + /* + * Reset BlueNRG again otherwise we won't + * be able to change its MAC address. + * aci_hal_write_config_data() must be the first + * command after reset otherwise it will fail. + */ + BlueNRG_RST(); + + if (hwVersion > 0x30) { /* X-NUCLEO-IDB05A1 expansion board is used */ + bnrg_expansion_board = IDB05A1; + /* + * Change the MAC address to avoid issues with Android cache: + * if different boards have the same MAC address, Android + * applications unless you restart Bluetooth on tablet/phone + */ + addr[5] = 0x02; + } + + /* The Nucleo board must be configured as SERVER */ + Osal_MemCpy(bdaddr, addr, BDADDR_SIZE); + + ret = aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, + CONFIG_DATA_PUBADDR_LEN, + bdaddr); + if(ret){ + PRINTF("Setting BD_ADDR failed.\n"); + return ret; + } + + ret = aci_gatt_init(); + if(ret){ + PRINTF("GATT_Init failed.\n"); + return ret; + } + + if (bnrg_expansion_board == IDB05A1) { + ret = aci_gap_init_IDB05A1(GAP_PERIPHERAL_ROLE_IDB05A1, 0, 0x07, &service_handle, &dev_name_char_handle, &appearance_char_handle); + } + else { + ret = aci_gap_init_IDB04A1(GAP_PERIPHERAL_ROLE_IDB04A1, &service_handle, &dev_name_char_handle, &appearance_char_handle); + } + + if(ret){ + PRINTF("GAP_Init failed.\n"); + return ret; + } + + ret = aci_gatt_update_char_value(service_handle, dev_name_char_handle, 0, + strlen(name), (uint8_t *)name); + + if(ret){ + PRINTF("aci_gatt_update_char_value failed.\n"); + return ret; + } + + ret = aci_gap_set_auth_requirement(MITM_PROTECTION_REQUIRED, + OOB_AUTH_DATA_ABSENT, + NULL, + 7, + 16, + USE_FIXED_PIN_FOR_PAIRING, + 123456, + BONDING); + if (ret) { + PRINTF("BLE Stack Initialization failed.\n"); + return ret; + } + + /* Set output power level */ + ret = aci_hal_set_tx_power_level(1,4); + + if (ret) { + PRINTF("Setting Tx Power Level failed.\n"); + } + + return ret; + } + + void setConnectable(void) { + tBleStatus ret; + + const char local_name[] = {AD_TYPE_COMPLETE_LOCAL_NAME,'B','l','u','e','C','a','r'}; + + if(set_connectable){ + /* disable scan response */ + hci_le_set_scan_resp_data(0,NULL); + PRINTF("General Discoverable Mode.\n"); + + ret = aci_gap_set_discoverable(ADV_IND, 0, 0, PUBLIC_ADDR, NO_WHITE_LIST_USE, + sizeof(local_name), local_name, 0, NULL, 0, 0); + if (ret != BLE_STATUS_SUCCESS) { + PRINTF("Error while setting discoverable mode (%d)\n", ret); + } + set_connectable = FALSE; + } + } + + int isConnected(void) { + return connected; + } + + tBleStatus Add_Car_Service(void) { + tBleStatus ret; + + /* + UUIDs: + D973F2E0-B19E-11E2-9E96-0800200C9A66 (service) + D973F2E1-B19E-11E2-9E96-0800200C9A66 (tx charac) + D973F2E2-B19E-11E2-9E96-0800200C9A66 (rx charac) + */ + + const uint8_t service_uuid[16] = {0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe0,0xf2,0x73,0xd9}; + const uint8_t charUuidTX[16] = {0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe1,0xf2,0x73,0xd9}; + const uint8_t charUuidRX[16] = {0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe2,0xf2,0x73,0xd9}; + + ret = aci_gatt_add_serv(UUID_TYPE_128, service_uuid, PRIMARY_SERVICE, 7, &sampleServHandle); /* original is 9?? */ + if (ret != BLE_STATUS_SUCCESS) goto fail; + + ret = aci_gatt_add_char(sampleServHandle, UUID_TYPE_128, charUuidTX, 20, CHAR_PROP_NOTIFY, ATTR_PERMISSION_NONE, 0, + 16, 1, &TXCharHandle); + if (ret != BLE_STATUS_SUCCESS) goto fail; + + ret = aci_gatt_add_char(sampleServHandle, UUID_TYPE_128, charUuidRX, 20, CHAR_PROP_WRITE|CHAR_PROP_WRITE_WITHOUT_RESP, ATTR_PERMISSION_NONE, GATT_NOTIFY_ATTRIBUTE_WRITE, + 16, 1, &RXCharHandle); + if (ret != BLE_STATUS_SUCCESS) goto fail; + + // Sample Service added + return BLE_STATUS_SUCCESS; + + fail: + // Error while adding Sample Service + return BLE_STATUS_ERROR; + } + + void GAP_ConnectionComplete_CB(uint8_t addr[BDADDR_SIZE], uint16_t handle) { + connected = TRUE; + connection_handle = handle; + + /* + PRINTF("Connected to device:"); + for(int i = 5; i > 0; i--){ + PRINTF("%02X-", addr[i]); + } + PRINTF("%02X\n", addr[0]); + */ + } + + void GAP_DisconnectionComplete_CB(void) { + /* Disconnected */ + connected = FALSE; + PRINTF("Disconnected\n"); + /* Make the device connectable again */ + set_connectable = TRUE; + DEVICE_CONNECTION_AUTHORIZED = FALSE; + DEVICE_CONNECTION_STATUS = CSTS_DISCONNECTED_BY_USER; + } + + void Attribute_Modified_CB(uint16_t handle, uint8_t data_length, uint8_t *att_data) { + if (handle == RXCharHandle + 1) { + receiveData(att_data, data_length); + } + } + + uint16_t charUuidTX_Handle, charUuidRX_Handle; + + uint8_t BLE_Rx_buffer[260]; + uint16_t BTLEArrivedDataLength; + Connection_status_t DEVICE_CONNECTION_STATUS; + + private: + void receiveData(uint8_t* data_buffer, uint8_t Nb_bytes) { + //uint16_t counter; + if (BTLEArrivedDataLength == 0) { + for (BTLEArrivedDataLength = 0; BTLEArrivedDataLength < Nb_bytes; BTLEArrivedDataLength++) + BLE_Rx_buffer[BTLEArrivedDataLength] = data_buffer[BTLEArrivedDataLength]; + if (!DEVICE_CONNECTION_AUTHORIZED) { + if (BLE_CheckAuthorization(BLE_Rx_buffer)) { + DEVICE_CONNECTION_AUTHORIZED = TRUE; + DEVICE_CONNECTION_STATUS = CSTS_CONNECTED; + } + BTLEArrivedDataLength = 0; + } + } + } + + uint8_t BLE_CheckAuthorization(uint8_t* buffer) { + // Authorization string [TD&E-BTE-bCAR] + if (BTLEArrivedDataLength != 13) return FALSE; + if (buffer[0] != 'T') return FALSE; + if (buffer[1] != 'D') return FALSE; + if (buffer[2] != '&') return FALSE; + if (buffer[3] != 'E') return FALSE; + if (buffer[4] != '-') return FALSE; + if (buffer[5] != 'B') return FALSE; + if (buffer[6] != 'T') return FALSE; + if (buffer[7] != 'E') return FALSE; + if (buffer[8] != '-') return FALSE; + if (buffer[9] != 'b') return FALSE; + if (buffer[10] != 'C') return FALSE; + if (buffer[11] != 'A') return FALSE; + if (buffer[12] != 'R') return FALSE; + + return TRUE; + } + + volatile uint16_t connection_handle; + + volatile bool connected; + volatile bool set_connectable; + + uint16_t sampleServHandle; + uint16_t TXCharHandle; + uint16_t RXCharHandle; + + uint8_t DEVICE_CONNECTION_AUTHORIZED; +}; + +NucleoCarServiceClass NucleoCarService; + +/** + * @brief Callback processing the ACI events. + * @note Inside this function each event must be identified and correctly + * parsed. + * @param void* Pointer to the ACI packet + * @retval None + */ +void NucleoCar_HCI_Event_CB(void *pckt) +{ + hci_uart_pckt *hci_pckt = (hci_uart_pckt *)pckt; + /* obtain event packet */ + hci_event_pckt *event_pckt = (hci_event_pckt*)hci_pckt->data; + + if(hci_pckt->type != HCI_EVENT_PKT) + return; + + switch(event_pckt->evt){ + + case EVT_DISCONN_COMPLETE: + { + NucleoCarService.GAP_DisconnectionComplete_CB(); + } + break; + + case EVT_LE_META_EVENT: + { + evt_le_meta_event *evt = (evt_le_meta_event *)event_pckt->data; + + switch(evt->subevent){ + case EVT_LE_CONN_COMPLETE: + { + evt_le_connection_complete *cc = (evt_le_connection_complete *)evt->data; + NucleoCarService.GAP_ConnectionComplete_CB(cc->peer_bdaddr, cc->handle); + } + break; + } + } + break; + + case EVT_VENDOR: + { + evt_blue_aci *blue_evt = (evt_blue_aci *)event_pckt->data; + switch(blue_evt->ecode){ + + case EVT_BLUE_GATT_ATTRIBUTE_MODIFIED: + { + /* this callback is invoked when a GATT attribute is modified + extract callback data and pass to suitable handler function */ + if (bnrg_expansion_board == IDB05A1) { + evt_gatt_attr_modified_IDB05A1 *evt = (evt_gatt_attr_modified_IDB05A1*)blue_evt->data; + NucleoCarService.Attribute_Modified_CB(evt->attr_handle, evt->data_length, evt->att_data); + } + else { + evt_gatt_attr_modified_IDB04A1 *evt = (evt_gatt_attr_modified_IDB04A1*)blue_evt->data; + NucleoCarService.Attribute_Modified_CB(evt->attr_handle, evt->data_length, evt->att_data); + } + } + break; + } + } + break; + } +} + + +/* Definitions ---------------------------------------------------------------*/ + + +/* Variables -----------------------------------------------------------------*/ + +int32_t speed_proxy = 0; +int32_t direction_proxy = 0; + +uint8_t speed = 50; +uint8_t direction = 50; + +int8_t correction = 0; +uint8_t functionality = 0; // Drive by BLE or Proximity + +/* ---------------- */ +/* X-NUCLEO-6180XA1 */ +/* ---------------- */ + +uint32_t range_top; +uint32_t range_left; +uint32_t range_right; + +/* ---------------- */ +/* X-NUCLEO-IHM02A1 */ +/* ---------------- */ + +// Motor Control Expansion Board. +XNucleoIHM02A1 *x_nucleo_ihm02a1; +SPIClass *dev_spi; +L6470 **motors; + +// Initialization parameters of the motors connected to the expansion board. +L6470_init_t L6470_init[L6470DAISYCHAINSIZE] = { + + /* First Motor. */ + { + 12.0, /* Motor supply voltage in V. */ + 400, /* Min number of steps per revolution for the motor. */ + 1.7, /* Max motor phase voltage in A. */ + 3.06, /* Max motor phase voltage in V. */ + 300.0, /* Motor initial speed [step/s]. */ + 500.0, /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */ + 500.0, /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */ + 992.0, /* Motor maximum speed [step/s]. */ + 0.0, /* Motor minimum speed [step/s]. */ + 602.7, /* Motor full-step speed threshold [step/s]. */ + 3.06, /* Holding kval [V]. */ + 3.06, /* Constant speed kval [V]. */ + 3.06, /* Acceleration starting kval [V]. */ + 3.06, /* Deceleration starting kval [V]. */ + 61.52, /* Intersect speed for bemf compensation curve slope changing [step/s]. */ + 392.1569e-6, /* Start slope [s/step]. */ + 643.1372e-6, /* Acceleration final slope [s/step]. */ + 643.1372e-6, /* Deceleration final slope [s/step]. */ + 0, /* Thermal compensation factor (range [0, 15]). */ + 3.06 * 1000 * 1.10, /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */ + 3.06 * 1000 * 1.00, /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */ + StepperMotor::STEP_MODE_1_128, /* Step mode selection. */ + 0xFF, /* Alarm conditions enable. */ + 0x2E88 /* Ic configuration. */ + }, + + /* Second Motor. */ + { + 12.0, /* Motor supply voltage in V. */ + 400, /* Min number of steps per revolution for the motor. */ + 1.7, /* Max motor phase voltage in A. */ + 3.06, /* Max motor phase voltage in V. */ + 300.0, /* Motor initial speed [step/s]. */ + 500.0, /* Motor acceleration [step/s^2] (comment for infinite acceleration mode). */ + 500.0, /* Motor deceleration [step/s^2] (comment for infinite deceleration mode). */ + 992.0, /* Motor maximum speed [step/s]. */ + 0.0, /* Motor minimum speed [step/s]. */ + 602.7, /* Motor full-step speed threshold [step/s]. */ + 3.06, /* Holding kval [V]. */ + 3.06, /* Constant speed kval [V]. */ + 3.06, /* Acceleration starting kval [V]. */ + 3.06, /* Deceleration starting kval [V]. */ + 61.52, /* Intersect speed for bemf compensation curve slope changing [step/s]. */ + 392.1569e-6, /* Start slope [s/step]. */ + 643.1372e-6, /* Acceleration final slope [s/step]. */ + 643.1372e-6, /* Deceleration final slope [s/step]. */ + 0, /* Thermal compensation factor (range [0, 15]). */ + 3.06 * 1000 * 1.10, /* Ocd threshold [ma] (range [375 ma, 6000 ma]). */ + 3.06 * 1000 * 1.00, /* Stall threshold [ma] (range [31.25 ma, 4000 ma]). */ + StepperMotor::STEP_MODE_1_128, /* Step mode selection. */ + 0xFF, /* Alarm conditions enable. */ + 0x2E88 /* Ic configuration. */ + } + +}; + + +/* Setup ---------------------------------------------------------------------*/ + +void setup() { + + int status; + SerialPort.begin(115200); + DEV_I2C.begin(); + + pinMode(LED_BUILTIN, OUTPUT); //D13 LED + pinMode(USER_BTN, INPUT); //D23 BUTTON + + SerialPort.println("---------------------------"); + + /* ---------------- */ + /* X-NUCLEO-IHM02A1 */ + /* ---------------- */ + + // Initializing SPI bus. + // dev_spi = new SPIClass(D11, D12, D3); // Use SPI1 + dev_spi = new SPIClass(D42, D43, D44); // Use SPI2 to avoid conflict with SPI1 used by BLE Board + + // Initializing Motor Control Expansion Board. + x_nucleo_ihm02a1 = new XNucleoIHM02A1(&L6470_init[0], &L6470_init[1], A4, A5, D4, A2, dev_spi); + + // Building a list of motor control components. + motors = x_nucleo_ihm02a1->get_components(); + + SerialPort.println("IHM02A1 Configuration Done!"); + + /* ---------------- */ + /* X-NUCLEO-6180XA1 */ + /* ---------------- */ + + // Create VL6180X top component. + gpio0_top = new STMPE1600DigiOut(&DEV_I2C, GPIO_12); + sensor_vl6180x_top = new VL6180X_X_NUCLEO_6180XA1(&DEV_I2C, gpio0_top, 0); + + // Switch off VL6180X top component. + sensor_vl6180x_top->VL6180x_Off(); + + // Create (if present) VL6180X left component. + gpio0_left = new STMPE1600DigiOut(&DEV_I2C, GPIO_14); + sensor_vl6180x_left = new VL6180X_X_NUCLEO_6180XA1(&DEV_I2C, gpio0_left, 0); + + // Switch off (if present) VL6180X left component. + sensor_vl6180x_left->VL6180x_Off(); + + // Create (if present) VL6180X right component. + gpio0_right = new STMPE1600DigiOut(&DEV_I2C, GPIO_15); + sensor_vl6180x_right = new VL6180X_X_NUCLEO_6180XA1(&DEV_I2C, gpio0_right, 0); + + // Switch off (if present) VL6180X right component. + sensor_vl6180x_right->VL6180x_Off(); + + // Initialize VL6180X top component. + status = sensor_vl6180x_top->InitSensor(0x10); + if(status) + { + SerialPort.println("Init sensor_vl6180x_top failed..."); + } + sensor_vl6180x_top->StartInterleavedMode(); + + // Initialize VL6180X left component. + status = sensor_vl6180x_left->InitSensor(0x11); + if(status) + { + SerialPort.println("Init sensor_vl6180x_left failed..."); + } + sensor_vl6180x_left->StartInterleavedMode(); + + // Initialize VL6180X right component. + status = sensor_vl6180x_right->InitSensor(0x12); + if(status) + { + SerialPort.println("Init sensor_vl6180x_right failed..."); + } + sensor_vl6180x_right->StartInterleavedMode(); + + SerialPort.println("6180XA1 Configuration Done!"); + + /* ---------------- */ + /* X-NUCLEO-IDB0XA1 */ + /* ---------------- */ + + int ret; + + if(BTLE.begin() == SPBTLERF_ERROR) + { + SerialPort.println("Bluetooth module configuration error!"); + while(1); + } + + if(NucleoCarService.begin(name, SERVER_BDADDR)) + { + SerialPort.println("NucleoCar service configuration error!"); + while(1); + } + + ret = NucleoCarService.Add_Car_Service(); + + if(ret == BLE_STATUS_SUCCESS) + SerialPort.println("Car service added successfully."); + else + SerialPort.println("Error while adding Car service."); + + //randomSeed(analogRead(A0)); + + SerialPort.println("IDB0XA1 Configuration Done!"); + + /* ---------------- */ + /* Wait USER Button */ + /* ---------------- */ + + // Read the state of USER_BTN pin + int buttonState = digitalRead(USER_BTN); + + SerialPort.println("Press USER Button"); + do { + buttonState = digitalRead(USER_BTN); + } while (buttonState == HIGH); + + SerialPort.println("Start - Set Wheels Home Position"); + motors[0]->set_home(); // Set Home for Turning Wheels + +} + +/* Loop ----------------------------------------------------------------------*/ + +void loop() { + + int buttonState = digitalRead(USER_BTN); + + // Check if the button is pressed + if (buttonState == LOW) { + // Wait until the button is released + do { + // Read the state of USER_BTN pin + buttonState = digitalRead(USER_BTN); + } while(buttonState == LOW); + + // Check the LED pin status + int ledState = digitalRead(LED_BUILTIN); + if(ledState == LOW) { + // If the LED is off, we switch it on + digitalWrite(LED_BUILTIN, HIGH); + functionality=1; + speed = 50; + direction = 50; + SerialPort.println("Proxy Mode"); + } else { + // If the LED is on, we switch it off + digitalWrite(LED_BUILTIN, LOW); + functionality=2; + speed = 50; + direction = 50; + SerialPort.println("BLE Mode"); + } + } + + BTLE.update(); + + if(NucleoCarService.isConnected() == TRUE) + { + + //if (NucleoCarService.DEVICE_CONNECTION_STATUS == CSTS_CONNECTED) + //{ + // SerialPort.println("BLE Connected"); + //} + + if (NucleoCarService.BTLEArrivedDataLength) + { + /* Data arrived from BLE: command decode */ + switch (NucleoCarService.BLE_Rx_buffer[0]) + { + /* Set speed and direction data command */ + case 0: + // Store last data + speed = NucleoCarService.BLE_Rx_buffer[1]; + direction = NucleoCarService.BLE_Rx_buffer[2]; + //SerialPort.print("Speed ="); + //SerialPort.println(speed); + //SerialPort.print("Direction ="); + //SerialPort.println(direction); + NucleoCarService.BTLEArrivedDataLength = 0; + break; + + default: + NucleoCarService.BTLEArrivedDataLength = 0; + break; + } + } + + } + else + { + //SerialPort.println("BLE Disconnected - Set Discovery Mode"); + + if (NucleoCarService.DEVICE_CONNECTION_STATUS == CSTS_DISCONNECTED_BY_USER) + { + NucleoCarService.BTLEArrivedDataLength = 0; + speed = 50; + direction = 50; + //SerialPort.print("Speed ="); + //SerialPort.println(speed); + //SerialPort.print("Direction ="); + //SerialPort.println(direction); + NucleoCarService.DEVICE_CONNECTION_STATUS = CSTS_DISCONNECTED; + + SerialPort.println("BLE Disconnected - Set Discovery Mode"); + } + + //Keep the Bluetooth module in discoverable mode + NucleoCarService.setConnectable(); + } + + // ----------- + + switch (functionality) + { + + case 1: // Ignore BLE e Motor controlled by Proximity Sensors + + // -------------------------------------- + // 0 / +200 = Speed value only Forward + // -200 / +200 = Direction value + // -------------------------------------- + + sensor_vl6180x_top->GetDistance(&range_top); + sensor_vl6180x_left->GetDistance(&range_left); + sensor_vl6180x_right->GetDistance(&range_right); + + // Speed by Motor1 + // --------------- + if (range_top!=255) + { + speed_proxy=200-range_top; + motors[1]->run(StepperMotor::FWD, speed_proxy*2); + } + else + { + //motors[1]->hard_stop(); // Keep wheel blocked + motors[1]->hard_hiz(); + } + + // Direction by Motor0 + // ------------------- + if (range_right!=255 || range_left!=255) + { + if (range_right>200) { range_right=200; } + if (range_left>200) { range_left=200; } + direction_proxy=((200-range_right)-(200-range_left)); + motors[0]->go_to(-direction_proxy*25); + } + else + { + motors[0]->go_home(); + } + + break; + + case 2: // Motor controlled by BLE and Proximity + + // ------------------------------------------------ + // |0 - 100| = Speed value + // 0 - 49: Backward; 50 = Stop; 51 - 100 = Forward + // |0 - 100| = Direction value + // 0 - 49: Left; 50 = Center; 51 - 100 = Right + // ------------------------------------------------ + + // Speed by Motor1 + // --------------- + + if (speed!=50) + { + if (speed>50) + { + if (range_right<75 || range_left<75) + { motors[1]->hard_stop(); } + else + { motors[1]->run(StepperMotor::FWD, (speed-50)*4); } + } + if (speed<50) { motors[1]->run(StepperMotor::BWD, (50-speed)*4); } + } + else + { + //motors[1]->hard_stop(); // Keep wheel blocked + motors[1]->hard_hiz(); + } + + // Direction by Motor0 + // ------------------- + + sensor_vl6180x_left->GetDistance(&range_left); + sensor_vl6180x_right->GetDistance(&range_right); + + if (range_right>200) { range_right=200; } + if (range_left>200) { range_left=200; } + correction=(range_right-range_left)/4; // -50 / +50 + + if (direction!=50) + { + if ((direction-50+correction)>50) + { motors[0]->go_to(50*100); } + else if ((direction-50+correction)<-50) + { motors[0]->go_to(-50*100); } + else + { motors[0]->go_to((direction-50+correction)*100); } + } + else + { + motors[0]->go_to(correction*100); + //motors[0]->go_home(); + } + + break; + + default: + break; + + } + +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..5c34ef7 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=STM32duino FP_Examples +version=1.0.0 +author=STMicroelectronics +maintainer=stm32duino +sentence=Provides several Function Packs that combine the usage of several X-NUCLEO boards +paragraph=This library provides several Function Packs that combine the usage of several X-NUCLEO boards together with a NUCLEO board +category=Other +url=https://github.com/stm32duino/FP_Examples +architectures=stm32 diff --git a/src/FP_Examples.h b/src/FP_Examples.h new file mode 100644 index 0000000..e69de29