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 <cas...@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 <cas...@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

Reply via email to