Problem with Arduino pwm_lib

Hi All,
I recently downloaded an Arduino library from here GitHub - antodom/pwm_lib: This is a C++ library to abstract the use of the eight hardware PWM channels available on Arduino DUE's Atmel ATSAM3X8E microcontroller.. The example program I tied, supplied with the library, works very well when compiled with Arduino IDE, but the same example file does not compile under Platformio and produces hundreds or error messages. They are (on cursory inspection) all the same message. I’ve pasted in some of them below.

In file included from lib/pwm_lib/pwm_lib.h:37:0,
                 from src/main.cpp:36:
/home/ian/.platformio/packages/framework-arduino-sam/system/CMSIS/Device/ATMEL/sam3xa/include/sam3x8e.h:494:21: error: 'reinterpret_cast<Pio*>(1074662912)' is not a constant expression
 #define PIOA       ((Pio    *)0x400E0E00U) /**< \brief (PIOA      ) Base Address */
                    ~^~~~~~~~~~~~~~~~~~~~~~
lib/pwm_lib/pwm_defs.h:98:37: note: in definition of macro 'pin_traits_specialization'
       static constexpr Pio* pio_p = pio; \
                                     ^~~
lib/pwm_lib/pwm_defs.h:109:52: note: in expansion of macro 'PIOA'
     pin_traits_specialization(pwm_pin::PWMH0_PA8 , PIOA, PIO_PA8B_PWMH0 , ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT,  PWM_CH0,   false  );
                                                    ^~~~
/home/ian/.platformio/packages/framework-arduino-sam/system/CMSIS/Device/ATMEL/sam3xa/include/sam3x8e.h:495:21: error: 'reinterpret_cast<Pio*>(1074663424)' is not a constant expression
 #define PIOB       ((Pio    *)0x400E1000U) /**< \brief (PIOB      ) Base Address */
                    ~^~~~~~~~~~~~~~~~~~~~~~
lib/pwm_lib/pwm_defs.h:98:37: note: in definition of macro 'pin_traits_specialization'
       static constexpr Pio* pio_p = pio; \
                                     ^~~
lib/pwm_lib/pwm_defs.h:110:52: note: in expansion of macro 'PIOB'
     pin_traits_specialization(pwm_pin::PWMH0_PB12, PIOB, PIO_PB12B_PWMH0, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT,  PWM_CH0,   false  );
                                                    ^~~~
/home/ian/.platformio/packages/framework-arduino-sam/system/CMSIS/Device/ATMEL/sam3xa/include/sam3x8e.h:496:21: error: 'reinterpret_cast<Pio*>(1074663936)' is not a constant expression
 #define PIOC       ((Pio    *)0x400E1200U) /**< \brief (PIOC      ) Base Address */
                    ~^~~~~~~~~~~~~~~~~~~~~~
lib/pwm_lib/pwm_defs.h:98:37: note: in definition of macro 'pin_traits_specialization'
       static constexpr Pio* pio_p = pio; \
                                     ^~~
lib/pwm_lib/pwm_defs.h:111:52: note: in expansion of macro 'PIOC'
     pin_traits_specialization(pwm_pin::PWMH0_PC3 , PIOC, PIO_PC3B_PWMH0 , ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT,  PWM_CH0,   false  );
                                                    ^~~~

I’ve updated all the libraries to the latest versions. Is there something else I need to do in Platformio to get this library to work?
Thanks,
Ian

In PlatformIO, what are your exact versions for the Atmel SAM (or Adafruit SAMD) platform? Which board are you using with what exact setttings? What version of that library is installed in Arduino IDE?

Do you have installed the latest platform updates for PlatformIO (pio platform update or via VSCode GUI)? What exact platformio.ini are you using?

Does changing the bleeding-edge version change anything?

lib_deps = https://github.com/antodom/pwm_lib.git

