Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -0,0 +1 @@
# Design Documents - Platform

View File

@@ -0,0 +1,418 @@
# Mbed OS clocks
# Table of contents
1. [Mbed OS clocks](#mbed-os-clocks).
1. [Table of contents](#table-of-contents).
1. [Revision history](#revision-history).
1. [Introduction](#introduction).
1. [Overview and background](#overview-and-background).
1. [Requirements and assumptions](#requirements-and-assumptions).
1. [System architecture and high-level design](#system-architecture-and-high-level-design).
1. [Which clock to use?](#which-clock-to-use).
1. [Detailed design](#detailed-design).
1. [Accessing Chrono APIs](#accessing-chrono-apis)
1. [The RTOS clock](#the-rtos-clock)
1. [High-resolution and low-power clocks](#high-resolution-and-low-power-clocks)
1. [The real-time clock](#the-real-time-clock)
1. [Comparison to standard C++ Chrono clocks](#comparison-to-standard-c++-chrono-clocks)
1. [Usage scenarios and examples](#usage-scenarios-and-examples).
1. [Using the RTOS clock](#using-the-rtos-clock)
1. [Using the high-resolution clock](#using-the-high-resolution-clock)
1. [Using the real-time clock](#using-the-real-time-clock)
1. [Being more generic](#being-more-generic)
1. [Other information](#other-information).
1. [Deprecations](#deprecations).
1. [References](#references).
### Revision history
1.0 - Initial revision (Mbed OS 6.0) - Kevin Bracey - 03 Mar 2020
# Introduction
### Overview and background
Mbed OS 6.0 provides a set of timing APIs that use C++'s `<chrono>` library. This provides strong typing for measuring time durations (`std::chrono::duration`) and time points (`std::chrono::time_point`). Previous APIs based on integer types are deprecated.
### Requirements and assumptions
The new API relies on C++14 to provide the library functions, and allow duration constants like `200ms`. Mbed OS 6.0 generally requires a C++14 or later toolchain, so the Chrono API is now possible. Some core APIs are also provided in C form.
# System architecture and high-level design
Mbed OS has four primary central clocks:
- The RTOS clock. This is managed by the RTOS if present, else based on a HAL clock, and has millisecond resolution.
- The high-resolution clock (`us_ticker`). This is provided by the target's HAL, and has approximately microsecond resolution. It does not run in deep sleep, so its users will usually lock deep sleep.
- The low-power clock (`lp_ticker`). This is provided by most targets' HAL, and has sub-millisecond resolution. It continues to run in deep sleep.
- The real-time clock. This is provided by some targets' HAL, often runs when the main CPU does not, and has one-second resolution.
The way these APIs map to hardware varies by target. In some cases, they may use four distinct peripherals, but often they share hardware.
Capabilities and uses of the clocks vary, but they all share the need to describe time points and durations, and as such use the `time_point` and `duration` template types from `<chrono>` to provide strongly-typed APIs.
### Which clock to use?
In many higher-level APIs, you do not directly specify a clock - for example `EventQueue` just takes relative times, with no direct indication of the clock being used. But when implementing such code, you will need to make a choice.
1. As an application, you should by default use the RTOS clock. This is the most general-purpose clock, with the best scheduling capability, and the API is available even in a bare-metal build.
1. If higher-resolution timing is required, then you can use the high-resolution clock. But this does mean locking deep sleep.
1. If real calendar/wall-clock time is required, then you can use the real-time clock. You may want to combine its use with another clock to get better-than-second resolution or event scheduling.
1. The low-power clock should not normally be used to schedule events. It is only really recommended as a slightly-higher-resolution time-point clock than the RTOS millisecond clock (4kHz to 64kHz). But it cannot be easily used for event scheduling as care must be taken to compensate for deep sleep wake latency, which is usually multiple milliseconds. Such latency compensation is included in the RTOS timing system.
`EventQueue` is a case study in API choice - previously it used the RTOS clock in RTOS builds and the low-power clock in bare-metal builds (because the RTOS clock was not available). It now uses the RTOS clock in all builds, meaning it now gets deep sleep wake latency compensation in bare metal builds too.
# Detailed design
### The RTOS clock
**API description**
The RTOS tracks time at millisecond resolution, and this clock is exposed in C++ form as `Kernel::Clock`.
All other RTOS APIs that use time, such as `ThisThread::sleep_for`, `Semaphore::try_acquire_for` and `EventFlags::wait_any_until` use this clock.
Unlike direct use of the low-power clock, RTOS wake events compensate for deep sleep latency. So requesting `ThisThread::sleep_for(10ms)` will wake after 10ms, even if it causes deep sleep and there is a 4ms wake delay from deep sleep.
The RTOS clock is the best general-purpose clock for most use cases. Subsystems such as `EventQueue` use the RTOS timing APIs internally.
The RTOS clock API and a subset of other RTOS APIs are available in bare-metal builds even when an actual RTOS is not present.
**RTOS clock generation**
There are three current ways that the system can produce the RTOS clock:
* The RTOS can use a dedicated millisecond ticker such as the SysTick peripheral. This ticker always runs, and deep sleep does not occur while the RTOS is active, unless manually requested by the application.
* The RTOS can be in "tickless" mode, where ticks and wake-ups from idle periods are generated using the low-power clock. Deep sleep is entered whenever idle, if it is unlocked and there is sufficient time before the next scheduled wake.
* The system is built as "bare-metal", so there is no actual RTOS. A subset of RTOS APIs are implemented using the low-power clock.
When there is an actual RTOS, the timing system is always present in the build, so it's a sunk cost. In a bare-metal build, the timer is not necessarily needed - it will be included in the build and started if used. The separation of APIs into distinct untimed and timed forms like `Mutex::try_lock` and `Mutex::try_lock_for` are intended to help exclude timer code from bare-metal builds.
### High-resolution and low-power clocks
The high-resolution and low-power clocks share a common API and implementation, so are described together.
Both present themselves via a microsecond-based API. The high-resolution clock has at least 250kHz (4us) resolution, and the low-power clock has 4kHz-64kHz (16us-250us) resolution, depending on target.
Aside from the resolution, key differences are:
* The high-resolution clock does not operate in deep sleep, so deep sleep must be locked to keep it running, affecting power consumption. It should normally only be used for measuring short times while the device is active. Unless the high resolution is needed, the RTOS timing APIs are preferable.
* The low-resolution clock permits deep sleep, so clock-timed wake-ups can suffer from deep sleep wake-up latency delays. It does not compensate for these, so a `LowPowerTimeout` requested for 10ms could easily wake up after 14ms. The RTOS timing APIs are usually preferable.
**API description**
At the lowest level, these clocks are obtained by calling `get_us_ticker data`or `get_lp_ticker_data`, and
using the returned `ticker_data_t *` with the C functions in `ticker_api.h`.
The underlying `ticker_data` can describe hardware clocks that can have varying bit-width and frequency. Each clock provides one single-shot interrupt.
The C ticker API functions convert the underlying clock to an absolute 64-bit microsecond timebase, and add a queue for registering multiple single-shot events. Interrupts are automatically scheduled before the underlying clock wraps to update the long-term 64-bit timebase.
The classes `HighResClock`, and `LowPowerClock` act as Chrono clock interfaces for the two primary clocks.
* `HighResClock`: reads `us_ticker` and provides manual locks for deep sleep; it is steady while locked.
* `LowPowerClock`: reads `lp_ticker`; the clock is inherently steady, but provides dummy lock methods to keep the same API as `HighResClock`.
If using the high-resolution clock, to save power it should only be run when necessary, which means using `HighResClock`'s `lock` and `unlock` methods to indicate when it is required.
Higher-level clock functions are provided via the following classes:
* `Timer` / `LowPowerTimer`: acts like a stopwatch for elapsed time - can be stopped, started and reset
* `Ticker` / `LowPowerTicker`: calls a callback from interrupt context periodically
* `Timeout` / `LowPowerTimeout`: calls a callback from interrupt context once
The classes without the `LowPower` prefix are the high-resolution ones; they should arguably be named `HighResTimer`, and so on.
Unlike direct clock access, those high-level classes always handle deep sleep locking automatically for the high-resolution clock. Deep sleep is locked whenever a high-resolution `Timer` is running, or when a `Ticker` or `Timeout` callback is pending, and it is unlocked when stopped, removed or destroyed.
**Other ticker_data_t clocks**
There is also a generic `TickerDataClock` which provides a Chrono Clock wrapper for a `ticker_data *`, so that `TickerDataClock::time_point` can be used to express absolute times for arbitrary clocks.
Note that the `TickerDataClock` is a non-standard Chrono clock, in that its `now` method is non-static. The Chrono type-checking will not detect that `TickerDataClock::time_point`s for different tickers are not interchangable. It is generally preferable to use the dedicated `HighResClock` or `LowPowerClock`, but `TickerDataClock` is used by some generic code, to avoid template bloat from separate code for each Clock.
The base classes `TimerBase`, `TickerBase` and `TimeoutBase` use `TickerDataClock` to provide the core of the high-level implementation, and these are then used to provide the separate strongly-typed high-resolution and low-power classes above.
Systems wishing to provide more HAL clocks beyond the basic two can use the same framework to give that clock its own custom `Clock/Timer/Ticker/Timeout` set of classes, using the base classes.
### The real-time clock
The real-time clock, if available, provides calendar date and time information, at one-second resolution. The RTC can continue to run while the CPU does not.
The C APIs in `rtc_api.h` read and write the time as a C `time_t`.
The class `RealTimeClock` provides a wrapper that acts as a Chrono clock, so that `RealTimeClock::time_point`can be used to express absolute real time.
The methods `to_time_t` and `from_time_t` convert to and from C `time_t`.
At present there are no other APIs using `RealTimeClock`, and no real-time-based wake or alarm facility, so utility is limited, but the class has been created for framework symmetry with the other clocks.
### Comparison to standard C++ Chrono clocks
Mbed OS does not provide the standard C++11 Chrono Clocks, as it is not possible to provide consistent behaviour across the various toolchains and libraries supported. Here's a suggested mapping from the 3 standard C++ Clocks to Mbed OS.
**std::chrono::steady_clock**
`std::chrono::steady_clock` represents a clock for which values of `time_point` never decrease as physical time advances and for which values of `time_point` advance at a steady rate relative to real time.
`Kernel::Clock` can be used in place of `std::chrono::steady_clock` for general use.
For slightly higher timestamp resolution you can use `LowPowerClock`, but if attempting to schedule time events, using RTOS APIs with `Kernel::Clock` will often work better due to the RTOS's deep sleep wake latency compensation.
If high resolution is required, you can use `HighResClock`, as long as the lock is held while in use to keep it steady.
**std::chrono::high_resolution_clock**
`std::chrono::high_resolution_clock` represents the clock with the shortest tick period.
`HighResClock` is the best choice for a high-resolution clock, but it will not run during deep sleep. You can use `HighResClock::lock` to keep it running, or otherwise ensure that deep sleep is locked.
**std::chrono::system_clock**
`std::chrono::system_clock` represents wall clock time from the system-wide realtime clock.
`RealTimeClock` can be used in place of `std::chrono::system_clock`, and provides the same `to_time_t` and `from_time_t` methods. However, unlike many implementations, its resolution is only seconds.
# Usage scenarios and examples
### Accessing Chrono APIs
Using the Chronos API needs a little thought about namespaces. This section covers that; the following sections will assume the complete Chrono API has been imported.
By default C++14 duration literals will be available after including `mbed.h` due to it including files that use `<chrono>` and having a `using namespace std` directive:
```C++
#include "mbed.h"
auto delay = 5ms;
```
If `MBED_NO_GLOBAL_USING_DIRECTIVE` is defined, or you are not including `mbed.h`, you will need your own directive, and possibly own include, to use the literals:
```C++
#include <chrono>
using namespace std::chrono_literals;
auto delay = 5ms;
```
All Chrono APIs are in the namespace `std::chrono`, so it can be convenient to have a directive to import this complete namespace to reduce typing:
```C++
#include <chrono>
using namespace std::chrono; // provides both types like std::chrono::microseconds and the chrono_literals
microseconds t = 1h;
printf("1 hour is %d us\n", int(t.count()));
```
Namespace directives should only be used in source files to avoid unexpected name collision for users. Header files intended for general use will need to fully qualify their use of Chrono with `std::chrono` prefixes. This also precludes use of literals:
```C++
// In a header file
#include <chrono>
void my_function(std::chrono::microseconds timeout = std::chrono::seconds{1});
```
### Using the RTOS clock
**Basic delays**
```C++
for (;;) {
LED1 = !LED1;
ThisThread::sleep_for(500ms);
}
```
**Prefer absolute time**
Using absolute time aids precision, guaranteeing that there is no drift due to code execution time. This applies to all clocks.
```C++
auto next_wake = Kernel::Clock::now();
for (;;) {
LED1 = !LED1;
next_wake += 500ms;
ThisThread::sleep_until(next_wake);
}
```
Periodic callback APIs such as `Ticker` or `EventQueue::call_every` use this mechanism. If manually rescheduling events yourself, you should use the same technique, rather than using `call_in` within a callback.
**Measuring elapsed time via the RTOS**
```C++
auto start = Kernel::Clock::now(); // type will be Kernel::Clock::time_point
do_operation();
milliseconds elapsed_time = Kernel::Clock::now() - start;
printf("elapsed time = %d ms\n", int(elapsed_time.count()));
```
Explicitly stating that `elapsed_time` is `milliseconds` provides a cross-check that the `count()` for the print really is milliseconds. If the clock had lower resolution, it would be implicitly converted to milliseconds. If the clock had higher resolution, it would be a compilation error - see "being more generic" below to handle this.
### Using the high-resolution clock
**Measuring elapsed time using Timer**
```C++
template<class F>
microseconds time_operation(const F &operation)
{
Timer timer;
timer.start(); // deep sleep is automatically locked while timer is running
operation();
return timer.elapsed_time();
} // Deep sleep automatically unlocked when timer is destroyed.
microseconds print_time = time_operation([] { printf("Hello!\n"); });
printf("Printing that took %d us\n", int(print_time.count()));
```
This example relies on the destruction of the timer to unlock the clock. If using a timer that doesn't get destroyed, you must remember to stop it manually to allow deep sleep to be entered again.
**Recording high-resolution time points**
```C++
HighResClock::lock(); // take lock to ensure clock is steady (by preventing deep sleep)
auto t1 = HighResClock::now();
do_operation1();
auto t2 = HighResClock::now();
do_operation2();
auto t3 = HighResClock::now();
HighResClock::unlock();
microseconds total = t3 - t1;
microseconds stage1 = t2 - t1;
microseconds stage2 = t3 - t2;
printf("total time = %d us\n", int(total.count()));
printf("stage 1 time = %d us\n", int(stage1.count()));
printf("stage 2 time = %d us\n", int(stage2.count()));
```
**Blinking an LED at 1kHz**
```C++
Ticker ticker;
ticker.attach([] { LED1 = !LED1; }, 500us);
```
### Using the real-time clock
**Logging times**
```C++
auto woken = RealTimeClock::now();
time_t t = RealTimeClock::to_time_t(woken);
printf("Woken at %s", ctime(&t));
do_work();
t = RealTimeClock::to_time_t(woken + 3h);
printf("Sleeping until %s", ctime(&t));
ThisThread::sleep_for(3h);
```
Note that RTOS APIs currently only accept RTOS time points, which is why the above example uses `sleep_for`; you would get a compile error for `ThisThread::sleep_until(woken + 3h)`. If the work took a long time, then the schedule would drift away from a regular 3 hour period. See next example for an absolute-time-based approach.
**Making helpers to combine clocks**
The above example could be adapted to use absolute wake times with a helper function, guaranteeing a regular 3-hour period, regardless of how long the work takes:
```C++
void sleep_until_rtc(RealTimeClock::time_point abs_time)
{
auto rel_time = abs_time - RealTimeClock::now();
ThisThread::sleep_until(Kernel::Clock::now() + rel_time);
}
auto woken = RealTimeClock::now();
time_t t = RealTimeClock::to_time_t(woken);
printf("Woken at %s", ctime(&t));
do_work();
auto wake = woken + 3h;
t = RealTimeClock::to_time_t(wake);
printf("Sleeping until %s", ctime(&t));
sleep_until_rtc(wake);
```
Note that `sleep_until_rtc` would not respond to any adjustments made to `RealTimeClock` made while sleeping.
### Being more generic
**Allowing choice of clock**
As the high-resolution and low-power clocks provide the same API, code can be written generically to work with either clock. For example:
```C++
#ifdef USE_HIGHRES_CLOCK // or Clock could be a template parameter
using Clock = HighResClock;
#else
using Clock = LowPowerClock;
#endif
Clock::lock(); // will lock deep sleep if high-res clock, else no-op
auto t1 = Clock::now();
do_operation1();
auto t2 = Clock::now();
do_operation2();
auto t3 = Clock::now();
Clock::unlock();
microseconds total = t3 - t1;
microseconds stage1 = t2 - t1;
microseconds stage2 = t3 - t2;
printf("total time = %d us\n", int(total.count()));
printf("stage 1 time = %d us\n", int(stage1.count()));
printf("stage 2 time = %d us\n", int(stage2.count()));
```
This same code would actually also work with `Kernel::Clock` and `RealTimeClock`, due to the care taken with the types, including explicit use of `microseconds`. For more details, see next section.
**Coping with different resolutions**
At present, the clocks have specified periods: seconds, milliseconds or microseconds. Chrono prevents any errors being made by mixing different-resolution clocks at compile time, except when entering or leaving the Chrono domain by constructing a `duration` or using `duration::count()`.
In principle, the periods of these clocks could be changed in future, for example to make `HighResClock` match the native hardware rate. Generic code itself may want to select between RTOS and high-resolution clocks which have different periods. To support both cases you may want to write code that always works and compiles regardless of resolution.
The basic rule is that Chrono conversions are implicit if they don't lose precision. So `milliseconds d = t1 - t2;` will work when `t1` and `t2` have millisecond precision or lower. If they were `RealTimeClock::time_point`s measured in seconds, then there would be an automatic multiplication by 1000 to convert rates. To permit precision-losing conversions, such as dividing by 1000, you need use `duration_cast` or `time_point_cast`.
Guidelines:
* use `auto` for your variables to match the clock you're using; don't convert to a specific representation unless necessary
* use `duration_cast` to round to a particular precision
* use templates to accept any resolution and round (see references for examples)
Here is the high-res timer example from above adjusted to still compile if the high-res timer was increased to higher than microsecond resolution:
```C++
Timer timer;
timer.start();
do_operation();
auto elapsed_time = duration_cast<microseconds>(timer.elapsed_time()); // rounds down
printf("elapsed time = %d us\n", int(elapsed_time.count()));
```
If the timer actually is microseconds, then this cast does not actually need to generate any code.
# Other information
### Deprecations
Many older C++ APIs using integer or float time repres are deprecated in favour of the Chrono APIs.
These include:
* `Kernel::get_ms_count`
* `Semaphore::try_acquire_for(uint32_t)` and similar RTOS functions
* `Semaphore::try_acquire_until(uint64_t)` and similar RTOS functions
* `Timer::read`
* `Timer::read_ms`
* `Timer::read_us`
* `Timer::read_high_resolution_us`
* `Timer::operator float`
* `Ticker::attach(F, float)`
* `Ticker::attach_us(Callback, us_timestamp_t )`
* `EventQueue::call_in(int, ...)`
* `EventQueue::call_every(int, ...)`
### References
General Chrono background:
* [N2661 - original C++ proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm)
* [Video: CppCon 2016: Howard Hinnant “A \<chrono\> Tutorial"](https://www.youtube.com/watch?v=P32hvk8b13M)
* [Introduction to std::chrono](http://rachelnertia.github.io/programming/2018/01/07/intro-to-std-chrono/)

View File

@@ -0,0 +1,300 @@
# Crash Reporting
# Table of contents
- [Crash Reporting](#crash-reporting)
- [Table of contents](#table-of-contents)
- [Revision history](#revision-history)
- [Introduction](#introduction)
- [Overview and background](#overview-and-background)
- [Requirements and assumptions](#requirements-and-assumptions)
- [System architecture and high-level design](#system-architecture-and-high-level-design)
- [System architecture and component interaction](#system-architecture-and-component-interaction)
- [Detailed design](#detailed-design)
- [Usage scenarios and examples](#usage-scenarios-and-examples)
- [Tools and configuration changes](#tools-and-configuration-changes)
- [Other information](#other-information)
- [Reusability](#reusability)
- [Deprecations](#deprecations)
- [References](#references)
### Revision history
1.0 - Initial version - Senthil Ramakrishnan - 10/22/2018
# Introduction
### Overview and background
MbedOS currently implements error/exception handlers which gets invoked when the system encounters a fatal error or processor exceptions. The error and exception handlers capture information such as type of error, location of error, register context, thread info etc and these are valuable information required to debug the problem later. This information is currently printed over the serial port, but in many cases the serial port is not accessible and the serial terminal log is not captured, particularly in the case of field deployed devices. We cannot save this information by sending it over network or writing to a file, as the state of the system might be unstable after the fatal error. And thus a different mechanism is needed to record and report this data. The idea here is to auto-reboot the system after a fatal error has occurred to bring the system back in stable state, without losing the RAM contents where we have the error information collected, and we can then save this information reliably to be logged externally(E.g:- ARM Pelion cloud) or can be written to file system.
### Requirements and assumptions
This feature requires 256 bytes of dedicated RAM allocated for storing the error and fault context information.
Following are some common terminologies used in this document:
Fault exception - This refers to processor exceptions such as HardFault, BusFault, MemManage fault or Usage fault.
Fatal error - This refers to any error reported by calling mbed_error().
Crash - This refers to the scenario where a fault exception or fatal error leading to system error handler(mbed_error()) being invoked.
# System architecture and high-level design
Below are the high-level goals for "Crash Reporting" feature:
**Error information collection including fault exception context**
The current error handling implementation in MbedOS already collects error and fault exception context. With this feature the above mentioned data structures should be placed in an uninitialized RAM region so that the data is retained after an auto-reboot(warm-reset).
**Mechanism to auto reboot(also called warm-reset) the system without losing RAM contents where error info is stored**
Implement auto-reboot functionality to reboot the system automatically after a fatal error. Note that the auto-reboot feature should be configurable.
**Mechanism to retrieve the error data after reboot**
Provide platform APIs to read the saved error information after reboot.
**Mechanism to report the error data after reboot**
During reboot the system should check if the reboot is caused by a fatal error and report the same using callback mechanism.
**Implementation should provide a mechanism to prevent constant reboot loop by limiting the number of auto-reboots**
System should implement mechanism to track number of times the system has auto-rebooted and be able to stop auto-reboot when a configurable limit is reached. That is, once the limit is reached the application main()
will not be entered and the system will halt execution.
**Implementation should provide following configuration options**
1. Configuration option to enable or disable this feature
1. Configuration option to enable or disable auto-reboot when the system enters a fatal error scenario
1. Configuration option to limit the number of auto-reboots
### System architecture and component interaction
The below diagram shows overall architecture of crash-reporting implementation.
![System architecture and component interaction](./diagrams/crash-report-seq.jpg)
As depicted in the above diagram, when the system gets into fatal error state the information collected by error and fault handlers are saved into RAM space allocated for Crash-Report. This is followed by a auto-reboot triggered from error handler. On reboot the the initialization routine validates the contents of Crash-Report space in RAM. This validation serves two purposes - to validate the captured content itself and also it tells the system if the previous reboot was caused by a fatal error. It then reads this information and calls an application defined callback function passing the crash-report information. The callback is invoked just before the entry to main() and thus the callback implementation may access libraries and other resources as other parts of the system have already initialized(like SDK, HAL etc) or can just capture the error information in application space to be acted upon later.
# Detailed design
### Error information collection including fault exception context
Current error and fault-exception handling implementation in Mbed OS already collects error and fault-exception context. But currently these data structures are implemented as statically allocated memory locations. With this feature these data structures should be placed in an uninitialized RAM region so that the data is retained after auto-reboot(warm-reset). So, this should be allocated as a dedicated region using linker command file(or in scatter file) for the corresponding target for each toolchain. Also note that this region should be marked as uninitialized region(not zero initialized) using the right toolchain attributes. For example, for ARM compiler we can define a new section as below:
```
RW_m_crash_data m_crash_report_ram_start EMPTY m_crash_report_ram_size { ; Dedicated Region to store crash report data m_crash_report_ram_size = 256 bytes
}
```
Note that the actual location of the data should be carefully chosen without affecting the current usage of other regions such as interrupt table region, flash configuration area etc. The absolute location of this Crash-Report RAM region may also differ for each target. The size of this RAM region should be 256 bytes. And internally the implementation would use the 256 byte region as two sub-areas with 128 bytes each. The upper 128 bytes will be used to store the fault context and the lower 128 bytes for error context, as shown in the diagram below.
![Crash report region](./diagrams/crash-report-region.jpg)
### Mechanism to auto reboot(also called warm-reset) the system without losing RAM contents where error info is stored
The current mbed_error() implementation should be modified to cause an auto-reboot at the end of error handling if this feature is enabled. The mechanism used for rebooting should make sure it doesn't cause a reset of RAM contents. This can be done by calling system_reset() function already implemented by MbedOS which cause the system to warm-reset without resetting the RAM. The mbed_error() implementation also should make sure it updates the error context stored in Crash-Report RAM with the right CRC value. The CRC value is calculated across all the members of mbed_error_ctx structure and the CRC is appended at the end of that structure. mbed_error() should also update the reboot count on every auto-reboot caused by fatal errors. The current mbed error context structure should be updated as below to capture reboot count, error processed status and the CRC value. The CRC value should be the last word in the struture.
```
typedef struct _mbed_error_ctx {
...
//Below are the new struct members
int32_t error_reboot_count; //everytime we write this struct we increment this value by 1, irrespective of time between reboots. Note that the data itself might change, but everytime we reboot due to error we update this count by 1
int32_t is_error_processed; //once this error is processed set this value to 1
uint32_t crc_error_ctx; //crc_error_ctx should always be the last member in this struct
} mbed_error_ctx;
```
The below pueudo-code shows how the mbed_error() implementation should be modified.
```
mbed_error_status_t mbed_error( ... )
{
//Handle the error just as we do now and then do the following to save the context into Crash-Report RAM and reset
Read the current Crash Report and calculate CRC
If CRC matches what's in Crash-Report RAM:
Update the location with new error information
Update Reboot Count
Calculate new CRC
Update with new CRC value
Else (if CRC doesn't match)
//This is the case when we dont have a crash report already stored.
Update the location with new error information
Set Reboot count to 1
Calculate new CRC
Update with new CRC value
Do a system reset //using system_reset() function
}
```
The Crash-Report RAM region should also be used for tracking other pieces of information such as the CRC value and the
auto-reboot count.
### Mechanism to retrieve and reset the error data after reboot
MbedOS error handling system should implement necessary APIs for application to retrieve and reset the error and/or fault context of the previous fatal error after auto-reboot.
The below APIs should be implemented.
The below API can be called by application to retrieve the error context captured in the Crash-Report RAM. The error context is copied into the location pointed by *error_info*. Note that the caller should allocate the memory for this location.
The function should return MBED_ERROR_NOT_FOUND if there is no error context currently stored.
```C
//Retrieve the reboot error context
mbed_error_status_t mbed_get_reboot_error_info(mbed_error_ctx *error_info)
```
The below API can be called by application to retrieve the fault context captured in the Crash-Report RAM. The error context is copied into the location pointed by *fault_context*. Note that the caller should allocate the memory for this location. Note that the fault context is valid only if the previous reboot was caused by a fault exception. Whether the previous reboot was caused by a fault exception can be determined from the error code stored in error context information retrieved using mbed_get_reboot_error_info() API above.
The function should return MBED_ERROR_NOT_FOUND if there is no fault context currently stored.
```C
//Call this function to retrieve the last reboot fault context
mbed_error_status_t mbed_get_reboot_fault_context (mbed_fault_context_t *fault_context);
```
The below API can be called by application to reset the error context captured in the Crash-Report RAM.
The function should return MBED_ERROR_NOT_FOUND if there is no error context currently stored.
```C
//Reset the reboot error context
mbed_error_status_t mbed_reset_reboot_error_info()
```
The below API can be called by application to reset(to be set to 0) the error reboot count captured in the Crash-Report RAM.
The function should return MBED_ERROR_NOT_FOUND if there is no error context currently stored.
```C
//Reset the reboot error context
mbed_error_status_t mbed_reset_reboot_count()
```
### Mechanism to report the error data after reboot
MbedOS initialization sequence should check if the reboot is caused by a fatal error and should report the same to the application using callback mechanism.
MbedOS initialization sequence should be modified as shown in below diagram to report the crash report and invoke the callback.
![Error report on reboot](./diagrams/boot-error-report.jpg)
Below should be the signature of the callback for reporting the error information.
The error handing system in MbedOS will call this callback function if it detects that the current reboot has been caused by a fatal error. This function will be defined with MBED_WEAK attribute by default and applications wanting to process the error report should override this function in application implementation.
```CS
void mbed_error_reboot_callback(mbed_error_ctx *error_context);
```
### System should implement mechanism to track number of times the system is auto-rebooted and be able to stop auto-reboot when a configurable limit is reached
Many a times rebooting may be a solution to bring the erroring device back into good state(after a fatal error for example)but there might be scenarios when the system has a permanent issue causing it to run into fatal error on every boot. In such scenarios, auto-reboot mechanism can cause a constant reboot loop situation. In order to avoid this, implementation should provide a mechanism to prevent constant reboot loop by limiting the number of auto-reboots. The number of times auto-reboot happens on fatal errors should be configurable. A configuration option should be provided to configure the
maximum number of auto-reboots(warm-resets). In order to implement this, system should track the number of times auto-reboot was effected using the Crash-Report RAM region.
### Implementation should provide following configuration options
Crash reporting implementation should provide enough parameters to control different aspects of crash reporting behavior so that developers can configure this feature to conform to their system design. Implementation should provide following configuration options to control the behavior as below.
1. Configuration option to enable or disable error the entire feature
1. Configuration option to enable or disable auto-reboot when the system enters a fatal error scenario
1. Configuration option to limit the number of auto-reboots
# Usage scenarios and examples
Below (pseudo code) are some common usage scenarios using the new error reporting APIs.
### Implementing crash reporting callback
In order to implement the callback the user can override the default callback function(*mbed_error_reboot_callback()*) implemented with MBED_WEAK attribute in platform layer as below.
```C
mbed_error_ctx my_error_ctx;
//Callback during reboot
void mbed_error_reboot_callback(mbed_error_ctx *error_context)
{
printf("Error callback received");
//Copy the error context in a local struct for processing it later
memcpy(&my_error_ctx, error_context, sizeof(mbed_error_ctx));
}
```
The above function will be called during boot with a pointer to *error_context* structure.
### Retrieving error info after reboot
The error context captured can be retrieved using mbed_get_reboot_error_info() API. See the below code
for example usage of that API. In the example below, a status variable reboot_error_detected has been used to track the presence of error context capture.
```C
mbed_error_ctx error_ctx;
int reboot_error_detected = 0;
//Callback during reboot
void mbed_error_reboot_callback(mbed_error_ctx *error_context)
{
printf("error callback received");
reboot_error_detected = 1;
}
// main() runs in its own thread in the OS
int main()
{
if (reboot_error_detected == 1) {
if (MBED_SUCCESS == mbed_get_reboot_error_info(&error_ctx)) {
printf("\nSuccessfully read error context\n");
}
//main continues...
}
```
### Retrieving fault context after reboot
The fault context captured can be retrieved using mbed_get_reboot_fault_context() API. See the below code
for example usage of that API. The example code below checks for error_status using the error context and then
retrieves the fault context using mbed_get_reboot_fault_context() API.
```C
mbed_error_ctx error_ctx;
mbed_fault_context_t fault_ctx;
int reboot_error_detected = 0;
//Callback during reboot
void mbed_error_reboot_callback(mbed_error_ctx * error_context)
{
printf("error callback received");
reboot_error_detected = 1;
}
// main() runs in its own thread in the OS
int main()
{
if (reboot_error_detected == 1) {
if (MBED_SUCCESS == mbed_get_reboot_error_info(&error_ctx)) {
printf("\nRead in reboot info\n");
if (error_ctx.error_status == MBED_ERROR_HARDFAULT_EXCEPTION) {
if (MBED_SUCCESS == mbed_get_reboot_fault_context(&fault_ctx)) {
printf("\nRead in fault context info\n");
}
}
}
}
//main continues...
}
```
# Tools and configuration changes
### Platform configuration options for error reporting infrastruture
Below is the list of new configuration options needed to configure error reporting functionality. All of these configuration options should be captured in mbed_lib.json file in platform directory.
**crash-capture-enabled**
Enables crash context capture when the system enters a fatal error/crash. When this is disabled it should also disable other dependent options.
**fatal-error-auto-reboot-enabled**
Enables auto-reboot on fatal errors.
**error-reboot-max**
Maximum number of auto reboots permitted when an error happens.
# Other information
### Reusability
### Deprecations
### References

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -0,0 +1 @@
<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" version="9.2.9" editor="www.draw.io" type="device"><diagram id="01923bba-a0aa-6e1f-5f9f-01d9f0e483c0" name="Page-1">5VpLc6M4EP41rto9zBYvYeaYOJnNHLIzFW/VbI4CGlCNQC4hJ878+pVAYEBk4jjg2XhziKXW+/u61d2yF+4q3/3J8Sa7ZTHQhWPFu4V7tXAc2/Ic+aEkT7UEWVYtSDmJdae9YE1+QDNSS7ckhrLXUTBGBdn0hRErCohET4Y5Z4/9bgmj/VU3OAVDsI4wNaXfSCyyWhogay+/AZJmzcp2c74QR99TzraFXm/huEn1VzfnuJlL9y8zHLPHjsi9XrgrzpioS/luBVRh28BWj/v0TGu7bw6FOGSA5ukB060++m0I8Ze1lF2qTTjWWmAu9GbFUwNQdURQk9gL9/IxIwLWGxyp1kepElKWiZzq5oRQumKU8WqsGyMIYk/KS8HZd+i0BE7o+r5s0bsCLmD37MnsFi+ph8ByEPxJdtEDXF9D3KpgXX3c82k3LGQdLl0tw1qF0nbmPYyyoJEcR9U1UL0DHCslzkD+X3FcZh/uYMMUstbdxe1P8LVejy+GIInG8PWjAMJkHnxbMF8C2JsAYM8A+HNpArtwfCoXvQy5LKWqVEGthqmJPsnib9uSFKnZsRSMg2Jsdbf63Ww2+cpYHm7LV3MlbwYnGuUq9kMfTWULTp8rxzK5amVdrloC30LWR4MsAz4o4gt1bctaRHFZkqiPGuyI+KdTvleG8Qdq0YHYuM8H2Mjl2JZH0NEfE64OHGgEjUbGgWJBHvorjiGkV/jKSCGeZ8P9OAC53qke1b28BxOhgQk6/mAieXWnIIyJKsLaYx/EoW0bJK5YIUixVRdawXiOVfdQ+ozKnt6duxhiiXx0On9hm274aBOpzaIxkqqlkNvpNKnqvfYsx5mP3l2tXh2X9+4tyl0OJho6qwktyn9fnLsm5+dxi56S8+WcnP+fXaE3nGg+V9is1CHxK6830wnv1YAiYWboKJjqCDwnhXKZL0eW7y4TaOunyAQcMzD5XDzIw6p5NxtKIqmfrJC1GBJSVDG9zPOpStTPEn3POyX6ZuByg8vqXgjr54NIAig/fZwrsIqw3FTHHgIPuwggrtjJ8a47gdlXT6kefxKSblWepnK5M8vR0Eg+PV+ONpJRv94z/STmmNprNWfuhiPPAXwaV2YPb0F0pCtrH0Ebg7Znc2WeeXlOGI/MkHc0b8Fd1p3/UgCzHJJ1MOvB8LlyPtbNS/u8c3nHO2Eu75mPv0fblPnctbepnkW94Sms2V7XpuxfepMid0Df8kibQssXJprQpkz/eYNp9f3JUykgn9SKkiCC8YAkDJCHrIkCkoEV+cGBgeUkVoTebkWH2sOv0vNhzuoPI/Jjk9+WqRn03Hy1ur9eG9RIrRN9MjiU5AcOqw5KQTdqM9X20OUCXUkJ3gpW1t8EqwGYkrSQZQqJmkqpsszl6IUWC6ZspJQmI33U36py9cGbRvG9ZkjLi2covjeiFlPE4Z75QnSG+KIevu5IpjMbvoGB719fzgteNEwkkRn9uHPBa37Xd+7wykRvLnhldf9LkPqy3v/cxr3+Fw==</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1 @@
<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" version="9.3.1" editor="www.draw.io" type="device"><diagram id="eb75ea10-d55d-edb6-ffc6-9548d3b38861" name="Page-1">3VZNj9sgEP01kdpDJRsnTnJMstn2stJqt1LbIzYTGy0xLsb56K/vYOP4A6dNpbSHrhQtPJgZ5r0Z8CTY7E8fFc3TJ8lATIjHTpPgYUII8cIF/jPIuUZ8n4Q1kijOLNYCr/wHWNCzaMkZFL2NWkqhed4HY5llEOseRpWSx/62nRT9qDlNwAFeYypc9AtnOq3Rxcxr8U/Ak7SJ7Ht2JaLxW6Jkmdl4ExLsqr96eU8bX3Z/kVImjx0o2E6CjZJS16P9aQPCkNvQVts9Xlm9nFtBpm8xCGqDAxWlTf2RlkIjtJGZhpMZfcCfT1BSb33WqAoJcUOwjhSOEjOyqehzQ19FAJgQHi4fU67hNaexWT1ixSCW6r3AmY/DHRdiI4VUlS3SBWEcI15oJd+gs8Lmy8jzLvEOoPCAV/P2L2ximYLcg1Zn3NLU6MIKYCt0OrXzYys3aURNO1I3dtRWWHJx3bKMA0v0OOmhQ3rDaZHTrGF1i3WsbhECw3Xt7qoGm8GCTcfUWJAoCMO/o8aM/EM15lfV0DRCDi+0WjCSeK0NQeUgqTmW4ElW+Qy/l6al1zEyAqqdN2YbRQtj8QK5VEbrl9WT22jvXkBTnqGWxJMH48dTEOFl8d7d+1lqatIks9DcS4OCMcfrH9iAbhYuwv4or7HLoo3HbjqEAcdIN3hfoUHhV23Tq+5+FWcyg0HJW6hJ0KYVrE15c3wfVnZhzxkzYUbbqd9w9+gPf9m/rTy3PwIy0h/kDv2xHOmPAdH4iuVmuBNwWpnnF9OGjNnhQyxoUfD4lxdN6NGlP6/s8HxfLXfV5Ft38gyKYwpGlAp07qWLo/qUwJyXfsA6flpQlYDuPIiuEB2iZyM8N5gCQTU/9COOkW8jPEue6Y7O5Mqr1LgoZKlisFbdZ33oaN53FPoDR3XKjqOqFi5p31QejedOfayiQopSY2N6QsZIiMzce4BBjiVSmJssazX4/bfFf9PUA4mmgdvT/uI+PY3T9pOy1rj9cA+2PwE=</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1 @@
<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" version="9.3.1" editor="www.draw.io" type="device"><diagram id="58887138-f8ca-3a51-ea37-682e74172fa5" name="Page-1">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</diagram></mxfile>

View File

@@ -0,0 +1,105 @@
# RAM memory model update - Mbed OS
# Table of contents
1. [RAM memory model update - Mbed OS](#mbed-os-ram-memory-model).
1. [Table of contents](#table-of-contents).
1. [Revision history](#revision-history).
1. [Introduction](#introduction).
1. [Current RAM memory model](#current-ram-memory-model).
1. [Proposed RAM memory model](#proposed-ram-memory-model).
1. [Phases](#phases).
1. Detailed Design (#detailed-design).
1. [Tools and configuration changes](#tools-and-configuration-changes).
### Revision history
1.0 - A brief description of this version. For example, Initial revision - Author name - Date.
**NOTE: You may also specify the Mbed OS version this revision of design document applies to.**
1.1 - Added new section - Author name - Date.
# Introduction
### Current RAM memory model
Single memory space is shared between stack and heap memory, start address is fixed but the size of both regions varies based on application and usage runtime.
Heap starts at the first address after the end of ZI growing up into higher memory address and stack starts at the last memory address of RAM growing downward into lower addresses.
+----------------------+ Stack Start (Last address of RAM)
| ISR stack |
| Main Stack(No RTOS) |
| | |
| V |
+----------------------+
| ^ |
| | |
| Heap |
+----------------------+ HEAP Start
| ZI |
|(Idle, Timer and Main |
| stack is in ZI for |
| RTOS) |
+----------------------+
| |
+----------------------+ First address of RAM
#### Drawbacks:
1. Collisions between stack and heap are hard to detect and result in hardfault.
1. Cannot check stack limit - In case of new ARM architecture stack limit registers are available to verify stack boundaries, but this feature cannot be used with dynamic stack size.
1. Stack size unification cannot be achieved across various targets.
1. GCC ARM: Memory allocator request memory at 4K boundary end of HEAP memory should be 4K aligned. Placing ISR stack (1K) after HEAP memory in case of RTOS, results in loss of 3K RAM memory
1. Memory allocators do not support HEAP split into multiple banks, hence with single region memory model HEAP is used only till end of first bank.
### Proposed RAM memory model
2-region memory model for heap and stack. Defined boundaries for ISR stack memory. Heap memory can be dynamic (starts at end of ZI and ends at last RAM address) or with fix boundaries in separate RAM bank.
+----------------------+ Heap Ends (Last address of RAM)
| ^ |
| | |
| Heap |
+----------------------+ HEAP Start
| ZI |
|(Idle, Timer and Main |
| stack is in ZI for |
| RTOS) |
+----------------------+Stack Ends
| ISR stack |
| Main Stack(No RTOS) |
| | |
| V |
+----------------------+Stack Start
| |
+----------------------+ First address of RAM
#### Drawbacks:
1. ISR Stack is not dynamic - This drawback is mainly for bare metal implementation (RTOS-less) where ISR and Main stack is same. With this limitation application writer should know if stack or heap will be usued more and tweaks the values accordingly.
# Phases:
This feature will be implemented in different phases as follow:
Phase 1 (5.12 Release):
1. Adopt 2-region memory model for Stack and Heap memory.
1. Unify the stack size accross all targets (RTOS: ISR stack - 1K Main thread Stack - 4K; Bare Metal(No RTOS) ISR/Main Stack - 4K)
Phase 2:
1. Heap memory to be dynamic and starts at the end of ZI growing up till end of RAM memory (In case of single RAM bank)
Heap memory to be dynamic and assigned partial or full RAM bank in case of multiple RAM banks, based on calculation of other RAM regions.
1. ISR Stack to be placed after vectors or before ZI memory section.
Note: Heap split support across multiple RAM banks, can also be achieved post this change.
# Detailed Design
1. Update tools to set define `MBED_BOOT_STACK_SIZE` from target config option `target.boot-stack-size`
1. Linker Scripts - Update linker scripts for ARM, IAR and GCC toolchain to use MBED_BOOT_STACK_SIZE define for standardizing size of ISR stack.
1. Update __user_setup_stackheap() implementation to adopt 2-region RAM memory model.
__user_setup_stackheap() works with systems where the application starts with a value of sp (r13) that is already correct. To make use of sp(stack base), implement __user_setup_stackheap() to set up r0 (heap base), r2 (heap limit), and r3 (stack limit) (for a two-region model) and return.
Reference http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0099a/armlib_cjagaaha.htm http://www.keil.com/support/man/docs/armlib/armlib_chr1359122863069.htm
1. Modify _sbrk() implementation for GCC to use 2-region memory model
# Tools and configuration changes
1. Target config option "target.boot-stack-size" which is passed to the linker as the define "MBED_BOOT_STACK_SIZE" so the linker can adjust the stack accordingly.
Boot stack size - the size of ISR and main stack will be 4K as default in targets.json for bare metal (non-RTOS) builds.
Boot stack size - the size of ISR stack will be over-written as 1K in `rtos/mbed_lib.json` for RTOS builds.