XMEGA A1U Input capture of 4 signals

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys,

 

I am trying to run a simple system, capturing 4 events (on inputs), but for some reason, my code doesn't work.

Here is what I am trying to do:

 

PORTC_OUT = 0x00;
PORTC_DIR = 0b00001110; 
PORTC_PIN0CTRL = PORT_ISC_RISING_gc; //Q-offset
PORTC_PIN4CTRL = PORT_ISC_FALLING_gc; //Q-offset
PORTC_PIN5CTRL = PORT_ISC_FALLING_gc; //Q-offset
PORTC_PIN6CTRL = PORT_ISC_RISING_gc; //Q-offset

/* configure timer E0, used for Tx sine input capture */
TCE0_PER = rxSinPeriod; //25 us = (800-1) cycles
TCE0_INTFLAGS = TC0_OVFIF_bm | TC0_CCAIF_bm | TC0_CCBIF_bm | TC0_CCCIF_bm | TC0_CCDIF_bm; //just in case clear interrupt flags
TCE0_CTRLB = TC_WGMODE_NORMAL_gc | TC0_CCAEN_bm | TC0_CCBEN_bm | TC0_CCCEN_bm | TC0_CCDEN_bm; //use normal mode to capture
TCE0_CTRLD = TC_EVACT_CAPT_gc | TC_EVSEL_CH1_gc;
TCE0_CNT = 2;//compensate the offset though it matters not - compensated by calibration actually, there is much bigger delay
TCE0_INTCTRLA = TC_OVFINTLVL_MED_gc;
TCE0_CTRLA = TC_CLKSEL_DIV1_gc;



*************************************************************************/
__inline void InitEvsys(void)
{
    EVSYS_CH0MUX = EVSYS_CHMUX_TCE1_OVF_gc; //use elsewhere
    EVSYS_CH1MUX = EVSYS_CHMUX_PORTC_PIN0_gc; //used for input capture on timer
    EVSYS_CH2MUX = EVSYS_CHMUX_PORTC_PIN5_gc; //used for input capture on timer
    EVSYS_CH3MUX = EVSYS_CHMUX_PORTC_PIN4_gc; //used for input capture on timer
    EVSYS_CH4MUX = EVSYS_CHMUX_PORTC_PIN6_gc; //used for input capture on timer
    //not used EVSYS_CH1MUX = EVSYS_CHMUX_TCF1_OVF_gc; //general timer 1ms, used to start the ADC channel sweep
}


//after the period is over, I try reading the results
void TCE0_CCA_interrupt(void)
{
    unsigned char s = CPU_SREG;

    inputCaptureA = TCE0_CCABUF &0x7fff; //the 0x7fff is used to clear the direction indication, automatically set when period is less than 0x8000
    inputCaptureB = TCE0_CCBBUF &0x7fff;
    inputCaptureC = TCE0_CCCBUF &0x7fff;
    inputCaptureD = TCE0_CCDBUF &0x7fff;

    TCE0_INTFLAGS = TC0_OVFIF_bm | TC0_CCAIF_bm | TC0_CCBIF_bm | TC0_CCCIF_bm | TC0_CCDIF_bm; //just in case clear interrupt flags
    CPU_SREG = s;
}

 

What happens is that all the events seem to be triggered at the same time, but I can see the signals have minimum of 50 cycles offset.

Last Edited: Fri. Oct 20, 2017 - 12:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One problem was that I was using CCA interrupt, instead as OVF. I fixed that, but it still does not work as expected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pnv_Creator wrote:
 does not work as expected.

So what, exactly, did you expect it to do?

 

And what, exactly, does it actually do?

 

And what testing/debugging/investigation have you done to explain the discrepancy?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, sure, I will try to explain better. Thank you for the questions.

 

I have some periodic signals, both input and output. I want to measure two signals coming as an input to detect their phase (offset towards my base signals) and how long they are high/low.

On the picture you can see those input signals on D4 and D5.

D4 signal goes to my Port C - pin 0 and pin 4, because I need to have an event on rising and falling edge.

D5 signal goes to my Port C - pin 5 and pin 6, because I need to have an event on rising and falling edge.

 

So, to sum it up I need events 1-4 to capture PC 0, 4, 5, 6, some on rising, some on falling edge. I need timestamps of these 4 events, which are periodic.

 

 

