{"id":19798636,"url":"https://github.com/eriknyquist/app_timer","last_synced_at":"2025-05-01T05:30:25.329Z","repository":{"id":39569141,"uuid":"370155064","full_name":"eriknyquist/app_timer","owner":"eriknyquist","description":"Friendly, lightweight, hardware-agnostic timer abstraction layer in C. Use a single timer/counter source to drive many timed events.","archived":false,"fork":false,"pushed_at":"2022-07-24T01:20:41.000Z","size":263,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-06T08:27:39.124Z","etag":null,"topics":["arduino","c","cprogramming","embedded","embedded-c","hardware-agnostic","linux","os-agnostic","portable","scheduling","timer","timers","timing","windows"],"latest_commit_sha":null,"homepage":"https://ekn.io","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eriknyquist.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-23T20:53:02.000Z","updated_at":"2024-12-05T14:26:03.000Z","dependencies_parsed_at":"2022-07-12T18:00:54.955Z","dependency_job_id":null,"html_url":"https://github.com/eriknyquist/app_timer","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fapp_timer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fapp_timer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fapp_timer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fapp_timer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eriknyquist","download_url":"https://codeload.github.com/eriknyquist/app_timer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251830449,"owners_count":21650802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","c","cprogramming","embedded","embedded-c","hardware-agnostic","linux","os-agnostic","portable","scheduling","timer","timers","timing","windows"],"created_at":"2024-11-12T07:30:56.303Z","updated_at":"2025-05-01T05:30:24.954Z","avatar_url":"https://github.com/eriknyquist.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"Hardware-agnostic  application timer layer in C\n###############################################\n\nThis is an \"application timers\" implementation in C, allowing you to use a single\ntimer/counter source to drive an arbitrary number of timed events. ``app_timer`` provides\na flexible abstraction for the timer/counter source used to measure time (referred to as\nthe \"hardware model\"). Whether your source of time is a timer interrupt in an embedded system,\nor a read-only monotonic counter that cannot generate interrupts, or something else entirely,\nyou can write a hardware model that will allow app_timer to work with it.\n\nIf you are writing C or C++ for an embedded device that has a timer/counter peripheral that can\nbe configured to generate an interrupt when a certain count value is reached, and you would\nlike to implement an application timer layer driven by those interrupts, then this module might\nbe useful to you.\n\nIf you are writing a desktop application in C or C++, and you don't have any hardware timer interrupts\nbut you would like to implement an application timer layer driven by a polling loop, then this\nmodule might also be useful to you.\n\nIt's the same idea as the \"app_timer\" library provided by Nordic's nRf5 SDK,\nexcept with an abstraction layer for the actual timer/counter hardware, so that it can\nbe easily ported to other projects or embedded systems.\n\nSee API documentation in ``app_timer_api.h`` for more details.\n\nFeatures / limitations\n----------------------\n\n- Use a single monotonic timer/counter source to drive many timed events.\n\n- Written in pure C99, with no external dependencies, just the standard C lib\n  (specifically, ``stdlib.h``, ``stdbool.h``, and ``stdint.h`` are required).\n\n- Flexible interface-- implement an interrupt-based app_timer layer for a microcontroller,\n  or a completely synchronous app_timer layer that relies on a polling loop with no interupts,\n  or something else entirely. There are no OS-specific or hardware-specific dependencies. You\n  can adapt ``app_timer`` to many different systems and situations (see examples in ``example_hw_models``).\n\n- No dynamic memory allocation, and no limit on the number of timers that can be running simultaneously. When you call\n  app_timer_start, your app_timer_t struct is linked into to a linked list with all other active timers (timers that\n  have been started but not yet expired). The number of timers you can have running at once is really only limited by\n  how much memory your system has available for declaring app_timer_t structs, whether statically or otherwise.\n\n- Automatic handling of timer/counter overflow; if you are using a timer/counter, for example, which overflows after\n  30 minutes with your specific configuration, and you call ``app_timer_start`` with an expiry time of, say, 72 hours,\n  then the overflow will be handled behind the scenes by the ``app_timer`` module and your timer handler function will\n  still only be called after 72 hours.\n\nGetting started\n---------------\n\n#. Implement a hardware model for your specific time source, or use one of the samples\n   in ``example_hw_models`` if there is an appropriate one. In this case, we'll use the\n   arduino UNO hardware model, ``arduino_app_timer.c`` and ``arduino_app_timer.h``,\n   for discussion's sake.\n\n#. In your application code, ensure that ``app_timer_init`` is being called, and that\n   a pointer to the app_timer_hw_model_t struct for your hardware model is passed in.\n   The arduino hardware model provides a ``arduino_app_timer_init`` function which\n   does exactly this.\n\n#. Ensure that ``app_timer.c`` and ``arduino_app_timer.c`` (or whatever hardware model\n   you are using, if not arduino) are compiled and linked in along with the rest of your\n   application.\n\n#. That's it. Now that ``app_timer`` has been initialized with a hardware model,\n   you can use the functions from ``app_timer_api.h`` in your application code to\n   create and run ``app_timer_t`` instances.\n\nBuild options\n-------------\n\nThere are several preprocessor symbols you can define to change various things at compile time.\nThe following sections provide some details about those options.\n\nOptimize for freerunning counter\n================================\n\nBy default, ``app_timer`` assumes that the counter is *not* free-running, and that the\ncounter will stop counting and/or reset when the target count is reached. However,\nif this is not the case, and the counter you are using will continue to count normally\nonce the target count is reached, then you can enable the following option to reduce\noverall timing jitter:\n\n+-----------------------------------+-------------------------------------------------+\n| **Symbol name**                   | **What you get if you define this symbol**      |\n+===================================+=================================================+\n| ``APP_TIMER_FREERUNNING_COUNTER`` | Optimization for freerunning counter is enabled |\n+-----------------------------------+-------------------------------------------------+\n\nEnable app_timer_stats function\n===============================\n\nEnables various runtime information to be collected via the ``app_timer_stats`` function.\nSee ``app_timer_stats_t`` struct definition in ``app_timer_api.h`` for more details.\n\nDisabled by default.\n\n+----------------------------+------------------------------------------------------------+\n| **Symbol name**            | **What you get if you define this symbol**                 |\n+============================+============================================================+\n| ``APP_TIMER_STATS_ENABLE`` | Runtime info collection via ``app_timer_stats`` is enabled |\n+----------------------------+------------------------------------------------------------+\n\nRe-configure counter without stopping \u0026 restarting it\n=====================================================\n\nThe default behaviour is to always stop the counter before setting a new period via\n``hw_model-\u003eset_timer_period_counts``, and then re-start the counter, like so:\n\n::\n\n    hw_model-\u003eset_timer_running(false);\n    hw_model-\u003eset_timer_period_counts(new_timer_period);\n    hw_model-\u003eset_timer_running(true);\n\nAlternatively, if you want the counter to be re-configured for a new period without\nstopping and re-starting, such that ``hw_model-\u003eset_timer_running(false)`` will only be called\nto stop the counter in the event that there are no active timers, you can define the following option;\n\n+---------------------------------------------+--------------------------------------------------------------------------------------------------+\n| **Symbol name**                             | **What you get if you define this symbol**                                                       |\n+=============================================+==================================================================================================+\n| ``APP_TIMER_RECONFIG_WITHOUT_STOPPING``     | Counter will not be stopped to set a new timer period with ``hw_model-\u003eset_timer_period_counts`` |\n+---------------------------------------------+--------------------------------------------------------------------------------------------------+\n\nEnable interrupts when running timer handler functions\n======================================================\n\n``app_timer_target_count_reached`` disables interrupts via the hardware model ``set_interrupt_enabled``\nfunction, in order to protect access to the timer hardware and the list of active timers. By default,\ninterrupts will be disabled the entire time that ``app_timer_target_count_reached`` is executing,\nincluding when timer handler functions are called. If you need interrupts to be functional\nwhen timer handler functions are called, you can define the following option;\n\n+---------------------------------------------+---------------------------------------------------------------------------------------------+\n| **Symbol name**                             | **What you get if you define this symbol**                                                  |\n+=============================================+=============================================================================================+\n| ``APP_TIMER_ENABLE_INTERRUPTS_FOR_HANDLER`` | ``app_timer_target_count_reached`` will re-enable interrupts to run timer handler functions |\n+---------------------------------------------+---------------------------------------------------------------------------------------------+\n\nDatatype used for app_timer_period_t\n====================================\n\nDetermines the datatype used to represent the period for a timer (e.g. the\n'time_from_now' parameter passed to app_timer_start).\n\nFor example, if you are using a hardware model that expects milliseconds for timer periods,\nand uint32_t is used for timer periods, then the max. timer period you can pass to app_timer_start\nis 2^32 milliseconds, or about 49 days.\n\nDefine one of the following options;\n\n+---------------------------------------+------------------------------------------------------------+\n| **Symbol name**                       | **What you get if you define this symbol**                 |\n+=======================================+============================================================+\n| ``APP_TIMER_PERIOD_UINT32``           | ``app_timer_period_t`` is type ``uint32_t`` **(default)**  |\n+---------------------------------------+------------------------------------------------------------+\n| ``APP_TIMER_PERIOD_UINT64``           | ``app_timer_period_t`` is type ``uint64_t``                |\n+---------------------------------------+------------------------------------------------------------+\n\n\nDatatype used for app_timer_count_t\n===================================\n\nDetermines the datatype used to represent a count value for the underlying hardware counter.\nThis should be set to a type that is large enough to hold the largest hardware counter value.\nFor example, if using a 24-bit counter, uint32_t would be sufficient, but not uint16_t.\n\nDefine one of the following options;\n\n+---------------------------------------+------------------------------------------------------------+\n| **Symbol name**                       | **What you get if you define this symbol**                 |\n+=======================================+============================================================+\n| ``APP_TIMER_COUNT_UINT16``            | ``app_timer_count_t`` is type ``uint16_t``                 |\n+---------------------------------------+------------------------------------------------------------+\n| ``APP_TIMER_COUNT_UINT32``            | ``app_timer_count_t`` is type ``uint32_t`` **(default)**   |\n+---------------------------------------+------------------------------------------------------------+\n\n\nDatatype used for app_timer_running_count_t\n===========================================\n\nDetermines the datatype used to represent a running counter that tracks total elapsed time\nsince one or more active timers have been running continuously.\n\nYou should pick this according to the expected lifetime of your system. Let's\nsay, for example, that you are using a counter driven by a 32KHz clock; this\nwould mean using uint32_t for the running counter allows the app_timer module\nto have timers running continuously for up to 2^32(-1) ticks, before the running\ncounter overflows. 2^32(-1) ticks at 32KHz is about 36 hours. Using\nuint64_t for the running counter, so 2^64(-1) ticks before overflow, with the same\nsetup would get you over a million years before overflow.\n\nThis running counter also gets reset to 0 when there are no active timers, so the overflow\ncondition will only occur when there have been one or more active timers continuously for\nthe maximum number of ticks.\n\nDefine one of the following options;\n\n+---------------------------------------+--------------------------------------------------------------------+\n| **Symbol name**                       | **What you get if you define this symbol**                         |\n+=======================================+====================================================================+\n| ``APP_TIMER_RUNNING_COUNT_UINT32``    | ``app_timer_running_count_t`` is type ``uint32_t`` **(default)**   |\n+---------------------------------------+--------------------------------------------------------------------+\n| ``APP_TIMER_RUNNING_COUNT_UINT64``    | ``app_timer_running_count_t`` is type ``uint64_t``                 |\n+---------------------------------------+--------------------------------------------------------------------+\n\n\nDatatype used for app_timer_int_status_t\n========================================\n\nDetermines the datatype used to represent the interrupt status passed to 'set_interrupts_enabled'.\n\nDefine one of the following options;\n\n+---------------------------------------+--------------------------------------------------------------------+\n| **Symbol name**                       | **What you get if you define this symbol**                         |\n+=======================================+====================================================================+\n| ``APP_TIMER_INT_UINT32``              | ``app_timer_int_status_t`` is type ``uint32_t`` **(default)**      |\n+---------------------------------------+--------------------------------------------------------------------+\n| ``APP_TIMER_INT_UINT64``              | ``app_timer_int_status_t`` is type ``uint64_t``                    |\n+---------------------------------------+--------------------------------------------------------------------+\n\n\nIncluded hardware model and example sketch for Arduino UNO\n----------------------------------------------------------\n\nThe ``example_hw_models/arduino_uno/`` directory contains an implementation of a hardware model for\nthe Arduino UNO, and also an example Arduino sketch (.ino file) that uses two app timer instances.\n\nExample sketch- app_timer_blinky.ino\n====================================\n\n.. code:: cpp\n\n    /**\n     * Example sketch showing how to use the app_timer module to re-create\n     * the \"blinky\" sketch without a blocking/polling loop\n     */\n\n    #include \"arduino_app_timer.h\"\n\n    static app_timer_t blink_timer;\n    static app_timer_t print_timer;\n\n    // tracks when the print timer has fired, so we can do the printing in the main loop and\n    // not in timer interrupt context\n    static volatile bool print_timer_fired = false;\n\n\n    // Called whenever \"blink_timer\" expires\n    void blink_timer_callback(void *context)\n    {\n        // Toggle the LED\n        digitalWrite(13, digitalRead(13) ^ 1);\n    }\n\n    // Called whenever \"print_timer\" expires\n    void print_timer_callback(void *context)\n    {\n        // Printing takes a long time, so just a set a flag here and do the\n        // actual printing in the main loop\n        print_timer_fired = true;\n    }\n\n    void setup()\n    {\n        // Initialize the pin to control the LED\n        pinMode(13, OUTPUT);\n\n        // Initialize Serial so we can print\n        Serial.begin(115200);\n\n        // Initialize the app_timer library (calls app_timer_init with the hardware model for arduino uno)\n        arduino_app_timer_init();\n\n        // Create a new timer that will repeat until we stop it, for blinking\n        app_timer_create(\u0026blink_timer, \u0026blink_timer_callback, APP_TIMER_TYPE_REPEATING);\n\n        // Create a new timer that will repeat until we stop it, for blinking\n        app_timer_create(\u0026print_timer, \u0026print_timer_callback, APP_TIMER_TYPE_REPEATING);\n\n        // Start the blink timer to expire every 1000 milliseconds\n        app_timer_start(\u0026blink_timer, 1000u, NULL);\n\n        // Start the print timer to expire every 1250 milliseconds\n        app_timer_start(\u0026print_timer, 1250u, NULL);\n    }\n\n    void loop()\n    {\n        // Check and see if print timer expired\n        if (print_timer_fired)\n        {\n            print_timer_fired = false;\n            Serial.println(\"print\");\n        }\n    }\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fapp_timer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feriknyquist%2Fapp_timer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fapp_timer/lists"}