MDM9206 with Vibration Motor

Skill LevelArea of FocusOperating SystemPlatform/HardwareCloud Services/Platform
IntermediateEmbedded, IoT, Robotics, Sensors, Smart CitiesRTOSQualcomm® MDM920x LTE for IoTGizwits Cloud Platform

This project is designed to use an application installed on a mobile phone to control the vibration motor provided by GoKit4 development kit to start/stop a vibration. The GoKit4 development kit is equipped with 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.

The project’s main objective is to get familiar with the GoKit4 development kit and cloud services. It is designed to use the application installed on a mobile phone to send commands to control the vibration motor provided by GoKit4 development kit to start/ stop the vibration.

Parts Used

Below are the items used in this project.

Parts used for the GoKit4 development kit Gizwits cloud connection

  1. Mobile phone with a universal application provided by Gizwits cloud installed. This application can be used to see the sensor data and control the vibration motor on the GoKit4 development kit.
  2. GoKit4 development board
  3. USB data cable, used to supply power
  4. Win7 PC

Deploying the Project

  1. First step is to define product named "Smart_vibrator" on the Gizwits cloud platform, including basic information, data point, hardware solution, etc.
  2. Generate code based on the SoC scheme. The Gizwits cloud does not currently support generating code based on the MDM9206 platform, so you will need to choose ESP_826632M as the hardware platform, then make some changes. Please refer to: http://club.gizwits.com/thread-9395-1-1.html for details.
  3. Add local data which will be sent to Gizwits cloud
  4. Install application apk from https://download.gizwits.com/zh-cn/p/98/99
  5. Register mobile IoT card to NB-IoT network
  6. Add driver related code
  7. Compile the code and flash the image
  8. Run the device and open the application to control it

How does it work?

First of all, let's see gpio and motor init.

  demo-Smart-vibrator/main/main.c
  
  void gagentMain( void )
  {
      getFreeHeap();
      sensorInit();
      gizwitsInit();
  }
  
  void sensorInit(void)
  {
      int32 ret = -1;
      
  gizLog(LOG_INFO,"Sensor initialization ...\n"); 
  led_init();						
  motor_init();						
  txm_module_object_allocate(&userTimer, sizeof(TX_TIMER));
  
      ret = tx_timer_create(userTimer, "userTimer", userTimerCB, NULL, 1,
                            100, TX_AUTO_ACTIVATE);
      if(ret != TX_SUCCESS)
      {
          gizLog(LOG_WARNING,"Failed to create UserTimer.\n");
      }
  }
  
  
  void led_init()
  {
  	gizLog(LOG_INFO,"in led_init ...\n"); 
  	led_gpio_config();
  }
  
  
  void motor_init()
  {
  	gizLog(LOG_INFO,"in motor_init ...\n"); 
  	motor_gpio_config();
  }
  
  demo-Smart-vibrator/gpio/gpio.c
  
  
   void led_gpio_config()
   {
  	    gizLog(LOG_INFO,"in led_gpio_config...\n"); 
  	   
  	    gpio_config(GPIO_BLUE, QAPI_GPIO_OUTPUT_E, QAPI_GPIO_NO_PULL_E, QAPI_GPIO_2MA_E);	
  		
  	    gpio_config(GPIO_RED, QAPI_GPIO_OUTPUT_E, QAPI_GPIO_NO_PULL_E, QAPI_GPIO_2MA_E);	
  		
  
  	    gpio_config(GPIO_GREEN, QAPI_GPIO_OUTPUT_E, QAPI_GPIO_NO_PULL_E, QAPI_GPIO_2MA_E);	
  		
   }
  
  void motor_gpio_config()
  {
  	     gizLog(LOG_INFO,"in motor_gpio_config ...\n"); 
  		 
  	     gpio_config(GPIO_MOTOR, QAPI_GPIO_OUTPUT_E, QAPI_GPIO_NO_PULL_E, QAPI_GPIO_2MA_E);	
  }

gpio_config: does some gpio initialization

  void gpio_config(MODULE_PIN_ENUM m_pin,qapi_GPIO_Direction_t gpio_dir,qapi_GPIO_Pull_t gpio_pull,qapi_GPIO_Drive_t gpio_drive)
  {
  	gizLog(LOG_INFO,"in gpio config.....\n"); 
  	
  	qapi_Status_t status = QAPI_OK;
  
  	tlmm_config[m_pin].pin   = gpio_map_tbl[m_pin].gpio_id;
  	tlmm_config[m_pin].func  = gpio_map_tbl[m_pin].gpio_func;
  	tlmm_config[m_pin].dir   = gpio_dir;
  	tlmm_config[m_pin].pull  = gpio_pull;
  	tlmm_config[m_pin].drive = gpio_drive;
  
  	// the default here
  	status = qapi_TLMM_Get_Gpio_ID(&tlmm_config[m_pin], &gpio_id_tbl[m_pin]);
  	
  	gizLog(LOG_INFO,"pin_num = %d, gpio_id[%d], status = %d ...\n",gpio_map_tbl[m_pin].pin_num, gpio_map_tbl[m_pin].gpio_id, status); 
  	
  	if (status == QAPI_OK)
  	{
  		status = qapi_TLMM_Config_Gpio(gpio_id_tbl[m_pin], &tlmm_config[m_pin]);
  
  		gizLog(LOG_INFO,"after qapi_TLMM_Config_Gpio, status = %d ...\n", status); 
  		
  		if (status != QAPI_OK)
  		{
  			gizLog(LOG_INFO,"gpio config failed.....\n"); 
  		}
  		
  		status = qapi_TLMM_Drive_Gpio(gpio_id_tbl[m_pin], gpio_map_tbl[m_pin].gpio_id, QAPI_GPIO_HIGH_VALUE_E);
  	}
  }

