Forum: Mikrocontroller und Digitale Elektronik Initialisierung ADC STM32F446 - gelöst


von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Guten Morgen,

ich habe mal wieder zu wenig Augen, um den Fehler zu finden. Ich will an 
einem STM32F446 einen ADC-Kanal nutzen. Geschwindigkeit, Genauigkeit und 
Quellimpedanz sind alle im untersten Schwierigkeitsgrad. Testweise hängt 
jetzt einfach ein 10 kOhm-Poti in Mittelstellung an PA4 an meinem 
Nucleo-64-Board. Der ADC-Test an einem STM32F103-Nucleo-64-Board 
funktioniert fehlerfrei und der Schaltplan des Nucleo-Boards sieht dort 
auch keine Gemeinheiten vor. Ich gehe also davon aus, daß es an der 
Initialisierung liegt.

Die Initialisierung und Abfrage sieht momentan so aus:
1
typedef struct
2
{
3
    GPIO_TypeDef *Gpio;
4
    uint16_t Pin;
5
}
6
Gpiopin_t;
7
8
9
#ifdef STM32F446ZE
10
/* GPIO passend zum ADC-Kanal auswaehlen */
11
static Gpiopin_t lookupIO(ADC_TypeDef *ADCx, enum adcChannel_e channel )
12
{
13
    switch( channel )
14
    {
15
        case adc1_ch4_PA4: // Fallthru
16
        case adc2_ch4_PA4:
17
            assert( ADCx == ADC1 || ADCx == ADC2 );
18
            return (Gpiopin_t) {.Gpio = GPIOA, .Pin =  GPIO_Pin_4};
19
20
        case adc3_ch4_PF6:
21
            assert( ADCx == ADC3 );
22
            return (Gpiopin_t) {.Gpio = GPIOF, .Pin =  GPIO_Pin_6};
23
24
        default:
25
            error("unknown channel");
26
            return (Gpiopin_t) {.Gpio = NULL, .Pin =  0};
27
    }
28
}
29
#else
30
    #error "unknown MCU"
31
#endif
32
33
34
35
36
/* Initialisierung ADC
37
 *
38
 * *ADCx : ADC1|ADC2|ADC3
39
 * return: Errorcode  */
40
uint_fast8_t adc_simple_init(ADC_TypeDef *ADCx, AdcInit_t Ini)
41
{
42
    //FIXME: Zu Debugzwecken
43
    ADCx = ADC1;
44
    Ini.channel = adc1_ch4_PA4;
45
    Ini.sampleRate = sampleRate_slow;
46
    // :EMXIF
47
48
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
49
    ADC_InitTypeDef  ADC_InitStructure;
50
    GPIO_InitTypeDef GPIO_InitStructure;
51
52
53
    uint8_t ADC_SampleTime;
54
55
    switch( Ini.sampleRate )
56
    {
57
        case sampleRate_slow:
58
            ADC_SampleTime = ADC_SampleTime_480Cycles;
59
            break;
60
61
        case sampleRate_fast:
62
            ADC_SampleTime = ADC_SampleTime_3Cycles;
63
            break;
64
65
        default:
66
            return EXIT_FAILURE;
67
    }
68
69
70
    GPIO_TypeDef *GPIOx = lookupIO(ADCx, Ini.channel).Gpio;
71
    uint16_t Pin        = lookupIO(ADCx, Ini.channel).Pin;
72
73
74
    //TODO:  Relikt von STM32F10x - ueberpruefen, inwieweit das auf die F4xxx auch zutrifft
75
    // ADC-Takt max. 14MHz, hier 72MHz / 6 = 12MHz
76
    //RCC_ADCCLKConfig(RCC_PCLK2_Div6);
77
    // Laut RM0390 kein aehnliches Konstrukt notwendig REMOVEME
78
79
80
    initGpioClock(GPIOx);
81
82
83
    if( ADCx==ADC1 )
84
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
85
    else if( ADCx==ADC2 )
86
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
87
    else if( ADCx==ADC3 )
88
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); // ADC3 noch nie getestet!
89
    else
90
        return EXIT_FAILURE;
91
92
93
    if( GPIOx != NULL ) // Es gibt auch ADC-Kanaele ohne GPIO
94
    {
95
        GPIO_InitStructure.GPIO_Pin  = Pin;
96
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
97
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
98
        GPIO_Init(GPIOx, &GPIO_InitStructure);
99
    }
100
101
    ADC_CommonInitStructure.ADC_Mode          = ADC_Mode_Independent;
102
    ADC_CommonInitStructure.ADC_Prescaler     = ADC_Prescaler_Div4;
103
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
104
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
105
    ADC_CommonInit(&ADC_CommonInitStructure);
106
107
    ADC_InitStructure.ADC_Resolution         = ADC_Resolution_12b;
108
    ADC_InitStructure.ADC_ScanConvMode       = DISABLE;
109
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
110
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
111
    ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_T1_CC1;
112
    ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;
113
    ADC_InitStructure.ADC_NbrOfConversion    = 1;
114
    ADC_Init(ADCx, &ADC_InitStructure);
115
116
117
    assert( ADC_Channel_4 == 4 );             // Paranoia
118
    ADC_RegularChannelConfig(ADCx, Ini.channel, 1, ADC_SampleTime);
119
120
121
122
123
    ADC_ContinuousModeCmd(ADCx, ENABLE);    // Setzt CONT in ADC_CR2
124
                                            // In keinem Beispiel der STDPeriphLBR drin.
125
                                            // setzt CR2 auf 2
126
    ADC_Cmd(ADCx, ENABLE);          // Setzt CR2 auf 3
127
128
129
    ADC_SoftwareStartConv(ADCx); //Start ADC1 Conversion
130
    // Sollte laut Quelltext Bit 30 in CR2 setzen, stattdessen bleibt CR2 im Debugger auf
131
    // 3, SR liest sich zu 0x12 -> injected channel start und enc of conversion
132
133
    adc_calib(ADCx);
134
    return EXIT_SUCCESS;
135
}
136
137
138
139
/* Der ADC braucht nicht deinitialisiert zu werden (er kann jederzeit mit anderen
140
 * Parametern darueberinitialisiert werden, aber der Vollstaendgkeit halber */
141
uint_fast8_t adc_simple_deinit(ADC_TypeDef *ADCx)
142
{
143
    ADC_Cmd(ADCx, DISABLE);
144
    return EXIT_SUCCESS;
145
}

Nach der Initialisierung lese ich aus dem Register ADC_DR die ersten 
paar Male einen kleinen Wert aus, der nach mehrmaligem Auslesen auf Null 
geht. Nie hat der Wert in DR irgendetwas mit der Schleiferstellung des 
Potis an PA4 zu tun.

Es ist mir rätselhaft, warum nach einer Initialisierung "regulärer" 
Kanäle im ADC_SR Flags für "injected" auftauchen.

Viele Grüße
W.T.

P.S.: Das Frühstück hat den Fehler gelöst. Das Enum adc1_ch4_PA4 hat 
nicht den Wert 4. Ich lasse das hier trotzdem mal stehen, falls jemand 
eine Initialisierung im free running mode sucht - notfalls als 
abschreckendes Beispiel.

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Und hier noch etwas weniger schlimm mit dem ganzen Fehlersuchkram 
entfernt.

von Walter T. (nicolas)


Lesenswert?

Meine Güte...das zappelt aber am STM32F446. Selbst wenn ich den Pin hart 
auf GND ziehe, wird zwischen 2 und 16 angezeigt (was mehr als 10 mV 
entspricht).

Am STM32F103 ist dagegen Ruhe - maximal die letzten beiden Bits zappeln 
am normalen Spannungsteiler.

Kann das an einer ungünstigen Wahl der Sampleparameter liegen? 
Eigentlich sollte ich doch die harmlosesten möglichen Parameter gewählt 
haben?

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.