You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2020/04/09 15:14:04 UTC
[mynewt-documentation] branch master updated:
tutorials/other/chg_ctrl_on_pinetime: Add Charge Control on PineTime doc
This is an automated email from the ASF dual-hosted git repository.
janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-documentation.git
The following commit(s) were added to refs/heads/master by this push:
new a1d4dc1 tutorials/other/chg_ctrl_on_pinetime: Add Charge Control on PineTime doc
a1d4dc1 is described below
commit a1d4dc1525f2594f65fa132a64d7772f4e71cfa8
Author: Casper Meijn <ca...@meijn.net>
AuthorDate: Tue Mar 31 16:46:10 2020 +0200
tutorials/other/chg_ctrl_on_pinetime: Add Charge Control on PineTime doc
---
docs/tutorials/other/chg_ctrl_on_pinetime.rst | 367 ++++++++++++++++++++++++++
docs/tutorials/other/other.rst | 4 +-
2 files changed, 370 insertions(+), 1 deletion(-)
diff --git a/docs/tutorials/other/chg_ctrl_on_pinetime.rst b/docs/tutorials/other/chg_ctrl_on_pinetime.rst
new file mode 100644
index 0000000..0f6471d
--- /dev/null
+++ b/docs/tutorials/other/chg_ctrl_on_pinetime.rst
@@ -0,0 +1,367 @@
+..
+ #
+ # Copyright 2020 Casper Meijn <ca...@meijn.net>
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ #
+
+Charge control on PineTime
+===========================================
+
+This tutorial shows you how to get the charge control status on PineTime smartwatch.
+
+.. contents::
+ :local:
+ :depth: 2
+
+Prerequisites
+~~~~~~~~~~~~~
+
+Ensure that you meet the following prerequisites before continuing with
+this tutorial:
+
+- Follow :doc:`Blinky on PineTime tutorial <../blinky/pinetime>` to create a
+ project with a basic application. You will extend that application in this
+ tutorial.
+- Make sure you have the charger input available. This can either be a fully
+ assembled PineTime (but this prevent you from accessing the SWD pins) or by
+ mounting a wire to the 5V charger pad.
+
+Charger hardware
+~~~~~~~~~~~~~~~~
+
+First a few words about the PineTime hardware. The PineTime smartwatch uses a
+SGM4056 charger chip. The chip gets it's power from the USB port via the
+charging pads at the back of the watch. The charger takes care of battery
+maintenance by providing the correct voltage and current during the charging
+process.
+
+The charger is connected to the main processor via two GPIO pins. This way the
+charger can report it's current charging state:
+
+- no source connected,
+- charging or
+- source connected but not charging.
+
+This tutorial will show you how to obtain this status.
+
+SGM4056 Driver
+~~~~~~~~~~~~~~
+
+Communication with the charger is done by the :doc:`SGM4056 Driver <../../os/modules/drivers/chg_ctrl/sgm4056>`.
+This abstracts the hardware and provides a simple interface to the charger. The :doc:`PineTime BSP <../../os/bsp/pinetime>`
+already initializes the driver, so we can use it directly in our the application.
+Let's extend the application with the following code:
+
+.. code-block:: c
+ :emphasize-lines: 1-2, 10-11, 20-22, 33-35, 37-39
+
+ #include "sgm4056/sgm4056.h"
+ #include "console/console.h"
+
+ ...
+
+ int
+ main(int argc, char **argv)
+ {
+ int rc;
+ struct sgm4056_dev *charger;
+ charge_control_status_t charger_status;
+
+ ...
+
+ sysinit();
+
+ g_led_pin = LED_BLINK_PIN;
+ hal_gpio_init_out(g_led_pin, 1);
+
+ /* Open charger device */
+ charger = (struct sgm4056_dev *) os_dev_open("charger", 0, 0);
+ assert(charger);
+
+ while (1) {
+ ++g_task1_loops;
+
+ /* Wait one second */
+ os_time_delay(OS_TICKS_PER_SEC);
+
+ /* Toggle the LED */
+ hal_gpio_toggle(g_led_pin);
+
+ /* Get charger state */
+ rc = sgm4056_get_charger_status(charger, &charger_status);
+ assert(rc == 0);
+
+ /* Print charger state */
+ console_printf("Charger state = %i\n", charger_status);
+ console_flush();
+ }
+ assert(0);
+
+ return rc;
+ }
+
+First we added a include file for the ``sgm4056`` driver and the console
+interface for output.
+
+We define a pointer to a ``sgm4056_dev`` charger device and a variable for
+the actual charger status.
+
+Then we open the charger device using ``os_dev_open``. This will get the driver
+instance that was initialized by the BSP.
+
+In the while loop we ask the driver to get the charger state and print it to
+the console as an number.
+
+Let's run this code on the device and watch the output of the console:
+
+.. code-block:: console
+
+ $ newt run blinky-pinetime 0
+
+.. code-block::
+
+ Charger state = 2
+ Charger state = 2
+ Charger state = 2
+ ...
+
+.. warning::
+
+ Currently the PineTime BSP doesn't support the serial console properly.
+ Therefore you need to setup ARM semihosting manually in the application to
+ make these instructions work. These step are beyond the scope of this tutorial.
+
+If you connect or disconnect the charger input, you will see the number changes.
+However it is not yet clear what the number actually means. Let's make that
+output more useful:
+
+.. code-block:: c
+ :emphasize-lines: 3-21, 30
+
+ ...
+
+ char * get_charger_status_string(charge_control_status_t status) {
+ static char * no_source_string = "no source detected";
+ static char * charging_string = "charging";
+ static char * complete_string = "charge completed";
+ switch (status)
+ {
+ case CHARGE_CONTROL_STATUS_NO_SOURCE:
+ return no_source_string;
+
+ case CHARGE_CONTROL_STATUS_CHARGING:
+ return charging_string;
+
+ case CHARGE_CONTROL_STATUS_CHARGE_COMPLETE:
+ return complete_string;
+
+ default:
+ return NULL;
+ }
+ }
+
+ ...
+
+ main(int argc, char **argv)
+ {
+ ...
+
+ /* Print charger state */
+ console_printf("Charger state = %s\n", get_charger_status_string(charger_status));
+ console_flush();
+
+ ...
+ }
+
+This adds a function for converting the status enum to a text and then it uses
+that to output a text representation of the state.
+
+Let's run this improved code and connect the charger:
+
+.. code-block:: console
+
+ $ newt run blinky-pinetime 0
+
+.. code-block::
+
+ Charger state = no source detected
+ Charger state = no source detected
+ Charger state = no source detected
+ Charger state = charging
+ Charger state = charging
+ Charger state = charging
+
+Great, that is more like it. This code can be used to make a great smartwatch
+application. However I think we can do better.
+
+Charge control
+~~~~~~~~~~~~~~
+
+The code of the last section works great, however it is very specific to the
+SGM4056 driver. Luckily we can fix that using the :doc:`Charge Control interface <../../os/modules/drivers/chg_ctrl/chg_ctrl>`.
+This is enabled by default for the SGM4056 driver, so we don't need to do any
+configuration for using this new interface.
+
+Charge control works with callbacks for reporting the status. Let's start with
+adding our callback to the application.
+
+.. code-block:: c
+ :emphasize-lines: 1, 5-16
+
+ #include "charge-control/charge_control.h"
+
+ ...
+
+ static int
+ charger_data_callback(struct charge_control *chg_ctrl, void *arg,
+ void *data, charge_control_type_t type)
+ {
+ if (type == CHARGE_CONTROL_TYPE_STATUS) {
+ charge_control_status_t charger_status = *(charge_control_status_t*)(data);
+
+ console_printf("Charger state = %s\n", get_charger_status_string(charger_status));
+ console_flush();
+ }
+ return 0;
+ }
+ ...
+
+First we include the ``charge_control.h`` header for the correct types. Then we
+define the callback, which is of the type ``charge_control_data_func_t``.
+
+The first argument is the a pointer to ``charge_control``. This is a
+representation of the charger. The second argument is a arg pointer. We will
+find out later where these two come from.
+
+The third and fourth argument are a pointer to the actual data and a indication
+of the type of data. This callback can only handle status data of type
+``CHARGE_CONTROL_TYPE_STATUS``. After checking that, we convert the data to the
+correct type and print it like in the previous section.
+
+Now we need to change the ``main`` function to actually call the callback:
+
+.. code-block:: c
+ :emphasize-lines: 5, 9-11, 16-20
+
+ int
+ main(int argc, char **argv)
+ {
+ int rc;
+ struct charge_control *charger;
+
+ ...
+
+ /* Open charger device */
+ charger = charge_control_mgr_find_next_bytype(CHARGE_CONTROL_TYPE_STATUS, NULL);
+ assert(charger);
+
+ while (1) {
+ ...
+
+ /* Get charger state */
+ rc = charge_control_read(charger, CHARGE_CONTROL_TYPE_STATUS,
+ charger_data_callback, NULL, OS_TIMEOUT_NEVER);
+ assert(rc == 0);
+ }
+ assert(0);
+
+ return rc;
+ }
+
+There are a few important changes:
+
+- The type of ``charger`` has changed. We now use the generic type
+ ``charge_control``, which will work for all charger drivers. Notice that
+ this is the same type as the first argument as the callback.
+- We don't open a OS device anymore, instead we call the Charge Control Manager
+ and ask for the first charger that supports ``CHARGE_CONTROL_TYPE_STATUS``.
+ Notice that this is the same type as in the callback function.
+- Then we execute a read on the ``charger``, for data of type
+ ``CHARGE_CONTROL_TYPE_STATUS``. When finished we want to it to call our callback
+ with the argument ``NULL`` and we disable the timeout.
+
+When you run this code, you will get the same results as the previous run,
+however this code will work with any charger.
+
+Charger interrupt
+~~~~~~~~~~~~~~~~~
+
+One of the advantages of charge control is that it supports interrupt-driven
+notifications. This reduces polling and therefore reduces power usage. This
+requires a few small changes to our application:
+
+.. code-block:: c
+ :emphasize-lines: 2-5, 21-23, 25-27, 30-31
+
+ ...
+ struct charge_control_listener charger_listener = {
+ .ccl_type = CHARGE_CONTROL_TYPE_STATUS,
+ .ccl_func = charger_data_callback,
+ };
+
+ ...
+
+ int
+ main(int argc, char **argv)
+ {
+ int rc;
+ struct charge_control *charger;
+
+ ...
+
+ /* Open charger device */
+ charger = charge_control_mgr_find_next_bytype(CHARGE_CONTROL_TYPE_STATUS, NULL);
+ assert(charger);
+
+ /* Set polling rate */
+ rc = charge_control_set_poll_rate_ms("charger", 10000);
+ assert(rc == 0);
+
+ /* Register charger callback */
+ rc = charge_control_register_listener(charger, &charger_listener);
+ assert(rc == 0);
+
+ while (1) {
+ /* No charger code needed here */
+ os_eventq_run(os_eventq_dflt_get());
+ }
+ assert(0);
+
+ return rc;
+ }
+
+First we need to define a ``charge_control_listener`` structure, this points to
+the callback function and indicates the type of data we are interested in. It
+could also define the argument, but in this example we are not interested in that.
+
+Then we need to set a polling rate, which we can set high as most changes are
+reported by interrupt. Lastly we register the listener to actually receive the
+callbacks.
+
+There is no charger code needed in the while loop. However we need the event queue
+to be handled as charge control will use events to do the polling and interrupt
+handling. Note that you need to remove the ``os_time_delay`` to make the events
+work properly.
+
+Run this code and you see that the charger state is only show every ten seconds.
+But when you connect the charger you see the output directly. This shows the
+combination of polling and interrupt-based data acquisition.
+
+Conclusion
+~~~~~~~~~~
+
+You now have an efficient charger status reading application. It will work with
+any charger driver, not just the one in the PineTime. It uses interrupts to be
+notified of changes quickly. The next step is to integrate this into your own
+project.
diff --git a/docs/tutorials/other/other.rst b/docs/tutorials/other/other.rst
index f475078..b49df30 100644
--- a/docs/tutorials/other/other.rst
+++ b/docs/tutorials/other/other.rst
@@ -6,4 +6,6 @@ Other
How to reduce Application Code Size <codesize>
Write a Test Suite for a Package <unit_test>
- Enable Wi-Fi on Arduino MKR1000 <wi-fi_on_arduino>
\ No newline at end of file
+ Enable Wi-Fi on Arduino MKR1000 <wi-fi_on_arduino>
+ chg_ctrl_on_pinetime
+
\ No newline at end of file