Skip to content

Commit

Permalink
samples: boards: firmware for Twinkie V2
Browse files Browse the repository at this point in the history
sample firmware for Twinkie V2 that toggles the LED based on charging
status.

Signed-off-by: Jason Yuan <[email protected]>
  • Loading branch information
ualbertagreen committed Jun 27, 2023
1 parent f60d8f5 commit 9557d88
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 0 deletions.
9 changes: 9 additions & 0 deletions samples/boards/google_twinkie_v2_pda/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(google_twinkie_v2)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
25 changes: 25 additions & 0 deletions samples/boards/google_twinkie_v2_pda/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.. _google_twinkie_v2_pda:

Twinkie Power Delivery
######################

Overview
********

This provides access to :ref:`Twinkie <google_twinkie_v2_board>` so you can try out
the supported features.

Building and Running
********************

Build and flash Twinkie as follows:

.. zephyr-app-commands::
:zephyr-app: samples/boards/google_pda
:board: google_twinkie_v2
:goals: build flash
:compact:

After flashing, the LED will start red. Putting the Twinkie in between any
usbc connection will cause the LED to turn blue. The LED will turn green instead
if the device is currently charging.
3 changes: 3 additions & 0 deletions samples/boards/google_twinkie_v2_pda/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CONFIG_ADC=y
CONFIG_ADC_STM32=y
CONFIG_GPIO=y
6 changes: 6 additions & 0 deletions samples/boards/google_twinkie_v2_pda/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sample:
name: Twinkie V2 usb Vbus snooper
tests:
sample.board.google_twinkie_v2:
platform_allow: google_twinkie_v2
tags: usb
102 changes: 102 additions & 0 deletions samples/boards/google_twinkie_v2_pda/src/meas.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2023 The ChromiumOS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/adc/voltage_divider.h>
#include <zephyr/drivers/adc/current_sense_amplifier.h>

/* The devicetree node identifier for the adc aliases. */
#define VBUS_V_MEAS_NODE DT_ALIAS(vbus)
#define VBUS_C_MEAS_NODE DT_ALIAS(cbus)

static const struct voltage_divider_dt_spec adc_vbus_v =
VOLTAGE_DIVIDER_DT_SPEC_GET(VBUS_V_MEAS_NODE);
static const struct current_sense_amplifier_dt_spec adc_vbus_c =
CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(VBUS_C_MEAS_NODE);

int meas_vbus_v(int32_t *v)
{
int ret;
int32_t sample_buffer = 0;

/* Structure defining an ADC sampling sequence */
struct adc_sequence sequence = {
.buffer = &sample_buffer,
/* buffer size in bytes, not number of samples */
.buffer_size = sizeof(sample_buffer),
.calibrate = true,
};
adc_sequence_init_dt(&adc_vbus_v.port, &sequence);

ret = adc_read(adc_vbus_v.port.dev, &sequence);
if (ret != 0) {
return ret;
}

*v = sample_buffer;
ret = adc_raw_to_millivolts_dt(&adc_vbus_v.port, v);
if (ret != 0) {
return ret;
}

ret = voltage_divider_scale_dt(&adc_vbus_v, v);
if (ret != 0) {
return ret;
}

return 0;
}

int meas_vbus_c(int32_t *c)
{
int ret;
int32_t sample_buffer = 0;

/* Structure defining an ADC sampling sequence */
struct adc_sequence sequence = {
.buffer = &sample_buffer,
/* buffer size in bytes, not number of samples */
.buffer_size = sizeof(sample_buffer),
.calibrate = true,
};
adc_sequence_init_dt(&adc_vbus_c.port, &sequence);

ret = adc_read(adc_vbus_c.port.dev, &sequence);
if (ret != 0) {
return ret;
}

*c = sample_buffer;
ret = adc_raw_to_millivolts_dt(&adc_vbus_c.port, c);
if (ret != 0) {
return ret;
}

/* prescaling the voltage offset */
*c -= adc_vbus_c.port.vref_mv / 2;
current_sense_amplifier_scale_dt(&adc_vbus_c, c);

return 0;
}

int meas_init(void)
{
int ret;

ret = adc_channel_setup_dt(&adc_vbus_v.port);
if (ret != 0) {
return ret;
}

ret = adc_channel_setup_dt(&adc_vbus_c.port);
if (ret != 0) {
return ret;
}

return 0;
}
36 changes: 36 additions & 0 deletions samples/boards/google_twinkie_v2_pda/src/meas.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2022 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __MEAS_H__
#define __MEAS_H__

/**
* @brief Initializes the measurement module, sets up all the adc channels through the device tree
* binding
*
* @return 0 on success
*/
int meas_init(void);

/**
* @brief Measure the voltage on VBUS
*
* @param v pointer where VBUS voltage, in millivolts, is stored
*
* @return 0 on success
*/
int meas_vbus_v(int32_t *v);

/**
* @brief Measure the current on VBUS
*
* @param c pointer where VBUS current, in milliamperes, is stored
*
* @return 0 on success
*/
int meas_vbus_c(int32_t *c);

#endif
118 changes: 118 additions & 0 deletions samples/boards/google_twinkie_v2_pda/src/view.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2022 The Chromium OS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/smf.h>
#include <zephyr/drivers/gpio.h>

#include <zephyr/device.h>

#include "meas.h"

/* The devicetree node identifier for the led aliases. */
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
#define LED2_NODE DT_ALIAS(led2)

static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
static const struct gpio_dt_spec led2 = GPIO_DT_SPEC_GET(LED2_NODE, gpios);

enum led_t {
LED_OFF,
LED_RED,
LED_GREEN,
LED_BLUE
};

static void set_led(enum led_t led)
{
switch (led) {
case LED_OFF:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 0);
break;
case LED_RED:
gpio_pin_set_dt(&led0, 1);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 0);
break;
case LED_GREEN:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 1);
gpio_pin_set_dt(&led2, 0);
break;
case LED_BLUE:
gpio_pin_set_dt(&led0, 0);
gpio_pin_set_dt(&led1, 0);
gpio_pin_set_dt(&led2, 1);
break;
}
}

int view_init(void)
{
int ret;

if (!device_is_ready(led0.port)) {
return -EIO;
}

if (!device_is_ready(led1.port)) {
return -EIO;
}

if (!device_is_ready(led2.port)) {
return -EIO;
}

ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}

ret = gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}

ret = gpio_pin_configure_dt(&led2, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return ret;
}

return 0;
}

#define CHARGING_VOLTAGE 5000
#define CHARGING_CURRENT 1000

void main(void)
{
meas_init();
view_init();

int32_t vbus_v = 0;
int32_t vbus_c = 0;

while (1) {
meas_vbus_v(&vbus_v);
meas_vbus_c(&vbus_c);

if (vbus_v > CHARGING_VOLTAGE) {
if (vbus_c > CHARGING_CURRENT) {
set_led(LED_GREEN);
} else {
set_led(LED_BLUE);
}
} else {
set_led(LED_RED);
}

k_usleep(500);
}
}

0 comments on commit 9557d88

Please sign in to comment.