What I actually get - 567, 564, 564, 567 in these 4 variables, inputCaptureA-D, which get the data from TCE0_CCA-D.

They results are flickering with 1-2 numbers, but they are always almost equal, an the timing of the events is most deffinitely not, so it seems my capturing algorithm does not work.

 

1) Configure event system to trigger event on input sense rising / falling edge

2) Configure TCE0 to work on input capture on those events

3) Read the data once per period in the interrupt

 

Last Edited: Thu. Oct 19, 2017 - 12:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please note that the Xmega family has it's own forum, I'll move the thread,

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nothing stands out to me as being wrong, but then it is past my bedtime...

 

As a test, I would try implementing it using the channel interrupts to capture each value, with the last capture setting a flag to indicate the capture is complete.  Something like this :

 

void InitCapture(void)
{
    PORTC_OUT = 0x00;
    PORTC_DIR = 0b00001110; 
    PORTC_PIN0CTRL = PORT_ISC_RISING_gc;
    PORTC_PIN4CTRL = PORT_ISC_FALLING_gc;
    PORTC_PIN5CTRL = PORT_ISC_FALLING_gc;
    PORTC_PIN6CTRL = PORT_ISC_RISING_gc;

    EVSYS_CH0MUX = EVSYS_CHMUX_TCE1_OVF_gc;
    EVSYS_CH1MUX = EVSYS_CHMUX_PORTC_PIN0_gc;
    EVSYS_CH2MUX = EVSYS_CHMUX_PORTC_PIN5_gc;
    EVSYS_CH3MUX = EVSYS_CHMUX_PORTC_PIN4_gc;
    EVSYS_CH4MUX = EVSYS_CHMUX_PORTC_PIN6_gc;

    TCE0.PER = rxSinPeriod;
    TCE0.CTRLB = TC_WGMODE_NORMAL_gc | TC0_CCAEN_bm | TC0_CCBEN_bm | TC0_CCCEN_bm | TC0_CCDEN_bm;
    TCE0.CTRLD = TC_EVACT_CAPT_gc | TC_EVSEL_CH1_gc;
    TCE0.INTCTRLA = TC_CCAINTLVL_MED_gc | TC_CCBINTLVL_MED_gc | TC_CCCINTLVL_MED_gc | TC_CCDINTLVL_MED_gc;
    TCE0.CTRLA = TC_CLKSEL_DIV1_gc;
}


ISR(TCE0_CCA_vect)
{
    inputCaptureA = TCE0_CCABUF & 0x7fff;
}


ISR(TCE0_CCB_vect)
{
    inputCaptureB = TCE0_CCBBUF & 0x7fff;
}


ISR(TCE0_CCC_vect)
{
    inputCaptureC = TCE0_CCCBUF & 0x7fff;
}


ISR(TCE0_CCD_vect)
{
    inputCaptureD = TCE0_CCABUF & 0x7fff;
    DoSomethingMeaningfulFlag = true;
}


void MeaningfulCaptureFunction(void)
{
    /*
     * your meaningful code goes here
     */

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        DoSomethingMeaningfulFlag = false;
    }
}

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, I will try that and report, I will also try using different timers, though I don't want to spare more resource than I can work with.

 

What worries me is that the program will have to enter in 4 interrupts instead of 1 and in 40 KHz frequency of those events = 25 us cycle (32 Mhz MCU clock) I think those will take about 50% of my MCU time, since one entry and exiting seems to take about 3 us (saving and restoring registers, etc.) and the interrupts will require a bit more logic in them... Still, if it works correctly, it might be ok, I will have to check if it results in bad performance/UX in the other functionalities.

 

Sorry, js, and thanks for the moderation.

 

 

Last Edited: Mon. Oct 23, 2017 - 12:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, it was a hardware shortcircuit between the two signals, but somehow it was not detected on the short circuit test by our hardware dev, it happens.

The control points from which are get the signal to oscilloscope go through some resistor groups to reduce the voltage level and then to the inputs of the MCU, so that's why the short circuit wasn't visible on the oscilloscope as well (s.c. was after those resistor groups).

 

The code works, Greg Muth's variant as well, though when the initial variant works, the alternative is not recommended due to performance issues.