Showing posts with label BLE. Show all posts
Showing posts with label BLE. Show all posts

Thursday, June 4, 2020

How to add you own custom board files to CC26xx BLE stack


The following steps show you how to add you own custom board files to CC26xx BLE stack using CC2650 BLE stack 2.2.04.06 version

1. Create CC2650_YK folder under C:\ti\simplelink\ble_sdk_2_02_04_06\src\boards\

2.
   2.1 Copy Board.h/CC2650_LAUNCHXL.h/CC2650_LAUNCHXL.c from C:\ti\simplelink\ble_sdk_2_02_04_06\src\boards\CC2650_LAUNCHXL to C:\ti\simplelink\ble_sdk_2_02_04_06\src\boards\CC2650_YK
  
   2.2 Rename CC2650_LAUNCHXL.h/CC2650_LAUNCHXL.c to CC2650_YK.h/CC2650_YK.c
  
   2.3 Revise #include "CC2650_LAUNCHXL.h" in Board.h to #include "CC2650_YK.h"

3. Create cc2650yk folder under C:\ti\simplelink\ble_sdk_2_02_04_06\src\target

4
   4.1 Copy cc2650lp_board.h/cc2650lp_board.c from C:\ti\simplelink\ble_sdk_2_02_04_06\src\target\cc2650lp to C:\ti\simplelink\ble_sdk_2_02_04_06\src\target\cc2650yk

   4.2 Rename cc2650lp_board.h/cc2650lp_board.c to cc2650yk_board.h/cc2650yk_board.c

   4.3 Add the following codes in cc2650yk_board.h
      
       #elif defined(CC2650_YK)
       #include <../../boards/CC2650_YK/Board.h>

   4.4 Add the following codes in cc2650yk_board.c

       #elif defined(CC2650_YK)
       #include <../../boards/CC2650_YK/Board.h>
       #include <../../boards/CC2650_YK/CC2650_YK.c>

5.
   5.1 Add the following codes in board.h
  
       #elif defined(CC2650_YK)
       #include "./cc2650yk/cc2650yk_board.h"

   5.2 Add the following codes in board.c
  
       #elif defined(CC2650_YK)
       #include "./cc2650yk/cc2650yk_board.c"

6. Change CC2650_LAUNCHXL in Predefined Symbols to CC2650_YK

7. Now you can build the code with your own custom board.

Tuesday, May 19, 2020

DIY SwitchBot using Silicon Labs Thunderboard BG22 Kit.

Due to COVID-19, people don't want to touch anything such as light switch arbitrarily and it is any super easy to DIY light switch robot to allow you to turn on or off light through BLE of you SmartPhone instead of touching the switch directly.
The follow steps show you how to DIY SwitchBot using Silicon Labs Thunderboard BG22 Kit and SG90 servo motor.

1. Add the following header files, defines, and global variables in app.c

#include "em_device.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "em_chip.h"
#include "em_gpio.h"
#include "em_timer.h"

// Global variables used to set top value and duty cycle of the timer
#define PWM_FREQ          50
#define DUTY_CYCLE_STEPS  0.05

static uint32_t topValue = 0;
static volatile float dutyCycle = 0;

2. Add the following functions for PWM (original from here) and SG90 servo motor control.

/**************************************************************************//**
 * @brief
 *    Interrupt handler for TIMER0 that changes the duty cycle
 *
 * @note
 *    This handler doesn't actually dynamically change the duty cycle. Instead,
 *    it acts as a template for doing so. Simply change the dutyCycle
 *    global variable here to dynamically change the duty cycle.
 *****************************************************************************/
void TIMER0_IRQHandler(void)
{
  // Acknowledge the interrupt
  uint32_t flags = TIMER_IntGet(TIMER0);
  TIMER_IntClear(TIMER0, flags);

  // Update CCVB to alter duty cycle starting next period
  TIMER_CompareBufSet(TIMER0, 0, (uint32_t)(topValue * dutyCycle));
}

/**************************************************************************//**
 * @brief
 *    GPIO initialization
 *****************************************************************************/
void initGpio(void)
{
  // Configure PA6 as output
  GPIO_PinModeSet(gpioPortA, 6, gpioModePushPull, 0);
}

/**************************************************************************//**
 * @brief
 *    CMU initialization
 *****************************************************************************/
