Author Topic: SAMc21 TC PWP and analog  (Read 2292 times)

0 Members and 1 Guest are viewing this topic.

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
SAMc21 TC PWP and analog
« on: November 08, 2021, 07:46:50 am »
Hi,

I'm pretty new with samc21. I have mu own prototype board wit c21g18. With this forum i got CANBUS to work but i'm still strucling with TC PWP since i should be able to measure pulse frequency and pulse width. Since i'm new i try to gather everything together with ASF4, but any kind of help will be appreciated.

So what i have been able to do so far:
- I have set up external IRQ's for pins i use with high level detection and event output (48MHz clock).   
- Setup event system channels to with asynchronous path, no edge detection, and event creation from pin.
- TC0 and TC2 in 32- bit mode with event input. enabled CAPTEN0, CAPTEN1 and PWP. 48MHZ clock with divider 2.

at main enabled the IRQ's:
Code: [Select]
  NVIC_DisableIRQ(TC0_IRQn);
      NVIC_ClearPendingIRQ(TC0_IRQn);
      NVIC_EnableIRQ(TC0_IRQn);

  NVIC_DisableIRQ(TC2_IRQn);
      NVIC_ClearPendingIRQ(TC2_IRQn);
      NVIC_EnableIRQ(TC2_IRQn);


TC0 IRQ handler:

Code: [Select]
void TC0_Handler(){

count0 = TC0->COUNT32.COUNT.reg;                    // Read the COUNT register

if (hri_tc_get_interrupt_OVF_bit(TC0)) {
              hri_tc_clear_interrupt_OVF_bit(TC0);
       }
       if(hri_tc_get_interrupt_ERR_bit(TC0)) {
              hri_tc_clear_interrupt_ERR_bit(TC0);
       }
       if(hri_tc_get_interrupt_MC1_bit(TC0)) {
             
              hri_tc_clear_interrupt_MC1_bit(TC0);
  hri_tc_clear_interrupt_MC0_bit(TC0);
              while(TC1->COUNT32.SYNCBUSY.bit.CC0);
              pulse_width = hri_tccount32_read_CC_reg(TC0, 0);
              while(TC1->COUNT32.SYNCBUSY.bit.CC1);
              period = hri_tccount32_read_CC_reg(TC0, 1);
       }

}

i still get same value as period and pulse_width.


And the Analogs.... I'm trying to read 8 channels. the logic of ADC hasn opened to me even i have tried. once i got some example code to read one channel but i did not get any real values. Now i have tried to use sync mode but i'm not even sure that is that right. At the moment i'm trying to archive to read all 8 channels MAX about 50hz speed and 12-bit accuracy but in future maybe something like 1khz to 10khz Sample speed.


 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #1 on: November 08, 2021, 12:30:58 pm »
Like several times before, i start to get things to  work after making a post. TC with PWP works now. it seems that only debug was showing weird results. I just added freq and duty calculations and everything works.

ADC still seems to be mystery. Hoping to get help/examples how to read all of those 8 channels
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #2 on: November 08, 2021, 05:32:03 pm »
What specifically does not work about ADC? Can you get at least one channel working?

Generally to sample multiple channels you have two options:
1. Manually switch channels. In this case free-running mode does not make sense, it is easier to set the channel and start a conversion. Then set another channel and start the conversion. This is a good option for slow sampling rates.
2. You can define a sequence of channels to sample using SEQCTRL register. In this case each conversion trigger will cause multiple channels to be sampled. Each channel will get its own interrupt, and you must be able to handle those interrupts in time, otherwise you will lose conversion results. In this mode you can use either free-running mode, or a single conversion mode. In case of a single conversion, you start once and then you get as many result as many channels you have in the sequence. Then sampling stops until the next trigger.
Alex
 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #3 on: November 15, 2021, 12:46:19 pm »
