Forum: Mikrocontroller und Digitale Elektronik [dsPIC] PGA am ADC?


von Wandeluhr (Gast)


Lesenswert?

Hallo,

Ich versuche grade den ADC von einem dsPIC zu nutzen.
Genauer gesagt ist es ein dsPIC33EP64GS504.
Hier das Datenblatt: 
http://ww1.microchip.com/downloads/en/DeviceDoc/70005127d.pdf

Ich nutze 2 ADCs. Der eine (ADC Core 2) tut auch wunderbar
was er soll. Eine einzelne Messung auf AN2. Für den zweiten
ADC möchte ich den PGA (Programmable Gain Amplifier) nutzen
den das Kerlchen eingebaut hat.

Ich habe die QFN-44 Version. Im Datenblatt Seite 5.
Meine Analogsignale hängen an Pin20 (PGA2N3) und Pin22
(PGA2P1). Beide haben ca. VCC/2 (1.65V bei VCC=3.3V).

Auf Seite 230 gibts eine schöne Übersicht von dem Aufbau.
PGA2 hätte ich gerne an ADC Core 1 geschaltet. Soweit sogut,
Bits gesetzt, doch wie wandel ich das Ding?

Der Freund hat leider nur die Möglichkeit die einzelnen Channel
zu triggern (Seite 251), statt den Core mit dem aktuell
eingestelltem Channel zu nehmen. Es gibt aber leider nur
für AN0 bis AN21 ready bits. Auch die Ausgangsbuffer
ADCBUF0 bis ADCBUF21 geben mir keine Möglichkeit den PGA
auszulesen.

Ich habe auch mal Testweise den Channel AN1 ausgelesen,
hängt ja am selben Core. Kommt wenig überraschend nur Null
raus.

Wie Les ich den PGA2 mit dem ADC aus??

Mein Code:
1
#include "system.h"
2
#include <xc.h>
3
4
#include <libpic30.h>
5
#include <stdio.h>
6
7
void SendUART(uint8_t data);
8
void SendUARTString(const char *str);
9
uint16_t ReadADC1();
10
uint16_t ReadADC2();
11
12
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt()
13
{
14
    IFS0bits.U1RXIF = 0;
15
     
16
    uint8_t data = U1RXREG & 0xff;
17
    if (data == 'q')
18
    {
19
        uint16_t val = ReadADC2();
20
        char buffer[32];
21
        sprintf(buffer, "%d/4096\n", val);
22
        SendUARTString(buffer);
23
    }
24
    else if (data == 's')
25
    {
26
        uint16_t val = ReadADC1();
27
        char buffer[32];
28
        sprintf(buffer, "%d/4096\n", val);
29
        SendUARTString(buffer);
30
    }
31
}
32
 
33
void InitUART()
34
{
35
    // map pins
36
    RPINR18bits.U1RXR = 55; // uart receive pin = RC7
37
    RPOR9bits.RP50R = 1; // uart transmit pin = RC2
38
    
39
    // interrupt
40
    IEC0bits.U1RXIE = 1;
41
    IPC2bits.U1RXIP = 1;
42
    
43
    // init UART
44
    U1BRG = 64; // 57600 baud
45
    U1MODEbits.UARTEN = 1; // enable UART
46
    U1STAbits.UTXEN = 1; // enable TX
47
}
48
void SendUART(uint8_t data)
49
{
50
    while (U1STAbits.UTXBF);
51
    U1TXREG = data;
52
}
53
void SendUARTString(const char *str)
54
{
55
    while (*str)
56
        SendUART((uint8_t)*str++);
57
}
58
59
void InitPGA()
60
{
61
    PGA2CALbits.PGACAL = (uint8_t)__builtin_tblrdl(0x800E4C);
62
    
63
    PGA2CONbits.SELPI = 0; // PGA2P1
64
    PGA2CONbits.SELNI = 2; // PGA2N3
65
    PGA2CONbits.GAIN = 6; // x64
66
    PGA2CONbits.PGAEN = 1;
67
}
68
69
void CalibrateADC()
70
{
71
    // Set initialization time to maximum
72
    ADCON5Hbits.WARMTIME = 15;
73
    // Turn on ADC module
74
    ADCON1Lbits.ADON = 1;
75
    // Turn on analog power for dedicated core 1
76
    ADCON5Lbits.C1PWR = 1;
77
    // Wait when the core 1 is ready for operation
78
    while(ADCON5Lbits.C1RDY == 0);
79
    // Turn on digital power to enable triggers to the core 1
80
    ADCON3Hbits.C1EN = 1;
81
    // Turn on analog power for dedicated core 2
82
    ADCON5Lbits.C2PWR = 1;
83
    // Wait when the core 2 is ready for operation
84
    while(ADCON5Lbits.C2RDY == 0);
85
    // Turn on digital power to enable triggers to the core 2
86
    ADCON3Hbits.C2EN = 1;
87
    // Enable calibration for the dedicated core 1
88
    ADCAL0Lbits.CAL1EN = 1;
89
    // Single-ended input calibration
90
    ADCAL0Lbits.CAL1DIFF = 0;
91
    // Start calibration
92
    ADCAL0Lbits.CAL1RUN = 1;
93
    // Poll for the calibration end
94
    while(ADCAL0Lbits.CAL1RDY == 0);
95
    // Differential input calibration
96
    ADCAL0Lbits.CAL1DIFF = 1;
97
    // Start calibration
98
    ADCAL0Lbits.CAL1RUN = 1;
99
    // Poll for the calibration end
100
    while(ADCAL0Lbits.CAL1RDY == 0);
101
    // End the core 0 calibration
102
    ADCAL0Lbits.CAL1EN = 0;
103
    // Enable calibration for the dedicated core 2
104
    ADCAL0Hbits.CAL2EN = 1;
105
    // Single-ended input calibration
106
    ADCAL0Hbits.CAL2DIFF = 0;
107
    // Start calibration
108
    ADCAL0Hbits.CAL2RUN = 1;
109
    // Poll for the calibration end
110
    while(ADCAL0Hbits.CAL2RDY == 0);
111
    // Differential input calibration
112
    ADCAL0Hbits.CAL2DIFF = 1;
113
    // Start calibration
114
    ADCAL0Hbits.CAL2RUN = 1;
115
    // Poll for the calibration end
116
    while(ADCAL0Hbits.CAL2RDY == 0);
117
    // End the core 2 calibration
118
    ADCAL0Hbits.CAL2EN = 0;
119
}
120
void InitADC()
121
{
122
    CalibrateADC();
123
    
124
    //ADCORE2Hbits.ADCS = 10;
125
    
126
    // PGA 2 and AN2
127
    ADCON4Hbits.C1CHS = 2; // PGA2
128
    
129
    ADTRIG0Lbits.TRGSRC1 = 1;
130
    ADTRIG0Hbits.TRGSRC2 = 1;
131
}
132
uint16_t ReadADC1()
133
{
134
    ADCON3Lbits.CNVCHSEL = 1;
135
    ADCON3Lbits.CNVRTCH = 1;
136
    
137
    while (!ADSTATLbits.AN1RDY);
138
    return ADCBUF0;
139
}
140
uint16_t ReadADC2()
141
{
142
    ADCON3Lbits.CNVCHSEL = 2;
143
    ADCON3Lbits.CNVRTCH = 1;
144
    
145
    while (!ADSTATLbits.AN2RDY);
146
    return ADCBUF2;
147
}
148
149
int main()
150
{
151
    InitClock();
152
    InitUART();
153
    InitPGA();
154
    InitADC();
155
    
156
    for (;;)
157
    {
158
    }
159
}

Ich initialisiere alles soweit, setze beim PGA die Eingänge,
setze den Gain auf x64, setze den ADC und UART. Auf Input
vom UART kann ich mir die beiden ADC Werte ausgeben lassen.
ADC2 liefert korrekte Werte, ADC1 nur Null.

Da da intern ein invertiedender Opamp drin ist würde ich
ebenfalls VCC/2 als "Ausgang" erwarten, sprich 2048
(bei 12 Bit Auflösung), jedoch nicht null.

von Rainer S. (enevile) Benutzerseite


Lesenswert?

Guck dir mal Seite 272 an.

The  output  voltage  of  the  PGAx  module  can  be
connected   to   the   DACOUTx   pin   by   setting   the
PGAOEN  bit  in  the  PGAx
CON  register.  When  the
PGAOEN bit is enabled, the output voltage of PGA1 is
connected  to  DACOUT1  and  PGA2  is  connected  to
DACOUT2.

Hilft dir das?

von Wandeluhr (Gast)


Lesenswert?

Rainer S. schrieb:
> The  output  voltage  of  the  PGAx  module  can  be
> connected   to   the   DACOUTx   pin   by   setting   the
> PGAOEN  bit  in  the  PGAx
> CON  register.  When  the
> PGAOEN bit is enabled, the output voltage of PGA1 is
> connected  to  DACOUT1  and  PGA2  is  connected  to
> DACOUT2.

Hilft leider nicht weil das ein externer Pin ist
(sofern das Device überhaupt diesen Pin hat), ich brauche
aber die interne Verbindung zum ADC.

Hab jetzt mit viel try n error alle register ausgelesen
und siehe da, ADCBUF1 scheint mit der Differenzspannung
zu korrelieren.

Wäre nur schön wenn das erwähnt würde im Datenblatt. Ich
denke mal der Hauptzweck eines PGAs wird es sein an den
ADC zu gehen. Sowohl das PGA als auch das ADC application
manual schweigt sich dazu aus...

Also:
AN1 -> AN1 auslesen
AN18 -> AN18 auslesen
PGA2 -> wieder AN1 auslesen

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.