void initCmu(void)
{
  // Enable clock to GPIO and TIMER0
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_TIMER0, true);
}

/**************************************************************************//**
 * @brief
 *    TIMER initialization
 *****************************************************************************/
void initTimer(void)
{
  uint32_t timerFreq = 0;
  // Initialize the timer
  TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
  // Configure TIMER0 Compare/Capture for output compare
  TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;

  // Use PWM mode, which sets output on overflow and clears on compare events
  timerInit.prescale = timerPrescale64;
  timerInit.enable = false;
  timerCCInit.mode = timerCCModePWM;

  // Configure but do not start the timer
  TIMER_Init(TIMER0, &timerInit);

  // Route Timer0 CC0 output to PA6
  GPIO->TIMERROUTE[0].ROUTEEN  = GPIO_TIMER_ROUTEEN_CC0PEN;
  GPIO->TIMERROUTE[0].CC0ROUTE = (gpioPortA << _GPIO_TIMER_CC0ROUTE_PORT_SHIFT)
                                    | (6 << _GPIO_TIMER_CC0ROUTE_PIN_SHIFT);

  // Configure CC Channel 0
  TIMER_InitCC(TIMER0, 0, &timerCCInit);

  // Start with 10% duty cycle
  dutyCycle = DUTY_CYCLE_STEPS;

  // set PWM period
  timerFreq = CMU_ClockFreqGet(cmuClock_TIMER0) / (timerInit.prescale + 1);
  topValue = (timerFreq / PWM_FREQ);
  // Set top value to overflow at the desired PWM_FREQ frequency
  TIMER_TopSet(TIMER0, topValue);

  // Set compare value for initial duty cycle
  TIMER_CompareSet(TIMER0, 0, (uint32_t)(topValue * dutyCycle));

  // Start the timer
  TIMER_Enable(TIMER0, true);

  // Enable TIMER0 compare event interrupts to update the duty cycle
  TIMER_IntEnable(TIMER0, TIMER_IEN_CC0);
  NVIC_EnableIRQ(TIMER0_IRQn);
}

void pwm_turn_on_sg90(void);
void pwm_turn_off_sg90(void);

void pwm_turn_on_sg90(void)
{
    gecko_cmd_hardware_set_soft_timer (TIMER_MS_2_TIMERTICK(100),SERVO_0_TIMER, true);
}

void pwm_turn_off_sg90(void)
{
    gecko_cmd_hardware_set_soft_timer (TIMER_MS_2_TIMERTICK(100),SERVO_180_TIMER, true);
}

3. Add the following three timer events in red in app_timer.h

typedef enum {
  UI_TIMER = 0,
  ADV_ALTERNATE_TIMER,
  IMU_SERVICE_ACC_TIMER,
  IMU_SERVICE_ORI_TIMER,
  BATT_SERVICE_TIMER,
  SENSOR_READOUT_TIMER,
  /** Temperature measurement timer.
   *  This is an auto-reload timer used for timing temperature measurements. */
  TEMP_TIMER,
  SERVO_0_TIMER,
  SERVO_90_TIMER,
  SERVO_180_TIMER

} appTimer_t;

4. Add the following code in appInit() of app.c to init PWM.

  initCmu();
  initGpio();
  initTimer();

5. Add the following three servo motor control event in "case gecko_evt_hardware_soft_timer_id:..." of appHandleEvents() in app.c.

        case SERVO_0_TIMER:
            dutyCycle = 0.1;
            // Set compare value for initial duty cycle
            TIMER_CompareSet(TIMER0, 0, (uint32_t)(topValue * dutyCycle));
            gecko_cmd_hardware_set_soft_timer (TIMER_MS_2_TIMERTICK(300),SERVO_90_TIMER, true);
          break;
        case SERVO_90_TIMER:
            dutyCycle = 0.05;
            // Set compare value for initial duty cycle
            TIMER_CompareSet(TIMER0, 0, (uint32_t)(topValue * dutyCycle));
            //gecko_cmd_hardware_set_soft_timer (TIMER_MS_2_TIMERTICK(300),SERVO_0_TIMER, true);
          break;

        case SERVO_180_TIMER:
            dutyCycle = 0.02;
            // Set compare value for initial duty cycle
            TIMER_CompareSet(TIMER0, 0, (uint32_t)(topValue * dutyCycle));
            gecko_cmd_hardware_set_soft_timer (TIMER_MS_2_TIMERTICK(300),SERVO_90_TIMER, true);
          break;