This is the code i found on some discussion:
Code: [Select]
adc_sync_set_inputs(&ADC_0,1,0x18,0);
adc_sync_read_channel(&ADC_0, 0, buffer, 2);
A1_Val=buffer[0]+buffer[1]*256;

//A2
adc_sync_set_inputs(&ADC_0,2,0x18,0);
adc_sync_read_channel(&ADC_0, 0, buffer, 2);
A2_Val=buffer[0]+buffer[1]*256;

//A3
adc_sync_set_inputs(&ADC_0,3,0x18,0);
adc_sync_read_channel(&ADC_0, 0, buffer, 2);
A3_Val=buffer[0]+buffer[1]*256;

But that doesn't seem to work.

I have set clock with divider to be 2Mhz as i found it should be the max clock for ADC.

Is there any example code to try, since it seems that i cannot get any real values from ADC. i get random about 1800 values even the pin is grounded.

As getting know to ADC i'm wondering that could i use async free running mode and read values as i need. I could also use that same mode in other function to setup window monitoring to make interrupt engine to get values from TC. Am i totally lost with my ideas?

If not any example coge how to do those?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #4 on: November 15, 2021, 05:17:33 pm »
How is your "buffer" defined?

Here is example of bare-metal ADC code - https://github.com/ataradov/dgw/blob/master/embedded/adc.c . It is for D21, but it will mostly apply to C21. I don't want to deal with ASF nonsense, so I have no idea what is wrong with it.
Alex
 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #5 on: November 15, 2021, 09:21:34 pm »
Thanks, that seem straight forward. If i have multiple analogs to read I just use input control reg to change the pin before reading again?
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #6 on: November 15, 2021, 09:38:29 pm »
Yes, your reading function would turn into something like this:
Code: [Select]
int adc_read(int channel)
{
  ADC->INPUTCTRL.reg = channel | ADC_INPUTCTRL_MUXNEG_GND | ADC_INPUTCTRL_GAIN_DIV2;
  ADC->SWTRIG.reg = ADC_SWTRIG_START;
  while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));
  return ADC->RESULT.reg;
}

int ch1_value = adc_read(ADC_INPUTCTRL_MUXPOS_PIN1);
int ch5_value = adc_read(ADC_INPUTCTRL_MUXPOS_PIN5);

Obviously configure all the involved pins to analog function.
Alex
 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #7 on: November 22, 2021, 01:13:48 pm »
I wasn't able to get your adc init code to work with c21.

I'm now trying to get the init with ASF4, but I'm missing something. The results i fet from adc is just nonsense. sometimes i get random values: 0, 2582, 3845... and so on.

Just cannot understand what i'm doing wrong.
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #8 on: November 22, 2021, 05:06:07 pm »
What specifically did not work? What was your final code?

If you want ASF help, I'm out. I don't care about ASF.
Alex
 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #9 on: November 22, 2021, 07:01:15 pm »
Actually I don't care about ASF either. I always try to do without it, but this processor is so new to me and I'm not a professional coder, so I cannot start to get a hang of how things work without asf's.

The problem seems to be that ADC is initiated, but results from ADC are bad. I created an array that shows list of results from ADC if pin is attached to GND or to 5V

The code that AFS has generated is (i gathered the code from few files) :
Code: [Select]
#define A0 GPIO(GPIO_PORTA, 2)
#define ADC ADC0

uint16_t A0_Val_arr[100];
uint8_t loopcount;

void ADC_0_CLOCK_init(void)
{
hri_mclk_set_APBCMASK_ADC0_bit(MCLK);
hri_gclk_write_PCHCTRL_reg(GCLK, ADC0_GCLK_ID, CONF_GCLK_ADC0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos));
}

void ADC_0_PORT_init(void)
{

// Disable digital pin circuitry
gpio_set_pin_direction(A0, GPIO_DIRECTION_OFF);

gpio_set_pin_function(A0, PINMUX_PA02B_ADC0_AIN0);
}