Process

gizIssuedProcess ---> ACTION_CONTROL_DEVICE ---> gizDataPoint2Event ---> gizwitsEventProcess

gizIssuedProcess: the function is called by the gagent to receive the relevant protocol data delivered from the cloud or the app.

  int32_t ICACHE_FLASH_ATTR gizIssuedProcess(uint8_t *didPtr, uint8_t *inData, uint32_t inLen,uint8_t *outData,int32_t *outLen)
  {
  	uint8_t i = 0;
  
  
      if((NULL == inData) || (NULL == outData) || (NULL == outLen)) 
      {
          gizLog(LOG_WARNING,"!!! IssuedProcess Error \n"); 
          return -1;
      }
  
      if(NULL == didPtr)
      {
          gizLog(LOG_INFO,"~~~gizIssuedProcess: did is NULL .\n");
      }
      else
      {
          gizLog(LOG_INFO,"~~~gizIssuedProcess: did %s\n", didPtr);
      }
  
      gizLog(LOG_INFO,"%s: ", "~~~issued data"); 
      //printf_bufs((uint8_t *)inData,inLen);
  
      if(NULL == didPtr) 
      { 
          switch(inData[0]) 
          {
              case ACTION_CONTROL_DEVICE:
  
                  gizDataPoint2Event((gizwitsIssued_t *)&inData[1], &gizwitsProtocol.issuedProcessEvent,&gizwitsProtocol.gizCurrentDataPoint); 
                  gizwitsEventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)&gizwitsProtocol.gizCurrentDataPoint, sizeof(dataPoint_t));
                  gizMemset((uint8_t *)&gizwitsProtocol.issuedProcessEvent, 0, sizeof(eventInfo_t));          
                  *outLen = 0; 
                  break;
                  
              case ACTION_READ_DEV_STATUS:
                  gizDataPoints2ReportData(&gizwitsProtocol.gizLastDataPoint,&gizwitsProtocol.reportData.devStatus);
                  gizwitsProtocol.reportData.action = ACTION_READ_DEV_STATUS_ACK;
                  gizMemcpy(outData, (uint8_t *)&gizwitsProtocol.reportData, sizeof(gizwitsReport_t));
                  *outLen = sizeof(gizwitsReport_t);
                  
                  gizLog(LOG_INFO,"%s: ", "~~~ReadReport \n");
                  //printf_bufs((uint8_t *)outData,*outLen);
                  break;
                  
              case ACTION_W2D_TRANSPARENT_DATA: 
  
                  gizMemcpy(gizwitsProtocol.transparentBuff, &inData[1], inLen-1);
                  gizwitsProtocol.transparentLen = inLen-1;
                  
                  gizwitsProtocol.issuedProcessEvent.event[0] = TRANSPARENT_DATA;
                  gizwitsProtocol.issuedProcessEvent.num = 1;
                  gizwitsEventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)gizwitsProtocol.transparentBuff, gizwitsProtocol.transparentLen);
  
                  gizMemset((uint8_t *)&gizwitsProtocol.issuedProcessEvent, 0, sizeof(eventInfo_t));
                  gizMemset((uint8_t *)gizwitsProtocol.transparentBuff, 0, BUFFER_LEN_MAX);
                  gizwitsProtocol.transparentLen = 0;
                  *outLen = 0;
  
                  break;       
       
              default:
  
                  break;
          }
      }
      else
      { 
          gizLog(LOG_WARNING," Error : didPtr  \n");
      }
  
      return 0;
  }

ACTION_CONTROL_DEVICE: Perform related processing of "controlled protocol"

gizDataPoint2Event: Generate "control events" according to the protocol and complete the conversion of the corresponding data type.

  static int8_t ICACHE_FLASH_ATTR gizDataPoint2Event(gizwitsIssued_t *issuedData, eventInfo_t *info, dataPoint_t *dataPoints)
  {
      if((NULL == issuedData) || (NULL == info) ||(NULL == dataPoints))
      {
          gizLog(LOG_WARNING,"gizDataPoint2Event Error , Illegal Param\n");
          return -1;
      }
      
      /** Greater than 1 byte to do bit conversion **/
      if(sizeof(issuedData->attrFlags) > 1)
      {
          if(-1 == gizByteOrderExchange((uint8_t *)&issuedData->attrFlags,sizeof(attrFlags_t)))
          {
              gizLog(LOG_WARNING,"gizByteOrderExchange Error\n");
              return -1;
          }
  }
  
      if(0x01 == issuedData->attrFlags.flagLed_Value)
      {
          info->event[info->num] = EVENT_Led_Value;
          info->num++;
          dataPoints->valueLed_Value = gizStandardDecompressionValue(Led_Value_BYTEOFFSET,Led_Value_BITOFFSET,Led_Value_LEN,(uint8_t *)&issuedData->attrVals.wBitBuf,sizeof(issuedData->attrVals.wBitBuf));
      }
          
      if(0x01 == issuedData->attrFlags.flagMotor_Value)
      {
          info->event[info->num] = EVENT_Motor_Value;
          info->num++;
          dataPoints->valueMotor_Value = gizStandardDecompressionValue(Motor_Value_BYTEOFFSET,Motor_Value_BITOFFSET,Motor_Value_LEN,(uint8_t *)&issuedData->attrVals.wBitBuf,sizeof(issuedData->attrVals.wBitBuf));
      }   
      return 0;
  }

gizwitsEventProcess: corresponding event processing according to the generated "control event" (calling the corresponding driver function)

  int8_t ICACHE_FLASH_ATTR gizwitsEventProcess(eventInfo_t *info, uint8_t *data, uint32_t len)
  {
      uint8_t i = 0;
      dataPoint_t * dataPointPtr = (dataPoint_t *)data;
      moduleStatusInfo_t * wifiData = (moduleStatusInfo_t *)data;
  
      if((NULL == info) || (NULL == data))
      {
          gizLog(LOG_WARNING,"!!! gizwitsEventProcess Error \n");
          return -1;
      }
  
      for(i = 0; i num; i++)
      {
          switch(info->event[i])
          {
          case EVENT_Led_Value :
              currentDataPoint.valueLed_Value = dataPointPtr->valueLed_Value;
              gizLog(LOG_INFO, "Evt: EVENT_LedValue %d \n", currentDataPoint.valueLed_Value);
              if(0x01 == currentDataPoint.valueLed_Value)
              {
                         //on led
  		gpio_high_low(true,GPIO_GREEN);	
              }
              else
              {
                        //off led
  		gpio_high_low(false, GPIO_GREEN);	
              }
              break;
          case EVENT_Motor_Value :
              currentDataPoint.valueMotor_Value = dataPointPtr->valueMotor_Value;
              gizLog(LOG_INFO,"Evt: EVENT_MotorValue %d \n", currentDataPoint.valueMotor_Value
              );
              if(0x01 == currentDataPoint.valueMotor_Value)
              {
                         //start motor
                         gpio_high_low(true,GPIO_MOTOR);	
              }
              else
              {
                      //stop motor
                      gpio_high_low(false,GPIO_MOTOR);	
              }
              break;
          ......
              
          default:
              break;
          }
      }
      gizSendQueue(SIG_UPGRADE_DATA);
      
      return 0; 
  }

gpio_high_low: mainly to control led or motor by setting the high/low level to the corresponding pin.

   void gpio_high_low(bool on, uint8_t pin_gpio)
   {
  	
  	if (on)
  	{
  		qapi_TLMM_Drive_Gpio(gpio_id_tbl[pin_gpio], gpio_map_tbl[pin_gpio].gpio_id, QAPI_GPIO_LOW_VALUE_E);
  	}
  	else
  	{
  		qapi_TLMM_Drive_Gpio(gpio_id_tbl[pin_gpio], gpio_map_tbl[pin_gpio].gpio_id, QAPI_GPImotor_gpio_configO_HIGH_VALUE_E);
  	}
   }
 
  1. Download code from GitHub according to the repository in https://github.com/ThunderSoft-XA/demo-Smart-vibrator
  2. Compile the code and flash the image to the GoKit4 development kit
  3. Connect the USB data cable between the PC and GoKit4 development board
  4. Open the serial debugging assistant
  5. Click on "Device log" in Gizwits cloud to check if the device is online
  6. When the device is online, you can click the "view" button, and you'll see data from local was sent to Gizwits cloud
  7. Download the app from https://download.gizwits.com/zh-cn/p/98/99 and install it to your phone
  8. Open the application apk, and you'll see "my device", and from here you can find your device by scanning the QR code
  9. Next, generate the QR code
    1. Open "gizwits debugging assistant_v2.3.9/GIZ_SerialTool.exe"
    2. Choose "small tools", click "QR code generation", input "product key" and "MAC/IMEI"
    3. Click "get QR code", wait for a moment, and you can see a QR code
  10. Click "my device", scan the generated QR code, and you can find your device
  11. Then you can control the device and view the data

Showing the local data and sending commands from application apk.

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

Qualcomm MDM9206 is a product of Qualcomm Technologies, Inc. and/or its subsidiaries.