Commit adacb3299b5d86d046f98294ec28fe1fda431604

Authored by Antonio Carlos Domínguez Brito
1 parent 9e04ec20
Exists in master

v1.1 - added overrun and stopped behavior, added example pwm_capture_test.ino

CMakeLists.txt
  1 +# CMakeLists.txt file for building project tc_lib
1 2 cmake_minimum_required(VERSION 2.8)
2 3  
  4 +include(cmake/build_library.cmake)
  5 +
3 6 set(PORT /dev/ttyACM0 CACHE STRING "uploading serial port")
4 7 set(IS_NATIVE_PORT true CACHE STRING "is it the native port? (true), or not? (false)")
5 8  
6   -set(CMAKE_TOOLCHAIN_FILE arduino_due_toolchain.cmake)
  9 +set(CMAKE_TOOLCHAIN_FILE cmake/arduino_due_toolchain.cmake)
7 10  
8 11 project(tc_lib C CXX)
9 12  
10   -#####################################################################
11   -# generating a static library for the standard Arduino library: begin
12   -#####################################################################
13   -
14   -file(
15   - GLOB ARDUINO_DUE_STD_LIB_SOURCE_FILES
16   - LIST_DIRECTORIES false
17   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/*.c
18   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/*.cpp
19   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/USB/*.c
20   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/USB/*.cpp
21   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/*.c
22   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/*.cpp
23   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/libraries/SPI/*.c
24   - $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/libraries/SPI/*.cpp
25   -)
26   -
27   -#mess(STATUS "ARDUINO_DUE_STD_LIB_SOURCE_FILES: ${ARDUINO_DUE_STD_LIB_SOURCE_FILES}")
28   -
29   -add_library(arduino_due_std_lib STATIC ${ARDUINO_DUE_STD_LIB_SOURCE_FILES})
30   -set_property(
31   - TARGET arduino_due_std_lib PROPERTY
32   - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
33   -)
34   -target_compile_options(
35   - arduino_due_std_lib PUBLIC
36   - -c -g -Os -w -ffunction-sections -fdata-sections -nostdlib -fno-threadsafe-statics --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -mcpu=cortex-m3 -std=gnu++11 -mthumb
  13 +# building Arduino Standard Library
  14 +build_library(
  15 + arduino_due_std_lib
  16 + SRC_PATHS
  17 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino
  18 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/USB
  19 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x
  20 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/libraries/SPI
  21 + INCLUDE_PATHS
  22 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino
  23 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/USB
  24 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x
  25 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/libraries/SPI
37 26 )
38 27  
39   -target_compile_definitions(
40   - arduino_due_std_lib PUBLIC
41   - -Dprintf=iprintf -DF_CPU=84000000L -DARDUINO=10605 -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM -D__SAM3X8E__ -DUSB_VID=0x2341 -DUSB_PID=0x003e -DUSBCON -DUSB_MANUFACTURER="Unknown" -DUSB_PRODUCT="Arduino Due"
42   -)
43   -#####################################################################
44   -# generating a static library for the standard Arduino library: end
45   -#####################################################################
46   -
47 28 # checking environment variable ARDUINO_IDE_LIBRARY_PATH
48 29 if(
49 30 NOT (DEFINED ENV{ARDUINO_IDE_LIBRARY_PATH})
... ... @@ -59,6 +40,13 @@ else()
59 40  
60 41 endif()
61 42  
  43 +# building Arduino Standard Library
  44 +build_library(
  45 + pwm_lib
  46 + SRC_PATHS
  47 + $ENV{ARDUINO_IDE_LIBRARY_PATH}/libraries/pwm_lib
  48 +)
  49 +
62 50 #####################################################################
63 51 # tc_lib examples: begin
64 52 #####################################################################
... ... @@ -66,6 +54,7 @@ endif()
66 54 set(
67 55 TC_EXAMPLES
68 56 capture_test
  57 + pwm_capture_test
69 58 action_test
70 59 )
71 60  
... ... @@ -93,10 +82,11 @@ foreach(src_example ${TC_EXAMPLES})
93 82 target_include_directories(
94 83 ${src_example}.cpp.elf PUBLIC
95 84 $ENV{ARDUINO_IDE_LIBRARY_PATH}/libraries/tc_lib
  85 + $ENV{ARDUINO_IDE_LIBRARY_PATH}/libraries/pwm_lib
96 86 )
97 87 target_link_libraries(
98 88 ${src_example}.cpp.elf
99   - -Os -Wl,--gc-sections -mcpu=cortex-m3 -T$ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/linker_scripts/gcc/flash.ld -Wl,-Map,${src_example}.cpp.map -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group arduino_due_std_lib $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a -Wl,--end-group -lm
  89 + -Os -Wl,--gc-sections -mcpu=cortex-m3 -T$ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/linker_scripts/gcc/flash.ld -Wl,-Map,${src_example}.cpp.map -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group arduino_due_std_lib pwm_lib $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a -Wl,--end-group -lm
100 90 )
101 91  
102 92 # bin
... ...
README.md
1   -## tc_lib v1.0
  1 +## tc_lib v1.1
2 2  
3 3 This is tc_lib library for the Arduino DUE electronic prototyping platform.
4 4  
... ... @@ -42,6 +42,31 @@ As soon as the object is configured the corresponding TC channel starts capturin
42 42  
43 43 Capture objects take advantage of TC module channels in *capture* mode to measure digital pulses. Concretely, using tc_lib capture objects we can obtain the last pulse duration (duty) and the last period of the measured signal. Example *capture_test.ino* use a PWM signal generated on analog pin 7 as the signal to measure. When nothing is measured the duty and the period measured by the capture object are zero. Take into account that the measured duty and period get stored inside the capture objects at the interrupt handlers associated with the TC channels involved.
44 44  
  45 +### 2.1 Fast signals and capture objects
  46 +
  47 +When capturing signals capture objects do intensive use of interrupts associated to the TC channel associated with the specific object. If the signal to capture is very fast (pulse duration around 1 microsecond or less), some interrupts will be missed to track the signal. Internally the TC channel in capture mode registers those situations with the signaling of a "load overrun" of one of the capture registers RA or RB (more details in ATSAM3X8E data sheet). Evidently, this may also happen in an application where the use of interrupts is very high, even if the signal to capture is not so fast. In any case, specially with fast signals (frequencies of around 1 Mhz) this massive use of interrupts could provoke the freezing of the CPU, since all CPU time was invested on interrupts. To avoid that situation, the capture object stops capturing when it detects too much overrun events, keeping internally the duty and period of the last pulse captured. Function *get_duty_and_period()* returns a status value where we can check if the capture objects was overrun and/or stopped. Here a snippet of code from example *pwm_capture_test.ino* illustrating its use:
  48 +
  49 +```
  50 +status=capture_pin2.get_duty_and_period(duty,period); <====
  51 +Serial.print("duty: ");
  52 +Serial.print(
  53 + static_cast<double>(duty)/
  54 + static_cast<double>(capture_pin2.ticks_per_usec()),
  55 + 3
  56 +);
  57 +Serial.print(" usecs. period: ");
  58 +Serial.print(
  59 + static_cast<double>(period)/
  60 + static_cast<double>(capture_pin2.ticks_per_usec()),
  61 + 3
  62 +);
  63 +Serial.print(" usecs. ");
  64 +if(capture_pin2.is_overrun(status)) Serial.print("[overrun]"); <====
  65 +if(capture_pin2.is_stopped(status)) Serial.print("[stopped]"); <====
  66 +Serial.println();
  67 +```
  68 +Once a capture object is stopped due to the occurrence of too many load overrun situations, the object is restarted when calling member function *get_duty_and_period()* or member function *restart()*.
  69 +
45 70 ### 3. Action objects
46 71  
47 72 The action objects available in tc_lib allow us to have a callback called periodically in our program.
... ... @@ -81,7 +106,11 @@ In addition you must add the flag -std=gnu++11 for compiling. For doing that add
81 106  
82 107 ### 5. Examples
83 108  
84   -On the examples directory you have available a basic example for using a capture object, *capture_test.ino*, and an example for using an action object, *action_test.ino*. We hope both examples are self-explaining.
  109 +On the examples directory you have available a basic example for using a capture object, *capture_test.ino*, and an example for using an action object, *action_test.ino*.
  110 +
  111 +There is third example, *pwm_capture_test.ino* which is specifically designed to check the capture objects with fast signals. For this example it is necessary the use of library pwm_lib, available at [https://github.com/antodom/pwm_lib](https://github.com/antodom/pwm_lib).
  112 +
  113 +I hope all three xamples are self-explaining.
85 114  
86 115 ### 6. Incompatibilities
87 116  
... ...
cmake/arduino_due_toolchain.cmake 0 → 100644
... ... @@ -0,0 +1,81 @@
  1 +# arduino_due_toolchain.cmake: toolchain file for arduino due
  2 +
  3 +include (CMakeForceCompiler)
  4 +
  5 +set(CMAKE_SYSTEM_NAME Generic)
  6 +set(CMAKE_SYSTEM_PROCESSOR arm)
  7 +
  8 +# checking environment variable ARDUINO_DUE_SOURCE_PATH
  9 +if(
  10 + NOT (DEFINED ENV{ARDUINO_DUE_ROOT_PATH})
  11 + OR
  12 + ($ENV{ARDUINO_DUE_ROOT_PATH} EQUAL "")
  13 +)
  14 +
  15 + message(FATAL_ERROR "[ERROR] Environment variable ARDUINO_DUE_ROOT_PATH not set!")
  16 +
  17 +else()
  18 +
  19 + message(STATUS "Environment variable ARDUINO_DUE_ROOT_PATH: $ENV{ARDUINO_DUE_ROOT_PATH}")
  20 +
  21 +endif()
  22 +
  23 +function(find_due_program DUE_PROGRAM_PATH DUE_PROGRAM WHERE)
  24 +
  25 + find_program(
  26 + ${DUE_PROGRAM_PATH}
  27 + ${DUE_PROGRAM}
  28 + PATH ${WHERE}
  29 + NO_SYSTEM_ENVIRONMENT_PATH
  30 + )
  31 + if(NOT ${DUE_PROGRAM_PATH})
  32 + message(FATAL_ERROR "[ERROR] \"${DUE_PROGRAM}\" not found!")
  33 + else()
  34 + message(STATUS "\"${DUE_PROGRAM}\" found: ${${DUE_PROGRAM_PATH}}")
  35 + endif()
  36 +
  37 +endfunction(find_due_program)
  38 +
  39 +find_due_program(
  40 + DUE_CC
  41 + arm-none-eabi-gcc
  42 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin
  43 +)
  44 +find_due_program(
  45 + DUE_CXX
  46 + arm-none-eabi-g++
  47 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin
  48 +)
  49 +find_due_program(
  50 + DUE_OBJCOPY
  51 + arm-none-eabi-objcopy
  52 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin
  53 +)
  54 +find_due_program(
  55 + DUE_SIZE_TOOL
  56 + arm-none-eabi-size
  57 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin
  58 +)
  59 +find_due_program(
  60 + DUE_OBJDUMP
  61 + arm-none-eabi-objdump
  62 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin
  63 +)
  64 +find_due_program(
  65 + DUE_BOSSAC
  66 + bossac
  67 + $ENV{ARDUINO_DUE_ROOT_PATH}/tools/bossac/1.6.1-arduino
  68 +)
  69 +
  70 +CMAKE_FORCE_C_COMPILER(${DUE_CC} arduino_due_arm)
  71 +CMAKE_FORCE_CXX_COMPILER(${DUE_CXX} arduino_due_arm)
  72 +
  73 +include_directories(
  74 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/system/libsam
  75 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/system/CMSIS/CMSIS/Include
  76 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/system/CMSIS/Device/ATMEL $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino
  77 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/cores/arduino/USB
  78 + $ENV{ARDUINO_DUE_ROOT_PATH}/hardware/sam/1.6.6/variants/arduino_due_x
  79 +)
  80 +
  81 +
... ...
cmake/build_library.cmake 0 → 100644
... ... @@ -0,0 +1,63 @@
  1 +# build_library.cmake: utilility function for building static
  2 +# libraries for the Arduino DUE platform
  3 +
  4 +include(CMakeParseArguments)
  5 +
  6 +# funtion build_library(
  7 +# library SRC_PATHS ... INCLUDE_PATHS ...
  8 +# )
  9 +function(build_library library)
  10 +
  11 + set(multi_value_args SRC_PATHS INCLUDE_PATHS)
  12 + cmake_parse_arguments(
  13 + ${library} "" "" "${multi_value_args}" ${ARGN} )
  14 +
  15 + #message(STATUS "${library}_SRC_PATHS: ${${library}_SRC_PATHS}")
  16 + #message(STATUS "${library}_INCLUDE_PATHS: ${${library}_INCLUDE_PATHS}")
  17 +
  18 + # adding *.c and *.cpp extensions to paths
  19 + set(compile_paths "")
  20 + foreach(src_path ${${library}_SRC_PATHS})
  21 + if(EXISTS ${src_path})
  22 + set(compile_paths ${compile_paths} ${src_path}/*.c)
  23 + set(compile_paths ${compile_paths} ${src_path}/*.cpp)
  24 + else()
  25 + message(SEND_ERROR "[ERROR] path ${src_path} not found!")
  26 + message(SEND_ERROR "[ERROR] library ${library} cannot be built!")
  27 + return()
  28 + endif()
  29 + endforeach(src_path)
  30 +
  31 + file(
  32 + GLOB LIB_SOURCE_FILES
  33 + LIST_DIRECTORIES false
  34 + ${compile_paths}
  35 + )
  36 +
  37 + #message(STATUS "LIB_SOURCE_FILES (${library}): ${LIB_SOURCE_FILES}")
  38 +
  39 + add_library(${library} STATIC ${LIB_SOURCE_FILES})
  40 + set_property(
  41 + TARGET ${library} PROPERTY
  42 + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
  43 + )
  44 + target_compile_options(
  45 + ${library} PUBLIC
  46 + -c -g -Os -w -ffunction-sections -fdata-sections -nostdlib -fno-threadsafe-statics --param max-inline-insns-single=500 -fno-rtti -fno-exceptions -MMD -mcpu=cortex-m3 -std=gnu++11 -mthumb
  47 + )
  48 +
  49 + target_compile_definitions(
  50 + ${library} PUBLIC
  51 + -Dprintf=iprintf -DF_CPU=84000000L -DARDUINO=10605 -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM -D__SAM3X8E__ -DUSB_VID=0x2341 -DUSB_PID=0x003e -DUSBCON -DUSB_MANUFACTURER="Unknown" -DUSB_PRODUCT="Arduino Due"
  52 + )
  53 +
  54 + target_include_directories(
  55 + ${library} PUBLIC
  56 + ${${library}_SRC_PATHS}
  57 + ${${library}_INCLUDE_PATHS}
  58 + )
  59 +
  60 +endfunction(build_library)
  61 +
  62 +
  63 +
... ...
examples/capture_test/capture_test.ino
... ... @@ -47,20 +47,21 @@ using namespace arduino_due;
47 47 // TC modules, you should consult uC Atmel ATSAM3X8E datasheet in section "36.
48 48 // Timer Counter (TC)"), and the Arduino pin mapping for the DUE.
49 49 capture_tc0_declaration();
  50 +auto& capture_pin2=capture_tc0;
50 51  
51 52 void setup() {
52 53 // put your setup code here, to run once:
53 54  
54 55 Serial.begin(9600);
55 56  
56   - // capture_tc0 initialization
57   - capture_tc0.config(CAPTURE_TIME_WINDOW);
  57 + // capture_pin2 initialization
  58 + capture_pin2.config(CAPTURE_TIME_WINDOW);
58 59  
59 60 Serial.println("========================================================");
60 61  
61   - Serial.print("ticks per usec: "); Serial.println(capture_tc0.ticks_per_usec());
  62 + Serial.print("ticks per usec: "); Serial.println(capture_pin2.ticks_per_usec());
62 63 Serial.print("max capture window: ");
63   - Serial.print(capture_tc0.max_capture_window());
  64 + Serial.print(capture_pin2.max_capture_window());
64 65 Serial.println(" usecs.");
65 66  
66 67 Serial.println("========================================================");
... ... @@ -71,14 +72,23 @@ void setup() {
71 72 void loop() {
72 73 // put your main code here,to run repeatedly:
73 74  
74   - uint32_t duty,period;
75   - capture_tc0.get_duty_and_period(duty,period);
  75 + uint32_t status,duty,period;
  76 + status=capture_pin2.get_duty_and_period(duty,period);
76 77  
77 78 Serial.println("********************************************************");
78   - Serial.print("--> duty: ");
79   - Serial.print(duty/capture_tc0.ticks_per_usec());
  79 + Serial.print("--> [PIN "); Serial.print(ANALOG_PIN);
  80 + Serial.print(" -> PIN 2] duty: ");
  81 + Serial.print(
  82 + static_cast<double>(duty)/
  83 + static_cast<double>(capture_pin2.ticks_per_usec()),
  84 + 3
  85 + );
80 86 Serial.print(" usecs. period: ");
81   - Serial.print(period/capture_tc0.ticks_per_usec());
  87 + Serial.print(
  88 + static_cast<double>(period)/
  89 + static_cast<double>(capture_pin2.ticks_per_usec()),
  90 + 3
  91 + );
82 92 Serial.println(" usecs.");
83 93 }
84 94  
... ...
examples/pwm_capture_test/pwm_capture_test.ino 0 → 100644
... ... @@ -0,0 +1,113 @@
  1 +/**
  2 + ** tc_lib library
  3 + ** Copyright (C) 2016
  4 + **
  5 + ** Antonio C. Domínguez Brito <adominguez@iusiani.ulpgc.es>
  6 + ** División de Robótica y Oceanografía Computacional <www.roc.siani.es>
  7 + ** and Departamento de Informática y Sistemas <www.dis.ulpgc.es>
  8 + ** Universidad de Las Palmas de Gran Canaria (ULPGC) <www.ulpgc.es>
  9 + **
  10 + ** This file is part of the tc_lib library.
  11 + ** The tc_lib library is free software: you can redistribute it and/or modify
  12 + ** it under the terms of the GNU General Public License as published by
  13 + ** the Free Software Foundation, either version 3 of the License, or any
  14 + ** later version.
  15 + **
  16 + ** The tc_lib library is distributed in the hope that it will be useful,
  17 + ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  19 + ** Public License for more details.
  20 + **
  21 + ** You should have received a copy (COPYING file) of the GNU General Public
  22 + ** License along with the tc_lib library.
  23 + ** If not, see: <http://www.gnu.org/licenses/>.
  24 + **/
  25 +/*
  26 + * File: pwm_capture_test.ino
  27 + * Description: This is an example to test how fast are the digital
  28 + * signals tc_lib is able to measure. For doing that it uses library
  29 + * pwm_lib at https://github.com/antodom/pwm_lib.
  30 + * Date: February 1st, 2015
  31 + * Author: Antonio C. Dominguez-Brito <adominguez@iusiani.ulpgc.es>
  32 + * ROC-SIANI - Universidad de Las Palmas de Gran Canaria - Spain
  33 + */
  34 +
  35 +#include "tc_lib.h"
  36 +#include "pwm_lib.h"
  37 +
  38 +using namespace arduino_due::pwm_lib;
  39 +
  40 +#define PWM_PERIOD_PIN_35 500 // tenths of usecs (1e-8 secs)
  41 +#define PWM_DUTY_PIN_35 50 // tenths of usecs (1e-8 secs)
  42 +
  43 +#define DUTY_KEEPING_TIME 1000 // msecs
  44 +
  45 +// defining pwm object using pin 35, pin PC3 mapped to pin 35 on the DUE
  46 +// this object uses PWM channel 0
  47 +pwm<pwm_pin::PWMH0_PC3> pwm_pin35;
  48 +
  49 +// To measure PWM signals generated by the previous pwm objects, we will use
  50 +// a capture object of tc_lib library as "oscilloscope" probe: capture_tc0.
  51 +// IMPORTANT: Take into account that for TC0 (TC0 and channel 0) the TIOA0 is
  52 +// PB25, which is pin 2 for Arduino DUE, so capture_tc0's capture pin is pin
  53 +// 2. For the correspondence between all TIOA inputs for the different
  54 +// TC module channels, you should consult uC Atmel ATSAM3X8E datasheet
  55 +// in section "36. Timer Counter (TC)"), and the Arduino pin mapping
  56 +// for the DUE.
  57 +// All in all, to meausure the pwm output in this example you should connect
  58 +// the PWM output of pin 35 to capture_tc0 object pin 2.
  59 +capture_tc0_declaration(); // TC0 and channel 0
  60 +auto& capture_pin2=capture_tc0;
  61 +
  62 +void setup() {
  63 + // put your setup code here, to run once:
  64 +
  65 + Serial.begin(9600);
  66 +
  67 + // initialization of capture objects
  68 + capture_pin2.config((PWM_PERIOD_PIN_35/100)<<1);
  69 +
  70 + // starting PWM signals
  71 + pwm_pin35.start(PWM_PERIOD_PIN_35,PWM_DUTY_PIN_35);
  72 +}
  73 +
  74 +template<typename pwm_type>
  75 +void change_duty(pwm_type& pwm_obj,uint32_t pwm_duty,uint32_t pwm_period)
  76 +{
  77 + uint32_t duty=pwm_obj.get_duty()+pwm_duty;
  78 + if(duty>pwm_period) duty=pwm_duty;
  79 + pwm_obj.set_duty(duty);
  80 +}
  81 +
  82 +void loop() {
  83 + // put your main code here,to run repeatedly:
  84 +
  85 + delay(DUTY_KEEPING_TIME);
  86 +
  87 + uint32_t status,duty,period;
  88 +
  89 + Serial.println("=======================================================================");
  90 + Serial.print("[PIN 35 -> PIN 2] ");
  91 + status=capture_pin2.get_duty_and_period(duty,period);
  92 + Serial.print("duty: ");
  93 + Serial.print(
  94 + static_cast<double>(duty)/
  95 + static_cast<double>(capture_pin2.ticks_per_usec()),
  96 + 3
  97 + );
  98 + Serial.print(" usecs. period: ");
  99 + Serial.print(
  100 + static_cast<double>(period)/
  101 + static_cast<double>(capture_pin2.ticks_per_usec()),
  102 + 3
  103 + );
  104 + Serial.print(" usecs. ");
  105 + if(capture_pin2.is_overrun(status)) Serial.print("[overrun]");
  106 + if(capture_pin2.is_stopped(status)) Serial.print("[stopped]");
  107 + Serial.println();
  108 + Serial.println("=======================================================================");
  109 +
  110 + // changing duty in pwm output pin 35
  111 + change_duty(pwm_pin35,PWM_DUTY_PIN_35,PWM_PERIOD_PIN_35);
  112 +}
  113 +
... ...
tc_defs.h
1 1 /**
2 2 ** tc_lib library
3   - ** Copyright (C) 2016
  3 + ** Copyright (C) 2015,2016
4 4 **
5 5 ** Antonio C. Domínguez Brito <adominguez@iusiani.ulpgc.es>
6 6 ** División de Robótica y Oceanografía Computacional <www.roc.siani.es>
... ... @@ -99,6 +99,26 @@ namespace arduino_due
99 99 static void enable_interrupts() { NVIC_EnableIRQ(info::irq); }
100 100 static void disable_interrupts() { NVIC_DisableIRQ(info::irq); }
101 101  
  102 + static void enable_lovr_interrupt()
  103 + {
  104 + info::tc_p->TC_CHANNEL[info::channel].TC_IER=
  105 + TC_IER_LOVRS;
  106 + }
  107 +
  108 + static bool is_enabled_lovr_interrupt()
  109 + {
  110 + return (
  111 + info::tc_p->TC_CHANNEL[info::channel].TC_IMR &
  112 + TC_IMR_LOVRS
  113 + );
  114 + }
  115 +
  116 + static void disable_lovr_interrupt()
  117 + {
  118 + info::tc_p->TC_CHANNEL[info::channel].TC_IDR=
  119 + TC_IDR_LOVRS;
  120 + }
  121 +
102 122 static void enable_ldra_interrupt()
103 123 {
104 124 info::tc_p->TC_CHANNEL[info::channel].TC_IER=
... ...
tc_lib.h
1 1 /**
2 2 ** tc_lib library
3   - ** Copyright (C) 2016
  3 + ** Copyright (C) 2015,2016
4 4 **
5 5 ** Antonio C. Domínguez Brito <adominguez@iusiani.ulpgc.es>
6 6 ** División de Robótica y Oceanografía Computacional <www.roc.siani.es>
... ... @@ -120,6 +120,8 @@ namespace arduino_due
120 120 {
121 121 public:
122 122  
  123 + static constexpr const uint32_t DEFAULT_MAX_OVERRUNS=100;
  124 +
123 125 capture() {}
124 126  
125 127 ~capture() {}
... ... @@ -134,19 +136,55 @@ namespace arduino_due
134 136 // the time window for measuring the duty of a PWM signal. As
135 137 // a rule of thumb if the PWM signal you want to measure has
136 138 // a period T, the capture window should be at least twice this
137   - // time, that is, 2T.
138   - bool config(uint32_t the_capture_window) { _ctx_.config(the_capture_window); }
  139 + // time, that is, 2T. Parameter the_overruns specify how many
  140 + // loading overruns are tolerated before ceasing capturing.
  141 + bool config(
  142 + uint32_t the_capture_window,
  143 + uint32_t the_overruns = DEFAULT_MAX_OVERRUNS
  144 + ) { _ctx_.config(the_capture_window,the_overruns); }
139 145  
140 146 constexpr uint32_t ticks_per_usec() { return _ctx_.ticks_per_usec(); }
141 147 constexpr uint32_t max_capture_window() { return _ctx_.max_capture_window(); }
142 148  
143   - uint32_t get_duty() { return _ctx_.duty; }
144   -
145   - void get_duty_and_period(uint32_t& the_duty, uint32_t& the_period)
  149 + // NOTE: member function get_duty_and_period() returns
  150 + // the status of the capture object. Returns in arguments
  151 + // the last valid measured duty and period.
  152 + uint32_t get_duty_and_period(uint32_t& the_duty, uint32_t& the_period)
146 153 { return _ctx_.get_duty_and_period(the_duty,the_period); }
147 154  
148 155 uint32_t get_capture_window() { return _ctx_.capture_window; }
149 156  
  157 + bool is_overrun(uint32_t the_status)
  158 + { return _ctx_.is_overrun(the_status); }
  159 +
  160 + // NOTE: when too much loading overrun have been detected
  161 + // the capture stops measuring to avoid the used of compu-
  162 + // tational resources. Take into account that if the sig-
  163 + // nal measured has a frequency around 1 Mhz or higher the
  164 + // interrupts due to the capture object will consume all
  165 + // CPU time. If this is the case, the capture object stops
  166 + // capturing when the overun threshold is surpassed.
  167 + bool is_stopped(uint32_t the_status)
  168 + { return _ctx_.is_stopped(the_status); }
  169 +
  170 + // NOTE:capture object is unset when not configured
  171 + bool is_unset(uint32_t the_status)
  172 + { return _ctx_.is_unset(the_status); }
  173 +
  174 + void stop() { _ctx_.stop(); }
  175 + void restart() { _ctx_.restart(); }
  176 +
  177 + void lock()
  178 + {
  179 + if( is_unset() || is_stopped() ) return;
  180 + timer::disable_interrupts();
  181 + }
  182 +
  183 + void unlock()
  184 + {
  185 + if( is_unset() || is_stopped() ) return;
  186 + timer::enable_interrupts();
  187 + }
150 188  
151 189 private:
152 190  
... ... @@ -154,10 +192,17 @@ namespace arduino_due
154 192  
155 193 struct _capture_ctx_
156 194 {
157   -
  195 + enum status_codes: uint32_t
  196 + {
  197 + UNSET=0,
  198 + SET=1,
  199 + OVERRUN=2,
  200 + STOPPED=4
  201 + };
  202 +
158 203 _capture_ctx_() {}
159 204  
160   - bool config(uint32_t the_capture_window);
  205 + bool config(uint32_t the_capture_window, uint32_t the_overruns);
161 206  
162 207 void tc_interrupt(uint32_t the_status);
163 208  
... ... @@ -176,30 +221,111 @@ namespace arduino_due
176 221 ticks_per_usec();
177 222 }
178 223  
179   - void get_duty_and_period(uint32_t& the_duty, uint32_t& the_period)
  224 + uint32_t get_duty_and_period(uint32_t& the_duty, uint32_t& the_period)
180 225 {
  226 + uint32_t the_status=status;
  227 + if(is_unset(the_status)) return the_status;
  228 +
181 229 timer::disable_interrupts();
182 230 the_duty=duty; the_period=period;
  231 + the_status=status;
  232 + status=status&(~status_codes::OVERRUN);
183 233 timer::enable_interrupts();
  234 +
  235 + if(is_stopped(the_status)) restart();
  236 +
  237 + return the_status;
  238 + }
  239 +
  240 + bool is_overrun(uint32_t the_status)
  241 + { return (the_status&status_codes::OVERRUN); }
  242 +
  243 + bool is_stopped(uint32_t the_status)
  244 + { return (the_status&status_codes::STOPPED); }
  245 +
  246 + bool is_unset(uint32_t the_status)
  247 + { return !the_status; }
  248 +
  249 + void stop()
  250 + {
  251 + uint32_t the_status=status;
  252 + if(
  253 + is_unset(the_status) ||
  254 + is_stopped(the_status)
  255 + ) return;
  256 +
  257 + timer::stop_interrupts();
  258 + status=status|status_codes::STOPPED;
184 259 }
185 260  
  261 + void restart()
  262 + {
  263 + uint32_t the_status=status;
  264 + if(
  265 + is_unset(the_status) ||
  266 + !is_stopped(the_status)
  267 + ) return;
  268 +
  269 + ra=duty=period=overruns=0;
  270 + status&=
  271 + ~(status_codes::OVERRUN|status_codes::STOPPED);
  272 +
  273 + // clearing pending interrupt flags
  274 + uint32_t dummy=TC_GetStatus(
  275 + timer::info::tc_p,
  276 + timer::info::channel
  277 + );
  278 + timer::start_interrupts();
  279 + }
  280 +
186 281 void end()
187 282 {
  283 + uint32_t the_status=status;
  284 + if(is_unset(the_status)) return;
  285 +
  286 + timer::stop_interrupts();
  287 + timer::disable_lovr_interrupt();
188 288 timer::disable_ldra_interrupt();
189 289 timer::disable_ldrb_interrupt();
190 290 timer::disable_rc_interrupt();
191   -
192   - timer::stop_interrupts();
193 291 pmc_disable_periph_clk(uint32_t(timer::info::irq));
  292 +
  293 + status=status_codes::UNSET;
  294 + }
  295 +
  296 + void load_overrun()
  297 + {
  298 + status=status|status_codes::OVERRUN;
  299 + if((++overruns)>max_overruns)
  300 + {
  301 + timer::stop_interrupts();
  302 + status=status|status_codes::STOPPED;
  303 + }
194 304 }
  305 +
  306 + void ra_loaded()
  307 + {
  308 + ra=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RA;
  309 + }
  310 +
  311 + void rb_loaded()
  312 + {
  313 + period=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RB;
  314 + duty=period-ra;
  315 + }
  316 +
  317 + void rc_matched() { ra=duty=period=0; }
195 318  
196 319 // capture values
197 320 volatile uint32_t ra;
198 321 volatile uint32_t duty;
199 322 volatile uint32_t period;
  323 + volatile uint32_t overruns;
  324 + volatile uint32_t status;
200 325  
201 326 uint32_t rc;
202 327 uint32_t capture_window;
  328 + uint32_t max_overruns;
203 329 };
204 330  
205 331 static _capture_ctx_ _ctx_;
... ... @@ -210,14 +336,17 @@ namespace arduino_due
210 336  
211 337 template<timer_ids TIMER>
212 338 bool capture<TIMER>::_capture_ctx_::config(
213   - uint32_t the_capture_window // in microseconds
  339 + uint32_t the_capture_window, // in microseconds
  340 + uint32_t the_overruns
214 341 )
215 342 {
216   - if(the_capture_window>max_capture_window())
  343 + if( (the_capture_window>max_capture_window()) || !the_overruns)
217 344 return false;
218 345  
219 346 capture_window=the_capture_window;
220   - ra=duty=period=0;
  347 + ra=duty=period=overruns=0;
  348 + max_overruns=the_overruns;
  349 + status=status_codes::SET;
221 350  
222 351 // capture window in ticks
223 352 rc=capture_window*ticks_per_usec();
... ... @@ -241,6 +370,7 @@ namespace arduino_due
241 370 // seting RC to the capture window
242 371 TC_SetRC(timer::info::tc_p,timer::info::channel,rc);
243 372  
  373 + timer::enable_lovr_interrupt();
244 374 timer::enable_ldra_interrupt();
245 375 timer::enable_ldrb_interrupt();
246 376 timer::enable_rc_interrupt();
... ... @@ -256,20 +386,25 @@ namespace arduino_due
256 386 uint32_t the_status
257 387 )
258 388 {
259   - // capture interrupt, RA loaded
260   - if((the_status & TC_SR_LDRAS) && timer::is_enabled_ldra_interrupt())
261   - { ra=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RA; }
262   -
263   - // capture interrupt, RB loaded
264   - if((the_status & TC_SR_LDRBS) && timer::is_enabled_ldrb_interrupt())
265   - {
266   - period=timer::info::tc_p->TC_CHANNEL[timer::info::channel].TC_RB;
267   - duty=period-ra; ra=0;
268   - }
269   -
270   - // RC compare interrupt
271   - if((the_status & TC_SR_CPCS) && timer::is_enabled_rc_interrupt())
272   - { ra=duty=period=0; }
  389 + if( // load overrun on RA or RB
  390 + (the_status && TC_SR_LOVRS) &&
  391 + timer::is_enabled_lovr_interrupt()
  392 + ) load_overrun();
  393 +
  394 + if( // RA loaded?
  395 + (the_status & TC_SR_LDRAS) &&
  396 + timer::is_enabled_ldra_interrupt()
  397 + ) ra_loaded();
  398 +
  399 + if( // RB loaded?
  400 + (the_status & TC_SR_LDRBS) &&
  401 + timer::is_enabled_ldrb_interrupt()
  402 + ) rb_loaded();
  403 +
  404 + if( // RC compare interrupt?
  405 + (the_status & TC_SR_CPCS) &&
  406 + timer::is_enabled_rc_interrupt()
  407 + ) rc_matched();
273 408 }
274 409  
275 410 template<timer_ids TIMER>
... ... @@ -294,8 +429,8 @@ namespace arduino_due
294 429  
295 430 void stop() { _ctx_.stop(); }
296 431  
297   - void lock() { _ctx_.disable_tc_interrupts(); }
298   - void unlock() { _ctx_.enable_tc_interrupts(); }
  432 + void lock() { timer::disable_tc_interrupts(); }
  433 + void unlock() { timer::enable_tc_interrupts(); }
299 434  
300 435 constexpr uint32_t max_period() { return _ctx_.max_period(); }
301 436  
... ...
tc_lib.vim 0 → 100644
No preview for this file type