mikrocontroller.net

Forum: Digitale Signalverarbeitung / DSP ADC 12Bit dsPIC33 CH Scanning DMA - Index of the analog input ( Bufferüberlauf )


Autor: Zumax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen hab mal wieder ein kleineres Problem und hoffe einer/eine 
von euch findigen Entwicklern kann mir helfen.
Ich benutze einen dsPIC33FJ256MC510 sowie den ADC1 im 12 Bit mode, zudem 
wird ein DMA Buffer im Scatter/Gather mode verwendet, MPLAB IDE v8.20 
und Michrochip C30 Toolsuit.
Nun folgende Problematik, ich möchte die Ports RB8/AN8 bis RB13/AN13 
also 6 Ports scannen, für jeden Port sollen 8 Samples gemacht werden. 
Das Problem ist nun das wenn ich AN0 AN1 An2 AN3 AN4 An5 scanne passt es 
wenn meine Structs jeweils 6 Arrays enthalten (Adc1Ch0-Adc1Ch5). Für 
mich klingt dies soweit einleuchtend, da ja 6 Inputs gescanned werden 
also werden auch 6 Buffer benötigt! So möchte ich aber nun anstelle von 
AN0 bis AN5 die Ports AN8 bis AN13 scannen, also auch wieder 6 Inputs, 
dache ich mir wäre es kein Problem einfach das Register AD1CSSL auf 
0x3F00 zu setzten und alles klappt wie zuvor, leider is dem nicht so, 
wie im Code teil zu erkennen ist muss ich nun mindestens 14 Arrays 
(Buffer) anlegen also (Adc1Ch0-Adc1Ch13).
Da nun aber ja nur die Channels AN8 bis AN13 gesacanned werden sind die 
Buffer von (Adc1Ch0-Adc1Ch7) alle leer mussten aber angelegt werden da 
ansonsten "CORE-E0003: Trap due to unimplemented RAM memory access, 
occurred from instruction at 0x000366" ausgespuckt wird! Nun is das ja 
aber ungeschickt weil die unteren 8 Buffer angelegt werden müssen die 
aber ja gar nicht befüllt werden! Auch wenn ich jetzt z.B. nur AN15 
scannen möchte muss ich trotzdem 16 Buffer anlegen wobei dann 15 von 
diesen 16 leer sind und nie befüllt werden...Huch

"The ADC module provides a Scatter/Gather address to the DMA channel,
based on the index of the analog input and the size of the DMA buffer." 
Dieser Satz besagt ja das er in dem Scatter/Gather mode eine Indezierung 
durchführt. Mein Ziel ist es nun einfach nur 6 buffer zu verwenden da ja 
auch nur 6 Inputs gescanned werden, leider vermute ich das dies nicht 
klappen wird...
Hoffentlich hab ich mich relativ verständlich ausgedrückt und hoffe 
jemand hatte auch shcon mal mit dieser Problematik zu tun und kann bzw. 
will Smiley mir weiterhelfen, auch wenn er mir dann nur bestätigt das es 
anders nicht geht.

viele Grüße & good coding
Thomas
#include "p33fxxxx.h"
void InitADC_DMA();
void __attribute__((__interrupt__,no_auto_psv)) _DMA5Interrupt(void);
void RunADC_DMA();
void ProcessADCSamples(unsigned int * AdcBuffer);
int main (void);

//int  BufferA[6][8] __attribute__((space(dma),aligned(64)));
//int  BufferB[6][8] __attribute__((space(dma),aligned(64)));
  
  struct
  {
    unsigned int Adc1Ch0[8];
    unsigned int Adc1Ch1[8];
    unsigned int Adc1Ch2[8];
    unsigned int Adc1Ch3[8];
    unsigned int Adc1Ch4[8];
    unsigned int Adc1Ch5[8];
          unsigned int Adc1Ch6[8];
    unsigned int Adc1Ch7[8];
    unsigned int Adc1Ch8[8];
    unsigned int Adc1Ch9[8];
    unsigned int Adc1Ch10[8];
    unsigned int Adc1Ch11[8];
    unsigned int Adc1Ch12[8];
    unsigned int Adc1Ch13[8];
    //unsigned int Adc1Ch14[8];
    //unsigned int Adc1Ch15[8];
  
  } BufferA __attribute__((space(dma)));
  struct
  {
    unsigned int Adc1Ch0[8];
    unsigned int Adc1Ch1[8];
    unsigned int Adc1Ch2[8];
    unsigned int Adc1Ch3[8];
    unsigned int Adc1Ch4[8];
    unsigned int Adc1Ch5[8];
    unsigned int Adc1Ch6[8];
    unsigned int Adc1Ch7[8];
    unsigned int Adc1Ch8[8];
    unsigned int Adc1Ch9[8];
    unsigned int Adc1Ch10[8];
    unsigned int Adc1Ch11[8];
    unsigned int Adc1Ch12[8];
    unsigned int Adc1Ch13[8];
    //unsigned int Adc1Ch14[8];
    //unsigned int Adc1Ch15[8];
  } BufferB __attribute__((space(dma)));