6. Call pwm_turn_on_sg90/pwm_turn_off_sg90 in aioDeviceDigitalOutWrite() of aio.c to control SG90 according to LED characteristics.

7. Build and download firmware into Thunderboard BG22 Kit.

8. Connect GND(EXP1)/3V0(EXP20)/PA6(EXP14) pins on Thunderboard BG22 Kit to BROWN(GND)/RED(PWR)/ORANGE(PWM) on SG90.

9.  Install Silicon Labs Thunderboard App on your SmartPhone and connect to Thunderboard BG22 Kit to control light switch.


Monday, May 18, 2020

SwitchBot DIY using LPSTK-CC1352R , SG90 servo motor, and ProjectZero to away from COVID-19.

Due to COVID-19, people don't want to touch anything such as light switch arbitrarily and it is any super easy to DIY light switch robot to allow you to turn on or off light through BLE of you SmartPhone instead of touching the switch directly.

The follow steps show you how to DIY SwitchBot using Texas Instruments LPSTK-CC1352R, SG90 servo motor, and ProjectZero.

1. Add CONFIG_PWM_0 and use DIO22 as PWM output pin in project_zero.syscfg



2. Add "#include < ti/drivers/PWM.h >" and the following global variables in project_zero.c to use PWM related APIs later.

/* Period and duty in microseconds */
int16_t   pwmPeriod = 20000;
int16_t   duty = 1500;
int16_t   dutyInc = 500;

int16_t i=0;

/* Sleep time in microseconds */
PWM_Handle pwm1 = NULL;
PWM_Params params;

3. Add the following PZ_SERVO_EVT, servoClock, and Servo_clockHandler to send PZ_SERVO_EVT.

#define PZ_SERVO_EVT         11
static Clock_Struct servoClock;static void Servo_clockHandler(UArg arg);

static void Servo_clockHandler(UArg arg)
{
    //PWM_setDuty(pwm1, duty);
    pzButtonState_t *pButtonState = ICall_malloc(sizeof(pzButtonState_t));
            if(pButtonState != NULL)
            {
                //*pButtonState = buttonMsg;
                if(ProjectZero_enqueueMsg(PZ_SERVO_EVT, pButtonState) != SUCCESS)
                {
                  ICall_free(pButtonState);
                }
            }
}

4. Add "case PZ_SERVO_EVT:" in ProjectZero_processApplicationMessage to put SG90 back to original position after writing ON/OFF characteristics

      case PZ_SERVO_EVT:
      {
          PWM_setDuty(pwm1, duty);
          break;
      }


5.  Init/start servoClock and PWM in ProjectZero_init.

    Util_constructClock(&servoClock, Servo_clockHandler, 300, 0, false, 0);
    Util_startClock(&servoClock);

    PWM_init();
    PWM_Params_init(&params);
    params.dutyUnits = PWM_DUTY_US;
    params.dutyValue = 0;
    params.periodUnits = PWM_PERIOD_US;
    params.periodValue = pwmPeriod;
    pwm1 = PWM_open(CONFIG_PWM_0, &params);
    if (pwm1 == NULL) {
        /* CONFIG_PWM_0 did not open */
        while (1);
    }

    PWM_start(pwm1);
    PWM_setDuty(pwm1, duty);

6. In "case LS_LED0_ID:..." section of ProjectZero_LedService_ValueChangeHandler. Add the following code to set PWM to rotate SG90 servo motor according to ON/OFF characteristics writing.

        if (pCharData->data[0]!=0){
            PWM_setDuty(pwm1, duty-500);
            Util_startClock(&servoClock);
        }
        else{
            PWM_setDuty(pwm1, duty+800);
            Util_startClock(&servoClock);
        }


7. Build and download firmware into LPSTK-CC1352R

8. Connect GND/3V3/DIO22 pins on LPSTK-CC1352R to BROWN(GND)/RED(PWR)/ORANGE(PWM) on SG90.

9. Power on LPSTK-CC1352R and use TI SimpleLink Starter App to connect to Project Zero to toggle ON/OFF.