Back to All
Project

MDM9206 with Motion Detector

 

Skill Level Area of Focus Operating System Platform/Hardware Cloud Services/Platform
Intermediate Healthcare, Sensors RTOS MDM920x LTE for IoT Gizwits 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.

Objective

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.

Materials Required / Parts List / Tools

 

 

Smart

ADXL345

ADXL345

DuPont

Source Code / Source Examples / Application Executable

Build / Assembly Instructions

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;
  }

Usage Instructions

  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

Parts

Opinions expressed in the content posted here are the personal opinions of the original authors, and do not necessarily reflect those of Qualcomm Incorporated or its subsidiaries ("Qualcomm"). The content is provided for informational purposes only and is not meant to be an endorsement or representation by Qualcomm or any other party. This site may also provide links or references to non-Qualcomm sites and resources. Qualcomm makes no representations, warranties, or other commitments whatsoever about any non-Qualcomm sites or third-party resources that may be referenced, accessible from, or linked to this site.

Project Authors
Thunder Software Technology (Shenzhen) Co., Ltd.
Shenzhen
Zhen
Rong
Kou
Jie
Eric

Sign up for the Developer Newsletter.

Get software and hardware tool resources to help optimize your development delivered to your inbox weekly.

Qualcomm relentlessly innovates to deliver intelligent computing everywhere, helping the world tackle some of its most important challenges. Our leading-edge AI, high performance, low-power computing, and unrivaled connectivity deliver proven solutions that transform major industries. At Qualcomm, we are engineering human progress.

Stay connected

Get the latest Qualcomm and industry information delivered to your inbox.

Subscribe
Manage your subscription

© Qualcomm Technologies, Inc. and/or its affiliated companies.

Snapdragon and Qualcomm branded products are products of Qualcomm Technologies, Inc. and/or its subsidiaries. Qualcomm patented technologies are licensed by Qualcomm Incorporated.

Note: Certain services and materials may require you to accept additional terms and conditions before accessing or using those items.

References to "Qualcomm" may mean Qualcomm Incorporated, or subsidiaries or business units within the Qualcomm corporate structure, as applicable.

Qualcomm Incorporated includes our licensing business, QTL, and the vast majority of our patent portfolio. Qualcomm Technologies, Inc., a subsidiary of Qualcomm Incorporated, operates, along with its subsidiaries, substantially all of our engineering, research and development functions, and substantially all of our products and services businesses, including our QCT semiconductor business.

Materials that are as of a specific date, including but not limited to press releases, presentations, blog posts and webcasts, may have been superseded by subsequent events or disclosures.

Nothing in these materials is an offer to sell or license any of the services or materials referenced herein.