Go Down

Topic: Configuring TC module to count pulses from external input (Read 147 times) previous topic - next topic

Rucus

Hello,

I have an Adafruit Feather M0 board, and I would like to configure its timers (at least one for now) to count pulses from an external source. I am using Arduino IDE 1.6.9. Just a quick note, Adafruit Feather M0 uses the same microprocessor as the Arduino Zero, except the the former do not have the EDBG chip on the board.

I found this code from MartinL posted here and modified it a little bit to try to configure the TC to count the pulses feed through pin 12 of the Feather M0 board.

Code: [Select]
void setup()   {               
  Serial.begin(115200);
 
  delay(7000);  //have ample time to catch text in serial monitor
 
  Serial.println("My Project");

  pinMode(DCDC_EN, OUTPUT);
 
  REG_PM_APBCMASK |= PM_APBCMASK_EVSYS;     // Switch on the event system peripheral
 
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |    // Divide the 48MHz system clock by x
                    GCLK_GENDIV_ID(5);      // Set division on Generic Clock Generator (GCLK) 5
  while (GCLK->STATUS.bit.SYNCBUSY);        // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK 5
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the clock source to 48MHz
                     GCLK_GENCTRL_ID(5);          // Set clock source on GCLK 5
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization*/

  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable the generic clock...
                     GCLK_CLKCTRL_GEN_GCLK5 |     // ....on GCLK5
                     GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed the GCLK5 to TCC2 and TC3
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
 
  digitalWrite(DCDC_EN, 0);                                               //Turn off sensor power
  delay(3000);

  NVIC_DisableIRQ(EIC_IRQn);
  NVIC_ClearPendingIRQ(EIC_IRQn);
  NVIC_SetPriority(EIC_IRQn, 0);
  NVIC_EnableIRQ(EIC_IRQn);

  // Enable GCLK for IEC (External Interrupt Controller)
  GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC));

  // Choose EIC external interrupt to use
  REG_EIC_EVCTRL |= EIC_EVCTRL_EXTINTEO3;                                 // Enable event output on external interrupt 3
 
  // Enable EIC
  EIC->CTRL.bit.ENABLE = 1;
  while (EIC->STATUS.bit.SYNCBUSY == 1) { }

  uint32_t ulPin = 12;                // Board pin to use
  EPioType ulPeripheral = PIO_EXTINT;
 
  if ( g_APinDescription[ulPin].ulPin & 1 ) // is pin odd?
  {
    uint32_t temp ;

    // Get whole current setup for both odd and even pins and remove odd one
    temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ;
    // Set new muxing
    PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
    // Enable port mux
    PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ;
  }
  else // even pin
  {
    uint32_t temp ;

    temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ;
    PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXE( ulPeripheral ) ;
    PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux
  }
 
  REG_EVSYS_USER = EVSYS_USER_CHANNEL(1) |                                // Attach the event user (receiver) to channel 0 (n + 1)
                   EVSYS_USER_USER(EVSYS_ID_USER_TC3_EVU);                // Set the event user (receiver) as timer TC3

  REG_EVSYS_CHANNEL = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // No event edge detection
                      EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Set event path as asynchronous
                      EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_3) |    // Set event generator (sender) as external interrupt 3
                      EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0

  REG_TC3_EVCTRL |= TC_EVCTRL_TCEI |              // Enable the TC event input
                    /*TC_EVCTRL_TCINV |*/         // Invert the event input
                    TC_EVCTRL_EVACT_COUNT;          // Set up the timer for counting events
                   
  REG_TC3_READREQ = TC_READREQ_RREQ |             // Enable a read request
                    TC_READREQ_ADDR(TC_COUNT16_COUNT_OFFSET);        // Offset of the COUNT register
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for (read) synchronization

  REG_TC3_CTRLBCLR = TC_CTRLBCLR_DIR;                     // Set register for counter to count up
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for (write) synchronization

  REG_TC3_COUNT16_COUNT = 0x0000;               // Clear timer's COUNT value
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);     // Wait for synchronization
 
  REG_TC3_CTRLA |= TC_CTRLA_PRESCALER_DIV1 |      // Set timer prescaler
                   TC_CTRLA_ENABLE;               // Enable TC3
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  Serial.println("Done with TC init");
  delay(1000);                        //wait for some delay before turning on power to sensors
   
  timer = millis();
  digitalWrite(DCDC_EN, 1);           
  delay(1000);                        //wait for some delay for power to stabilize
}

void loop() {
  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();
 
  if (millis() - timer > 100) {
    timer = millis(); // reset the timer

    ReadCountValTC3();  //print COUNT register value every ~100ms.
  }
}

void ReadCountValTC3()
{
  static uint32_t sampleCntr=0;
 
  if(TC3->COUNT16.INTFLAG.bit.OVF && TC3->COUNT16.INTENSET.bit.OVF)
  {
    Serial.println("OVF!");
  }
  else
  {
    REG_TC3_READREQ = TC_READREQ_RREQ |           // Enable a read request
                      TC_READREQ_ADDR(TC_COUNT16_COUNT_OFFSET);      // Offset address of the COUNT register
    while (TC3->COUNT16.STATUS.bit.SYNCBUSY);     // Wait for (read) synchronization
    Serial.println(TC3->COUNT16.COUNT.reg, DEC);
    TC3->COUNT16.COUNT.reg = 0x0000;
//    REG_TC3_COUNT16_COUNT = 0x0000;
    while (TC3->COUNT16.STATUS.bit.SYNCBUSY);     // Wait for synchronization
  }
}


What I struggle with is understanding how to configure the EVENT system, the EIC, GCLK, and PORT (MUX's), so I the signal from the pin where I feed the pulses to can propagate to the TC3 timer module. I read these modules in SAMD21 datasheet but I personally think the information there is just not enough for me to be able to manipulate the registers to do what I wanted to do. Or maybe it's just me who thinks it is what it is.

Any help from you guys would be greatly appreciated. Thanks a lot!

-Ruch

mrburnette

@Ruch,

My guess is there are not too many 'feathers' out with our forum members which is why no one is answering.

My previous experience with Adafruit forums has not been a great experience, but you did pay a premium for your board and a portion of that cost is for technical support... maybe you will get lucky if you ask in the Adafruit forum.

good luck,

Ray

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy