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


von Zumax (Gast)


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
1
#include "p33fxxxx.h"
2
void InitADC_DMA();
3
void __attribute__((__interrupt__,no_auto_psv)) _DMA5Interrupt(void);
4
void RunADC_DMA();
5
void ProcessADCSamples(unsigned int * AdcBuffer);
6
int main (void);
7
8
//int  BufferA[6][8] __attribute__((space(dma),aligned(64)));
9
//int  BufferB[6][8] __attribute__((space(dma),aligned(64)));
10
  
11
  struct
12
  {
13
    unsigned int Adc1Ch0[8];
14
    unsigned int Adc1Ch1[8];
15
    unsigned int Adc1Ch2[8];
16
    unsigned int Adc1Ch3[8];
17
    unsigned int Adc1Ch4[8];
18
    unsigned int Adc1Ch5[8];
19
          unsigned int Adc1Ch6[8];
20
    unsigned int Adc1Ch7[8];
21
    unsigned int Adc1Ch8[8];
22
    unsigned int Adc1Ch9[8];
23
    unsigned int Adc1Ch10[8];
24
    unsigned int Adc1Ch11[8];
25
    unsigned int Adc1Ch12[8];
26
    unsigned int Adc1Ch13[8];
27
    //unsigned int Adc1Ch14[8];
28
    //unsigned int Adc1Ch15[8];
29
  
30
  } BufferA __attribute__((space(dma)));
31
  struct
32
  {
33
    unsigned int Adc1Ch0[8];
34
    unsigned int Adc1Ch1[8];
35
    unsigned int Adc1Ch2[8];
36
    unsigned int Adc1Ch3[8];
37
    unsigned int Adc1Ch4[8];
38
    unsigned int Adc1Ch5[8];
39
    unsigned int Adc1Ch6[8];
40
    unsigned int Adc1Ch7[8];
41
    unsigned int Adc1Ch8[8];
42
    unsigned int Adc1Ch9[8];
43
    unsigned int Adc1Ch10[8];
44
    unsigned int Adc1Ch11[8];
45
    unsigned int Adc1Ch12[8];
46
    unsigned int Adc1Ch13[8];
47
    //unsigned int Adc1Ch14[8];
48
    //unsigned int Adc1Ch15[8];
49
  } BufferB __attribute__((space(dma)));
50
51
52
void InitADC_DMA()
53
{
54
  AD1CON1bits.ADON = 0;   //ADC is Off, set it off bevor configuration
55
  AD1CON1bits.FORM = 0;   // Data Output Format: Signed Fraction (Q15 format)
56
  AD1CON1bits.SSRC = 2;   // Sample Clock Source: GP Timer starts conversion
57
  AD1CON1bits.ASAM = 1;   // Sampling begins immediately after conversion
58
  AD1CON1bits.AD12B = 1;  // 12-bit ADC operation
59
  AD1CON1bits.SIMSAM = 1; // Samples multiple channels sequentially
60
  
61
        AD1CON2bits.BUFM = 0;
62
  AD1CON2bits.CSCNA = 1;  // Scan CH0+ Input Selections during Sample A bit
63
  AD1CON2bits.CHPS = 0;   // Converts CH0
64
  
65
        AD1CON3bits.ADRC = 0;   // ADC Clock is derived from Systems Clock
66
  AD1CON3bits.ADCS = 63;  // ADC Conversion Clock
67
  
68
       //AD1CHS0: A/D Input Select Register
69
  AD1CHS0bits.CH0SA = 0;  // MUXA +ve input selection (AIN0) for CH0
70
  AD1CHS0bits.CH0NA = 0;  // MUXA -ve input selection (Vref-) for CH0
71
  
72
       //AD1CHS123: A/D Input Select Register
73
  AD1CHS123bits.CH123SA = 0; // MUXA +ve input selection (AIN0) for CH1
74
  AD1CHS123bits.CH123NA = 0; // MUXA -ve input selection (Vref-) for CH1
75
  
76
       //AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
77
  AD1CSSH = 0x0000;
78
  AD1CSSL = 0x3F00; // Scan AIN8, AIN9, AIN10, AIN11, AIN12, AIN13 inputs
79
  
80
  //Set up Timer3 to trigger ADC1 conversions:
81
  
82
  TMR3 = 0x0000;
83
  PR3 = 4999;        // Trigger ADC1 every 125usec
84
  IFS0bits.T3IF = 0; // Clear Timer 3 interrupt
85
  IEC0bits.T3IE = 0; // Disable Timer 3 interrupt
86
  T3CONbits.TON = 1; //Start Timer 3
87
  
88
  //Set up DMA Channel 5 for Peripheral Indirect Addressing:
89
90
  DMA5CONbits.AMODE = 2; // Configure DMA for Peripheral indirect mode
91
  DMA5CONbits.MODE = 2;  // Configure DMA for Continuous Ping-Pong mode
92
  DMA5PAD = (volatile unsigned int)&ADC1BUF0;// Point DMA to ADC1BUF0
93
  DMA5CNT = 47; // 48 DMA request (6 buffers, each with 8 words)
94
  DMA5REQ = 13; // Select ADC1 as DMA Request source
95
  DMA5STA = __builtin_dmaoffset(&BufferA);
96
  DMA5STB = __builtin_dmaoffset(&BufferB);
97
  IFS3bits.DMA5IF = 0; //Clear the DMA interrupt flag bit
98
  IEC3bits.DMA5IE = 1; //Set the DMA interrupt enable bit
99
  
100
101
}  
102
void __attribute__((__interrupt__,no_auto_psv)) _DMA5Interrupt(void)
103
{
104
  IFS3bits.DMA5IF = 0; //Clear the DMA5 Interrupt Flag
105
  unsigned int DmaBuffer = 0;  
106
// Switch between Primary and Secondary Ping-Pong buffers
107
  if(DmaBuffer == 0)
108
  {
109
  /*
110
  ProcessADCSamples(BufferA.Adc1Ch0);
111
  ProcessADCSamples(BufferA.Adc1Ch1);
112
  ProcessADCSamples(BufferA.Adc1Ch2);
113
  ProcessADCSamples(BufferA.Adc1Ch3);
114
  */
115
  }
116
  else
117
  {
118
  /*
119
  ProcessADCSamples(BufferB.Adc1Ch0);
120
  ProcessADCSamples(BufferB.Adc1Ch1);
121
  ProcessADCSamples(BufferB.Adc1Ch2);
122
  ProcessADCSamples(BufferB.Adc1Ch3);
123
  */
124
  }
125
126
  DmaBuffer ^= 1;
127
128
}
129
  //Set up ADC1 for DMA operation:
130
void RunADC_DMA()
131
{
132
  AD1CON1bits.ADDMABM = 0; // DMA buffers are built in scatter/gather mode
133
  AD1CON2bits.SMPI    = 5; // 6 ADC buffers
134
  AD1CON4bits.DMABL   = 3; // Each buffer contains 8 words
135
          
136
  IFS0bits.AD1IF      = 0; // Clear the A/D interrupt flag bit
137
  IEC0bits.AD1IE      = 0; // Do Not Enable A/D interrupt 
138
  DMA5CONbits.CHEN    = 1; //Enable DMA0 channel
139
  AD1CON1bits.ADON    = 1; // Turn on the A/D converter
140
}
141
142
143
void ProcessADCSamples(unsigned int * AdcBuffer)
144
{
145
  char AdcBuffer_string[32];
146
//  itoa_o(*AdcBuffer, AdcBuffer_string, 10);
147
}
148
149
150
int main (void)
151
{
152
InitADC_DMA();
153
RunADC_DMA();
154
while (1){}
155
}

von Gast (Gast)


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.

von Ben (Gast)


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
}

von Gast (Gast)


Lesenswert?

LöSUNG:

AMODE = 0;

kein ahnung wieso, aber so funktionierts!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.