Hi Max, thanks for replying.
I was in the middle of writing a long and detailed reply to answer your requests when I had, as a friend of mine used to call it, a “lucid moment”.
I was using another program I have that does some similar things with registers to get examples of what they do (thinking it might help you work out what was happening), when it suddenly dawned on me that that program worked fine! It had no problems compiling for the Due at all. And it is using the same registers. So, maybe not a Platformio problem. Maybe a library problem. No idea how, unless it’s loading libraries from somewhere other than the PIO libraries somehow. I’m not techie enough to figure that out.
So I think it might be time to abandon the pwm_lib library, interesting though it is. I don’t think it’s worth wasting too much more time on it if I can’t even get the example to compile!

Thanks for your time anyway, and apologies for wasting so much of it.
:wink:

1 Like

Intereseting, good that it’s working for you.

Nevertheless I dug a little deeper and found the cause of the error. The error is indeed right and reproducable. The code

    #define pin_traits_specialization(the_pwm_pin,pio,pio_pin,pio_id,pio_type,pio_conf,pwm_channel,pwm_inverted) \
    template<> struct pin_traits< \
      the_pwm_pin \
    > \
    { \
      static constexpr Pio* pio_p = pio; \
      static constexpr const uint32_t pin = pio_pin; \
      static constexpr const uint32_t id = pio_id; \
      static constexpr const EPioType type= pio_type; \
      static constexpr const uint32_t conf = pio_conf; \
      static constexpr const EPWMChannel channel = pwm_channel; \
      static constexpr const bool inverted = pwm_inverted; \
    };

Initializes a static constexpr Pio* pio_p = pio;. When the template is used in the line

    pin_traits_specialization(pwm_pin::PWMH0_PA8 , PIOA, PIO_PA8B_PWMH0 , ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT,  PWM_CH0,   false  ); 

It will use PIOA for the pio parameter and it will thus expand

static constexpr Pio* pio_p = PIOA; 

PIOA is defined in the CMSIS Atmel files, as

 #define PIOA       ((Pio    *)0x400E0E00U) /**< \brief (PIOA      ) Base Address */

in PlatformIO.

Since the header version that PlatformIO uses does a C-style cast (with the (Pio *)), also called reinterpret_cast in C++, it is not a constant expression anymore in the eyes of the C++ compiler and thus gives the error

error: 'reinterpret_cast<Pio*>(1074662912)' is not a constant expression

So something is up with PlatformIO and the Arduino IDE version not using the same ATMEL CMSIS files… Which is contradicted when looking in the Github files though

So PlatformIO does use the same file as the Arduino core. Hm.

Hah I got it.

I saw that it compiled perfectly fine within the Arduino IDE when invoked with

“C:\Users\Maxi\AppData\Local\Arduino15\packages\arduino\tools\arm-none-eabi-gcc\4.8.3-2014q1/bin/arm-none-eabi-g++” -c -g -Os -w -std=gnu++11 […]

That’s GCC version 4.8.3 from 6 years ago. PlatformIO uses 7.2.1

When manually picking the archive with the old version for my OS in Service End for Bintray, JCenter, GoCenter, and ChartCenter | JFrog and setting it using the platformio.ini (docs)

[env:due]
platform = atmelsam
board = due 
framework = arduino
platform_packages = 
	toolchain-gccarmnoneeabi @ https://bintray.com/platformio/dl-packages/download_file?file_path=toolchain-gccarmnoneeabi-windows-1.40804.0.tar.gz
lib_deps = 
	https://github.com/antodom/tc_lib.git
	https://github.com/antodom/pwm_lib.git

The project compiled successfully!

