pw_thread_freertos: update docs

Change-Id: I41c4252f884bccd8323c49ae8ddccbee76cd2741
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/45500
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_thread_freertos/docs.rst b/pw_thread_freertos/docs.rst
index 6628718..6633d1e 100644
--- a/pw_thread_freertos/docs.rst
+++ b/pw_thread_freertos/docs.rst
@@ -1,8 +1,157 @@
 .. _module-pw_thread_freertos:
 
-------------------
+==================
 pw_thread_freertos
-------------------
-This is a set of backends for pw_thread based on FreeRTOS. It is not ready for
-use, and is under construction.
+==================
+This is a set of backends for pw_thread based on FreeRTOS.
 
+.. contents::
+   :local:
+   :depth: 1
+
+.. Warning::
+  This module is still under construction, the API is not yet stable.
+
+-----------------------
+Thread Creation Backend
+-----------------------
+A backend for ``pw::thread::Thread`` is offered using ``xTaskCreateStatic()``.
+Optional dynamic allocation for threads is supported using ``xTaskCreate()``.
+Optional joining support is enabled via an ``StaticEventGroup_t`` in each
+thread's context.
+
+This backend always permits users to start threads where static contexts are
+passed in as an option. As a quick example, a detached thread can be created as
+follows:
+
+.. code-block:: cpp
+
+  #include "FreeRTOS.h"
+  #include "pw_thread/detached_thread.h"
+  #include "pw_thread_freertos/context.h"
+  #include "pw_thread_freertos/options.h"
+
+  pw::thread::freertos::StaticContextWithStack<42> example_thread_context;
+  void StartExampleThread() {
+    pw::thread::DetachedThread(
+        pw::thread::freertos::Options()
+            .set_name("static_example_thread")
+            .set_priority(kFooPriority)
+            .set_static_context(example_thread_context),
+        example_thread_function)
+  }
+
+Alternatively when ``PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED`` is
+enabled, dynamic thread allocation can be used. The above example could instead
+be done as follows:
+
+.. code-block:: cpp
+
+  #include "FreeRTOS.h"
+  #include "pw_thread/detached_thread.h"
+  #include "pw_thread_freertos/context.h"
+  #include "pw_thread_freertos/options.h"
+
+  void StartExampleThread() {
+    pw::thread::DetachedThread(
+        pw::thread::freertos::Options()
+            .set_name("dyanmic_example_thread")
+            .set_priority(kFooPriority)
+            .set_stack_size(42),
+        example_thread_function)
+  }
+
+
+Module Configuration Options
+============================
+The following configurations can be adjusted via compile-time configuration of
+this module, see the
+:ref:`module documentation <module-structure-compile-time-configuration>` for
+more details.
+
+.. c:macro:: PW_THREAD_FREERTOS_CONFIG_JOINING_ENABLED
+
+  Whether thread joining is enabled. By default this is disabled.
+
+  We suggest only enabling this when thread joining is required to minimize
+  the RAM and ROM cost of threads.
+
+  Enabling this grows the RAM footprint of every ``pw::thread::Thread`` as it
+  adds a ``StaticEventGroup_t`` to every thread's
+  ``pw::thread::freertos::Context``. In addition, there is a minute ROM cost to
+  construct and destroy this added object.
+
+  ``PW_THREAD_JOINING_ENABLED`` gets set to this value.
+
+.. c:macro:: PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED
+
+  Whether dynamic allocation for threads (stacks and contexts) is enabled. By
+  default this matches the FreeRTOS configuration on whether dynamic
+  allocations are enabled. Note that static contexts **must** be provided if
+  dynamic allocations are disabled.
+
+.. c:macro:: PW_THREAD_FREERTOS_CONFIG_DEFAULT_STACK_SIZE_WORDS
+
+   The default stack size in words. By default this uses the minimal FreeRTOS
+   stack size based on ``configMINIMAL_STACK_SIZE``.
+
+.. c:macro:: PW_THREAD_FREERTOS_CONFIG_DEFAULT_PRIORITY
+
+   The default stack size in words. By default this uses the minimal FreeRTOS
+   priority level above the idle priority (``tskIDLE_PRIORITY + 1``).
+
+FreeRTOS Thread Options
+=======================
+.. cpp:class:: pw::thread::freertos::Options
+
+  .. cpp:function:: set_name(const char* name)
+
+    Sets the name for the FreeRTOS task, note that this will be truncated
+    based on ``configMAX_TASK_NAME_LEN``. This is deep copied by FreeRTOS into
+    the task's task control block (TCB).
+
+  .. cpp:function:: set_priority(UBaseType_t priority)
+
+    Sets the priority for the FreeRTOS task. This must be a value between
+    ``tskIDLE_PRIORITY`` or ``0`` to ``configMAX_PRIORITIES - 1``. Higher
+    priority values have a higher priority.
+
+  .. cpp:function:: set_stack_size(size_t size_words)
+
+    Set the stack size in words for a dynamically thread.
+
+    This is only available if
+    ``PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED`` is enabled.
+
+    Precondition: size_words must be >= ``configMINIMAL_STACK_SIZE``
+
+  .. cpp:function:: set_static_context(pw::thread::freertos::Context& context)
+
+    Set the pre-allocated context (all memory needed to run a thread). The
+    ``StaticContext`` can either be constructed with an externally provided
+    ``std::span<StackType_t>`` stack or the templated form of
+    ``StaticContextWithStack<kStackSizeWords>`` can be used.
+
+
+-----------------------------
+Thread Identification Backend
+-----------------------------
+A backend for ``pw::thread::Id`` and ``pw::thread::get_id()`` is offerred using
+``xTaskGetCurrentTaskHandle()``. It uses ``DASSERT`` to ensure that it is not
+invoked from interrupt context and if possible that the scheduler has started
+via ``xTaskGetSchedulerState()``.
+
+--------------------
+Thread Sleep Backend
+--------------------
+A backend for ``pw::thread::sleep_for()`` and ``pw::thread::sleep_until()`` is
+offerred using ``vTaskDelay()`` if the duration is at least one tick, else
+``taskYIELD()`` is used. It uses ``pw::this_thread::get_id() != thread::Id()``
+to ensure it invoked only from a thread.
+
+--------------------
+Thread Yield Backend
+--------------------
+A backend for ``pw::thread::yield()`` is offered using via ``taskYIELD()``.
+It uses ``pw::this_thread::get_id() != thread::Id()`` to ensure it invoked only
+from a thread.
diff --git a/pw_thread_freertos/public/pw_thread_freertos/options.h b/pw_thread_freertos/public/pw_thread_freertos/options.h
index 921faa4..7a70d12 100644
--- a/pw_thread_freertos/public/pw_thread_freertos/options.h
+++ b/pw_thread_freertos/public/pw_thread_freertos/options.h
@@ -48,21 +48,24 @@
 
   // Sets the name for the FreeRTOS task, note that this will be truncated
   // based on configMAX_TASK_NAME_LEN.
+  // This is deep copied by FreeRTOS into the task's task control block (TCB).
   constexpr Options set_name(const char* name) {
     name_ = name;
     return *this;
   }
 
-  // Sets the priority for the FreeRTOS task, see FreeRTOS xTaskCreate for more
-  // detail.
+  // Sets the priority for the FreeRTOS task. This must be a value between
+  // tskIDLE_PRIORITY or 0 to configMAX_PRIORITIES - 1. Higher priority values
+  // have a higher priority.
   constexpr Options set_priority(UBaseType_t priority) {
     priority_ = priority;
     return *this;
   }
 
 #if PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED
-  // Set the stack size for dynamic thread allocations, see FreeRTOS xTaskCreate
-  // for more detail.
+  // Set the stack size of dynamic thread allocations.
+  //
+  // Precondition: size_words must be >= configMINIMAL_STACK_SIZE
   constexpr Options set_stack_size(size_t size_words) {
     PW_DASSERT(size_words >= config::kMinimumStackSizeWords);
     stack_size_words_ = size_words;