int32_t adc_sync_init(struct adc_sync_descriptor *const descr, void *const hw, void *const func)
{
ASSERT(descr && hw);

return _adc_sync_init(&descr->device, hw);
}


void ADC_0_init(void)
{
ADC_0_CLOCK_init();
ADC_0_PORT_init();
adc_sync_init(&ADC_0, ADC0, _adc_get_adc_sync());
}

int adc_read(int channel)
{
ADC->INPUTCTRL.reg = channel ;//| ADC_INPUTCTRL_MUXNEG;
ADC->SWTRIG.reg = ADC_SWTRIG_START;
while (0 == (ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY));
return ADC->RESULT.reg;
}

int main(void)
{
ADC_0_init();
ADC0 -> CTRLA.bit.ENABLE = 1;

while(1){
        loopcount++;
A0_Val_arr[loopcount]=adc_read(ADC_INPUTCTRL_MUXPOS_AIN0) ;

}
}
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #10 on: November 22, 2021, 07:08:25 pm »
You are using ASF initialization and my reading code. reading code depends on the initialization. You can't mix and match and expect good results.

Here is a minimal ADC code specifically for C21. This replaces everything related to ADC from ASF. You can keep GPIO configuration from ASF, that should not affect anything.
Code: [Select]
void adc_init(void)
{
  HAL_GPIO_ADC_in();
  HAL_GPIO_ADC_pmuxen(HAL_GPIO_PMUX_B);

  MCLK->APBCMASK.reg |= MCLK_APBCMASK_ADC0;

  GCLK->PCHCTRL[ADC0_GCLK_ID].reg = GCLK_PCHCTRL_GEN(0) | GCLK_PCHCTRL_CHEN;
  while (0 == (GCLK->PCHCTRL[ADC0_GCLK_ID].reg & GCLK_PCHCTRL_CHEN));

  ADC0->CTRLA.reg = ADC_CTRLA_SWRST;
  while (ADC0->CTRLA.reg & ADC_CTRLA_SWRST);

  ADC0->REFCTRL.reg = ADC_REFCTRL_REFSEL_INTVCC2 | ADC_REFCTRL_REFCOMP;
  ADC0->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64;
  ADC0->CTRLC.reg = ADC_CTRLC_RESSEL_12BIT;
  ADC0->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1;
  ADC0->INPUTCTRL.reg = ADC_INPUTCTRL_MUXPOS_AIN0 | ADC_INPUTCTRL_MUXNEG(0x18/*GND*/);

  ADC0->CTRLA.reg = ADC_CTRLA_ENABLE;
}

int adc_read(void)
{
  ADC0->SWTRIG.reg = ADC_SWTRIG_START;
  while (0 == (ADC0->INTFLAG.reg & ADC_INTFLAG_RESRDY));
  return ADC0->RESULT.reg;
}
« Last Edit: November 22, 2021, 07:09:56 pm by ataradov »
Alex
 

Offline matti.saloTopic starter

  • Contributor
  • Posts: 15
  • Country: fi
Re: SAMc21 TC PWP and analog
« Reply #11 on: November 23, 2021, 02:05:58 pm »
Thanks again! Works like a charm.

I now a code to read all analog channels i need, but.. I'm now wondering that should i need some pull-down resistor to zero the value if nothing is connected? I'm getting just random value about middle of range. Or can i enable pull-down from processor?

Now i started to transform my ASF code to bare code. That takes again con trial and error :) but still think it's worth it.
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11643
  • Country: us
    • Personal site
Re: SAMc21 TC PWP and analog
« Reply #12 on: November 23, 2021, 05:35:29 pm »
It is up to you and your application what to do when nothing is connected. I personally see no issue with reading random values if pin is floating.

But remember if you add anything to the pin, it will be there when the real signal is applied, so you need to take that into account. If you pit a pull-down resistor, it has to be large enough (100 kOhm or more).

I'm not sure if internal pull-down will work when analog function is selected, it might and it does not hurt to try.
Alex
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf