• AVR Freaks

Hot!dsPIC33CK - ADC Scan + DMA

Author
JPortici
Super Member
  • Total Posts : 1174
  • Reward points : 0
  • Joined: 2012/11/17 06:27:45
  • Location: Grappaland
  • Status: offline
2019/03/27 03:30:25 (permalink)
0

dsPIC33CK - ADC Scan + DMA

Hi,
has somebody been able to use continous channel scan + dma in the dsPIC33CK?
I'm struggling to achieve both.
Basically, i want to replicate channel scan then transfert using DMA in scatter/gather mode as it can be done in dsPIC33EV
 
First, i'm trying to implement channel scan. According to the reference manual DS70005213F in order to enable scan on the shared core one has to select the same trigger source for every channel i want to scan.
 
Then, to scan channels continously i have to use the Common Level-Sensitive Software Trigger. I assume this is working simillarly to Auto Sample + Auto convert..
 
But it seems that only the first channel is getting triggered, no matter what.
 
For now i'm trying with two channels, 12 and 17 so beside the rest of the configuration i've added
 
//Disable all Channel Interrupts
  ADIEL = 0;
  ADIEH = 0;
 
  //To perform channel scan all channels have to share the same trigger
  ADTRIG3Lbits.TRGSRC12 = 2;
  ADTRIG4Lbits.TRGSRC17 = 2;
  ADLVLTRGLbits.LVLEN12 = 1;
  ADLVLTRGHbits.LVLEN17 = 1;
  ADCON3Lbits.SWLCTRG = 1;  //Scan continously using the software level trigger

 
Then i would like to use DMA to transfer every sample into another buffer... but i'm struggling to understand if and how it's possible to replicate scatter/gather mode. I'm even fine with transferring the whole ADCBUF area if it's not possible to only copy what i want.
 
Still reading through the DMA reference manual, i can't get it to trigger with ADC..
 
Man, we need code examples for this..
#1

