diff options
| author | Yuxin Zhou <[email protected]> | 2022-07-26 02:04:40 +0000 |
|---|---|---|
| committer | Yuxin Zhou <[email protected]> | 2022-07-26 02:04:40 +0000 |
| commit | 8c3c08f10826c4d5332a6d8e2fdf014b793a456a (patch) | |
| tree | c6c2528d7901b11ec5173bdd0bc38339ab18288f /utility | |
| parent | 54cda6ee9e68cd9701d759df13e3f6e41429b9bc (diff) | |
Release 6.1.12v6.1.12_rel
Diffstat (limited to 'utility')
| -rw-r--r-- | utility/execution_profile_kit/smp_version/tx_execution_profile.c | 1278 | ||||
| -rw-r--r-- | utility/execution_profile_kit/smp_version/tx_execution_profile.h | 93 | ||||
| -rw-r--r-- | utility/low_power/low_power.md | 258 | ||||
| -rw-r--r-- | utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c | 33 |
4 files changed, 1621 insertions, 41 deletions
diff --git a/utility/execution_profile_kit/smp_version/tx_execution_profile.c b/utility/execution_profile_kit/smp_version/tx_execution_profile.c new file mode 100644 index 00000000..b1dad888 --- /dev/null +++ b/utility/execution_profile_kit/smp_version/tx_execution_profile.c @@ -0,0 +1,1278 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Execution Profile Kit */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_execution_profile.h" + +/* The thread execution profile kit is designed to track thread execution time + based on the hardware timer defined by TX_EXECUTION_TIME_SOURCE and + TX_EXECUTION_MAX_TIME_SOURCE below. When the thread's total time reaches + the maximum value, it remains there until the time is reset to 0 via a call + to tx_thread_execution_time_reset. There are several assumptions to the + operation of this kit, as follows: + + 1. In tx_port.h replace: + + #define TX_THREAD_EXTENSION_3" + + with: + + #define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; + + Note: if 64-bit time source is present, the tx_thread_execution_time_last_start type should be unsigned long long. + + 2. The TX_EXECUTION_TIME_SOURCE and TX_EXECUTION_MAX_TIME_SOURCE macros are + defined to utilize a local hardware time source. + + 3. ThreadX 5.4 (or later) is being used, with the assembly code enabled to + call the following routines from assembly code: + + VOID _tx_execution_thread_enter(void); + VOID _tx_execution_thread_exit(void); + VOID _tx_execution_isr_enter(void); + VOID _tx_execution_isr_exit(void); + + 4. The ThreadX library assembly code must be rebuilt with TX_ENABLE_EXECUTION_CHANGE_NOTIFY so + that these macros are expanded in the TX_THREAD structure and so the assembly code macros + are enabled to call the execution profile routines. + + 5. Add tx_execution_profile.c to the application build. */ + + +/* Externally reference several internal ThreadX variables. */ + +extern ULONG _tx_thread_system_state[TX_THREAD_SMP_MAX_CORES]; +extern UINT _tx_thread_preempt_disable; +extern TX_THREAD *_tx_thread_current_ptr[TX_THREAD_SMP_MAX_CORES]; +extern TX_THREAD *_tx_thread_execute_ptr[TX_THREAD_SMP_MAX_CORES]; +extern TX_THREAD *_tx_thread_created_ptr; +extern ULONG _tx_thread_created_count; + + +/* Define the total time for all threads. This is accumulated as each thread's total time is accumulated. */ + +EXECUTION_TIME _tx_execution_thread_time_total[TX_THREAD_SMP_MAX_CORES]; + + +/* Define the ISR time gathering information. This is setup to track total ISR time presently, but + could easily be expanded to track different ISRs. Also, only ISRs that utilize _tx_thread_context_save + and _tx_thread_context_restore are tracked by this utility. */ + +EXECUTION_TIME _tx_execution_isr_time_total[TX_THREAD_SMP_MAX_CORES]; +EXECUTION_TIME_SOURCE_TYPE _tx_execution_isr_time_last_start[TX_THREAD_SMP_MAX_CORES]; + + +/* Define the system idle time gathering information. For idle time that exceeds the range of the timer + source, another timer source may be needed. In addition, the total thread execution time added to the + total ISR time, less the total system time is also a measure of idle time. */ + +EXECUTION_TIME _tx_execution_idle_time_total[TX_THREAD_SMP_MAX_CORES]; +EXECUTION_TIME_SOURCE_TYPE _tx_execution_idle_time_last_start[TX_THREAD_SMP_MAX_CORES]; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_enter PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called whenever thread execution starts. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_schedule Thread scheduling */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +VOID _tx_execution_thread_enter(void) +{ + +TX_THREAD *thread_ptr; +EXECUTION_TIME_SOURCE_TYPE last_start_time; +EXECUTION_TIME_SOURCE_TYPE current_time; +EXECUTION_TIME delta_time; +EXECUTION_TIME total_time; +EXECUTION_TIME new_total_time; +UINT core; + + + /* Pickup the current time. */ + current_time = TX_EXECUTION_TIME_SOURCE; + + /* Pickup the core index. */ + core = TX_SMP_CORE_ID; + + /* Pickup the current thread control block. */ + thread_ptr = _tx_thread_current_ptr[core]; + + /* This thread is being scheduled. Simply setup the last start time in the + thread control block. */ + thread_ptr -> tx_thread_execution_time_last_start = current_time; + + /* Pickup the last idle start time. */ + last_start_time = _tx_execution_idle_time_last_start[core]; + + /* Determine if idle time is being measured. */ + if (last_start_time) + { + + /* Determine how to calculate the difference. */ + if (current_time >= last_start_time) + { + + /* Simply subtract. */ + delta_time = (EXECUTION_TIME) (current_time - last_start_time); + } + else + { + + /* Timer wrapped, compute the delta assuming incrementing time counter. */ + delta_time = (EXECUTION_TIME) (current_time + (((EXECUTION_TIME_SOURCE_TYPE) TX_EXECUTION_MAX_TIME_SOURCE) - last_start_time)); + } + + /* Pickup the total time. */ + total_time = _tx_execution_idle_time_total[core]; + + /* Now compute the new total time. */ + new_total_time = total_time + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < total_time) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Now store back the total idle time. */ + _tx_execution_idle_time_total[core] = new_total_time; + + /* Disable the idle time measurement. */ + _tx_execution_idle_time_last_start[core] = 0; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_exit PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called whenever a thread execution ends. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_system_return Thread exiting */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +VOID _tx_execution_thread_exit(void) +{ + +TX_THREAD *thread_ptr; +EXECUTION_TIME total_time; +EXECUTION_TIME new_total_time; +EXECUTION_TIME_SOURCE_TYPE last_start_time; +EXECUTION_TIME_SOURCE_TYPE current_time; +EXECUTION_TIME delta_time; +UINT core; + + + /* Pickup the core index. */ + core = TX_SMP_CORE_ID; + + /* Pickup the current thread control block. */ + thread_ptr = _tx_thread_current_ptr[core]; + + /* Determine if there is a thread. */ + if (thread_ptr) + { + + /* Pickup the current time. */ + current_time = TX_EXECUTION_TIME_SOURCE; + + /* Pickup the last start time. */ + last_start_time = thread_ptr -> tx_thread_execution_time_last_start; + + /* Determine if there is an actual start time. */ + if (last_start_time) + { + + /* Clear the last start time. */ + thread_ptr -> tx_thread_execution_time_last_start = 0; + + /* Determine how to calculate the difference. */ + if (current_time >= last_start_time) + { + + /* Simply subtract. */ + delta_time = (EXECUTION_TIME) (current_time - last_start_time); + } + else + { + + /* Timer wrapped, compute the delta assuming incrementing time counter. */ + delta_time = (EXECUTION_TIME) (current_time + (((EXECUTION_TIME_SOURCE_TYPE) TX_EXECUTION_MAX_TIME_SOURCE) - last_start_time)); + } + + /* Pickup the total time. */ + total_time = thread_ptr -> tx_thread_execution_time_total; + + /* Now compute the new total time. */ + new_total_time = total_time + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < total_time) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Store back the new total time. */ + thread_ptr -> tx_thread_execution_time_total = new_total_time; + + /* Now accumulate this thread's execution time into the total thread execution time. */ + new_total_time = _tx_execution_thread_time_total[core] + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < _tx_execution_thread_time_total[core]) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Store back the new total time. */ + _tx_execution_thread_time_total[core] = new_total_time; + } + + /* Is the system now idle? */ + if (_tx_thread_execute_ptr[core] == TX_NULL) + { + + /* Yes, idle system. Pickup the start of idle time. */ + _tx_execution_idle_time_last_start[core] = TX_EXECUTION_TIME_SOURCE; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_isr_enter PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called whenever ISR processing starts. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_context_save ISR context save */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +VOID _tx_execution_isr_enter(void) +{ + +TX_THREAD *thread_ptr; +EXECUTION_TIME_SOURCE_TYPE current_time; +EXECUTION_TIME total_time; +EXECUTION_TIME new_total_time; +EXECUTION_TIME_SOURCE_TYPE last_start_time; +EXECUTION_TIME delta_time; +UINT core; + + + /* Pickup the core index. */ + core = TX_SMP_CORE_ID; + + /* Determine if this is the first interrupt. Nested interrupts are all treated as + general interrupt processing. */ + if (_tx_thread_system_state[core] == 1) + { + /* Pickup the current time. */ + current_time = TX_EXECUTION_TIME_SOURCE; + + /* Pickup the current thread control block. */ + thread_ptr = _tx_thread_current_ptr[core]; + + /* Determine if a thread was interrupted. */ + if (thread_ptr) + { + + /* Pickup the last start time. */ + last_start_time = thread_ptr -> tx_thread_execution_time_last_start; + + /* Determine if there is an actual start time. */ + if (last_start_time) + { + + /* Clear the last start time. */ + thread_ptr -> tx_thread_execution_time_last_start = 0; + + /* Determine how to calculate the difference. */ + if (current_time >= last_start_time) + { + + /* Simply subtract. */ + delta_time = (EXECUTION_TIME) (current_time - last_start_time); + } + else + { + + /* Timer wrapped, compute the delta assuming incrementing time counter. */ + delta_time = (EXECUTION_TIME) (current_time + (((EXECUTION_TIME_SOURCE_TYPE) TX_EXECUTION_MAX_TIME_SOURCE) - last_start_time)); + } + + /* Pickup the total time. */ + total_time = thread_ptr -> tx_thread_execution_time_total; + + /* Now compute the new total time. */ + new_total_time = total_time + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < total_time) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Store back the new total time. */ + thread_ptr -> tx_thread_execution_time_total = new_total_time; + + /* Now accumulate this thread's execution time into the total thread execution time. */ + new_total_time = _tx_execution_thread_time_total[core] + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < _tx_execution_thread_time_total[core]) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Store back the new total time. */ + _tx_execution_thread_time_total[core] = new_total_time; + } + } + + /* Has idle time started? */ + else if (_tx_execution_idle_time_last_start[core]) + { + + /* Pickup the last idle start time. */ + last_start_time = _tx_execution_idle_time_last_start[core]; + + /* Determine how to calculate the difference. */ + if (current_time >= last_start_time) + { + + /* Simply subtract. */ + delta_time = (EXECUTION_TIME) (current_time - last_start_time); + } + else + { + + /* Timer wrapped, compute the delta assuming incrementing time counter. */ + delta_time = (EXECUTION_TIME) (current_time + (((EXECUTION_TIME_SOURCE_TYPE) TX_EXECUTION_MAX_TIME_SOURCE) - last_start_time)); + } + + /* Pickup the total time. */ + total_time = _tx_execution_idle_time_total[core]; + + /* Now compute the new total time. */ + new_total_time = total_time + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < total_time) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Now store back the total idle time. */ + _tx_execution_idle_time_total[core] = new_total_time; + + /* Disable the idle time measurement. */ + _tx_execution_idle_time_last_start[core] = 0; + } + + /* Save the ISR start time. */ + _tx_execution_isr_time_last_start[core] = current_time; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_isr_exit PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called whenever ISR processing ends. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_context_restore Thread de-scheduling */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +VOID _tx_execution_isr_exit(void) +{ + +TX_THREAD *thread_ptr; +EXECUTION_TIME total_time; +EXECUTION_TIME new_total_time; +EXECUTION_TIME_SOURCE_TYPE last_start_time; +EXECUTION_TIME_SOURCE_TYPE current_time; +EXECUTION_TIME delta_time; +UINT core; + + + /* Pickup the core index. */ + core = TX_SMP_CORE_ID; + + /* Determine if this is the first interrupt. Nested interrupts are all treated as + general interrupt processing. */ + if (_tx_thread_system_state[core] == 1) + { + + /* Pickup the current time. */ + current_time = TX_EXECUTION_TIME_SOURCE; + + /* Pickup the last start time. */ + last_start_time = _tx_execution_isr_time_last_start[core]; + + /* Determine how to calculate the difference. */ + if (current_time >= last_start_time) + { + + /* Simply subtract. */ + delta_time = (EXECUTION_TIME) (current_time - last_start_time); + } + else + { + + /* Timer wrapped, compute the delta assuming incrementing time counter. */ + delta_time = (EXECUTION_TIME) (current_time + (((EXECUTION_TIME_SOURCE_TYPE) TX_EXECUTION_MAX_TIME_SOURCE) - last_start_time)); + } + + /* Pickup the total time. */ + total_time = _tx_execution_isr_time_total[core]; + + /* Now compute the new total time. */ + new_total_time = total_time + delta_time; + + /* Determine if a rollover on the total time is present. */ + if (new_total_time < total_time) + { + + /* Rollover. Set the total time to max value. */ + new_total_time = (EXECUTION_TIME) TX_EXECUTION_MAX_TIME_SOURCE; + } + + /* Store back the new total time. */ + _tx_execution_isr_time_total[core] = new_total_time; + + /* Pickup the current thread control block. */ + thread_ptr = _tx_thread_current_ptr[core]; + + /* Was a thread interrupted? */ + if (thread_ptr) + { + + /* Now determine if the thread will execution is going to occur immediately. */ + if ((thread_ptr == _tx_thread_execute_ptr[core]) || (_tx_thread_preempt_disable)) + { + + /* Yes, setup the thread last start time in the thread control block. */ + thread_ptr -> tx_thread_execution_time_last_start = current_time; + } + } + + /* Determine if the system is now idle. */ + if (_tx_thread_execute_ptr[core] == TX_NULL) + { + + /* Yes, idle system. Pickup the start of idle time. */ + _tx_execution_idle_time_last_start[core] = TX_EXECUTION_TIME_SOURCE; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_time_reset PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resets the execution time of the specified thread. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_thread_time_reset(TX_THREAD *thread_ptr) +{ + + /* Reset the total time to 0. */ + thread_ptr -> tx_thread_execution_time_total = 0; + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_total_time_reset PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resets the total thread execution time. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_thread_total_time_reset(void) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +UINT total_threads; +UINT core; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Reset the total time for all cores. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + _tx_execution_thread_time_total[core] = 0; + } + + /* Loop through threads to clear their accumulated time. */ + total_threads = _tx_thread_created_count; + thread_ptr = _tx_thread_created_ptr; + while (total_threads--) + { + thread_ptr -> tx_thread_execution_time_total = 0; + thread_ptr = thread_ptr -> tx_thread_created_next; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_isr_time_reset PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resets the execution time of the ISR calculation. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_isr_time_reset(void) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT core; + + /* Disable interrupts. */ + TX_DISABLE + + /* Reset the ISR total time to 0. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + _tx_execution_isr_time_total[core] = 0; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_idle_time_reset PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resets the idle execution time calculation. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_idle_time_reset(void) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT core; + + /* Disable interrupts. */ + TX_DISABLE + + /* Reset the idle total time to 0. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + _tx_execution_idle_time_total[core] = 0; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the execution time of the specified thread. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to the thread */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_thread_time_get(TX_THREAD *thread_ptr, EXECUTION_TIME *total_time) +{ + + /* Return the total time. */ + *total_time = thread_ptr -> tx_thread_execution_time_total; + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_thread_total_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the execution time of all threads. */ +/* */ +/* INPUT */ +/* */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_thread_total_time_get(EXECUTION_TIME *total_time) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT core; + + /* Disable interrupts. */ + TX_DISABLE + + /* Return the total thread time. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + *total_time = _tx_execution_thread_time_total[core]; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_isr_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the execution time of all ISRs. */ +/* */ +/* INPUT */ +/* */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_isr_time_get(EXECUTION_TIME *total_time) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT core; + + /* Disable interrupts. */ + TX_DISABLE + + /* Return the total ISR time. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + /* Return the total time. */ + *total_time = _tx_execution_isr_time_total[core]; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_idle_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the total system idle time. */ +/* */ +/* INPUT */ +/* */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_idle_time_get(EXECUTION_TIME *total_time) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT core; + + /* Disable interrupts. */ + TX_DISABLE + + /* Return the total time. */ + for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++) + { + + /* Return the total time. */ + *total_time = _tx_execution_idle_time_total[core]; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_core_thread_total_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the total thread execution time of the */ +/* specified core. */ +/* */ +/* INPUT */ +/* */ +/* core Specified core */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_core_thread_total_time_get(UINT core, EXECUTION_TIME *total_time) +{ + + /* Determine if the core is valid. */ + if (core >= TX_THREAD_SMP_MAX_CORES) + { + + /* Invalid core, return an error. */ + return(TX_NOT_DONE); + } + + /* Return the total thread time for the core. */ + *total_time = _tx_execution_thread_time_total[core]; + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_core_isr_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the execution time of ISRs on the specified */ +/* core. */ +/* */ +/* INPUT */ +/* */ +/* core Specified core */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_core_isr_time_get(UINT core, EXECUTION_TIME *total_time) +{ + + /* Determine if the core is valid. */ + if (core >= TX_THREAD_SMP_MAX_CORES) + { + + /* Invalid core, return an error. */ + return(TX_NOT_DONE); + } + + /* Return the total ISR time for this core. */ + *total_time = _tx_execution_isr_time_total[core]; + + /* Return success. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_execution_core_idle_time_get PORTABLE SMP */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the idle time of the specified core. */ +/* */ +/* INPUT */ +/* */ +/* core Specified core */ +/* total_time Destination for total time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 07-29-2022 William E. Lamie Initial Version 6.1.12 */ +/* */ +/**************************************************************************/ +UINT _tx_execution_core_idle_time_get(UINT core, EXECUTION_TIME *total_time) +{ + + /* Determine if the core is valid. */ + if (core >= TX_THREAD_SMP_MAX_CORES) + { + + /* Invalid core, return an error. */ + return(TX_NOT_DONE); + } + + /* Return the total idle time for this core. */ + *total_time = _tx_execution_idle_time_total[core]; + + /* Return success. */ + return(TX_SUCCESS); +} diff --git a/utility/execution_profile_kit/smp_version/tx_execution_profile.h b/utility/execution_profile_kit/smp_version/tx_execution_profile.h new file mode 100644 index 00000000..7149a79f --- /dev/null +++ b/utility/execution_profile_kit/smp_version/tx_execution_profile.h @@ -0,0 +1,93 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Execution Profile Kit */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#ifndef TX_EXECUTION_PROFILE_H +#define TX_EXECUTION_PROFILE_H + + +/* The thread execution profile kit is designed to track thread execution time + based on the hardware timer defined by TX_EXECUTION_TIME_SOURCE and + TX_EXECUTION_MAX_TIME_SOURCE below. When the thread's total time reaches + the maximum value, it remains there until the time is reset to 0 via a call + to tx_thread_execution_time_reset. There are several assumptions to the + operation of this kit, as follows: + + 1. In tx_port.h replace: + #define TX_THREAD_EXTENSION_3" + with: + #define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long tx_thread_execution_time_last_start; + + 2. The TX_EXECUTION_TIME_SOURCE and TX_EXECUTION_MAX_TIME_SOURCE macros are + defined to utilize a local hardware time source. + + 3. The following routines are called from assembly code: + VOID _tx_execution_thread_enter(void); + VOID _tx_execution_thread_exit(void); + VOID _tx_execution_isr_enter(void); + VOID _tx_execution_isr_exit(void); + + 4. The ThreadX library must be rebuilt with TX_ENABLE_EXECUTION_CHANGE_NOTIFY so + that these macros are expanded in the TX_THREAD structure and so the assembly code macros + are enabled to call the execution profile routines. + + 5. Add tx_execution_profile.c to the application build. */ + +/* Define the basic time typedefs for 64-bit accumulation and a 32-bit timer source, which is the + most common configuration. */ + +typedef unsigned long long EXECUTION_TIME; +typedef unsigned long EXECUTION_TIME_SOURCE_TYPE; +/* For 64-bit time source, the typedef would be: */ +/* typedef unsigned long long EXECUTION_TIME_SOURCE_TYPE; */ + +/* Define basic constants for the execution profile kit. */ + +ULONG _tx_thread_smp_time_get(void); + +#define TX_EXECUTION_TIME_SOURCE (EXECUTION_TIME_SOURCE_TYPE) _tx_thread_smp_time_get(); +#define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFFFFFF +/* For 64-bit time source, the constant would be: */ +/* #define TX_EXECUTION_MAX_TIME_SOURCE 0xFFFFFFFFFFFFFFFF */ + + +/* Define APIs of the execution profile kit. */ + +struct TX_THREAD_STRUCT; +VOID _tx_execution_thread_enter(void); +VOID _tx_execution_thread_exit(void); +VOID _tx_execution_isr_enter(void); +VOID _tx_execution_isr_exit(void); +UINT _tx_execution_thread_time_reset(struct TX_THREAD_STRUCT *thread_ptr); +UINT _tx_execution_thread_total_time_reset(void); +UINT _tx_execution_isr_time_reset(void); +UINT _tx_execution_idle_time_reset(void); +UINT _tx_execution_thread_time_get(struct TX_THREAD_STRUCT *thread_ptr, EXECUTION_TIME *total_time); +UINT _tx_execution_thread_total_time_get(EXECUTION_TIME *total_time); +UINT _tx_execution_isr_time_get(EXECUTION_TIME *total_time); +UINT _tx_execution_idle_time_get(EXECUTION_TIME *total_time); +UINT _tx_execution_core_thread_total_time_get(UINT core, EXECUTION_TIME *total_time); +UINT _tx_execution_core_isr_time_get(UINT core, EXECUTION_TIME *total_time); +UINT _tx_execution_core_idle_time_get(UINT core, EXECUTION_TIME *total_time); + +#endif diff --git a/utility/low_power/low_power.md b/utility/low_power/low_power.md index 8be714a3..ed25ccd6 100644 --- a/utility/low_power/low_power.md +++ b/utility/low_power/low_power.md @@ -8,25 +8,209 @@ ms.topic: article ms.service: rtos
---
-# Low Power APIs
+# ThreadX Low Power Utilities
-## Summary of Low Power APIs
+These low power utilities are intended to maintain ThreadX timers and the internal tick count while the processor is in a low-power/sleep state. The terms "low power" and "sleep" are used interchangeably throughout this document.
-There are additional API functions available for low power, as follows:
+The low power utilities may be used with any ThreadX port except SMP.
-- ***tx_low_power_enter*** - *Enter low power mode*
-- ***tx_low_power_exit*** - *Exit low power mode*
-- ***tx_time_increment*** - *Increment ThreadX timers by specific amount*
-- ***tx_timer_get_next*** - *Get next ThreadX timer expiration*
+## Installation of Low Power Utilities
+
+The ThreadX low power utilities are comprised of two files:
+
+ - [tx_low_power.c](tx_low_power.c)
+ - [tx_low_power.h](tx_low_power.h)
+
+These files can be built with the ThreadX library or built in the user application.
+
+## Detailed Description
+
+By default, ThreadX spins in an idle loop in the scheduler when there are no threads ready to run. It may be desireable to put the processor in a low power state while idle. Functions ```tx_low_power_enter``` and ```tx_low_power_exit``` are designed to enter and exit low power mode, respectively.
+
+The ```tx_low_power_enter``` and ```tx_low_power_exit``` functions manage the ThreadX timers and invoke optional macros that the user must define in order to configure the hardware for low power mode. These macros are discussed in a section below.
+
+For convenience, the Cortex-M and RX ports have calls to the low power APIs already integrated into their schedulers. If symbol **TX_LOW_POWER** is defined, functions ```tx_low_power_enter``` and ```tx_low_power_exit``` are called in the scheduler idle loop. It is assumed that the processor will exit sleep mode and resume execution in the idle loop (or in an interrupt and then return to the idle loop). For processors that exhibit different behavior (such as waking from sleep at the reset vector), these low power functions may need to be called elsewhere.
+
+### Low Power Timer and Tick-less Low Power Mode
+
+If accurate timekeeping is not desired while in low power mode, macros **TX_LOW_POWER_TIMER_SETUP** and **TX_LOW_POWER_TICKLESS** do not need to be defined. The internal ThreadX tick count will not reflect the time spent in low power mode.
+
+If **TX_LOW_POWER_TIMER_SETUP** is defined, there are two use cases for timekeeping in low power operation:
+1. Keep track of elapsed time in low power mode only when ThreadX timers are active. If there are ThreadX timers active, the elapsed time while in low power mode must be measured, thus a low power hardware timer is required (this timer can be configured in **TX_LOW_POWER_TIMER_SETUP**). If there are no ThreadX timers active when entering low power mode, then no hardware timer needs to keep track of elapsed time. This is "tick-less" operation. To enable this feature, the symbol **TX_LOW_POWER_TICKLESS** must be defined. The internal ThreadX tick count will not reflect the time spent in low power mode when no ThreadX timers are active.
+2. Always keep track of time in low power mode. This is necessary to keep the internal ThreadX tick count accurate. In this case, **TX_LOW_POWER_TICKLESS** must *not* be defined, as a hardware timer will always be needed in low power mode to measure elapsed time. The hardware timer is intended to be configured in **TX_LOW_POWER_TIMER_SETUP**.
+
+> Example 1: No low power timer is in use (**TX_LOW_POWER_TIMER_SETUP** is *not* defined). There is a ThreadX timer with 50 ticks remaining. The internal ThreadX tick count is 1000. The processor goes into low power mode for some length of time. After exiting low power mode, the ThreadX timer still has 50 ticks remaining. The internal ThreadX tick count is 1000.
+
+> Example 2: A low power timer is available (**TX_LOW_POWER_TIMER_SETUP** is defined). **TX_LOW_POWER_TICKLESS** is defined. There is a ThreadX timer A with 50 ticks remaining and another ThreadX timer B with 20 ticks remaining. The internal ThreadX tick count is 1000. The processor goes into low power mode for 20 ticks. Upon exiting low power mode, the ThreadX timer A will have 30 ticks remaining. The expiration function for ThreadX timer B will be executed. The internal ThreadX tick count is 1020.
+After executing for some time, the internal ThreadX tick count is 2000 and there are no ThreadX timers active. The processor goes into low power mode for some length of time. After exiting low power mode, the internal ThreadX tick count is 2000.
+
+> Example 3: A low power timer is always used (**TX_LOW_POWER_TIMER_SETUP** is defined and **TX_LOW_POWER_TICKLESS** is *not* defined). The internal ThreadX tick count is 1000 and there are no ThreadX timers active. The processor goes into low power mode for some length of time. Upon exiting low power mode, it is determined that the processor was in low power mode for 20 ticks. The internal ThreadX tick count is updated to 1020.
----
## User-defined Macros
-- **TX_LOW_POWER_TIMER_SETUP** - an optional macro to a user routine that sets up a low power clock. To set up a low power timer or operate ticklessly in low power mode, this must be defined. This is called in **tx_low_power_enter**.
-- **TX_LOW_POWER_TICKLESS** - an optional define to operate ticklessly in low power mode. Symbol **TX_LOW_POWER_TIMER_SETUP** must also be defined. With this defined, there is no need to set up a low power timer to keep track of time. ThreadX will not maintain/update the internal tick count during or after exiting low power mode.
-- **TX_LOW_POWER_USER_ENTER** - an optional macro to a user routine that configures the processor for entering low power mode (e.g. turn off peripherals and select a sleep mode). This is called in **tx_low_power_enter**.
-- **TX_LOW_POWER_USER_EXIT** - an optional macro to a user routine that configures the processor for exiting low power mode (e.g. turn on peripherals). This is called in **tx_low_power_exit**.
-- **TX_LOW_POWER_USER_TIMER_ADJUST** - an optional user macro to determine how much time has elapsed while in low power mode (in units of ThreadX ticks). This is called in **tx_low_power_exit** to get the number of ticks needed to adjust the ThreadX timers.
+The following macros invoke functions that the user may want to define/implement.
+
+### Summary of user-defined macros
+
+ - ```TX_LOW_POWER_TIMER_SETUP``` - *set up low power timer*
+ - ```TX_LOW_POWER_USER_ENTER``` - *configure processor to enter low power mode*
+ - ```TX_LOW_POWER_USER_EXIT``` - *configure processor to exit low power mode*
+ - ```TX_LOW_POWER_USER_TIMER_ADJUST``` - *return the number of ticks the processor was in low power mode*
+
+---
+
+### TX_LOW_POWER_TIMER_SETUP
+```c
+VOID TX_LOW_POWER_TIMER_SETUP(ULONG tx_low_power_next_expiration);
+```
+
+### Input parameters
+
+- *tx_low_power_next_expiration* - the number of ticks to configure the low power timer.
+
+### Return values
+
+- *none*
+
+**TX_LOW_POWER_TIMER_SETUP** is a macro invoking user-defined function that sets up a low power timer. To set up a low power timer or operate ticklessly in low power mode, this symbol must be defined. This macro is called in ```tx_low_power_enter```. If **TX_LOW_POWER_TICKLESS** is not defined and there are no timers active, the *tx_low_power_next_expiration* parameter will be set to 0xFFFFFFFF.
+
+> Note: The number of ThreadX ticks is the input to this function. The frequency of a ThreadX timer tick is defined in **TX_TIMER_TICKS_PER_SECOND** (typically defined in file tx_api.h, tx_user.h, or tx_port.h).
+
+> Note: do not put the processor to sleep in this macro.
+
+### Optional Define
+
+- **TX_LOW_POWER_TICKLESS** - an optional define to operate ticklessly in low power mode only if no ThreadX timers are active. With symbol **TX_LOW_POWER_TICKLESS** defined, if there are no ThreadX timers active, **TX_LOW_POWER_TIMER_SETUP** will not be called in ```tx_low_power_enter```. ThreadX will not maintain/update the internal tick count during or after exiting low power mode. Symbol **TX_LOW_POWER_TIMER_SETUP** must also be defined if defining **TX_LOW_POWER_TICKLESS**.
+
+### Example
+
+```c
+/* Low power timer function prototype. */
+void low_power_timer_config(ULONG ticks);
+
+/* Define the TX_LOW_POWER_TIMER_SETUP macro. */
+#define TX_LOW_POWER_TIMER_SETUP low_power_timer_config
+
+void low_power_timer_config(ULONG ticks)
+{
+ /* Insert code here to configure a hardware timer
+ to wake the processor from sleep after
+ ticks/TX_TIMER_TICKS_PER_SECOND seconds. */
+}
+```
+
+---
+
+### TX_LOW_POWER_USER_ENTER
+A macro invoking a user-defined function that configures the processor for entering low power mode (e.g. turn off peripherals and select a sleep mode). This macro is called in ```tx_low_power_enter```.
+
+### Input parameters
+
+- *none*
+
+### Return values
+
+- *none*
+
+### Example
+
+```c
+/* Low power enter function prototype. */
+void low_power_enter(void);
+
+/* Define the TX_LOW_POWER_USER_ENTER macro. */
+#define TX_LOW_POWER_USER_ENTER low_power_enter
+
+void low_power_enter(void)
+{
+ /* Insert code here to configure the processor to enter low power mode. */
+}
+```
+---
+
+### TX_LOW_POWER_USER_EXIT
+A macro invoking a user-defined function that configures the processor for exiting low power mode (e.g. turn on peripherals). This is called in ```tx_low_power_exit```.
+
+### Input parameters
+
+- *none*
+
+### Return values
+
+- *none*
+
+### Example
+
+```c
+/* Low power exit function prototype. */
+void low_power_exit(void);
+
+/* Define the TX_LOW_POWER_USER_EXIT macro. */
+#define TX_LOW_POWER_USER_EXIT low_power_exit
+
+void low_power_exit(void)
+{
+ /* Insert code here to configure the processor to exit low power mode. */
+}
+```
+
+---
+
+### TX_LOW_POWER_USER_TIMER_ADJUST
+
+```c
+ULONG TX_LOW_POWER_USER_TIMER_ADJUST(VOID);
+```
+
+A macro invoking a user-defined function to determine how much time has elapsed while in low power mode (in units of ThreadX ticks). This is called in ```tx_low_power_exit``` and returns the number of ticks needed to adjust the ThreadX timers.
+
+When exiting low power mode, there are two possibilities:
+ 1. The processor slept for the entire time the timer was configured to sleep.
+ 2. The processor was awakened early.
+
+### Input parameters
+
+- *none*
+
+### Return values
+
+- *tx_low_power_adjust_ticks*
+
+### Example
+
+```c
+/* Low power timer adjust function prototype. */
+ULONG low_power_timer_adjust(void);
+
+/* Define the TX_LOW_POWER_USER_TIMER_ADJUST macro. */
+#define TX_LOW_POWER_USER_TIMER_ADJUST low_power_timer_adjust
+
+ULONG low_power_timer_adjust(void)
+{
+ ULONG actual_ticks_slept;
+ ULONG elapsed_time_in_ms;
+
+ /* Insert code here to read timer registers to determine
+ how long the processor actually slept. */
+ elapsed_time_in_ms = read_timer_register();
+
+ /* Convert elapsed time to ThreadX ticks. */
+ actual_ticks_slept = elapsed_time_in_ms / (1000/TX_TIMER_TICKS_PER_SECOND);
+
+ return(actual_ticks_slept);
+}
+```
+
+---
+
+## Summary of Low Power APIs
+
+- ```tx_low_power_enter``` - *Enter low power mode*
+- ```tx_low_power_exit``` - *Exit low power mode*
+- ```tx_time_increment``` - *Increment ThreadX timers by specific amount*
+- ```tx_timer_get_next``` - *Get next ThreadX timer expiration*
+
+---
## tx_low_power_enter
@@ -40,26 +224,24 @@ VOID tx_low_power_enter(VOID); ### Description
-This service enters low power mode.
-For keeping track of time while in low power mode, there are two possibilities:
+This service enters low power mode. The macros **TX_LOW_POWER_TIMER_SETUP** and **TX_LOW_POWER_USER_ENTER** are called in this function to allow the user to configure a low power timer and configure the hardware for low power mode.
-1. A ThreadX timer is active. Function **tx_timer_get_next** returns **TX_TRUE**. Note that in this situation, a low power clock must be used in order to wake up the CPU for the next ThreadX timer expiration. Therefore an alternative clock must be programmed. Program the hardware timer source such that the next timer interrupt is equal to: *tx_low_power_next_expiration \* tick_frequency*. The *tick_frequency* is application-specific and typically set up in **tx_low_level_initialize**.
+For keeping track of time while in low power mode, there are two possibilities:
-2. There are no ThreadX timers active. Function **tx_timer_get_next** returns **TX_FALSE**.
- 1. The application may choose not to keep the ThreadX internal
- tick count updated (define **TX_LOW_POWER_TICKLESS**), therefore there is no need
- to set up a low power clock.
+1. A ThreadX timer is active. Function ```tx_timer_get_next``` returns **TX_TRUE**. Note that in this situation, a low power clock must be used in order to wake up the CPU for the next ThreadX timer expiration. Therefore a low power timer/clock must be programmed. Program the hardware timer source such that the next timer interrupt is equal to: *tx_low_power_next_expiration \* tick_frequency*. The *tick_frequency* is application-specific and typically set up in ```tx_low_level_initialize```.
- 2. The application still needs to keep the ThreadX tick up-to-date. In this case
- a low power clock needs to be set up.
+2. There are no ThreadX timers active. Function ```tx_timer_get_next``` returns *TX_FALSE*.
+ 1. The application may choose **not** to keep the ThreadX internal
+ tick count updated (define **TX_LOW_POWER_TICKLESS**), therefore there is no need to set up a low power clock.
+ 2. The application still needs to keep the ThreadX tick up-to-date. In this case a low power clock needs to be configured.
### Input parameters
-- **none**
+- *none*
### Return values
-- **none**
+- *none*
### Allowed from
@@ -67,7 +249,7 @@ Internal ThreadX code, application ### Example
-ARM assembly
+ARM Cortex-M assembly
```c
#ifdef TX_LOW_POWER
PUSH {r0-r3}
@@ -106,15 +288,15 @@ VOID tx_low_power_exit(VOID); ### Description
-This service exits low power mode.
+This service exits low power mode. Macro **TX_LOW_POWER_USER_EXIT** is called in this function to allow the user to configure the hardware to exit low power mode. Macro **TX_LOW_POWER_USER_TIMER_ADJUST** is called in this function to determine how long the processor actually slept.
### Input parameters
-- **none**
+- *none*
### Return values
-- **none**
+- *none*
### Allowed from
@@ -150,7 +332,7 @@ Internal ThreadX code, application ## tx_time_increment
-This function increments the current time by a specified value. The value was derived by the application by calling the **tx_timer_get_next** function prior to this call, which was right before the processor was put in low power mode.
+This function increments the current time by a specified value. The value was derived by the application by calling the ```tx_timer_get_next``` function prior to this call, which was right before the processor was put in low power mode.
### Prototype
@@ -160,15 +342,15 @@ VOID tx_time_increment(ULONG time_increment); ### Description
-This function increments the current time by a specified value. The value was derived by the application by calling the **tx_timer_get_next** function prior to this call, which was right before the processor was put in low power mode.
+This function increments the current time by a specified value. The value was derived by the application by calling the ```tx_timer_get_next``` function prior to this call, which was right before the processor was put in low power mode.
### Input parameters
-- **time_increment** Number of ThreadX ticks to increment time and timers.
+- *time_increment* - Number of ThreadX ticks to increment time and timers.
### Return values
-- **none**
+- *none*
### Allowed from
@@ -176,7 +358,7 @@ Internal ThreadX code, application ### Example
-From **tx_low_power_exit**:
+From ```tx_low_power_exit```:
```c
/* Call the low-power timer driver code to obtain the amount of time (in ticks)
@@ -213,16 +395,16 @@ ULONG tx_timer_get_next(ULONG *next_timer_tick_ptr); ### Description
-This service gets the next ThreadX timer expiration, in ticks.
+This service gets the next ThreadX timer expiration, in ticks.
### Input parameters
-- **next_timer_tick_ptr** pointer to hold number of ticks
+- *next_timer_tick_ptr* - pointer to hold number of ticks
### Return values
-- **TX_TRUE** (1) At least one timer is active.
-- **TX_FALSE** (0) No timers are currently active.
+- *TX_TRUE* (1) At least one timer is active.
+- *TX_FALSE* (0) No timers are currently active.
### Allowed from
@@ -230,7 +412,7 @@ Internal ThreadX code, application ### Example
-From **tx_low_power_enter**:
+From ```tx_low_power_enter```:
```c
ULONG tx_low_power_next_expiration; /* The next timer expiration (units of ThreadX timer ticks). */
diff --git a/utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c b/utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c index ee617a59..9882b654 100644 --- a/utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c +++ b/utility/rtos_compatibility_layers/FreeRTOS/tx_freertos.c @@ -29,10 +29,15 @@ /* 01-31-2022 William E. Lamie Modified comment(s), and */ /* fixed compiler warnings, */ /* resulting in version 6.1.10 */ +/* 07-29-2022 Cindy Deng Added simple static scheduler */ +/* start flag, corrected stack */ +/* allocation size, */ +/* resulting in version 6.1.12 */ /* */ /**************************************************************************/ #include <stdint.h> +#include <limits.h> #include <tx_api.h> #include <tx_thread.h> @@ -63,6 +68,7 @@ static TX_BYTE_POOL txfr_heap; static UINT txfr_heap_initialized; #if (TX_FREERTOS_AUTO_INIT == 1) static UINT txfr_initialized; +static UINT txfr_scheduler_started; #endif // #if (TX_FREERTOS_AUTO_INIT == 1) // TODO - do something with malloc. @@ -263,6 +269,7 @@ void vPortExitCritical(void) void vTaskStartScheduler(void) { #if (TX_FREERTOS_AUTO_INIT == 1) + txfr_scheduler_started = 1u; _tx_thread_schedule(); #else // Nothing to do, THREADX scheduler is already started. @@ -272,6 +279,11 @@ void vTaskStartScheduler(void) BaseType_t xTaskGetSchedulerState(void) { +#if (TX_FREERTOS_AUTO_INIT == 1) + if(txfr_scheduler_started == 0u) { + return taskSCHEDULER_NOT_STARTED; + } +#endif if(_tx_thread_preempt_disable > 0u) { return taskSCHEDULER_SUSPENDED; } else { @@ -315,6 +327,7 @@ TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode, { UINT prio; UINT ret; + ULONG stack_depth_bytes; TX_INTERRUPT_SAVE_AREA; configASSERT(pxTaskCode != NULL); @@ -329,6 +342,13 @@ TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode, } #endif + if(ulStackDepth > (ULONG_MAX / sizeof(StackType_t))) { + /* Integer overflow in stack depth */ + TX_FREERTOS_ASSERT_FAIL(); + return NULL; + } + stack_depth_bytes = ulStackDepth * sizeof(StackType_t); + TX_MEMSET(pxTaskBuffer, 0, sizeof(*pxTaskBuffer)); pxTaskBuffer->p_task_arg = pvParameters; pxTaskBuffer->p_task_func = pxTaskCode; @@ -342,7 +362,7 @@ TaskHandle_t xTaskCreateStatic(TaskFunction_t pxTaskCode, prio = txfr_prio_fr_to_tx(uxPriority); ret = tx_thread_create(&pxTaskBuffer->thread, (CHAR *)pcName, txfr_thread_wrapper, (ULONG)pvParameters, - puxStackBuffer, ulStackDepth, prio, prio, 0u, TX_DONT_START); + puxStackBuffer, stack_depth_bytes, prio, prio, 0u, TX_DONT_START); if(ret != TX_SUCCESS) { TX_FREERTOS_ASSERT_FAIL(); return NULL; @@ -375,6 +395,7 @@ BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, txfr_task_t *p_task; UINT ret; UINT prio; + ULONG stack_depth_bytes; TX_INTERRUPT_SAVE_AREA; configASSERT(pvTaskCode != NULL); @@ -387,8 +408,14 @@ BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, tx_freertos_auto_init(); } #endif + if((usStackDepth > (SIZE_MAX / sizeof(StackType_t))) + || (usStackDepth > (ULONG_MAX / sizeof(StackType_t)))) { + /* Integer overflow in stack depth */ + return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + stack_depth_bytes = usStackDepth * sizeof(StackType_t); - p_stack = txfr_malloc(usStackDepth); + p_stack = txfr_malloc((size_t)stack_depth_bytes); if(p_stack == NULL) { return errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } @@ -417,7 +444,7 @@ BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, prio = txfr_prio_fr_to_tx(uxPriority); ret = tx_thread_create(&p_task->thread, (CHAR *)pcName, txfr_thread_wrapper, (ULONG)pvParameters, - p_stack, usStackDepth, prio, prio, 0u, TX_DONT_START); + p_stack, stack_depth_bytes, prio, prio, 0u, TX_DONT_START); if(ret != TX_SUCCESS) { (void)tx_semaphore_delete(&p_task->notification_sem); txfr_free(p_stack); |
