Testsetup BMI088 (SEED), gyro ok, Acc Problem T:\T-IMS-IndNav\01_Technisches\70_Hardwareentwicklung\20190828_083342.jpg

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
altb2
Date:
Wed Aug 28 08:32:22 2019 +0000
Commit message:
First implement, ; acc does not work (it worked once!)

Changed in this revision

BMI088.cpp Show annotated file Show diff for this revision Revisions of this file
BMI088.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BMI088.cpp	Wed Aug 28 08:32:22 2019 +0000
@@ -0,0 +1,414 @@
+/*    
+ * A library for Grove - 6-Axis Accelerometer&Gyroscope(BMI088)
+ *   
+ * Copyright (c) 2018 seeed technology co., ltd.  
+ * Author      : Wayen Weng  
+ * Create Time : June 2018
+ * Change Log  : 
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "BMI088.h"
+
+BMI088::BMI088(void) : i2c(PA_10,PA_9)//L432KC
+{
+    devAddrAcc = BMI088_ACC_ADDRESS;
+    devAddrGyro = BMI088_GYRO_ADDRESS;
+    i2c.frequency(100000);
+
+}
+
+void BMI088::initialize(void)
+{
+    setAccPoweMode(ACC_ACTIVE);
+    wait_ms(150);
+//    setAccOutputDataRate(ODR_25);
+    wait_ms(50);
+    setAccScaleRange(RANGE_3G);
+    
+    setGyroScaleRange(RANGE_500);
+    setGyroOutputDataRate(ODR_200_BW_23);
+    setGyroPoweMode(GYRO_NORMAL);
+}
+
+bool BMI088::isConnection(void)
+{
+    uint8_t val1 = getGyroID();
+    uint8_t val2 = getAccID();
+    return ((val1 == 0x0F) && (val2 == 0x1E));
+}
+
+void BMI088::resetAcc(void)
+{
+    write8(ACC, BMI088_ACC_SOFT_RESET, 0xB6);
+}
+
+void BMI088::resetGyro(void)
+{
+    write8(GYRO, BMI088_GYRO_SOFT_RESET, 0xB6);
+}
+
+uint8_t BMI088::getAccID(void)
+{
+    return read8(ACC, BMI088_ACC_CHIP_ID);
+}
+
+uint8_t BMI088::getGyroID(void)
+{
+    return read8(GYRO, BMI088_GYRO_CHIP_ID);
+}
+
+void BMI088::setAccPoweMode(acc_power_type_t mode)
+{
+    if(mode == ACC_ACTIVE)
+    {
+        write8(ACC, BMI088_ACC_PWR_CTRl, 0x04);
+        write8(ACC, BMI088_ACC_PWR_CONF, 0x00);
+    }
+    else if(mode == ACC_SUSPEND)
+    {
+        write8(ACC, BMI088_ACC_PWR_CONF, 0x03);
+        write8(ACC, BMI088_ACC_PWR_CTRl, 0x00);
+    }
+}
+
+void BMI088::setGyroPoweMode(gyro_power_type_t mode)
+{
+    if(mode == GYRO_NORMAL)
+    {
+        write8(GYRO, BMI088_GYRO_LPM_1, (uint8_t)GYRO_NORMAL);
+    }
+    else if(mode == GYRO_SUSPEND)
+    {
+        write8(GYRO, BMI088_GYRO_LPM_1, (uint8_t)GYRO_SUSPEND);
+    }
+    else if(mode == GYRO_DEEP_SUSPEND)
+    {
+        write8(GYRO, BMI088_GYRO_LPM_1, (uint8_t)GYRO_DEEP_SUSPEND);
+    }
+}
+
+void BMI088::setAccScaleRange(acc_scale_type_t range)
+{
+    if(range == RANGE_3G) accRange = 3000;
+    else if(range == RANGE_6G) accRange = 6000;
+    else if(range == RANGE_12G) accRange = 12000;
+    else if(range == RANGE_24G) accRange = 24000;
+    
+    write8(ACC, BMI088_ACC_RANGE, (uint8_t)range);
+}
+
+void BMI088::setAccOutputDataRate(acc_odr_type_t odr)
+{
+    uint8_t data = 0;
+    
+    data = read8(ACC, BMI088_ACC_CONF);
+    data = data & 0xf0;     // get higher 4 bits
+    data = data | (uint8_t)odr;
+    wait_ms(10);
+    write8(ACC, BMI088_ACC_CONF, data);
+}
+
+void BMI088::setGyroScaleRange(gyro_scale_type_t range)
+{
+    if(range == RANGE_2000) gyroRange = 2000;
+    else if(range == RANGE_1000) gyroRange = 1000;
+    else if(range == RANGE_500) gyroRange = 500;
+    else if(range == RANGE_250) gyroRange = 250;
+    else if(range == RANGE_125) gyroRange = 125;
+    
+    write8(GYRO, BMI088_GYRO_RANGE, (uint8_t)range);
+}
+
+void BMI088::setGyroOutputDataRate(gyro_odr_type_t odr)
+{
+    write8(GYRO, BMI088_GYRO_BAND_WIDTH, (uint8_t)odr);
+}
+
+void BMI088::getAcceleration(float* x, float* y, float* z)
+{
+    char buf[6] = {0};
+    uint16_t ax = 0, ay = 0, az = 0;
+    int16_t value = 0;
+    
+    read(ACC, BMI088_ACC_X_LSB, buf, 6);
+
+    //printf("ACCBUFF: %02X %02X %02X %02X %02X %02X\r\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
+    ax = buf[0] | (buf[1] << 8);
+    ay = buf[2] | (buf[3] << 8);
+    az = buf[4] | (buf[5] << 8);
+    
+    value = (int16_t)ax;
+    *x = accRange * value / 32768000 * 9.81f;        // units: m/s^2
+    
+    value = (int16_t)ay;
+    *y = accRange * value / 32768000 * 9.81f;        // units: m/s^2
+    
+    value = (int16_t)az;
+    *z = accRange * value / 32768000 * 9.81f;        // units: m/s^2
+}
+
+float BMI088::getAccelerationX(void)
+{
+    uint16_t ax = 0;
+    float value = 0;
+    
+    ax = read16(ACC, BMI088_ACC_X_LSB);
+    
+    value = (int16_t)ax;
+    value = accRange * value / 32768000 * 9.81f;     // units: m/s^2
+    
+    return value;
+}
+
+float BMI088::getAccelerationY(void)
+{
+    uint16_t ay = 0;
+    float value = 0;
+    
+    ay = read16(ACC, BMI088_ACC_Y_LSB);
+    
+    value = (int16_t)ay;
+    value = accRange * value / 32768000 * 9.81f;     // units: m/s^2
+    
+    return value;
+}
+
+float BMI088::getAccelerationZ(void)
+{
+    uint16_t az = 0;
+    float value = 0;
+    
+    az = read16(ACC, BMI088_ACC_Z_LSB);
+    
+    
+    value = (int16_t)az;
+    value = accRange * value / 32768000 * 9.81f;     // units: m/s^2
+    
+    return value;
+}
+
+void BMI088::getGyroscope(float* x, float* y, float* z)
+{
+    char buf[6] = {0};
+    uint16_t gx = 0, gy = 0, gz = 0;
+    int16_t value = 0;
+    
+    read(GYRO, BMI088_GYRO_RATE_X_LSB, buf, 6);
+    
+    gx = buf[0] | (buf[1] << 8);
+    gy = buf[2] | (buf[3] << 8);
+    gz = buf[4] | (buf[5] << 8);
+    
+    value = (int16_t)gx;
+    *x = gyroRange * value / 32768 * 3.1415927f/180.0f;
+    
+    value = (int16_t)gy;
+    *y = gyroRange * value / 32768 * 3.1415927f/180.0f;
+    
+    value = (int16_t)gz;
+    *z = gyroRange * value / 32768 * 3.1415927f/180.0f;
+}
+
+float BMI088::getGyroscopeX(void)
+{
+    uint16_t gx = 0;
+    float value = 0;
+    
+    gx = read16(GYRO, BMI088_GYRO_RATE_X_LSB);
+    
+    value = (int16_t)gx;
+    value = gyroRange * value / 32768 * 3.1415927f/180.0f;
+    
+    return value;
+}
+
+float BMI088::getGyroscopeY(void)
+{
+    uint16_t gy = 0;
+    float value = 0;
+    
+    gy = read16(GYRO, BMI088_GYRO_RATE_Y_LSB);
+    
+    value = (int16_t)gy;
+    value = gyroRange * value / 32768 * 3.1415927f/180.0f;
+    
+    return value;
+}
+
+float BMI088::getGyroscopeZ(void)
+{
+    uint16_t gz = 0;
+    float value = 0;
+    
+    gz = read16(GYRO, BMI088_GYRO_RATE_Z_LSB);
+    
+    value = (int16_t)gz;
+    value = gyroRange * value / 32768 * 3.1415927f/180.0f;
+    
+    return value;
+}
+
+uint16_t BMI088::getTemperature(void)
+{
+    uint16_t data = 0;
+    
+    data = read16Be(ACC, BMI088_ACC_TEMP_MSB);
+    data = data >> 5;
+    
+    if(data > 1023) data = data - 2048;
+    
+    return (uint16_t)(data / 8 + 23);
+}
+
+void BMI088::write8(device_type_t dev, char reg, uint8_t val)
+{
+    int addr = 0;
+    
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+    
+    int succw = i2c.write(addr, &reg, val); 
+ //   printf("Write 8 succes: %d\r\n",succw);
+    
+    /*Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.write(val);
+    Wire.endTransmission();*/
+}
+
+char BMI088::read8(device_type_t dev, char reg)
+{
+    int addr =0;;
+    char data = 0;
+    
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+    
+    int succw = i2c.write(addr, &reg, 0x01); 
+    int succr = i2c.read( addr, &data, 0x01);
+    
+    /*Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.endTransmission();
+
+    Wire.requestFrom(addr, 1);
+    while(Wire.available())
+    {
+        data = Wire.read();
+    }
+    */
+    return data;
+}
+
+uint16_t BMI088::read16(device_type_t dev, char reg)
+{
+    int addr = 0;
+    char buf[2];
+    
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+
+    int succw = i2c.write(addr, &reg, 0x01); 
+    int succr = i2c.read( addr, buf, 0x02);
+
+
+    /*Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.endTransmission();
+    
+    Wire.requestFrom(addr, 2);
+    while(Wire.available())
+    {
+        lsb = Wire.read();
+        msb = Wire.read();
+    }
+*/
+    return (buf[0] | (buf[1] << 8));
+}
+
+uint16_t BMI088::read16Be(device_type_t dev, char reg)
+{
+    uint8_t addr = 0;
+    uint16_t msb = 0, lsb = 0;
+    
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+
+  /*  Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.endTransmission();
+    
+    Wire.requestFrom(addr, 2);
+    while(Wire.available())
+    {
+        msb = Wire.read();
+        lsb = Wire.read();
+    }
+*/
+    return (lsb | (msb << 8));
+}
+
+uint32_t BMI088::read24(device_type_t dev, char reg)
+{
+    int addr;
+    char data = 0;
+    
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+
+/*    Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.endTransmission();
+    
+    Wire.requestFrom(addr, 3);
+    while(Wire.available())
+    {
+        lsb = Wire.read();
+        msb = Wire.read();
+        hsb = Wire.read();
+    }
+*/
+    return 0;//(lsb | (msb << 8) | (hsb << 16));
+}
+
+void BMI088::read(device_type_t dev, char reg, char *buf, uint16_t len)
+{
+    int addr;
+        
+    if(dev) addr = devAddrGyro;
+    else addr = devAddrAcc;
+    int succw = i2c.write(addr, &reg, 0x01); 
+    int succr = i2c.read( addr, buf, len);
+    //printf("\r\nread: succes w: %d, succes r: %d, buf[1]:%d\r\n",succw,succr,buf[1]);
+  /*  
+    Wire.beginTransmission(addr);
+    Wire.write(reg);
+    Wire.endTransmission();
+    
+    Wire.requestFrom(addr, len);
+    while(Wire.available())
+    {
+        for(uint16_t i = 0; i < len; i ++) buf[i] = Wire.read();
+    }
+    */
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BMI088.h	Wed Aug 28 08:32:22 2019 +0000
@@ -0,0 +1,212 @@
+/*    
+ * A library for Grove - 6-Axis Accelerometer&Gyroscope(BMI088)
+ *   
+ * Copyright (c) 2018 seeed technology co., ltd.  
+ * Author      : Wayen Weng  
+ * Create Time : June 2018
+ * Change Log  : 
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "mbed.h"
+
+#ifndef __BOSCH_BMI088_H__
+#define __BOSCH_BMI088_H__
+
+#define BMI088_ACC_ADDRESS          0x19<<1    //0x19<<1
+
+#define BMI088_ACC_CHIP_ID          0x00 // Default value 0x1E
+#define BMI088_ACC_ERR_REG          0x02
+#define BMI088_ACC_STATUS           0x03
+
+#define BMI088_ACC_X_LSB            0x12
+#define BMI088_ACC_X_MSB            0x13
+#define BMI088_ACC_Y_LSB            0x14
+#define BMI088_ACC_Y_MSB            0x15
+#define BMI088_ACC_Z_LSB            0x16
+#define BMI088_ACC_Z_MSB            0x17
+
+#define BMI088_ACC_SENSOR_TIME_0    0x18
+#define BMI088_ACC_SENSOR_TIME_1    0x19
+#define BMI088_ACC_SENSOR_TIME_2    0x1A
+
+#define BMI088_ACC_INT_STAT_1       0x1D
+
+#define BMI088_ACC_TEMP_MSB         0x22
+#define BMI088_ACC_TEMP_LSB         0x23
+
+#define BMI088_ACC_CONF             0x40
+#define BMI088_ACC_RANGE            0x41
+
+#define BMI088_ACC_INT1_IO_CTRL     0x53
+#define BMI088_ACC_INT2_IO_CTRL     0x54
+#define BMI088_ACC_INT_MAP_DATA     0x58
+
+#define BMI088_ACC_SELF_TEST        0x6D
+
+#define BMI088_ACC_PWR_CONF         0x7C
+#define BMI088_ACC_PWR_CTRl         0x7D
+
+#define BMI088_ACC_SOFT_RESET       0x7E
+
+#define BMI088_GYRO_ADDRESS             0x69<<1//0xD2    //0x69<<1
+
+#define BMI088_GYRO_CHIP_ID             0x00 // Default value 0x0F
+
+#define BMI088_GYRO_RATE_X_LSB          0x02
+#define BMI088_GYRO_RATE_X_MSB          0x03
+#define BMI088_GYRO_RATE_Y_LSB          0x04
+#define BMI088_GYRO_RATE_Y_MSB          0x05
+#define BMI088_GYRO_RATE_Z_LSB          0x06
+#define BMI088_GYRO_RATE_Z_MSB          0x07
+
+#define BMI088_GYRO_INT_STAT_1          0x0A
+
+#define BMI088_GYRO_RANGE               0x0F
+#define BMI088_GYRO_BAND_WIDTH          0x10
+
+#define BMI088_GYRO_LPM_1               0x11
+
+#define BMI088_GYRO_SOFT_RESET          0x14
+
+#define BMI088_GYRO_INT_CTRL            0x15
+#define BMI088_GYRO_INT3_INT4_IO_CONF   0x16
+#define BMI088_GYRO_INT3_INT4_IO_MAP    0x18
+
+#define BMI088_GYRO_SELF_TEST           0x3C
+
+enum device_type_t // device type
+{
+    ACC = 0x00, // 
+    GYRO = 0x01, // 
+};
+
+enum acc_scale_type_t // measurement rage
+{
+    RANGE_3G = 0x00, // 
+    RANGE_6G = 0x01, // 
+    RANGE_12G = 0x02, // 
+    RANGE_24G = 0x03, // 
+};
+
+enum acc_odr_type_t // output data rate
+{
+    ODR_12 = 0x05, // 
+    ODR_25 = 0x06, // 
+    ODR_50 = 0x07, // 
+    ODR_100 = 0x08, // 
+    ODR_200 = 0x09, // 
+    ODR_400 = 0x0A, // 
+    ODR_800 = 0x0B, // 
+    ODR_1600 = 0x0C, // 
+};
+
+enum acc_power_type_t // power mode
+{
+    ACC_ACTIVE = 0x00, // 
+    ACC_SUSPEND = 0x03, // 
+};
+
+enum gyro_scale_type_t // measurement rage
+{
+    RANGE_2000 = 0x00, // 
+    RANGE_1000 = 0x01, // 
+    RANGE_500 = 0x02, // 
+    RANGE_250 = 0x03, // 
+    RANGE_125 = 0x04, // 
+};
+
+enum gyro_odr_type_t // output data rate
+{
+    ODR_2000_BW_532 = 0x00, // 
+    ODR_2000_BW_230 = 0x01, // 
+    ODR_1000_BW_116 = 0x02, // 
+    ODR_400_BW_47 = 0x03, // 
+    ODR_200_BW_23 = 0x04, // 
+    ODR_100_BW_12 = 0x05, // 
+    ODR_200_BW_64 = 0x06, // 
+    ODR_100_BW_32 = 0x07, // 
+};
+
+enum gyro_power_type_t // power mode
+{
+    GYRO_NORMAL = 0x00, // 
+    GYRO_SUSPEND = 0x80, // 
+    GYRO_DEEP_SUSPEND = 0x20, // 
+};
+
+class BMI088
+{
+    public:
+        
+        BMI088(void);
+        
+        bool isConnection(void);
+        
+        void initialize(void);
+
+        void setAccPoweMode(acc_power_type_t mode);
+        void setGyroPoweMode(gyro_power_type_t mode);
+        
+        void setAccScaleRange(acc_scale_type_t range);
+        void setAccOutputDataRate(acc_odr_type_t odr);
+        
+        void setGyroScaleRange(gyro_scale_type_t range);
+        void setGyroOutputDataRate(gyro_odr_type_t odr);
+        
+        void getAcceleration(float* x, float* y, float* z);
+        float getAccelerationX(void);
+        float getAccelerationY(void);
+        float getAccelerationZ(void);
+        
+        void getGyroscope(float* x, float* y, float* z);
+        float getGyroscopeX(void);
+        float getGyroscopeY(void);
+        float getGyroscopeZ(void);
+        
+        uint16_t getTemperature(void);
+        
+        uint8_t getAccID(void);
+        uint8_t getGyroID(void);
+        
+        void resetAcc(void);
+        void resetGyro(void);
+        
+    private:
+        
+        void write8(device_type_t dev, char reg, uint8_t val);
+        char read8(device_type_t dev, char reg);
+        uint16_t read16(device_type_t dev, char reg);
+        uint16_t read16Be(device_type_t dev, char reg);
+        uint32_t read24(device_type_t dev, char reg);
+        void read(device_type_t dev, char reg, char *, uint16_t len);
+        
+        float accRange;
+        float gyroRange;
+        uint8_t devAddrAcc;
+        uint8_t devAddrGyro;
+    protected:
+        I2C i2c;
+};
+
+extern BMI088 bmi088;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Aug 28 08:32:22 2019 +0000
@@ -0,0 +1,45 @@
+#include "mbed.h"
+#include "BMI088.h"
+/* Testsetup fuer SEED BMI088 siehe 
+T:\T-IMS-IndNav\01_Technisches\70_Hardwareentwicklung\20190828_083342.jpg             
+*/
+
+
+DigitalOut myled(LED1);
+
+Serial pc(SERIAL_TX, SERIAL_RX);
+Timer ti;
+
+BMI088 bmi088;
+
+int main() {
+    pc.baud(115200);
+    ti.start();
+    ti.reset();
+    float x,y,z;
+    pc.printf("BMI088 Raw Data\r\n");
+    wait_ms(100);
+    //bmi088.resetAcc();
+    while(1)
+    {
+        if(bmi088.isConnection())
+        {
+           bmi088.initialize();
+            pc.printf("BMI088 is init and connected\r\n");
+            break;
+        }
+        else pc.printf("BMI088 is not connected\r\n");
+        
+        wait_ms(500);
+        }
+    //bmi088.resetAcc();
+    wait_ms(500);
+    while (1) {
+        bmi088.getGyroscope(&x,&y,&z);
+        printf("%2.2f %2.4f %2.4f %2.4f  \r\n",ti.read(),x,y,z);
+        //wait_ms(1);
+        bmi088.getAcceleration(&x,&y,&z);    // Accel does not work!!!???
+        printf("%2.4f %2.4f %2.4f \r\n",x,y,z);
+        wait(.2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Aug 28 08:32:22 2019 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file