MDM9206 with Motion Detector

Skill LevelArea of FocusOperating SystemPlatform/HardwareCloud Services/Platform
IntermediateHealthcare, SensorsRTOSMDM920x LTE for IoTGizwits Cloud Platform

This project is designed to use the ADXL345 sensor to detect three axis acceleration values using the Qualcomm® MDM9206 LTE modem, a multimode communication chipset that supports Cat-M1/eMTC, Cat-NB1/NB-IoT, 2G/E-GPRS technologies and more than 15 RF bands, making it ideal for global IoT applications. When axis acceleration values change beyond the set range, an LED lights up.

The main objective of this project is to connect the ADXL345 sensor to the SPI interface of the MDM9206 chipset provided by the GoKit development board and collect three axis acceleration values. When axis acceleration values change beyond the set range, an LED lights up.

Parts Used

Below are the items used in this project.

  1. Win7 PC
  2. GoKit4 development board
  3. ADXL345 sensor, used to detect axis acceleration values
  4. LED, when axis acceleration values changes beyond the set range, the LED lights up
  5. DuPont cable, used to connect other components as wires

How does it work?

Below are some usage instructions to test the project.

Now let's introduce the demo-Smart-Motion-detector’s workflow.

  gagentMain---->sensorInit---->led_init---->motion_init---->tx_timer_create

Register a callback in the interface named "tx_timer_create", when time is up, call the callback "userTimerCB".

  demo-Smart-Motion-detector/main/main.c
  void gagentMain( void )
  {
      getFreeHeap();
      sensorInit();
      gizwitsInit();
  }

