The use of __FILE__ macro to get a usable identifier from the driver path
causes the path of the file to be stored in the .text region of the binary.
Given that this remains for the entire duration of the program, storing a
pointer to this string as an identifier is more efficient than copying the
contents of the string during lookup/insertion.
Sleep manager tracing strips the path from filenames and uses the result as an
identifier to track drivers that unlock/lock sleep tracing. Replace the function
that strips the path from the string, replace this function with a new macro,
__FILENAME__ which performs the same action in a compiler specific manner.
- GCC_ARM, use __builtin_strrchr which is optimized out at compile time.
- ARM, use __MODULE__ which returns the filename without path.
- IAR, specifiy the --no_path_in_file_macros compiler flag.
Add tracing output to console to track when drivers lock and unlock deep
sleep. Tracing output is enabled by configuring the
'SLEEP_PROFILING_ENABLED' at compile time.
- Wrapped sleep_manager_lock/sleep_manager_unlock in a macro to
conditionally call tracing functions when 'SLEEP_PROFILING_ENABLED' is
set.
- Define a global structure to track driver names and how many locks
they hold in the sleep manager.
When ticker is not driven by the 1 MHz clock and HAL driver need to perform conversion between microseconds and ticks, then the interrupt might be scheduled in the past. For details see: https://github.com/ARMmbed/mbed-os/issues/6054.
This patch provides fix for such case. Interrupt is fired immidiatelly when last read tick is equal to the calculated tick when interrupt should be generated.
Call underlying HAL implementation to enter critical section/disable interrupts
before incrementing the global critical section counter.
Modify HAL implementations to track first entrances to the critical section and
only update the saved state on first enter.
- Define header functions for Critical Section HAL API
- hal_critical_section_enter()
- hal_critical_section_exit()
- Add weak default implementation for HAL API. The default implementation
matches the previous behaviour stored in mbed_critical:
- The first call to enter a critical section stores the state of interrupts
before disabling and each successive call re-disables interrupts.
- The last call (non-nested) will restore the IRQ state that was set on the
enter to the critical section. Nested calls are ignored.
- Add function 'core_util_in_critical_section' to User facing API to determine
if the program is currently in a critical section, instead of depending on
'core_util_interrupts_enabled'.
This API is added primarily for testing purposes, to be able to test HAL drivers without using upper layers to handle ticker interrupt.
By default IRQ handler is set to ticker_irq_handler() for us ticker and lp ticker - original one.
Usage example (setting custom ticker irq handler):
void my_irq_handler(const ticker_data_t *const) {
// handle interrupt
}
ticker_irq_handler_type old_handler = set_us_ticker_irq_handler(my_irq_handler);
Respectively for lp timer set_lp_ticker_irq_handler() API should be used.
Allow tickers to specify their native frequency and number of bits.
This allows the conversion to happen in common code rather than in
each vendor's implementation.
Sleep manager provides API to lock/unlock deepsleep. This API allows a user to
control deep sleep.
This API should be done via atomic operations (to be IRQ/thread safe).
fire_interrupt function should be used for events in the past. As we have now
64bit timestamp, we can figure out what is in the past, and ask a target to invoke
an interrupt immediately. The previous attemps in the target HAL tickers were not ideal, as it can wrap around easily (16 or 32 bit counters). This new
functionality should solve this problem.
set_interrupt for tickers in HAL code should not handle anything but the next match interrupt. If it was in the past is handled by the upper layer.
It is possible that we are setting next event to the close future, so once it is set it is already in the past. Therefore we add a check after set interrupt to verify it is in future.
If it is not, we fire interrupt immediately. This results in
two events - first one immediate, correct one. The second one might be scheduled in far future (almost entire ticker range),
that should be discarded.
The specification for the fire_interrupts are:
- should set pending bit for the ticker interrupt (as soon as possible),
the event we are scheduling is already in the past, and we do not want to skip
any events
- no arguments are provided, neither return value, not needed
- ticker should be initialized prior calling this function (no need to check if it is already initialized)
All our targets provide this new functionality, removing old misleading if (timestamp is in the past) checks.
On some platforms, the in-application memory is not memory mapped
and therefore cannot be accessed using memcpy.
The flash_read function added to flash_api.h (with a weak
implementation using memcpy in mbed_flash_api.c) can be used for
reading data from areas that are not memory mapped.
- A new 64 timestamp type has been added: us_timestamp_t.
- Changed type of timestamp in ticker_events iinto us_timestamp_t.
- Event queue now have a to store a current, absolute timestamp.
- Add alternative versions of ticker_insert_event and ticker_read which accept
in input us_timestamp_t.
- Add documentation explaining the limitation and behavior of ticker_read and
ticker_insert_event.
ticker_insert_event() can crash on KLXX (and probably other platforms) if an event is inserted with a timestamp before the current real time.
The problem is easy to trigger: you just need to set up a Ticker object, and then disable interrupts for slightly longer than the Ticker object's interval. It's generally bad practice to disable interrupts for too long, but there are some cases where it's unavoidable, and anyway it would be better for the core library function not to crash. The case where I had an unavoidably long interrupts-off interval was writing flash with the FTFA. The FTFA hardware prohibits flash reads while an FTFA command is in progress, so interrupts must be disabled for the whole duration of each command to ensure that there are no instruction fetches from flash-resident ISRs in the course of the execution. An FTFA "erase sector" command takes a fairly long time (milliseconds), and I have a fairly high frequency Ticker (1ms).
The problem and the fix are pretty straightforward. ticker_insert_event() searches the linked list to figure out where to insert the new event, looking for a spot earlier than any event currently queued. If the event is in the past, it'll usually end up at the head of the list. When the routine sees that the new event belongs at the head of the list, it calls data->interface->set_interrupt() to schedule the interrupt for the event, since it's the new soonest event. The KLXX version of us_ticker_set_interrupt() then looks to see if the event is in the past, which we've stipulated that it is, so rather than actually setting the interrupt, it simply calls the handler directly. The first thing the Ticker interrupt handler does is re-schedule itself, so we re-enter ticker_insert_event() at this point. This is where the problem comes in: we didn't finish updating the linked list before we called set_interrupt() and thus before we recursed back into ticker_insert_event(). We set the head of the list to the new event but we didn't set the new event's 'next' pointer.
The fix is simply to finish updating the list before we call set_interrupt(), which we can do by moving the obj->next initialization ahead of the head pointer update.
If target supports flash algo, it can get common HAL implementation, providing
feature "HAL_FLASH_CMSIS_ALGO". This simplifies target code, and having
one implementation that can be shared by many targets.
Be careful with flash cmsis algo, in some cases they execute code that
can affect the system. For instance, it can disable cache, or affect
some system clocks. Therefore this feature should be well tested.
Add sleep/deepsleep functions to platform layer which are replacing HAL
functions with the same name, rename existing symbols in HAL layer
to hal_sleep/hal_deepsleep. This way sleep functions
are always available, even if target doesn't implement them, which makes
the code using sleep clearer. It also enables us to make decision on in
which builds (debug/release) the sleep will be enabled.
Unfortunately, it is very difficult to infer the parameters of
function-objects generically in C++03 without any additional type
information. The current implementation fails to do so, and the compiler
simply bails with "unable to deduce template parameter".
Rather than leaving the user with a small novel of error messages, this
patch removes the problematic callback overloads, leaving only callback
overloads for the original pointer types.
The callback class can now accept generalized function-objects:
class Thing {
public:
int value;
void operator()() {
printf("hi! %d\n", value);
}
};
Callback<void()> cb(Thing(2));
However, with the intention of avoiding implicit dynamic-memory
allocations, the Callback class is limited to a single word of storage.
Exceeding this size will eliminate the function-object type from the
overload set and fail to compile.
Effort was invested to make this situation very clear to the user. Here
is an example error message with noise removed:
[ERROR] ./main.cpp: In function 'int main()':
./mbed-os/hal/api/Ticker.h:101:10: note:
no known conversion for argument 1 from 'BigFunc' to 'mbed::Callback<void()>'
The real benefit of this change is the ability for users to hook into
the attributes of the Callback class. This mostly allows lifetime
management of the function-objects from third-party libraries (such as
the Event class from mbed-events).
Note: The convenient `callback` function may become ambiguous if
provided with a type that defines multiple incompatible `operator()`
member functions.
This allows additional attributes to be attached to the internally
generated type such as move and destructor operations with no increase
in RAM footprint.
The current overloads can't take advantage of this, but it does open
the possibility for more powerful overloads that can provide these
additional attributes.
Changes to mbed-os memory consumption:
.text .data .bss
before 57887 2292 7692
after 57842 2292 7691
Enable the low power timer for the following targets:
- NUCLEO_F411RE
- NUCLEO_F401RE
- DISCO_F429ZI
- NUCLEO_F446RE
- NUCLEO_F410RB
- DISCO_F469NI
- NUCLEO_F446ZE
- B86B_F446VE
This change allows a port to provide its own implementation of:
* core_util_critical_section_enter
* core_util_critical_section_exit
Some system like the NRF series require specific behavior for the critical
section and now can override it properly.
* 'master' of https://github.com/ARMmbed/mbed-os: (63 commits)
[XDOT_L151] add IAR support
Modify mbedtls scripts to add config-no-entropy.h
Remove extra spaces
[XDOT_L151] include xDot in mbed 5 releases
[STM32F429ZI] INITIAL_SP correction
[STM32F091RC] patch for tests-mbedmicro-rtos-mbed-threads
mbedtls trng - remove MBEDTLS_ENTROPY_HARDWARE_ALT
targets - add TRNG device_has to STM32F7 targets
mbedtls - move TRNG mbed impl into platform folder
TRNG HAL - fix length doc wording for get_bytes
HAL TRNG - add dummy variable to empty structs
TRNG - protect HAL implementation if DEVICE_TRNG is not defined
TRNG - remove set seed function
HAL - RNG rename to TRNG
HAL - rng nuvoton cleanup code style
RNG - fix warnings due to obj not used for some targets
RNG - rename rng_get_numbers to rng_get_bytes
mbedtls - mbed wrapper rename to mbed_rng
HAL: Add rng set seed value function
NUMAKER_PFM_NUC472: Add RGN HAL API implementation
...
# Conflicts:
# hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/serial_api.c
[XDOT_L151] copy new target CMSIS files from NZ32_SC151 target
[XDOT_L151] remove Modtronix code, add HardFault_Handler, update clock configuration to match xDot hardware
[XDOT_L151] copy new target HAL files from NZ32_SC151 target
[XDOT_L151] update HAL to match xDot hardware
[XDOT_L151] add xdot_eeprom.* and xdot_low_power.* files
[XDOT_L151] add RTOS support for target
Conflicts:
rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c
[XDOT_L151] match NUCLEO_L152RE startup code for GCC_ARM so RTOS works
[XDOT_L151] fix GPIO write failure
[XDOT_L151] add XDOT_L151CC target to targets.json
[XDOT_L151] change xDot default stack size to 256 bytes and main stack size to 1.5kB
[XDOT_L151] update PinNames.h to match rev E hardware - no change to external pinout
[XDOT_L151] update style in custom xDot HAL files
Conflicts:
rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h
rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c