Running TC with an external clock and externally triggered capture (Zero/M0)


tl;dr: if can point me working samd21 example of running 32 bit tc both external clock (gclkio) , externally trigged count captures (via eic/evsys), appreciated. seem able 1 of working @ time.


hardware: board arduino m0 samd21g18 processor. datasheet (~ 17mb). external frequency (1k - 2mhz) generator on pa21 (m0 pin 7) , , 1 pps gps signal on pa17 (m0 pin 13). should apply arduino 0 well.

the objective: i'm trying capture events on tc4/tc5 in 32 bit mode external clock on pa21. captures should triggered pa17. in principle don't care choice of pins , have tried moving around.

the paradox: running tc4/5 on pa21 (arduino 7) via gclkio5 works fine cannot make capture via eic-events on pa17 (arduino 13). however, running tc on main clock (either via gclk5, or directly on gclk0) happily capture 1 pps pulses. only change made.

please see complete (non-)working example below; changing boolean in top switches between clocks , result in behaviour described above.

i'm assuming it's me forgetting configure obvious somewhere i'm starting run out of suggestions. interestingly, changing tc clock source 32 khz crystal (available @ gclk1) not have working count captures. makes me suspect synchronisation issue between clock domains.

any suggestions? thoughts appreciated.

thank you.

johan

ps: sorry longish, messy code it's shortest complete , working example think of exact point across.

code: [select]

void setup()
{
    // change here use main clock or input pin
    bool use_clk_pin = false ;

    serial1.begin(115200);
    while (!serial1);
    serial1.print("\r\nbegin config\r\n");

    pinmode(11, output) ;
    pinmode(12, output) ;

    // setup main clocks first
    reg_pm_apbamask |= pm_apbamask_gclk ;
    reg_pm_apbbmask |= pm_apbbmask_port ;
    reg_pm_apbcmask |= pm_apbcmask_evsys | pm_apbcmask_tc4 | pm_apbcmask_tc5 ;

    //
    //    setup gate input on pa17 (m0 pin 13)
    //  

    // send generic gclk0 eic peripheral
    reg_gclk_clkctrl = gclk_clkctrl_clken | gclk_clkctrl_gen_gclk0 | gclk_clkctrl_id_eic ;
    while(gclk->status.bit.syncbusy) ;

    reg_gclk_clkctrl = gclk_clkctrl_clken | gclk_clkctrl_gen_gclk0 | gclk_clkctrl_id_evsys_0 ;
    while(gclk->status.bit.syncbusy) ;

    // send pin pa17 eic (line 1)
    port->group[porta].pmux[17 >> 1].reg |= port_pmux_pmuxo_a ;
    port->group[porta].pincfg[17].reg |= port_pincfg_pmuxen ;

    // enable ext1 int rising edge event system
    reg_eic_evctrl |= eic_evctrl_extinteo1 ;
    reg_eic_config0 |= eic_config_sense1_rise ;
    reg_eic_ctrl |= eic_ctrl_enable;
    while (eic->status.bit.syncbusy);

    // direct ext3 event tc4
    reg_evsys_user = evsys_user_channel(1) | evsys_user_user(evsys_id_user_tc4_evu) ;
    reg_evsys_channel = evsys_channel_edgsel_no_evt_output | evsys_channel_path_asynchronous
                        | evsys_channel_evgen(evsys_id_gen_eic_extint_1) | evsys_channel_channel(0) ;

    //
    //    setup timer clock input on pa21 (pin 7 on m0)
    //

    // source gclk pa21 (gclkio 5)
    port->group[porta].pmux[21 / 2].reg = port_pmux_pmuxo_h ;
    port->group[porta].pincfg[21].reg = port_pincfg_pmuxen ;

    // tick count: gclk_io5 => tc4-5
    reg_gclk_gendiv = gclk_gendiv_id(5) ; // gclk5: no div

    // clock pin pa21
    //reg_gclk_genctrl = gclk_genctrl_genen | gclk_genctrl_runstdby | gclk_genctrl_src_gclkin  | gclk_genctrl_id(5) ;
    //while (gclk->status.bit.syncbusy);



    if(use_clk_pin) {
        // feed gclk_io
        reg_gclk_genctrl = gclk_genctrl_genen | gclk_genctrl_runstdby | gclk_genctrl_src_gclkin  | gclk_genctrl_id(5) ;
        while (gclk->status.bit.syncbusy);
    } else {
        // clock main clock
        reg_gclk_genctrl = gclk_genctrl_genen | gclk_genctrl_runstdby | gclk_genctrl_src_dfll48m | gclk_genctrl_id(5) ;
        while (gclk->status.bit.syncbusy);
    }

    // feed gclk5 tc4/tc5
    reg_gclk_clkctrl = gclk_clkctrl_clken | gclk_clkctrl_gen_gclk5 | gclk_clkctrl_id_tc4_tc5 ;
    while (gclk->status.bit.syncbusy);
    
    //
    // general timer tc4-tc5 setup 32 bit
    //

    // enable event input
    reg_tc4_evctrl |= tc_evctrl_tcei ;

    // set capture on channel 0
    reg_tc4_readreq = tc_readreq_rreq | tc_readreq_addr(0x06) ;
    while (tc4->count32.status.bit.syncbusy) ;
    reg_tc4_ctrlc |= tc_ctrlc_cpten0 ;
    while (tc4->count32.status.bit.syncbusy) ;

    // enable timer tc4 interrupt capture events
    nvic_setpriority(tc4_irqn, 0) ;
    nvic_enableirq(tc4_irqn) ;
    reg_tc4_intenset = tc_intenset_mc0 ;

    // no prescaler, 32 bit mode: run timer!
    reg_tc4_ctrla |= tc_ctrla_prescaler_div1 | tc_ctrla_mode_count32 | tc_ctrla_enable ;
    while (tc4->count16.status.bit.syncbusy) ;

    serial1.print("config done\r\n") ;
}