The function named "gagentMain" was called by "GAgent", the main role of GAgent is data forwarding, which is a data interaction bridge between device data, Wit Cloud, and the application. Function "sensorInit", does some sensor initialization:

  void sensorInit(void)
  {
      int32 ret = -1; 
      gizLog(LOG_INFO,"Sensor initialization ...\n"); 
    led_init();
    motion_init();
      txm_module_object_allocate(&userTimer, sizeof(TX_TIMER));
      ret = tx_timer_create(userTimer, "userTimer", userTimerCB, NULL, 1,
                            200, TX_AUTO_ACTIVATE);			
      if(ret != TX_SUCCESS)
      {
          gizLog(LOG_ERROR,"Failed to create UserTimer.\n");
      }
  }
  
  void led_init()
  {
    led_gpio_config();
    led_on_off(false,led_green);	    //init status is off
    led_on_off(true,GPIO_BLUE);		//init status is off
  }
  
  void motion_init()
  { 
    adxl345_init();
  }
  
  demo-Smart-Motion-detector/driver/adxl345/adxl345.c
  
  /*do some initialization about SPI and ADXL345 sensor.*/
  
  void adxl345_init()
  {
    static uint8 data;
    uint8 *data_addr;
    spi_init();
    data_addr = spi_reg_read(0x00);  //read device id;
    qapi_Timer_Sleep(10, QAPI_TIMER_UNIT_TICK, true);
    data = *data_addr;
    gizLog(LOG_INFO, "Device id is 0x%02x\n", data);
  
    spi_reg_write(0x31, 0x2B);	
    spi_reg_write(0x2C, 0x08); 	
    spi_reg_write(0x2D, 0x08); 	
    spi_reg_write(0x2E, 0x00); 	
    spi_reg_write(0x2F, 0x00); 	
    spi_reg_write(0x2E, 0x02); 	
    spi_reg_write(0x38, 0x9F); 
  }
  demo-Smart-Motion-detector/driver/spi/spi.c
  /*do SPI initialization*/
  void spi_init(void)
  {
      /*Get a handle to an SPI instance.*/
  qapi_SPIM_Open(QAPI_SPIM_INSTANCE_6_E, &spi_hdl); 
  
  /*Turn on all resources required for a successful SPI transaction.*/
      qapi_SPIM_Power_On(spi_hdl);
  
  /*spi interface config*/
  
  /*set the spi mode, determined by slave device*/
  spi_config.SPIM_Mode = QAPI_SPIM_MODE_3_E;                      
  
  /*set CS low as active, determined by slave device*/
  spi_config.SPIM_CS_Polarity = QAPI_SPIM_CS_ACTIVE_LOW_E;        
  
      spi_config.SPIM_endianness  = SPI_LITTLE_ENDIAN;
      spi_config.SPIM_Bits_Per_Word = 8;
  spi_config.SPIM_Slave_Index = 0;
  
  /*config spi clk about 1Mhz */
      spi_config.Clk_Freq_Hz = 1000000;                               
  spi_config.SPIM_CS_Mode = QAPI_SPIM_CS_KEEP_ASSERTED_E;
  
  /*don't care, set 0 is ok.*/
  spi_config.CS_Clk_Delay_Cycles = 0;    
  
  /*don't care, set 0 is ok.*/ 
      spi_config.Inter_Word_Delay_Cycles = 0;  
      spi_config.loopback_Mode = 0;
  }
  
  /*used to write data to registers*/
  
  qapi_Status_t spi_reg_write(uint8 reg, uint8 data)
  {
      qapi_Status_t res = QAPI_OK; 
      qapi_SPIM_Descriptor_t spi_desc;
      int num;
  
      tx_buf[0] = reg & 0x3f;
      tx_buf[1] = data;
  
      spi_desc.rx_buf = rx_buf;
      spi_desc.tx_buf = tx_buf;
      spi_desc.len = 2;
      spi_status.status = 0;
      spi_status.read_addr = NULL;
      spi_status.len = 1;
  
      /*used to performs a data transfer over the SPI bus */
      res = qapi_SPIM_Full_Duplex(spi_hdl, &spi_config, &spi_desc, 1, qapi_spi_cb_func, &spi_status, false);
  
      if (res != QAPI_OK)
          return res;
  
  for(num = 0; num < 100; num++)
    {
          gizLog(LOG_INFO,"num = %d\n", num);
          if (spi_status.status == QAPI_SPI_COMPLETE) 
  {
          gizLog(LOG_INFO,"spi write reg(0x%02x) = 0x%02x\n", reg, data);
              return QAPI_OK;
          } 
  else if (spi_status.status != 0)
    {
              gizLog(LOG_INFO,"spi write err\n");
              return QAPI_ERROR;
          }
          qapi_Timer_Sleep(1, QAPI_TIMER_UNIT_TICK, true);
      }
  
      return QAPI_ERR_TIMEOUT;
  }
  
  demo-Smart-Motion-detector/main/main.c
  
  /*”userTimerCB” is registered in the inteface named “tx_timer_create”*/
  
  
  void ICACHE_FLASH_ATTR userTimerCB(void)
  {
      static uint8_t ctime = 0;
      static uint8_t ccount = 0;
      GETAXIS_ERROR_t status = 0;
    static uint8_t num = 0;
    int tmp_x = 0, tmp_y = 0, tmp_z = 0;
    
    int32_t X_axis_Value = 0;
    int32_t Y_axis_Value = 0;
    int32_t Z_axis_Value = 0;
  
    if (QUERY_INTERVAL < ctime)			
    {
      ctime = 0;
            status=getaxis(&X_axis_Value,&Y_axis_Value,&Z_axis_Value);
      if( status != GETAXIS_OK)
      {
        return;	
      }
      if(num == 0)
      {
        old_axis_val.X =  X_axis_Value;
        old_axis_val.Y =  Y_axis_Value;
        old_axis_val.Z =  Z_axis_Value;
        num += 1;
      }
      else
      {
        tmp_x = old_axis_val.X > X_axis_Value ? old_axis_val.X - X_axis_Value:X_axis_Value - old_axis_val.X;
        tmp_y = old_axis_val.Y > Y_axis_Value ? old_axis_val.Y - Y_axis_Value:Y_axis_Value - old_axis_val.Y;
        tmp_z = old_axis_val.Z > Z_axis_Value ? old_axis_val.Z - Z_axis_Value:Z_axis_Value - old_axis_val.Z;
        gizLog(LOG_INFO, "tmp_x= %d, tmp_y = %d , tmp_z = %d\n",  tmp_x, tmp_y, tmp_z);
        if(tmp_x > X_AXIS_THRESHOLD || tmp_y > Y_AXIS_THRESHOLD || tmp_z > Z_AXIS_THRESHOLD)
        { 	
          led_on_off(true,led_green);	
          gizLog(LOG_INFO, "LED ON\n");
        }
        else
        {
          led_on_off(false, led_green);
          gizLog(LOG_INFO, "LED OFF\n");
        }
        old_axis_val.X =  X_axis_Value;
        old_axis_val.Y =  Y_axis_Value;
        old_axis_val.Z =  Z_axis_Value;
          }
      currentDataPoint.valueX_axis_Value = X_axis_Value;
      currentDataPoint.valueY_axis_Value = Y_axis_Value;
      currentDataPoint.valueZ_axis_Value = Z_axis_Value;
    }
      ctime++;  
  }
  
  demo-Smart-Motion-detector/driver/adxl345/adxl345.c
  
  /*used to get three axis acceleration values*/
  
  uint8_t getaxis(int32_t *X_axis_Value, int32_t *Y_axis_Value, int32_t *Z_axis_Value)
  {
    qapi_Status_t res = QAPI_ERROR;
    uint8_t data;
    uint8_t *data_addr;
    SENSOR_DATA_TypeDef axis_converted_avg;
  
    data_addr = spi_reg_read(0x30);
  
    if (data_addr == NULL) {
      gizLog(LOG_ERROR, "read 0x30 err\n");
      return GETAXIS_ERR;
    }
  
    qapi_Timer_Sleep(10, QAPI_TIMER_UNIT_TICK, true);
    data = *data_addr;
  
    if (data & 0x02)
    {
      res = ADXL345_READ_FIFO(&axis_converted_avg);
      if (res != QAPI_OK)
        return GETAXIS_ERR;
  
      *X_axis_Value = axis_converted_avg.X;
      *Y_axis_Value = axis_converted_avg.Y;
      *Z_axis_Value = axis_converted_avg.Z;
      return GETAXIS_OK;
    }
    else
    {
      return GETAXIS_NO_INT;
    }
  }
  
  demo-Smart-Motion-detector/driver/spi/spi.c
  
  /*used to read data from registers*/
  
  uint8 *spi_reg_read(uint8 reg)
  {
      qapi_Status_t res = QAPI_OK; 
      qapi_SPIM_Descriptor_t spi_desc;
      int num;
  
      tx_buf[0] = reg | 0x80 & 0xbf;
      tx_buf[1] = 0xff;
  
      rx_buf [0] = 0;
      rx_buf [1] = 0;
  
      spi_desc.rx_buf = rx_buf;
      spi_desc.tx_buf = tx_buf;
      spi_desc.len = 2;
      spi_status.status = 0;
      spi_status.read_addr = NULL;
      spi_status.len = 1;
  
  
      res = qapi_SPIM_Full_Duplex(spi_hdl, &spi_config, &spi_desc, 1, qapi_spi_cb_func, &spi_status, false);
  
      gizLog(LOG_INFO,"read spi end\n");
  
      if (res != QAPI_OK)
          return NULL;
  
      return rx_buf + 1;
  }
  
  demo-Smart-Motion-detector/driver/adxl345/adxl345.c
  
  /*used to get data from slave device*/
  
  qapi_Status_t ADXL345_READ_FIFO(SENSOR_DATA_TypeDef *axis_converted_avg)
  {
    uint16_t axis_raw_data[10][3];
    static uint8_t data_buf[6];
    uint8 *data_addr;
    SENSOR_DATA_TypeDef axis_converted[10];
  
    for (uint8_t i = 0; i < 10; i++)
    {
      for(uint8_t m = 0; m < 6; m++) {
        data_addr = spi_reg_read(0x32 + m);
        qapi_Timer_Sleep(10, QAPI_TIMER_UNIT_TICK, true);
        data_buf[m] = *data_addr;
      }
  
      /*x, y, z raw val*/
      for(uint8_t n = 0; n < 6; n++){
        gizLog(LOG_INFO, "data_buf[%d] = 0x%x\n", n, data_buf[n]);
      }
  
      axis_raw_data[i][0] = data_buf[0] | (((uint16_t)data_buf[1]) << 8);
      axis_raw_data[i][1] = data_buf[2] | (((uint16_t)data_buf[3]) << 8);
      axis_raw_data[i][2] = data_buf[4] | (((uint16_t)data_buf[5]) << 8);
      gizLog(LOG_INFO, "dtat[%d].x = 0x%x, dtat[%d].y = 0x%x, dtat[%d].z = 0x%x\n", i, axis_raw_data[i][0], i, axis_raw_data[i][1], i, axis_raw_data[i][2]);
      axis_converted[i] = ADXL345_DATA_CONVERT(axis_raw_data[i]);	
    }
  
    *axis_converted_avg = ADXL345_AVERAGE(axis_converted, 10);
  
    return QAPI_OK;
  }
  
  
  /*used to deal with raw data*/
  
  SENSOR_DATA_TypeDef ADXL345_DATA_CONVERT(uint16_t *data)
  {
    int8_t sign = 1;
    uint16_t temp = 0;
    uint8_t i = 0;
    uint32_t val = 0;
  
    SENSOR_DATA_TypeDef converted_data;
  
    for (i = 0; i < 3; i++)
    {
      sign = 1;
      temp = data[i];
  
      if ((temp & 0xF000) == 0xF000)
      {
        sign = -1;
        temp = -temp;
      }
  
      if (i == 0)
      {
              /*calibrate out x axis offset*/
        converted_data.X = ((temp & 0x0FFF) * 4) * sign; 
      }
      else if (i == 1)
      {
              /*calibrate out y axis offset*/
        converted_data.Y = ((temp & 0x0FFF) * 4) * sign;
      }
      else if (i == 2)
      {
              /*calibrate out z axis offset*/
        converted_data.Z = ((temp & 0x0FFF) * 4) * sign; 
      }
    }
  
    gizLog(LOG_INFO, "converted_data.X = %d, converted_data.Y = %d, converted_data.Z = %d\n", converted_data.X, converted_data.Y, converted_data.Z);
  
    return converted_data;
  }
  
  /*Average 10 sets of raw data*/
  
  SENSOR_DATA_TypeDef ADXL345_AVERAGE(SENSOR_DATA_TypeDef *data, uint8_t len)
  {
    SENSOR_DATA_TypeDef result = {0};
    uint32_t i;
    for (i = 0; i < len; i++)
    {
      result.X += data[i].X;
      result.Y += data[i].Y;
      result.Z += data[i].Z;
    }
  
    result.X /= len;
    result.Y /= len;
    result.Z /= len;
  
    return result;
  }
  1. Download code from GitHub the repository: “https://github.com/ThunderSoft-XA/demo-Smart-Motion-detector
  2. Compile the code and flash the image to GoKit4 development kit.
  3. Connect the ADXL345 sensor to the SPI interface of the GoKit development board.
  4. Connect one pin of the LED to the D9 pin of the development board, and the other pin is connected to the Vcc.
  5. Connect the USB data cable between the PC and GoKit development board.
  6. Open the serial debugging assistant.
  7. Shake the ADXL345 sensor and you can see that the data has changed.

When axis acceleration values change beyond the set range, the LED will be lit.

Parts used for the GoKit4 development kit demo-Smart-Motion-detector

Parts used for the GoKit4 development kit demo-Smart-Motion-detector

NameEmailTitle/Company
Zhen[email protected]Thundersoft
Rong[email protected]Thundersoft
Jie[email protected]Thundersoft
Kou[email protected]Thundersoft
Eric[email protected]Thundersoft