void InitADC_DMA()
{
  AD1CON1bits.ADON = 0;   //ADC is Off, set it off bevor configuration
  AD1CON1bits.FORM = 0;   // Data Output Format: Signed Fraction (Q15 format)
  AD1CON1bits.SSRC = 2;   // Sample Clock Source: GP Timer starts conversion
  AD1CON1bits.ASAM = 1;   // Sampling begins immediately after conversion
  AD1CON1bits.AD12B = 1;  // 12-bit ADC operation
  AD1CON1bits.SIMSAM = 1; // Samples multiple channels sequentially
  
        AD1CON2bits.BUFM = 0;
  AD1CON2bits.CSCNA = 1;  // Scan CH0+ Input Selections during Sample A bit
  AD1CON2bits.CHPS = 0;   // Converts CH0
  
        AD1CON3bits.ADRC = 0;   // ADC Clock is derived from Systems Clock
  AD1CON3bits.ADCS = 63;  // ADC Conversion Clock
  
       //AD1CHS0: A/D Input Select Register
  AD1CHS0bits.CH0SA = 0;  // MUXA +ve input selection (AIN0) for CH0
  AD1CHS0bits.CH0NA = 0;  // MUXA -ve input selection (Vref-) for CH0
  
       //AD1CHS123: A/D Input Select Register
  AD1CHS123bits.CH123SA = 0; // MUXA +ve input selection (AIN0) for CH1
  AD1CHS123bits.CH123NA = 0; // MUXA -ve input selection (Vref-) for CH1
  
       //AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
  AD1CSSH = 0x0000;
  AD1CSSL = 0x3F00; // Scan AIN8, AIN9, AIN10, AIN11, AIN12, AIN13 inputs
  
  //Set up Timer3 to trigger ADC1 conversions:
  
  TMR3 = 0x0000;
  PR3 = 4999;        // Trigger ADC1 every 125usec
  IFS0bits.T3IF = 0; // Clear Timer 3 interrupt
  IEC0bits.T3IE = 0; // Disable Timer 3 interrupt
  T3CONbits.TON = 1; //Start Timer 3
  
  //Set up DMA Channel 5 for Peripheral Indirect Addressing:

  DMA5CONbits.AMODE = 2; // Configure DMA for Peripheral indirect mode
  DMA5CONbits.MODE = 2;  // Configure DMA for Continuous Ping-Pong mode
  DMA5PAD = (volatile unsigned int)&ADC1BUF0;// Point DMA to ADC1BUF0
  DMA5CNT = 47; // 48 DMA request (6 buffers, each with 8 words)
  DMA5REQ = 13; // Select ADC1 as DMA Request source
  DMA5STA = __builtin_dmaoffset(&BufferA);
  DMA5STB = __builtin_dmaoffset(&BufferB);
  IFS3bits.DMA5IF = 0; //Clear the DMA interrupt flag bit
  IEC3bits.DMA5IE = 1; //Set the DMA interrupt enable bit
  

}  
void __attribute__((__interrupt__,no_auto_psv)) _DMA5Interrupt(void)
{
  IFS3bits.DMA5IF = 0; //Clear the DMA5 Interrupt Flag
  unsigned int DmaBuffer = 0;  
// Switch between Primary and Secondary Ping-Pong buffers
  if(DmaBuffer == 0)
  {
  /*
  ProcessADCSamples(BufferA.Adc1Ch0);
  ProcessADCSamples(BufferA.Adc1Ch1);
  ProcessADCSamples(BufferA.Adc1Ch2);
  ProcessADCSamples(BufferA.Adc1Ch3);
  */
  }
  else
  {
  /*
  ProcessADCSamples(BufferB.Adc1Ch0);
  ProcessADCSamples(BufferB.Adc1Ch1);
  ProcessADCSamples(BufferB.Adc1Ch2);
  ProcessADCSamples(BufferB.Adc1Ch3);
  */
  }

  DmaBuffer ^= 1;

}
  //Set up ADC1 for DMA operation:
void RunADC_DMA()
{
  AD1CON1bits.ADDMABM = 0; // DMA buffers are built in scatter/gather mode
  AD1CON2bits.SMPI    = 5; // 6 ADC buffers
  AD1CON4bits.DMABL   = 3; // Each buffer contains 8 words
          
  IFS0bits.AD1IF      = 0; // Clear the A/D interrupt flag bit
  IEC0bits.AD1IE      = 0; // Do Not Enable A/D interrupt 
  DMA5CONbits.CHEN    = 1; //Enable DMA0 channel
  AD1CON1bits.ADON    = 1; // Turn on the A/D converter
}


void ProcessADCSamples(unsigned int * AdcBuffer)
{
  char AdcBuffer_string[32];
//  itoa_o(*AdcBuffer, AdcBuffer_string, 10);
}


int main (void)
{
InitADC_DMA();
RunADC_DMA();
while (1){}
}

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

schon eine Antwort gefunden?

Kann zwar zu deiner Frage nichts beitragen, jedoch ist mir aufgefallen, 
dass du immer den BufferA auslesen wirst, da deine Variable DmaBuffer 
nur lokal ist und nach jedem Funktionsaufruf verworfen wird.
Also entweder static deklarieren oder außerhalb der Funktion definieren.

Autor: Ben (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe ein ähnliches problem wie oben beschrieben. mein code ist aus 
den examples in den datasheets. der example-code funtkioniert sehr gut 
wenn nur 4 channel gescannt werden sollen. ich möchte aber 5 channels 
scannen und habe entsprechende anpassungen vorgenommen.

Anapassungen:
- AD1CSSL = 0x001F;
- AD1CON2bits.SMPI = 4;
- DMA0CNT = 39;

leider geht das so nicht, keine ahnung wieso. vielleciht kann mir jemand 
weiterhelfen?
vielen dank für die Hilfe!



/*====================================================================== 
====================
ADC Initialization for Channel Scan
======================================================================== 
===================*/
void adcInit(void){
initDma0();

AD1CON1bits.FORM = 0; // Data Output Format: Signed Fraction (Q15 
format)
AD1CON1bits.SSRC = 2; // Sample Clock Source: GP Timer starts conversion
AD1CON1bits.ASAM = 1; // ADC Sample Control: Sampling begins immediately 
after conversion
AD1CON1bits.AD12B = 1; // 12-bit ADC operation
AD1CON1bits.SIMSAM = 0; // Samples multiple channels individually in 
sequence
AD1CON2bits.BUFM = 0;
AD1CON2bits.CSCNA = 1; // Scan Input Selections for CH0+ during Sample A 
bit
AD1CON2bits.CHPS = 0; // Converts CH0
AD1CON3bits.ADRC = 0; // ADC Clock is derived from Systems Clock
AD1CON3bits.ADCS = 63; // ADC Conversion Clock
//AD1CHS0: A/D Input Select Register
AD1CHS0bits.CH0SA = 0; // MUXA +ve input selection (AIN0) for CH0
AD1CHS0bits.CH0NA = 0; // MUXA -ve input selection (Vref-) for CH0

//AD1CHS123: A/D Input Select Register
AD1CHS123bits.CH123SA = 0; // MUXA +ve input selection (AIN0) for CH1
AD1CHS123bits.CH123NA = 0; // MUXA -ve input selection (Vref-) for CH1
//AD1CSSL: A/D Input Scan Selection Register
AD1CSSL = 0x001F; // Scan AIN0, AIN1, AIN2, AIN3, AIN4 inputs
AD1CON1bits.ADDMABM = 0; // DMA buffers are built in scatter/gather mode
AD1CON2bits.SMPI = 4; // 5 ADC buffers
AD1CON4bits.DMABL = 3; // Each buffer contains 8 words
IFS0bits.AD1IF = 0; // Clear the A/D interrupt flag bit
IEC0bits.AD1IE = 0; // Do Not Enable A/D interrupt
AD1CON1bits.ADON = 1; // Turn on the A/D converter
initTmr3();
}
/*====================================================================== 
================
Timer 3 is setup to time-out every 125 microseconds (8Khz Rate). As a 
result, the module
will stop sampling and trigger a conversion on every Timer3 time-out, 
i.e., Ts=125us.
======================================================================== 
===============*/
void initTmr3(void)
{
TMR3 = 0x0000;
PR3 = 4999; // Trigger ADC1 every 125usec
IFS0bits.T3IF = 0; // Clear Timer 3 interrupt
IEC0bits.T3IE = 0; // Disable Timer 3 interrupt
T3CONbits.TON = 1; //Start Timer 3
}

// Linker will allocate these buffers from the bottom of DMA RAM.
struct
{
unsigned int Adc1Ch0[8];
unsigned int Adc1Ch1[8];
unsigned int Adc1Ch2[8];
unsigned int Adc1Ch3[8];
unsigned int Adc1Ch4[8];
} BufferA __attribute__((space(dma)));

struct
{
unsigned int Adc1Ch0[8];
unsigned int Adc1Ch1[8];
unsigned int Adc1Ch2[8];
unsigned int Adc1Ch3[8];
unsigned int Adc1Ch4[8];
} BufferB __attribute__((space(dma)));
// DMA0 configuration
// Direction: Read from peripheral address 0-x300 (ADC1BUF0) and write 
to DMA RAM
// AMODE: Peripheral Indirect Addressing Mode
// MODE: Continuous, Ping-Pong Mode
// IRQ: ADC Interrupt

void initDma0(void)
{
DMA0CONbits.AMODE = 2; // Configure DMA for Peripheral indirect mode
DMA0CONbits.MODE = 2; // Configure DMA for Continuous Ping-Pong mode
DMA0PAD = 0x0300; // Point DMA to ADC1BUF0
DMA0CNT = 39; // 40 DMA request (4 buffers, each with 8 words)
DMA0REQ = 13; // Select ADC1 as DMA Request source
DMA0STA = __builtin_dmaoffset(&BufferA);
DMA0STB = __builtin_dmaoffset(&BufferB);
IFS0bits.DMA0IF = 0; //Clear the DMA interrupt flag bit
IEC0bits.DMA0IE = 1; //Set the DMA interrupt enable bit
DMA0CONbits.CHEN=1; // Enable DMA
}

/*====================================================================== 
==================
_DMA0Interrupt(): ISR name is chosen from the device linker script.
======================================================================== 
================*/
unsigned int DmaBuffer = 0;
void __attribute__((_interrupt_)) _DMA0Interrupt(void)
{
if(DmaBuffer == 0){
xMsb = (unsigned char)(BufferA.Adc1Ch0[1] >> 8);
xLsb = (unsigned char)(BufferA.Adc1Ch0[1] & 0xFF);
yMsb = (unsigned char)(BufferA.Adc1Ch1[1] >> 8);
yLsb = (unsigned char)(BufferA.Adc1Ch1[1] & 0xFF);
vrefMsb = (unsigned char)(BufferA.Adc1Ch2[1] >> 8);
vrefMsb = (unsigned char)(BufferA.Adc1Ch2[1] & 0xFF);
temperatureMsb = (unsigned char)(BufferA.Adc1Ch3[1] >> 8);
temperatureLsb = (unsigned char)(BufferA.Adc1Ch3[1] & 0xFF);
zMsb = (unsigned char)(BufferA.Adc1Ch4[1] >> 8);
zLsb = (unsigned char)(BufferA.Adc1Ch4[1] & 0xFF);

}
else
{
xMsb = (unsigned char)(BufferB.Adc1Ch0[1] >> 8);
xLsb = (unsigned char)(BufferB.Adc1Ch0[1] & 0xFF);
yMsb = (unsigned char)(BufferB.Adc1Ch1[1] >> 8);
yLsb = (unsigned char)(BufferB.Adc1Ch1[1] & 0xFF);
vrefMsb = (unsigned char)(BufferB.Adc1Ch2[1] >> 8);
vrefMsb = (unsigned char)(BufferB.Adc1Ch2[1] & 0xFF);
temperatureMsb = (unsigned char)(BufferB.Adc1Ch3[1] >> 8);
temperatureLsb = (unsigned char)(BufferB.Adc1Ch3[1] & 0xFF);
zMsb = (unsigned char)(BufferB.Adc1Ch4[1] >> 8);
zLsb = (unsigned char)(BufferB.Adc1Ch4[1] & 0xFF);
}

DmaBuffer ^= 1;
IFS0bits.DMA0IF = 0; //Clear the DMA0 Interrupt Flag
}

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LöSUNG:

AMODE = 0;

kein ahnung wieso, aber so funktionierts!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.