Skip to content

Commit ffc7b91

Browse files
minosgalanakishug-dev
authored andcommitted
CM3DS: update tickers implementation
The HAL implementation (us_ticker.c and lp_ticker.c) now calls function in cmsdk_ticker.c file. This file contains the necessary logic to be able to only use one hardware timer (CMSDK timer) per mbed ticker. This commit also updates the timer driver and removes legacy definition. Change-Id: If40413822832117f9b78f38d2cdda7847284b035 Signed-off-by: Galanakis, Minos <[email protected]> Signed-off-by: Hugues de Valon <[email protected]>
1 parent ccff46d commit ffc7b91

File tree

14 files changed

+1080
-663
lines changed

14 files changed

+1080
-663
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing software
11+
* distributed under the License is distributed on an "AS IS" BASIS
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* \file cmsdk_ticker.c
19+
* Two abstracted functionalities for CMSDK APB Timers
20+
* 1. Measure elapsed time
21+
* 2. Timer interval interrupt
22+
*
23+
* Passed \ref tick_drv_data_t should be initialized by the caller
24+
* for using these services accordingly.
25+
* See details \ref tick_cfg_t and \ref tick_data_t.
26+
*/
27+
28+
#include "cmsdk_ticker.h"
29+
30+
void cmsdk_ticker_init(const struct tick_drv_data_t* timer_data)
31+
{
32+
if (!timer_data->data->is_initialized) {
33+
timer_cmsdk_init(timer_data->cfg->timer_driver);
34+
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
35+
TIMER_CMSDK_MAX_RELOAD);
36+
timer_cmsdk_enable_interrupt(timer_data->cfg->timer_driver);
37+
NVIC_EnableIRQ(timer_data->cfg->irq_n);
38+
39+
timer_data->data->max_interval_time =
40+
timer_data->cfg->convert_tick_to_time(TIMER_CMSDK_MAX_RELOAD);
41+
timer_data->data->reload_time = timer_data->data->max_interval_time;
42+
timer_data->data->is_initialized = true;
43+
timer_cmsdk_enable(timer_data->cfg->timer_driver);
44+
}
45+
}
46+
47+
uint32_t cmsdk_ticker_read(const struct tick_drv_data_t* timer_data)
48+
{
49+
uint32_t current_elapsed = 0;
50+
51+
if (!timer_data->data->is_initialized) {
52+
cmsdk_ticker_init(timer_data);
53+
}
54+
current_elapsed = timer_cmsdk_get_elapsed_value(timer_data->cfg->timer_driver);
55+
/*
56+
* If for the same reload cycle (ie. cumulated_time is the same) the
57+
* current elapsed time is lower than the previous one, it means that the
58+
* timer has wrapped around without the system logging it. To ensure that
59+
* we are always returning an increasing time in those condition, we return
60+
* the time perviously read.
61+
*/
62+
if ((timer_data->data->previous_cumulated_time ==
63+
timer_data->data->cumulated_time) &&
64+
(current_elapsed < timer_data->data->previous_elapsed)) {
65+
current_elapsed = timer_data->data->previous_elapsed;
66+
}
67+
68+
timer_data->data->previous_elapsed = current_elapsed;
69+
timer_data->data->previous_cumulated_time =
70+
timer_data->data->cumulated_time;
71+
72+
return (timer_data->data->cumulated_time +
73+
timer_data->cfg->convert_tick_to_time(current_elapsed));
74+
}
75+
76+
void cmsdk_ticker_set_interrupt(const struct tick_drv_data_t* timer_data,
77+
uint32_t timestamp)
78+
{
79+
uint32_t interval = 0;
80+
uint32_t interval_reload_tick = 0;
81+
82+
/* Stop before read to avoid race condition with IRQ. */
83+
timer_cmsdk_disable(timer_data->cfg->timer_driver);
84+
uint32_t current_time = cmsdk_ticker_read(timer_data);
85+
86+
timer_data->data->interval_callback_enabled = true;
87+
88+
/*
89+
* We always assume that the event is in the future, even if this
90+
* substraction underflows it is still corect.
91+
*/
92+
interval = (timestamp - current_time);
93+
94+
if (interval >= timer_data->data->max_interval_time) {
95+
/* Event will be in the future but the time is too big: set max */
96+
interval_reload_tick = TIMER_CMSDK_MAX_RELOAD;
97+
timer_data->data->reload_time = timer_data->data->max_interval_time;
98+
} else {
99+
/* Event will be in the future in a time that can be set */
100+
interval_reload_tick =
101+
timer_data->cfg->convert_time_to_tick(interval);
102+
timer_data->data->reload_time = interval;
103+
}
104+
105+
/* Store the current elapsed time, before reset the timer */
106+
timer_data->data->cumulated_time = current_time;
107+
/* Reset the timer with new reload value */
108+
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
109+
interval_reload_tick);
110+
timer_cmsdk_reset(timer_data->cfg->timer_driver);
111+
112+
timer_cmsdk_enable(timer_data->cfg->timer_driver);
113+
}
114+
115+
void cmsdk_ticker_disable_interrupt(const struct tick_drv_data_t* timer_data)
116+
{
117+
if (!timer_data->data->is_initialized) {
118+
cmsdk_ticker_init(timer_data);
119+
}
120+
121+
timer_data->data->interval_callback_enabled = false;
122+
123+
/* Stop before read to avoid race condition with IRQ. */
124+
timer_cmsdk_disable(timer_data->cfg->timer_driver);
125+
/* If interval interrupt is disabled, restore the default max interval,
126+
* but save the current elapsed time before changing the timer. */
127+
timer_data->data->cumulated_time = cmsdk_ticker_read(timer_data);
128+
/* Reset the timer with default reload value */
129+
timer_cmsdk_set_reload_value(timer_data->cfg->timer_driver,
130+
TIMER_CMSDK_MAX_RELOAD);
131+
timer_data->data->reload_time = timer_data->data->max_interval_time;
132+
133+
timer_cmsdk_reset(timer_data->cfg->timer_driver);
134+
timer_cmsdk_enable(timer_data->cfg->timer_driver);
135+
}
136+
137+
void cmsdk_ticker_clear_interrupt(const struct tick_drv_data_t* timer_data)
138+
{
139+
timer_cmsdk_clear_interrupt(timer_data->cfg->timer_driver);
140+
}
141+
142+
void cmsdk_ticker_fire_interrupt(const struct tick_drv_data_t* timer_data)
143+
{
144+
NVIC_SetPendingIRQ(timer_data->cfg->irq_n);
145+
}
146+
147+
void cmsdk_ticker_irq_handler(const struct tick_drv_data_t* timer_data)
148+
{
149+
uint32_t reload_val = 0;
150+
/* If timer's internal interrupt status is not active, then not overflow,
151+
* but explicit interrupt request was fired by cmsdk_ticker_fire_interrupt.
152+
*/
153+
if (timer_cmsdk_is_interrupt_active(timer_data->cfg->timer_driver)) {
154+
/* 1. Calculate cumulated time by overflow */
155+
timer_cmsdk_clear_interrupt(timer_data->cfg->timer_driver);
156+
reload_val = timer_cmsdk_get_reload_value(timer_data->cfg->timer_driver);
157+
timer_data->data->cumulated_time +=
158+
timer_data->cfg->convert_tick_to_time(reload_val);
159+
}
160+
161+
/* 2. Call mbed interval interrupt handler if it's required */
162+
if (timer_data->data->interval_callback_enabled) {
163+
cmsdk_ticker_disable_interrupt(timer_data);
164+
timer_data->cfg->interval_callback();
165+
}
166+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* Copyright (c) 2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
/**
19+
* \file cmsdk_ticker.h
20+
* CMSDK Ticker implements the functionalities of mbed tickers:
21+
* 1. Elapsed time measurement
22+
* 2. Interval interrupt request
23+
*
24+
* This ticker service is based on CMSDK APB Timers, abstracting
25+
* the HAL logic, the timer driver and interrupt number.
26+
* These parameters should be passed to the functions by
27+
* an initialized \ref tick_drv_data_t pointer.
28+
*/
29+
30+
#ifndef CMSDK_TICKER_H
31+
#define CMSDK_TICKER_H
32+
33+
#include <stdbool.h>
34+
35+
#include "CMSDK_CM3DS.h"
36+
#include "timer_cmsdk_drv.h"
37+
38+
#define SEC_TO_USEC_MULTIPLIER 1000000U
39+
40+
/**
41+
* brief Encapsulating struct for config data \ref tick_cfg_t and
42+
* the current status \ref tick_data_t.
43+
*/
44+
struct tick_drv_data_t {
45+
const struct tick_cfg_t* const cfg;
46+
struct tick_data_t* const data;
47+
};
48+
49+
/**
50+
* brief Configuration data of the CMSDK ticker
51+
*/
52+
struct tick_cfg_t {
53+
/** Pointer to the used CMSDK Timer's device structure */
54+
struct timer_cmsdk_dev_t* const timer_driver;
55+
/** IRQ number of the used CMSDK Timer */
56+
const IRQn_Type irq_n;
57+
/** Interval callback of mbed*/
58+
void (*const interval_callback)();
59+
/** Function pointers to call for conversions of clock ticks and defined
60+
* time unit.
61+
* These conversions define the unit of the measured time.
62+
*/
63+
uint32_t (*const convert_tick_to_time)(uint32_t tick);
64+
uint32_t (*const convert_time_to_tick)(uint32_t time);
65+
};
66+
67+
/**
68+
* brief Current state data of the CMSDK ticker
69+
*/
70+
struct tick_data_t {
71+
/** True if initialized the ticker, false otherwise */
72+
bool is_initialized;
73+
/** Measured elapsed time in the defined unit by
74+
* \ref convert_tick_to_time and \ref convert_time_to_tick */
75+
uint32_t cumulated_time;
76+
/** Max interval time possible to set, in the defined unit by
77+
* \ref convert_tick_to_time and \ref convert_time_to_tick */
78+
uint32_t max_interval_time;
79+
/** Current reload time in the defined unit by
80+
* \ref convert_tick_to_time and \ref convert_time_to_tick */
81+
uint32_t reload_time;
82+
/** Interval IRQ callback is requested */
83+
bool interval_callback_enabled;
84+
/** Previous cumulated time calculated for this ticker. Used in the
85+
* cmsdk_ticker_read function to detect that the timer has wrapped. */
86+
uint32_t previous_cumulated_time;
87+
/** Previous elapsed value for this ticker. Used in the
88+
* cmsdk_ticker_read function to detect that the timer has wrapped. */
89+
uint32_t previous_elapsed;
90+
};
91+
92+
/**
93+
* \brief Init the CMSDK Ticker
94+
*
95+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
96+
*/
97+
void cmsdk_ticker_init(const struct tick_drv_data_t* timer_data);
98+
99+
/**
100+
* \brief Read elapsed time by CMSDK Ticker
101+
*
102+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
103+
*
104+
* \return Elapsed time in the unit defined by \ref convert_tick_to_time
105+
*/
106+
107+
uint32_t cmsdk_ticker_read(const struct tick_drv_data_t* timer_data);
108+
109+
/**
110+
* \brief Request interval interrupt by time stamp \ref timestamp_t
111+
*
112+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
113+
* \param[in] timestamp Absolute time \ref timestamp_t value when the interval
114+
* is requested. Unit of the timestamp is defined by
115+
* \ref convert_tick_to_time and \ref convert_time_to_tick
116+
*/
117+
void cmsdk_ticker_set_interrupt(const struct tick_drv_data_t* timer_data,
118+
uint32_t timestamp);
119+
120+
/**
121+
* \brief Disable interval interrupt
122+
*
123+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
124+
*/
125+
void cmsdk_ticker_disable_interrupt(const struct tick_drv_data_t* timer_data);
126+
127+
/**
128+
* \brief Clear interval interrupt
129+
*
130+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
131+
*/
132+
void cmsdk_ticker_clear_interrupt(const struct tick_drv_data_t* timer_data);
133+
134+
/**
135+
* \brief Set pending interrupt that should be fired right away.
136+
*
137+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
138+
*/
139+
void cmsdk_ticker_fire_interrupt(const struct tick_drv_data_t* timer_data);
140+
141+
/**
142+
* \brief Interrupt handler of the given CMSDK Timer
143+
*
144+
* \warning This function may be called from multiple interrupt handlers,
145+
* so extra care must be taken for re-entrancy!
146+
*
147+
* \param[in] timer_data Pointer to the used CMSDK Timer's device structure
148+
*/
149+
void cmsdk_ticker_irq_handler(const struct tick_drv_data_t* timer_data);
150+
#endif

0 commit comments

Comments
 (0)