Commit 28682b5923ba5095e2bcf52b8c65d0dd5c725712
1 parent
b08d202b
Exists in
master
Changes:
1. Added versions of functions is_stopped(), is_unset() and is_overrun() without arguments. 2. Functions get_duty_and_period() and get_duty_period_and_pulses() is order to avoid restarting if desired. These changes have been carried out thanks to the comments and suggestions of Github's user balinthanula.
Showing
1 changed file
with
274 additions
and
247 deletions
Show diff stats
tc_lib.h
... | ... | @@ -120,262 +120,289 @@ namespace arduino_due |
120 | 120 | { |
121 | 121 | public: |
122 | 122 | |
123 | - static constexpr const uint32_t DEFAULT_MAX_OVERRUNS=100; | |
123 | + static constexpr const uint32_t DEFAULT_MAX_OVERRUNS=100; | |
124 | 124 | |
125 | - capture() {} | |
125 | + capture() {} | |
126 | 126 | |
127 | - ~capture() {} | |
127 | + ~capture() {} | |
128 | 128 | |
129 | 129 | capture(const capture&) = delete; |
130 | - capture(capture&&) = delete; | |
131 | - capture& operator=(const capture&) = delete; | |
132 | - capture& operator=(capture&&) = delete; | |
133 | - | |
134 | - static void tc_interrupt(uint32_t the_status) | |
135 | - { _ctx_.tc_interrupt(the_status); } | |
136 | - | |
137 | - // NOTE: the_capture_window parameter in config() refers to | |
138 | - // the time window for measuring the duty of a PWM signal. As | |
139 | - // a rule of thumb if the PWM signal you want to measure has | |
140 | - // a period T, the capture window should be at least twice this | |
141 | - // time, that is, 2T. Parameter the_overruns specify how many | |
142 | - // loading overruns are tolerated before ceasing capturing. | |
143 | - bool config( | |
144 | - uint32_t the_capture_window, | |
145 | - uint32_t the_overruns = DEFAULT_MAX_OVERRUNS | |
146 | - ) { return _ctx_.config(the_capture_window,the_overruns); } | |
147 | - | |
148 | - constexpr uint32_t ticks_per_usec() { return _ctx_.ticks_per_usec(); } | |
149 | - constexpr uint32_t max_capture_window() { return _ctx_.max_capture_window(); } | |
150 | - | |
151 | - // NOTE: member function get_duty_and_period() returns | |
152 | - // the status of the capture object. Returns in arguments | |
153 | - // the last valid measured and period. | |
154 | - uint32_t get_duty_and_period( | |
155 | - uint32_t& the_duty, | |
156 | - uint32_t& the_period | |
157 | - ) | |
158 | - { return _ctx_.get_duty_and_period(the_duty,the_period); } | |
159 | - | |
160 | - // NOTE: member function get_duty_and_period() returns | |
161 | - // the status of the capture object. Returns in arguments | |
162 | - // the last valid measured and period, and the count of | |
163 | - // pulses accumulated since the last config. | |
164 | - uint32_t get_duty_period_and_pulses( | |
165 | - uint32_t& the_duty, | |
166 | - uint32_t& the_period, | |
167 | - uint32_t& the_pulses | |
168 | - ) | |
169 | - { | |
170 | - return _ctx_.get_duty_period_and_pulses( | |
171 | - the_duty, | |
172 | - the_period, | |
173 | - the_pulses | |
174 | - ); | |
175 | - } | |
176 | - | |
177 | - uint32_t get_capture_window() { return _ctx_.capture_window; } | |
178 | - | |
179 | - bool is_overrun(uint32_t the_status) | |
180 | - { return _ctx_.is_overrun(the_status); } | |
181 | - | |
182 | - // NOTE: when too much loading overruns have been detected | |
183 | - // the capture stops measuring to avoid the use of compu- | |
184 | - // tational resources. Take into account that if the sig- | |
185 | - // nal measured has a frequency around 1 Mhz or higher the | |
186 | - // interrupts due to the capture object will consume all | |
187 | - // CPU time. If this is the case, the capture object stops | |
188 | - // capturing when the overun threshold is surpassed. | |
189 | - bool is_stopped(uint32_t the_status) | |
190 | - { return _ctx_.is_stopped(the_status); } | |
191 | - | |
192 | - // NOTE:capture object is unset when not configured | |
193 | - bool is_unset(uint32_t the_status) | |
194 | - { return _ctx_.is_unset(the_status); } | |
195 | - | |
196 | - void stop() { _ctx_.stop(); } | |
197 | - void restart() { _ctx_.restart(); } | |
198 | - | |
199 | - void lock() | |
200 | - { | |
201 | - if( is_unset() || is_stopped() ) return; | |
202 | - timer::disable_interrupts(); | |
203 | - } | |
204 | - | |
205 | - void unlock() | |
206 | - { | |
207 | - if( is_unset() || is_stopped() ) return; | |
208 | - timer::enable_interrupts(); | |
209 | - } | |
130 | + capture(capture&&) = delete; | |
131 | + capture& operator=(const capture&) = delete; | |
132 | + capture& operator=(capture&&) = delete; | |
133 | + | |
134 | + static void tc_interrupt(uint32_t the_status) | |
135 | + { _ctx_.tc_interrupt(the_status); } | |
136 | + | |
137 | + // NOTE: the_capture_window parameter in config() refers to | |
138 | + // the time window for measuring the duty of a PWM signal. As | |
139 | + // a rule of thumb if the PWM signal you want to measure has | |
140 | + // a period T, the capture window should be at least twice this | |
141 | + // time, that is, 2T. Parameter the_overruns specify how many | |
142 | + // loading overruns are tolerated before ceasing capturing. | |
143 | + bool config( | |
144 | + uint32_t the_capture_window, | |
145 | + uint32_t the_overruns = DEFAULT_MAX_OVERRUNS | |
146 | + ) { return _ctx_.config(the_capture_window,the_overruns); } | |
147 | + | |
148 | + constexpr uint32_t ticks_per_usec() { return _ctx_.ticks_per_usec(); } | |
149 | + constexpr uint32_t max_capture_window() { return _ctx_.max_capture_window(); } | |
150 | + | |
151 | + // NOTE: member function get_duty_and_period() returns | |
152 | + // the status of the capture object. Returns in arguments | |
153 | + // the last valid measured and period. By default, the | |
154 | + // capture object get restarted when stopped, setting | |
155 | + // do_restart to false avoid restarting | |
156 | + uint32_t get_duty_and_period( | |
157 | + uint32_t& the_duty, | |
158 | + uint32_t& the_period, | |
159 | + bool do_restart = true | |
160 | + ) | |
161 | + { return _ctx_.get_duty_and_period( | |
162 | + the_duty, | |
163 | + the_period, | |
164 | + do_restart); | |
165 | + } | |
166 | + | |
167 | + // NOTE: member function get_duty_and_period() returns | |
168 | + // the status of the capture object. Returns in arguments | |
169 | + // the last valid measured and period, and the count of | |
170 | + // pulses accumulated since the last config. By default, the | |
171 | + // capture object get restarted when stopped, setting | |
172 | + // do_restart to false avoid restarting | |
173 | + | |
174 | + uint32_t get_duty_period_and_pulses( | |
175 | + uint32_t& the_duty, | |
176 | + uint32_t& the_period, | |
177 | + uint32_t& the_pulses, | |
178 | + bool do_restart = true | |
179 | + ) | |
180 | + { | |
181 | + return _ctx_.get_duty_period_and_pulses( | |
182 | + the_duty, | |
183 | + the_period, | |
184 | + the_pulses, | |
185 | + do_restart | |
186 | + ); | |
187 | + } | |
188 | + | |
189 | + uint32_t get_capture_window() { return _ctx_.capture_window; } | |
190 | + | |
191 | + bool is_overrun() { return _ctx_.is_overrun(); } | |
192 | + | |
193 | + bool is_overrun(uint32_t the_status) | |
194 | + { return _ctx_.is_overrun(the_status); } | |
195 | + | |
196 | + // NOTE: when too much loading overruns have been detected | |
197 | + // the capture stops measuring to avoid the use of compu- | |
198 | + // tational resources. Take into account that if the sig- | |
199 | + // nal measured has a frequency around 1 Mhz or higher the | |
200 | + // interrupts due to the capture object will consume all | |
201 | + // CPU time. If this is the case, the capture object stops | |
202 | + // capturing when the overun threshold is surpassed. | |
203 | + bool is_stopped() { return _ctx_.is_stopped(); } | |
204 | + | |
205 | + bool is_stopped(uint32_t the_status) | |
206 | + { return _ctx_.is_stopped(the_status); } | |
207 | + | |
208 | + // NOTE:capture object is unset when not configured | |
209 | + bool is_unset() { return _ctx_.is_unset(); } | |
210 | + | |
211 | + bool is_unset(uint32_t the_status) | |
212 | + { return _ctx_.is_unset(the_status); } | |
213 | + | |
214 | + void stop() { _ctx_.stop(); } | |
215 | + void restart() { _ctx_.restart(); } | |
216 | + | |
217 | + void lock() | |
218 | + { | |
219 | + if( is_unset() || is_stopped() ) return; | |
220 | + timer::disable_interrupts(); | |
221 | + } | |
222 | + | |
223 | + void unlock() | |
224 | + { | |
225 | + if( is_unset() || is_stopped() ) return; | |
226 | + timer::enable_interrupts(); | |
227 | + } | |
210 | 228 | |
211 | 229 | private: |
212 | 230 | |
213 | - using timer = tc_core<TIMER>; | |
231 | + using timer = tc_core<TIMER>; | |
214 | 232 | |
215 | 233 | struct _capture_ctx_ |
216 | - { | |
217 | - enum status_codes: uint32_t | |
218 | - { | |
219 | - UNSET=0, | |
220 | - SET=1, | |
221 | - OVERRUN=2, | |
222 | - STOPPED=4 | |
223 | - }; | |
224 | - | |
225 | - _capture_ctx_() {} | |
226 | - | |
227 | - bool config(uint32_t the_capture_window, uint32_t the_overruns); | |
228 | - | |
229 | - void tc_interrupt(uint32_t the_status); | |
230 | - | |
231 | - static constexpr uint32_t ticks_per_usec() | |
232 | - { | |
233 | - // NOTE: we will be using the fastest clock for TC ticks | |
234 | - // just using a prescaler of 2 | |
235 | - return | |
236 | - static_cast<uint32_t>( ((VARIANT_MCK)>>1)/1000000 ); | |
237 | - } | |
238 | - | |
239 | - static constexpr uint32_t max_capture_window() | |
240 | - { | |
241 | - return | |
242 | - static_cast<uint32_t>( | |
243 | - (static_cast<long long>(1)<<32)-static_cast<long long>(1) | |
244 | - ) / ticks_per_usec(); | |
245 | - } | |
246 | - | |
247 | - uint32_t get_duty_and_period( | |
248 | - uint32_t& the_duty, | |
249 | - uint32_t& the_period | |
250 | - ) | |
251 | - { | |
252 | - uint32_t the_status=status; | |
253 | - if(is_unset(the_status)) return the_status; | |
254 | - | |
255 | - timer::disable_interrupts(); | |
256 | - the_duty=duty; the_period=period; | |
257 | - the_status=status; | |
258 | - status=status&(~status_codes::OVERRUN); | |
259 | - timer::enable_interrupts(); | |
260 | - | |
261 | - if(is_stopped(the_status)) restart(); | |
262 | - | |
263 | - return the_status; | |
264 | - } | |
265 | - | |
266 | - uint32_t get_duty_period_and_pulses( | |
267 | - uint32_t& the_duty, | |
268 | - uint32_t& the_period, | |
269 | - uint32_t& the_pulses | |
270 | - ) | |
271 | - { | |
272 | - uint32_t the_status=status; | |
273 | - if(is_unset(the_status)) return the_status; | |
274 | - | |
275 | - timer::disable_interrupts(); | |
276 | - the_duty=duty; the_period=period; the_pulses=pulses; | |
277 | - the_status=status; | |
278 | - status=status&(~status_codes::OVERRUN); | |
279 | - timer::enable_interrupts(); | |
280 | - | |
281 | - if(is_stopped(the_status)) restart(); | |
282 | - | |
283 | - return the_status; | |
284 | - } | |
285 | - | |
286 | - bool is_overrun(uint32_t the_status) | |
287 | - { return (the_status&status_codes::OVERRUN); } | |
288 | - | |
289 | - bool is_stopped(uint32_t the_status) | |
290 | - { return (the_status&status_codes::STOPPED); } | |
291 | - | |
292 | - bool is_unset(uint32_t the_status) | |
293 | - { return !the_status; } | |
294 | - | |
295 | - void stop() | |
296 | - { | |
297 | - uint32_t the_status=status; | |
298 | - if( | |
299 | - is_unset(the_status) || | |
300 | - is_stopped(the_status) | |
301 | - ) return; | |
302 | - | |
303 | - timer::stop_interrupts(); | |
304 | - status=status|status_codes::STOPPED; | |
305 | - } | |
306 | - | |
307 | - void restart() | |
308 | - { | |
309 | - uint32_t the_status=status; | |
310 | - if( | |
311 | - is_unset(the_status) || | |
312 | - !is_stopped(the_status) | |
313 | - ) return; | |
314 | - | |
315 | - ra=duty=period=overruns=0; | |
316 | - status&= | |
317 | - ~(status_codes::OVERRUN|status_codes::STOPPED); | |
318 | - | |
319 | - // clearing pending interrupt flags | |
320 | - uint32_t dummy=TC_GetStatus( | |
321 | - timer::info::tc_p, | |
322 | - timer::info::channel | |
323 | - ); | |
324 | - timer::start_interrupts(); | |
325 | - } | |
326 | - | |
327 | - void end() | |
328 | - { | |
329 | - uint32_t the_status=status; | |
330 | - if(is_unset(the_status)) return; | |
331 | - | |
332 | - timer::stop_interrupts(); | |
333 | - timer::disable_lovr_interrupt(); | |
334 | - timer::disable_ldra_interrupt(); | |
335 | - timer::disable_ldrb_interrupt(); | |
336 | - timer::disable_rc_interrupt(); | |
337 | - pmc_disable_periph_clk(uint32_t(timer::info::irq)); | |
338 | - | |
339 | - status=status_codes::UNSET; | |
340 | - } | |
341 | - | |
342 | - void load_overrun() | |
343 | - { | |
344 | - status=status|status_codes::OVERRUN; | |
345 | - if((++overruns)>max_overruns) | |
346 | - { | |
347 | - timer::stop_interrupts(); | |
348 | - status=status|status_codes::STOPPED; | |
349 | - } | |
350 | - } | |
351 | - | |
352 | - void ra_loaded() | |
353 | - { | |
354 | - ra=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RA; | |
355 | - } | |
356 | - | |
357 | - void rb_loaded() | |
358 | - { | |
359 | - period=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RB; | |
360 | - duty=period-ra; pulses++; | |
361 | - } | |
362 | - | |
363 | - void rc_matched() { ra=duty=period=0; } | |
364 | - | |
365 | - // capture values | |
366 | - volatile uint32_t ra; | |
367 | - volatile uint32_t duty; | |
368 | - volatile uint32_t period; | |
369 | - volatile uint32_t pulses; | |
370 | - volatile uint32_t overruns; | |
371 | - volatile uint32_t status; | |
372 | - | |
373 | - uint32_t rc; | |
374 | - uint32_t capture_window; | |
375 | - uint32_t max_overruns; | |
376 | - }; | |
377 | - | |
378 | - static _capture_ctx_ _ctx_; | |
234 | + { | |
235 | + enum status_codes: uint32_t | |
236 | + { | |
237 | + UNSET=0, | |
238 | + SET=1, | |
239 | + OVERRUN=2, | |
240 | + STOPPED=4 | |
241 | + }; | |
242 | + | |
243 | + _capture_ctx_() {} | |
244 | + | |
245 | + bool config(uint32_t the_capture_window, uint32_t the_overruns); | |
246 | + | |
247 | + void tc_interrupt(uint32_t the_status); | |
248 | + | |
249 | + static constexpr uint32_t ticks_per_usec() | |
250 | + { | |
251 | + // NOTE: we will be using the fastest clock for TC ticks | |
252 | + // just using a prescaler of 2 | |
253 | + return | |
254 | + static_cast<uint32_t>( ((VARIANT_MCK)>>1)/1000000 ); | |
255 | + } | |
256 | + | |
257 | + static constexpr uint32_t max_capture_window() | |
258 | + { | |
259 | + return | |
260 | + static_cast<uint32_t>( | |
261 | + (static_cast<long long>(1)<<32)-static_cast<long long>(1) | |
262 | + ) / ticks_per_usec(); | |
263 | + } | |
264 | + | |
265 | + uint32_t get_duty_and_period( | |
266 | + uint32_t& the_duty, | |
267 | + uint32_t& the_period, | |
268 | + bool do_restart | |
269 | + ) | |
270 | + { | |
271 | + uint32_t the_status=status; | |
272 | + if(is_unset(the_status)) return the_status; | |
273 | + | |
274 | + timer::disable_interrupts(); | |
275 | + the_duty=duty; the_period=period; | |
276 | + the_status=status; | |
277 | + status=status&(~status_codes::OVERRUN); | |
278 | + timer::enable_interrupts(); | |
279 | + | |
280 | + if(is_stopped(the_status) && do_restart) restart(); | |
281 | + | |
282 | + return the_status; | |
283 | + } | |
284 | + | |
285 | + uint32_t get_duty_period_and_pulses( | |
286 | + uint32_t& the_duty, | |
287 | + uint32_t& the_period, | |
288 | + uint32_t& the_pulses, | |
289 | + bool do_restart | |
290 | + ) | |
291 | + { | |
292 | + uint32_t the_status=status; | |
293 | + if(is_unset(the_status)) return the_status; | |
294 | + | |
295 | + timer::disable_interrupts(); | |
296 | + the_duty=duty; the_period=period; the_pulses=pulses; | |
297 | + the_status=status; | |
298 | + status=status&(~status_codes::OVERRUN); | |
299 | + timer::enable_interrupts(); | |
300 | + | |
301 | + if(is_stopped(the_status) && do_restart) restart(); | |
302 | + | |
303 | + return the_status; | |
304 | + } | |
305 | + | |
306 | + bool is_overrun() | |
307 | + { return (status&status_codes::OVERRUN); } | |
308 | + | |
309 | + bool is_overrun(uint32_t the_status) | |
310 | + { return (the_status&status_codes::OVERRUN); } | |
311 | + | |
312 | + bool is_stopped() | |
313 | + { return (status&status_codes::STOPPED); } | |
314 | + | |
315 | + bool is_stopped(uint32_t the_status) | |
316 | + { return (the_status&status_codes::STOPPED); } | |
317 | + | |
318 | + bool is_unset() { return !status; } | |
319 | + | |
320 | + bool is_unset(uint32_t the_status) { return !the_status; } | |
321 | + | |
322 | + void stop() | |
323 | + { | |
324 | + uint32_t the_status=status; | |
325 | + if( | |
326 | + is_unset(the_status) || | |
327 | + is_stopped(the_status) | |
328 | + ) return; | |
329 | + | |
330 | + timer::stop_interrupts(); | |
331 | + status=status|status_codes::STOPPED; | |
332 | + } | |
333 | + | |
334 | + void restart() | |
335 | + { | |
336 | + uint32_t the_status=status; | |
337 | + if( | |
338 | + is_unset(the_status) || | |
339 | + !is_stopped(the_status) | |
340 | + ) return; | |
341 | + | |
342 | + ra=duty=period=overruns=0; | |
343 | + status&= | |
344 | + ~(status_codes::OVERRUN|status_codes::STOPPED); | |
345 | + | |
346 | + // clearing pending interrupt flags | |
347 | + uint32_t dummy=TC_GetStatus( | |
348 | + timer::info::tc_p, | |
349 | + timer::info::channel | |
350 | + ); | |
351 | + timer::start_interrupts(); | |
352 | + } | |
353 | + | |
354 | + void end() | |
355 | + { | |
356 | + uint32_t the_status=status; | |
357 | + if(is_unset(the_status)) return; | |
358 | + | |
359 | + timer::stop_interrupts(); | |
360 | + timer::disable_lovr_interrupt(); | |
361 | + timer::disable_ldra_interrupt(); | |
362 | + timer::disable_ldrb_interrupt(); | |
363 | + timer::disable_rc_interrupt(); | |
364 | + pmc_disable_periph_clk(uint32_t(timer::info::irq)); | |
365 | + | |
366 | + status=status_codes::UNSET; | |
367 | + } | |
368 | + | |
369 | + void load_overrun() | |
370 | + { | |
371 | + status=status|status_codes::OVERRUN; | |
372 | + if((++overruns)>max_overruns) | |
373 | + { | |
374 | + timer::stop_interrupts(); | |
375 | + status=status|status_codes::STOPPED; | |
376 | + } | |
377 | + } | |
378 | + | |
379 | + void ra_loaded() | |
380 | + { | |
381 | + ra=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RA; | |
382 | + } | |
383 | + | |
384 | + void rb_loaded() | |
385 | + { | |
386 | + period=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RB; | |
387 | + duty=period-ra; pulses++; | |
388 | + } | |
389 | + | |
390 | + void rc_matched() { ra=duty=period=0; } | |
391 | + | |
392 | + // capture values | |
393 | + volatile uint32_t ra; | |
394 | + volatile uint32_t duty; | |
395 | + volatile uint32_t period; | |
396 | + volatile uint32_t pulses; | |
397 | + volatile uint32_t overruns; | |
398 | + volatile uint32_t status; | |
399 | + | |
400 | + uint32_t rc; | |
401 | + uint32_t capture_window; | |
402 | + uint32_t max_overruns; | |
403 | + }; | |
404 | + | |
405 | + static _capture_ctx_ _ctx_; | |
379 | 406 | }; |
380 | 407 | |
381 | 408 | template<timer_ids TIMER> | ... | ... |