4 Replies Related Threads

    JPortici
    Super Member
    • Total Posts : 1174
    • Reward points : 0
    • Joined: 2012/11/17 06:27:45
    • Location: Grappaland
    • Status: offline
    Re: dsPIC33CK - ADC Scan + DMA 2019/03/27 10:22:21 (permalink)
    0
    So, i was able to get scan mode to work.. sort of.
     
    -> I want to achieve a global samplerate of 10kS/s, so set up REFO to produce a 10kHz clock
    -> Route REFO to ADCTRIG31 via virtual pin remapping (love the feature)
    -> Set up ADC as usual, make sure that (sampling time + conversion time) x number of channels fits the sampling period
    -> Set all channels that have to be scanned to have ADCTRIG31 as a trigger source (ADTRIGnH/L)
    -> Disable level triggering (ADLVLTRIGH/L)
    -> Enable the interrupt signalling for channel completition for every channel (ADIEH/ADIEL) *
    -> Enable the interrupt events for channel completition (_ADCANxxIE) *
    -> Start ADC
     
    Then, an interrupt routine per each ADC channel to move the data from the buffer somewhere else, otherwise the value won't be updated at the next conversion.. and the scan won't even go on. Plus, you have to read the ADC result buffer in order to be able to clear the flag. *
     
    *: These passages shouldn't be needed but i can't do it any other way.
     
    I was also able to kind of get DMA to transfer something, but it's not what i want to acheive.
    -> Set up DMAH/L for whole memory range
    -> Set up DMASRC0 to be ADCBUF0
    -> Set up DMADST0 to be an array of 32 uint16
    -> Set up DMACNT0 to be 25 (so that all ADC buffers get copied)
    -> Set up DMA CH0 trigger to be an ADC CHx conversion done (x is one of the scanned channels)
    -> Enable DMACH0
     
    but the only non-zero value is the first channel of the scan sequence and apparently it doesn't proceed with the scanning (if i enable the _ADCANxxIE interrupts i get inside the interrupt and i can't clear the flag, as if the value wasn't actually read.
    This way
    #2
    JPortici
    Super Member
    • Total Posts : 1174
    • Reward points : 0
    • Joined: 2012/11/17 06:27:45
    • Location: Grappaland
    • Status: offline
    Re: dsPIC33CK - ADC Scan + DMA 2019/03/28 02:13:48 (permalink)
    0
    Almost done it!
    Now i can get the ADC to scan the channels and DMA to transfert the content.
     
    To acheive channel scan i had to use a convoluted way.
    "Common Level-Sensitive Software Trigger" won't get you to scan channels, only to continously convert the first channel in the sequence. Either an hardware bug or a missing bits in the documentation, that shall be addressed.
    MCCP/SCCP interrupt while in timer mode won't get you to trigger a channel acquisition. I thought it was something wrong in my code but then i saw this thread from six weeks ago: https://www.microchip.com/forums/m1086397.aspx
    and basically it's a simple documentation error. Yeah.
     
    Well, in my application it's not a problem as the MCCP/SCCP will be used for other stuff.
    Being able to use say TMR1 rollover to trigger an acquisition would have been nice for me but apparently you can't. Maybe with the PTG? but i never used that peripheral.
    Instead, i used the REFO module and i routed the output to ADCTRIG31 via virtual pin remapping
    _ADCTRGR = 176;
    _RP176R = 14;

     
    Then, after configuring the ADC, i set up channels for scan. The interrupts enabled so that ADC interrupt flags are generated
    ADIELbits.IE12 = 1;
    ADIEHbits.IE17 = 1;

    //To perform channel scan all channels have to share the same trigger
    ADTRIG3Lbits.TRGSRC12 = 31;
    ADTRIG4Lbits.TRGSRC17 = 31;
    ADLVLTRGLbits.LVLEN12 = 0;
    ADLVLTRGHbits.LVLEN17 = 0;

     
    Then, set up DMA to transfer the whole ADC buffer area to an array of 25 uint16_t (there are 25 channels total) called adcRes, when an ADC Group Done Interrupt occours

    //DMA Can operate on whole SFR Area
    DMAH = 0x6FFF;
    DMAL = 0x1000;
     
    //DMA Channel 0 (Highest Priority) for ADC
    DMACON = 0x8000;          //Enable DMA with Fixed Priority scheme
     
    //Channel 0: ADC (Shared Core)
    DMACH0 = 0;
    DMACH0bits.SAMODE = 1;    //Source is incremented after transfert
    DMACH0bits.DAMODE = 1;    //Destination is incremented after transfert
    DMACH0bits.TRMODE = 3;    //Mode is Repeated Continous
    DMACH0bits.SIZE = 0;      //16 Bit Transferts
    DMACH0bits.RELOAD = 1;    //Reload Addresses after transfer
     
    DMAINT0 = 0;              //Disable All Interrupts
    DMAINT0bits.CHSEL = 0x27; //Trigger Source is ADC12
     
    DMASRC0 = (uint16_t) &ADCBUF0;
    DMADST0 = (uint16_t) &adcRes;
    DMACNT0 = 25;
     
     
     
    DMACH0bits.CHEN = 1;

     
    I am trying to find any information on the ADC Group Done Event. In my mind this event would be triggered after a series of channels have been acquired (if only one triggered, set after the conversion. If more than one triggered, set after the last conversion is done)
     
    Anyway, this is apparently working, i'm sending the data out on the serial port every 1sec and it's updated with the current value, value matches the analog inputs voltage (+/- 1LSB with low impedance channels, +/- 4lsb with higher impedance channels, which goes down to +/-1 LSB if enough sampling time.. the ADC is ACCURATE! -To that guy that wouldn't understand how the ADC works-)
     
    BUT: The DMA overrun flag is constantly being set and i don't understand why.
    Actual conversion time is 6.712-3us per channel (corresponds to 235 TAD per sampling time + 14.5 TAD per conversion = circa 250 TAD = 6.7125us at FAD = 32MHz ) so 128kS/s max, but i'm triggering the conversion with a 10kHz clock, so 10kS/s per channel, two channels.
     
    I refuse to believe that the DMA can't transfert 25 words in 100us so i don't understand why OVIF is being set... my theory is that the Group Done IF is being constantly re-set so that the DMA is costantly being triggered but this happens also if i use other ADC events as source. For example Channel 12 Done (i'm using Channel 12 and channel 17)
     
    OBVIOUSLY i can't use REFO to trigger the DMA. Well, not directly ;) Using CLC1 to get a rising edge interrupt with the rising edge of REFO
    //Use CLC 1 to get an interrupt at every REFO Rising Edge
    CLC1CONH = 0x000E;        //Gates 2,3,4 have an inverted output
    CLC1SEL = 0x0004;         //CLC1 Data Selection 1 is REFO
    CLC1GLSL = 0x0002;        //Gate 1 has only Input 1, True
    CLC1GLSH = 0;
    CLC1CONL = 0x8802;        //Enable CLC1 and Rising Edge interrupt. 4-in AND

    //DMA Can operate on whole SFR Area
    DMAH = 0x6FFF;
    DMAL = 0x1000;

    //DMA Channel 0 (Highest Priority) for ADC
    DMACON = 0x8000;          //Enable DMA with Fixed Priority scheme

    //Channel 0: ADC (Shared Core)
    DMACH0 = 0;
    DMACH0bits.SAMODE = 1;    //Source is incremented after transfert
    DMACH0bits.DAMODE = 1;    //Destination is incremented after transfert
    DMACH0bits.TRMODE = 3;    //Mode is Repeated Continous
    DMACH0bits.SIZE = 0;      //16 Bit Transferts
    DMACH0bits.RELOAD = 1;    //Reload Addresses after transfer

    DMAINT0 = 0;              //Disable All Interrupts
    DMAINT0bits.CHSEL = 0x44; //Trigger Source is CLC1 Rising Edge Interrupt

    DMASRC0 = (uint16_t) &ADCBUF0;
    DMADST0 = (uint16_t) &adcRes;
    DMACNT0 = 25;

    DMACH0bits.CHEN = 1;

     
    and now no OVIF.
     
    post edited by JPortici - 2019/03/28 02:18:57
    #3
    spdmtl
    New Member
    • Total Posts : 21
    • Reward points : 0
    • Status: offline
    Re: dsPIC33CK - ADC Scan + DMA 2019/05/01 16:11:33 (permalink)
    5 (1)
    There was a recent errata added to 33c devices regarding ADC and DMA.
     
    For 33CK, DS80000796D-page 8
    28. Module: DMA
    The DMA receives multiple continuous triggers from the ADC until the trigger event from the ADC is cleared. The OVRUNIF flag (DMAINTn[3]) will be set. When the OVRUNIF bit changes state from ‘0’ to ‘1’, a DMA interrupt is generated.
    Work around Ignore the OVRUNIF bit and the first DMA interrupt. Clear the ADC trigger source (ANxRDY) with a DMA read of the ADC buffer, ADCBUFx, for the corresponding ADC channel.
    #4
    bodypilllow
    New Member
    • Total Posts : 1
    • Reward points : 0
    • Joined: 2020/09/16 19:59:19
    • Location: 0
    • Status: offline
    Re: dsPIC33CK - ADC Scan + DMA 2020/09/29 11:56:37 (permalink)
    0
    Did you ever find any information about the ADC Group Done interrupt?  It is really strange that there is no mention of it anywhere in the ADC peripheral datasheet, nor almost anywhere else in the documentation or online.  Although the more I read about this device in general, the more strange things I see.
     
    Anyway: I have found similar issues in replicating scatter gather mode due to the characteristics of this new DMA module. I was hoping to be able to do something like the following:
    1. Receive a DMA trigger when the final sample in my scanning sequence is converted and stored
    2. Do a block transfer of the ADCXBUF register data (of all scanned channels) to RAM
    3. Reset the DMASRC address to the first ADCXBUF in the sequence
    4. Leave the DMADST register incremented so that it is pointing at the next block of RAM for the subsequent vector of samples to go into
    5. Repeat 1)-4) N times, then:
    6. Reset both the SRC and the DST addresses, process the multiple samples from multiple channels all at once, while in parallel the ADC+DMA goes back to 1)
    The underlined portions of 2,3,4 don't seem simultaneously possible given that the repeated transfer mode of DMA automatically resets both the SRC and DST addresses once CNT=0, whether you'd like it to or not.  So I will have to have a few interrupts throughout my main to do the transfer work, in order to process multiple samples from multiple channels at the top of main as I would like to.
     
    This combined with the odd triggering-by-CCP issues reported (still absent from the silicon errata as far as I've seen) is going to make this development a bit more of a nightmare than I was hoping.
    #5
    Jump to:
    © 2020 APG vNext Commercial Version 4.5