void tc4_handler()
{
    uint32_t count ;
  
    // check match counter 0 (mc0) interrupt
    // read automatically clears flag      
    if (tc4->count16.intflag.bit.mc0)
    {
        reg_tc4_readreq = tc_readreq_rreq | tc_readreq_addr(0x18);
        while (tc4->count32.status.bit.syncbusy);
        count = reg_tc4_count32_cc0;

        // print out debug
        serial1.print("count capture: ") ;
        serial1.print(count) ;
        serial1.print("\r\n") ;
    }
  
    static bool toggle = false ;
    toggle = !toggle ;
    digitalwrite(11, toggle) ;
}


void loop()
{
  delay(1000) ;
  
  reg_tc4_readreq = tc_readreq_rreq | tc_readreq_addr(0x10) ; // count offset 0x10
  while (tc4->count32.status.bit.syncbusy) ;
  volatile uint32_t count = reg_tc4_count32_count ;
  while (tc4->count32.status.bit.syncbusy) ;

  serial1.print("current count: ") ;
  serial1.print(count) ;
  serial1.print("\r\n") ;

  static bool toggle = false ;
  toggle = !toggle ;
  digitalwrite(12, toggle) ;
}



edit: should add output data. gclk0 case:

code: [select]

begin config
config done
count capture: 12462258
current count: 47993356
count capture: 60431073
current count: 95993356
count capture: 108403724
current count: 143993350
count capture: 156378173
current count: 191993356
count capture: 204352597
current count: 239993353
count capture: 252328812
current count: 287993358
count capture: 300305004
current count: 335993350
count capture: 348278533
current count: 383993359
count capture: 396254598
current count: 431993356
count capture: 444231927
current count: 479993350
count capture: 492208871
current count: 527993359


also, forgot mention, every once in blue moon, odd capture happen in non-working scenario. talking every 10 min or so. ~2 mhz gclkio[5] case:

code: [select]

begin config
config done
current count: 2015338
current count: 4030983
current count: 6046728
current count: 8062300
current count: 10077785
current count: 12093356
current count: 14108933
current count: 16124468
count capture: 17447337
current count: 18139945
current count: 20155267
current count: 22170451
current count: 24185506
current count: 26200437
current count: 28215295
current count: 30230214
current count: 32245066
current count: 34259869
current count: 36274630
current count: 38289377
current count: 40303980
current count: 42318587
current count: 44333123
current count: 46347657
current count: 48362252
current count: 50376876
current count: 52391547
current count: 54406037


again, thoughts appreciated :)

problem solved. event source , receiver need in synchronisation.

so, eic , tc clock must same (asynchronous/synchronous) or event channel needs resynchronised. have not tested assume 1 can away different frequencies in asynchronous case.

solution: change event system setup resynchronised rising edge detect.

code: [select]

    reg_evsys_channel = evsys_channel_edgsel_rising_edge | evsys_channel_path_resynchronized
                        | evsys_channel_evgen(evsys_id_gen_eic_extint_1) | evsys_channel_channel(0) ;


i tried clocking eic unit directly gclk input pin (gclk5) works (but has working below 48 mhz core frequency.)

relevant section datasheet (page 410):

quote
the resynchronized path should used when event generator , event channel not share same generic
clock generator. when resynchronized path used, resynchronization of event event generator done
in channel.
edit: tried playing around little , seems asynchronous path can trusted when eic frequency around half tc frequency. above there occasional glitch , when frequencies same (but not in sync!), event/capture missed regularly.


Arduino Forum > Using Arduino > Microcontrollers > Running TC with an external clock and externally triggered capture (Zero/M0)


arduino

Comments

Popular posts from this blog

Error compiling for board Arduino/Genuino Uno.

Installation database is corrupt

esp8266 (nodemcu 0.9) client.write très lent ???