Processing due (platform: atmelsam; board: due; framework: arduino)
--------------------------------------------------------------------------------
PackageManager: Installing toolchain-gccarmnoneeabi
Downloading...
Unpacking...
toolchain-gccarmnoneeabi @ 1.40804.0 has been successfully installed!
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelsam/due.html
PLATFORM: Atmel SAM 4.3.0 > Arduino Due (Programming Port)
HARDWARE: AT91SAM3X8E 84MHz, 96KB RAM, 512KB Flash
DEBUG: Current (atmel-ice) External (atmel-ice, blackmagic, jlink, stlink)
PACKAGES: 
 - framework-arduino-sam 1.6.12 
 - framework-cmsis 1.40500.0 (4.5.0) 
 - framework-cmsis-atmel 1.2.0 
 - toolchain-gccarmnoneeabi 1.40804.0 (4.8.4)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 6 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <tc_lib> 1.0 #28682b5
|-- <pwm_lib> 1.0 #168cc25
Building in release mode
Compiling .pio\build\due\src\main.cpp.o
Archiving .pio\build\due\lib014\libtc_lib.a
Indexing .pio\build\due\lib014\libtc_lib.a
Compiling .pio\build\due\libd7c\pwm_lib\pwm_defs.cpp.o
Compiling .pio\build\due\FrameworkArduinoVariant\variant.cpp.o
Compiling .pio\build\due\FrameworkArduino\IPAddress.cpp.o
Compiling .pio\build\due\FrameworkArduino\Print.cpp.o
Compiling .pio\build\due\FrameworkArduino\Reset.cpp.o
Compiling .pio\build\due\FrameworkArduino\RingBuffer.cpp.o
Compiling .pio\build\due\FrameworkArduino\Stream.cpp.o
Compiling .pio\build\due\FrameworkArduino\UARTClass.cpp.o
Compiling .pio\build\due\FrameworkArduino\USARTClass.cpp.o
Compiling .pio\build\due\FrameworkArduino\USB\CDC.cpp.o
src\main.cpp: In function 'void loop()':
src\main.cpp:128:12: warning: variable 'status' set but not used [-Wunused-but-set-variable]
   uint32_t status,duty,period;
            ^
Compiling .pio\build\due\FrameworkArduino\USB\PluggableUSB.cpp.o
In file included from src\main.cpp:36:0:
.pio\libdeps\due\tc_lib/tc_lib.h: In instantiation of 'void arduino_due::tc_lib::capture<TIMER>::_capture_ctx_::restart() [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)0u]':
.pio\libdeps\due\tc_lib/tc_lib.h:280:62:   required from 'uint32_t arduino_due::tc_lib::capture<TIMER>::_capture_ctx_::get_duty_and_period(uint32_t&, uint32_t&, bool) [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)0u; uint32_t = long unsigned int]'
.pio\libdeps\due\tc_lib/tc_lib.h:164:23:   required from 'uint32_t arduino_due::tc_lib::capture<TIMER>::get_duty_and_period(uint32_t&, uint32_t&, bool) [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)0u; uint32_t = long unsigned int]'
src\main.cpp:131:54:   required from here
.pio\libdeps\due\tc_lib/tc_lib.h:347:22: warning: unused variable 'dummy' [-Wunused-variable]
             uint32_t dummy=TC_GetStatus( 
                      ^
.pio\libdeps\due\tc_lib/tc_lib.h: In instantiation of 'void arduino_due::tc_lib::capture<TIMER>::_capture_ctx_::restart() [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)1u]':
.pio\libdeps\due\tc_lib/tc_lib.h:280:62:   required from 'uint32_t arduino_due::tc_lib::capture<TIMER>::_capture_ctx_::get_duty_and_period(uint32_t&, uint32_t&, bool) [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)1u; uint32_t = long unsigned int]'
.pio\libdeps\due\tc_lib/tc_lib.h:164:23:   required from 'uint32_t arduino_due::tc_lib::capture<TIMER>::get_duty_and_period(uint32_t&, uint32_t&, bool) [with arduino_due::tc_lib::timer_ids TIMER = (arduino_due::tc_lib::timer_ids)1u; uint32_t = long unsigned int]'
src\main.cpp:142:55:   required from here
.pio\libdeps\due\tc_lib/tc_lib.h:347:22: warning: unused variable 'dummy' [-Wunused-variable]
Compiling .pio\build\due\FrameworkArduino\USB\USBCore.cpp.o
Compiling .pio\build\due\FrameworkArduino\WInterrupts.c.o
Compiling .pio\build\due\FrameworkArduino\WMath.cpp.o
Compiling .pio\build\due\FrameworkArduino\WString.cpp.o
Archiving .pio\build\due\libd7c\libpwm_lib.a
src\main.cpp:139:52: warning: 'period' may be used uninitialized in this function [-Wmaybe-uninitialized]
   Serial.print(period/capture_pin2.ticks_per_usec());
                                                    ^
src\main.cpp:137:3: warning: 'duty' may be used uninitialized in this function [-Wmaybe-uninitialized]
   );
   ^
Compiling .pio\build\due\FrameworkArduino\abi.cpp.o
Indexing .pio\build\due\libd7c\libpwm_lib.a
Archiving .pio\build\due\libFrameworkArduinoVariant.a
Indexing .pio\build\due\libFrameworkArduinoVariant.a
Compiling .pio\build\due\FrameworkArduino\avr\dtostrf.c.o
Compiling .pio\build\due\FrameworkArduino\cortex_handlers.c.o
Compiling .pio\build\due\FrameworkArduino\hooks.c.o
Compiling .pio\build\due\FrameworkArduino\iar_calls_sam3.c.o
Compiling .pio\build\due\FrameworkArduino\itoa.c.o
Compiling .pio\build\due\FrameworkArduino\main.cpp.o
Compiling .pio\build\due\FrameworkArduino\new.cpp.o
Compiling .pio\build\due\FrameworkArduino\syscalls_sam3.c.o
Compiling .pio\build\due\FrameworkArduino\watchdog.cpp.o
Compiling .pio\build\due\FrameworkArduino\wiring.c.o
Compiling .pio\build\due\FrameworkArduino\wiring_analog.c.o
Compiling .pio\build\due\FrameworkArduino\wiring_digital.c.o
Compiling .pio\build\due\FrameworkArduino\wiring_pulse.cpp.o
Compiling .pio\build\due\FrameworkArduino\wiring_pulse_asm.S.o
Compiling .pio\build\due\FrameworkArduino\wiring_shift.c.o
Archiving .pio\build\due\libFrameworkArduino.a
Indexing .pio\build\due\libFrameworkArduino.a
Linking .pio\build\due\firmware.elf
Building .pio\build\due\firmware.bin
Checking size .pio\build\due\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   3.0% (used 2928 bytes from 98304 bytes)
Flash: [=         ]   5.6% (used 29108 bytes from 524288 bytes)
========================= [SUCCESS] Took 43.20 seconds =========================

You can maybe try other, higher version than I did (4.8.4 is very old…) which still work. But this confirms the problem. Older compiler versions simply don’t see the casting operation the same as newer ones.

2 Likes

Hi Max,
I am very impressed with a) your perseverance in the pursuit of the issue, and b) your technical expertise. I would never have been able to discover the problem.
I am gobsmacked that the very latest bleeding edge version of Arduino IDE is using such an old compiler! Why would that be? Makes no sense to me. But I never use Arduino IDE any more anyway (well, hardly ever).
But on a completely different note, this program compiles fine, and it uses TC2->blah blah pointer construct and ditto PIOD. Same board. Since you seem to be stuck at home (like the rest of us) maybe this will keep you amused for a while. :slight_smile:


/*
  The original code came from a post on the Arduino forum.  
  It was written to output on the Due D2 pin.  I needed D11 since the
  "shield" I'd designed used that pin.

  There's a mini-menu in the serial monitor to demonstrate some of the
  features I need to support.

  Pin D11 is used as PPM to an RF deck and has a driver transistor.
  D12 is intended as an aux output for flight sim.  Since the sim and
  RF deck could have different requirements for polarity and separation
  pulse, they need to be independently programmable.  

  Use an o'scope triggered on pin D8 to watch the PPM waveforms on D11 or D12.
*/

/*
Register A is loaded with a value for the channel separation pulse, typically around 400uS.
Different radio brands have different specs, so this value is user programmable.  The register
A value does not change during the generation of PPM.

An interrupt is attached to counter = Register C.  Register C is later loaded with the actual
time of a single channel cycle from an array containing nine different values representing the
eight different channels and the "leftover" time separating PPM frames.  Polarity of the waveform
is determined by ACPA and ACPC bits in TC_CMR.  One will set A and the other will clear A.  For
this example, we'll use ACPA_SET and ACPC_CLEAR.

When the counter = Register C, an NVIC interrupt occurs, the signal will clear (ACPC_CLEAR).
The counter begins counting from zero until it reaches the value of Register A and the signal
sets (ACPA_SET).  The counter continues until it reaches the value in Register C, where the
signal again clears (ACPC_CLEAR) and the NVIC interrupt is triggered.  In the interrupt routine,
Register C is loaded with the next value from the PPM array.  When all channel values in the
array have been processed, the final array element value is calculated from the known frame
time period and the sum of eight channel values (frameTime - sum).

Register B, in the same counter, can hold a different compare value, as well as use a different
BCPB and BCPC configuration.  This can allow for a different channel separator pulsewidth,
as well as matching or opposing polarity, while maintaining the frame timing and "data".

*/
#include <Arduino.h>

bool d11Normal = 1;  //1 is normal, 0 is inverted
bool d12Normal = 1;
uint32_t ppm_channels[8];
uint32_t Frame = 22500;   //time of frame repetition
uint32_t multiplier = 42; // timer is clocked at 42MHz, so 42 ticks per us
uint32_t periods[9];
uint32_t num_periods=8+1;      // number of channels +1

uint32_t d11Sep = 300*multiplier; // channel separation pulse for D11
uint32_t d12Sep = 300*multiplier; // channel separation pulse for D12

//********************************************************************
void TC8_Handler()
{
  static bool toggle = 0;
  uint32_t dummy = TC2->TC_CHANNEL[2].TC_SR;  // vital - reading this clears some flag otherwise you get infinite interrupts

  static uint16_t i=0;

  TC2->TC_CHANNEL[2].TC_RC = periods[i++];
  i %= num_periods;

  if (i == 0)   {   //for o'scope sync.  Also indicates interrupt is triggering...
    toggle = !toggle;
    digitalWrite(8,toggle);
  }
}
//********************************************************************

void setup(){
  Serial.begin(115200);

  PMC->PMC_WPMR = 0x504D4300;  //power management controller write protect

  PMC->PMC_PCER1 |= PMC_PCER1_PID35;        //PMC Peripheral Clock Enable Register 1, set PID35 high

  PIOD->PIO_PDR |= PIO_PDR_P7 | PIO_PDR_P8;  // disable PIO, enable peripherals for D11 & D12

  PIOD->PIO_ABSR |= PIO_ABSR_P7 | PIO_PDR_P8;     // select peripherals for D11 & D12

  TC2->TC_WPMR = 0x54494D00;    // enable write to registers, can comment & still runs!
  TC2->TC_CHANNEL[2].TC_CMR =  TC_CMR_TCCLKS_TIMER_CLOCK1  // channel mode register base configuration
                             | TC_CMR_EEVT_XC0
                             | TC_CMR_WAVSEL_UP_RC
                             | TC_CMR_WAVE;

  if (d11Normal)  {
    TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR);  // channel mode register - D11 normal
  }
  else  {
    TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);  // channel mode register - D11 inverted
  }

  if (d12Normal)  {
    TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_BCPB_SET | TC_CMR_BCPC_CLEAR);  // channel mode register - D12 normal
  }
  else  {
    TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_SET);  // channel mode register - D12 inverted
  }

  TC2->TC_CHANNEL[2].TC_RC = 100000000;   // initialize counter period with some value
  TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;      // start counter

  TC2->TC_CHANNEL[2].TC_IER =  TC_IER_CPCS;  // enable interrupt on counter = rc
  TC2->TC_CHANNEL[2].TC_IDR = ~(TC_IDR_CPCS);  // disable other interrupts

  TC2->TC_CHANNEL[2].TC_RA = d11Sep;  // channel separation pulse for D11
  TC2->TC_CHANNEL[2].TC_RB = d12Sep;  // channel separation pulse for D12

  ppm_channels[0]= 2000;          // channel 1, 1.0mS
  ppm_channels[1]= 1500;          // channel 2, 1.0mS
  ppm_channels[2]= 1000;          // channel 3, 1.5mS
  ppm_channels[3]= 1500;          // channel 4, 2.0mS
  ppm_channels[4]= 2000;          // channel 5, 1.0mS
  ppm_channels[5]= 1500;          // channel 6, 1.0mS
  ppm_channels[6]= 1000;          // channel 7, 1.0mS
  ppm_channels[7]= 1500;          // channel 8, 1.0mS

  NVIC_EnableIRQ(TC8_IRQn);      // enable TC2 interrupts

  Serial.println(" i\tinverted PPM on D12");
  Serial.println(" n\tnormal PPM on D12");
  Serial.println(" I\tinverted PPM on D11");
  Serial.println(" N\tnormal PPM on D11");
  Serial.println(" k\tkill PPM");
  Serial.println(" r\trestart PPM");

}
//********************************************************************

void loop() {
  char serIn = ' ';

  // Calculate the 8 channels
  periods[8] = 22500 * multiplier;
  for (int i = 0; i < 8; i++)  {
    periods[i] = (ppm_channels[i] * multiplier) + 300;
    periods[8] -= periods[i];
  }
  serIn = Serial.read();

  switch (serIn) {
    case 'i':  //D12 (aux) inverted PPM
      TC2->TC_CHANNEL[2].TC_CMR &= ~(TC_CMR_BCPB_SET | TC_CMR_BCPC_CLEAR);  //zero out TIOB compare bits, maintain current TIOA compare bits
      TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_SET);   //channel mode register - D12 inverted
      d12Normal = 0;
      break;
    case 'n':  //D12 (aux) normal PPM
      TC2->TC_CHANNEL[2].TC_CMR &= ~(TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_SET);  //zero out TIOB compare bits, maintain current TIOA compare bits
      TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_BCPB_SET | TC_CMR_BCPC_CLEAR);   //channel mode register - D12 normal
      d12Normal = 1;
      break;
    case 'I':  //D11 (RF module) inverted PPM
      TC2->TC_CHANNEL[2].TC_CMR &= ~(TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR);  //zero out TIOA compare bits, maintain current TIOB compare bits
      TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);   //channel mode register - D11 inverted
      d11Normal = 0;
      break;
    case 'N':  //D11 (RF module) normal PPM
      TC2->TC_CHANNEL[2].TC_CMR &= ~(TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);  //zero out TIOA compare bits, maintain current TIOB compare bits
      TC2->TC_CHANNEL[2].TC_CMR |= (TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR);   //channel mode register - D11 normal
      d11Normal = 1;
      break;
    case 'k':  //kill PPM
      TC2->TC_CHANNEL[2].TC_CCR  = !TC_CCR_SWTRG | TC_CCR_CLKDIS | !TC_CCR_CLKEN;       // stop counter
      break;
    case 'r':  //restart PPM
      PIOD->PIO_PDR |= PIO_PDR_P7 | PIO_PDR_P8;  // disable PIO, enable peripherals for D11 & D12
      PIOD->PIO_ABSR |= PIO_ABSR_P7 | PIO_ABSR_P8;     // select peripherals for D11 & D12
      TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;
      break;
    default:
    break;
  }
}

1 Like