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.


1 comment: