Difference between revisions of "Nrf52-timer-config"
m |
m (→^ Sources and leads to review) |
||
Line 205: | Line 205: | ||
./integration/nrfx/legacy/nrf_drv_timer.h:107:#define nrf_drv_timer_task_address_get nrfx_timer_task_address_get | ./integration/nrfx/legacy/nrf_drv_timer.h:107:#define nrf_drv_timer_task_address_get nrfx_timer_task_address_get | ||
<!-- comment --> | <!-- comment --> | ||
+ | |||
+ | == [[#top|^]] References == | ||
+ | <ul> | ||
+ | * https://www.eng.auburn.edu/~nelsovp/courses/elec3040_3050/LabLectures/ELEC30x0%20Lab7%20PWM%20Slides.pdf | ||
+ | </ul> |
Revision as of 17:26, 28 April 2021
Contents
Overview . . .
These notes started to support work with nRF52832 Bluetooth System On Chip (SoC) device. First task involves utilizing an available timer along side implemented and active "soft device" of type S132. A good reference for nRF52 SoC:
2021-04-25
Looking at some example code in nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/components/app_simple_timer.c
, there are routines to init, start, stop (pause) and to uninitialize. Given a task to assure that a Nordic chip goes into lower or lowest possible power mode, we'll first examine the 'stop' and 'uninit' routines in this Nordic demo code.
The routine uint32_t app_simple_timer_stop(void)
is a wrapper to nrf_drv_timer_pause(nrfx_timer_t const * const p_instance)
. Going through reverse engineering steps this routine is first defined via a macro:
./integration/nrfx/legacy/nrf_drv_timer.h:82:#define nrf_drv_timer_pause nrfx_timer_pause
The definition of nrfx_timer_pause()
is in the following .c file,
./modules/nrfx/drivers/include/nrfx_timer.h:186:void nrfx_timer_pause(nrfx_timer_t const * const p_instance); ./modules/nrfx/drivers/src/nrfx_timer.c:170:void nrfx_timer_pause(nrfx_timer_t const * const p_instance)
First Nordic demo code directories in which we're reviewing files:
nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/components/libraries/simple_timer nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/modules nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/modules/nrfx/drivers/include nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/modules/nrfx/drivers/src nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/integration/nrfx/legacy
Something interesting in file nrfx_timer.c, looks like a compile time evaluation may determine the size of an array of time_control_block_t
types:
64 static timer_control_block_t m_cb[NRFX_TIMER_ENABLED_COUNT];
. . . sure enough, in ../include/nrfx_timer.h
there is an enum whose members are conditionally compiled. Clever!:
enum { #if NRFX_CHECK(NRFX_TIMER0_ENABLED) NRFX_TIMER0_INST_IDX, #endif #if NRFX_CHECK(NRFX_TIMER1_ENABLED) NRFX_TIMER1_INST_IDX, #endif #if NRFX_CHECK(NRFX_TIMER2_ENABLED) NRFX_TIMER2_INST_IDX, #endif #if NRFX_CHECK(NRFX_TIMER3_ENABLED) NRFX_TIMER3_INST_IDX, #endif #if NRFX_CHECK(NRFX_TIMER4_ENABLED) NRFX_TIMER4_INST_IDX, #endif NRFX_TIMER_ENABLED_COUNT };
So the first demo routine of interest, to pause or equivalently stop a timer is:
void nrfx_timer_pause(nrfx_timer_t const * const p_instance) { NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED); nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP); NRFX_LOG_INFO("Paused instance: %d.", p_instance->instance_id); }
We're looking at this to determine whether stopping a timer removes power from the timer peripheral in the nRF52 SoC. Looks like there is another layer of routine nesting with the call here to nrf_timer_task_trigger()
. There may be some clue as to how this routine works, and possibly one of the parameters it accepts will power off a given timer. Here are all calls to it in the nrfx/drivers directory:
ted@localhost$ ./nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/modules/nrfx/drivers $ grep -nr nrf_timer_task_trigger ./* ./src/nrfx_timer.c:144: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START); ./src/nrfx_timer.c:152: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN); ./src/nrfx_timer.c:166: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_START); ./src/nrfx_timer.c:173: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_STOP); ./src/nrfx_timer.c:180: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_CLEAR); ./src/nrfx_timer.c:188: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_COUNT); ./src/nrfx_timer.c:197: nrf_timer_task_trigger(p_instance->p_reg,
From the file ./hal/nrf_timer.h
looks also like nrf_timer_task_trigger() is normally an in-lined routine:
#ifndef SUPPRESS_INLINE_IMPLEMENTATION __STATIC_INLINE void nrf_timer_task_trigger(NRF_TIMER_Type * p_reg, nrf_timer_task_t task) { *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)task)) = 0x1UL; }
So this routine writes a timer peripheral control register with the value 1. Seems a little odd, is there some syntax I am misreading here? . . .
^ nRF5x shutting down timer
Well here is something interesting and promising, the comment along side the following definition of NRF_TIMER_TASK_SHUTDOWN
implies that this action powers off the timer:
/nRF5SDK153059ac345/nRF5_SDK_15.3.0_59ac345/modules/nrfx $ grep -nr NRF_TIMER_TASK_SHUTDOWN ./* ./drivers/src/nrfx_timer.c:152: nrf_timer_task_trigger(p_instance->p_reg, NRF_TIMER_TASK_SHUTDOWN); ./hal/nrf_timer.h:108: NRF_TIMER_TASK_SHUTDOWN = offsetof(NRF_TIMER_Type, TASKS_SHUTDOWN), ///< Task for powering off the timer.
So then where and how is offsetof()
defined?
^ offsetof() routine definition
Looks like this offsetof()
is defined in components/libraries/util/app_util.h:
./components/libraries/util/app_util.h:190:#undef offsetof ./components/libraries/util/app_util.h:191:#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
Here are the lines and some conditional directives to activate or disable the possible redefinition of offsetof()
:
187 /*Segger embedded studio originally has offsetof macro which cannot be used in macros (like STATIC_ASSERT). 188 This redefinition is to allow using that. */ 189 #if defined(__SES_ARM) && defined(__GNUC__) 190 #undef offsetof 191 #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) 192 #endif
A couple of references to explain offsetof() purpose:
- https://gcc.gnu.org/onlinedocs/gcc/Offsetof.html
- https://stackoverflow.com/questions/400116/what-is-the-purpose-and-return-type-of-the-builtin-offsetof-operator#:~:text=The%20purpose%20of%20a%20built-in%20__offsetof%20operator%20is,when%20%28%26lvalue%29%20returned%20the%20address%20of%20that%20rvalue.
^ SIMPLE_TIMER definition
The symbol SIMPLE_TIMER
we encounter first in _59ac345/components/libraries/simple_timer/app_simple_timer.c on line 64:
64 const nrf_drv_timer_t SIMPLE_TIMER = NRF_DRV_TIMER_INSTANCE(SIMPLE_TIMER_CONFIG_INSTANCE);:w
nrf_drv_timer_t
is a typedef of nrfx_timer_t
, defined in ./modules/nrfx/drivers/include/nrfx_timer.h:
97 /** 98 * @brief Timer driver instance configuration structure. 99 */ 100 typedef struct 101 { 102 nrf_timer_frequency_t frequency; ///< Frequency. 103 nrf_timer_mode_t mode; ///< Mode of operation. 104 nrf_timer_bit_width_t bit_width; ///< Bit width. 105 uint8_t interrupt_priority; ///< Interrupt priority. 106 void * p_context; ///< Context passed to interrupt handler. 107 } nrfx_timer_config_t;
...345/integration/nrfx/legacy/nrf_drv_timer.h:
63 /** @brief Macro for forwarding the new implementation. */ 64 #define NRF_DRV_TIMER_INSTANCE NRFX_TIMER_INSTANCE
Ok so the big question of where is the timer instance expressed and used in these SDK library code is about to be answered. Symbol NRFX_TIMER_INSTANCE
is defined in file [unzip_location]/nRF5_SDK_15.3.0_59ac345/modules/nrfx/drivers/include/nrfx_timer.h:
68 /** 69 * @brief Macro for creating a timer driver instance. 70 */ 71 #define NRFX_TIMER_INSTANCE(id) \ 72 { \ 73 .p_reg = NRFX_CONCAT_2(NRF_TIMER, id), \ 74 .instance_id = NRFX_CONCAT_3(NRFX_TIMER, id, _INST_IDX), \ 75 .cc_channel_count = NRF_TIMER_CC_CHANNEL_COUNT(id), \ 76 }
Finally symbol SIMPLE_TIMER_CONFIG_INSTANCE is, relative to the app_simple_timer.c source file, defined in the following sdk_config.h file:
./examples/peripheral/simple_timer/pca10040/blank/config/sdk_config.h:622:#ifndef SIMPLE_TIMER_CONFIG_INSTANCE ./examples/peripheral/simple_timer/pca10040/blank/config/sdk_config.h:623:#define SIMPLE_TIMER_CONFIG_INSTANCE 1
^ Sources and leads to review
Things to review:
- Following code seems to reference timer task counting, might this relate to using two or more capture/compare registers with a given nRF timer?
./components/libraries/experimental_libuarte/nrf_libuarte.c:183: nrfx_timer_task_address_get(&p_libuarte->timer, NRF_TIMER_TASK_COUNT),
- Let's look into this as well, code to obtain address of a timer task:
./integration/nrfx/legacy/nrf_drv_timer.h:107:#define nrf_drv_timer_task_address_get nrfx_timer_task_address_get