Forum: Mikrocontroller und Digitale Elektronik STM32F429ZI ADC schneller als erwartet


von Michael K. (ampfing)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe einen STM32F429ZI und versuche den ADC1 dieses Controllers über 
den TIM2 jede Sekunde triggern und einen Kanal (Kanal 3) konvertieren zu 
lassen.
Dabei habe ich 480 ADC-Takte als Sample-Zeit bei 12 Bit Auflösung 
konfiguriert und würde daher erwarten, dass der ADC ca. 33 µs für die 
Wandlung braucht (ADC-Prescaler ist 6, APB2-Clock sind 90 MHz - das 
hatte ich auch über den TIM1 überprüft).

Da ich kein Oszilloskop besitze habe ich über Segger SystemView beide 
ISRs entsprechend vorbereitet und bekomme auch etwas über den Debugger 
geliefert (s. SystemViewScreenshot.png, ISR44 = TIM2 Interrupt, ISR34 == 
ADC Interrupt).
Entgegen der Erwartung, dass der ADC-Interrupt ca. 33 µs nach dem 
TIM2-Interrupt angesprungen wird braucht das Ganze nur 2,6 µs.

Kann mir das jemand erklären?

Hier der Code (in der ZIP-Datei ist das komplette Segger Studio-Projekt 
enthalten):
1
/*********************************************************************
2
*                    SEGGER Microcontroller GmbH                     *
3
*                        The Embedded Experts                        *
4
**********************************************************************
5
*                                                                    *
6
*            (c) 2014 - 2020 SEGGER Microcontroller GmbH             *
7
*                                                                    *
8
*           www.segger.com     Support: support@segger.com           *
9
*                                                                    *
10
**********************************************************************
11
*                                                                    *
12
* All rights reserved.                                               *
13
*                                                                    *
14
* Redistribution and use in source and binary forms, with or         *
15
* without modification, are permitted provided that the following    *
16
* conditions are met:                                                *
17
*                                                                    *
18
* - Redistributions of source code must retain the above copyright   *
19
*   notice, this list of conditions and the following disclaimer.    *
20
*                                                                    *
21
* - Neither the name of SEGGER Microcontroller GmbH                  *
22
*   nor the names of its contributors may be used to endorse or      *
23
*   promote products derived from this software without specific     *
24
*   prior written permission.                                        *
25
*                                                                    *
26
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND             *
27
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,        *
28
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF           *
29
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE           *
30
* DISCLAIMED.                                                        *
31
* IN NO EVENT SHALL SEGGER Microcontroller GmbH BE LIABLE FOR        *
32
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR           *
33
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  *
34
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;    *
35
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF      *
36
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT          *
37
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE  *
38
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH   *
39
* DAMAGE.                                                            *
40
*                                                                    *
41
**********************************************************************
42
43
-------------------------- END-OF-HEADER -----------------------------
44
45
File    : main.c
46
Purpose : Generic application start
47
48
*/
49
50
//#include <stdio.h>
51
//#include <stdlib.h>
52
53
#include <stm32f4xx.h>
54
#include "SEGGER_SYSVIEW.h"
55
56
void ClockInit(void)
57
{
58
    uint32_t timeout = 1000000;
59
    
60
    // enable flash prefetch
61
    FLASH->ACR |= FLASH_ACR_PRFTEN;
62
    // set 5 wait states (needed for high PLL frequency)
63
    FLASH->ACR &= ~FLASH_ACR_LATENCY_Msk;
64
    FLASH->ACR |= FLASH_ACR_LATENCY_5WS;
65
    do
66
    {
67
        timeout--;
68
    } while (((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != FLASH_ACR_LATENCY_5WS) && (timeout > 0));
69
    
70
    // switch on external clock, bypass HSE with it and wait for clock to be ready
71
    RCC->CR |= (RCC_CR_HSEON | RCC_CR_HSEBYP);
72
    timeout = 1000000;
73
    do
74
    {
75
        timeout--;
76
    } while (((RCC->CR & RCC_CR_HSERDY_Msk) != RCC_CR_HSERDY) && (timeout > 0));
77
    
78
    // configure (HSE as clock source, M = 4, N = 180, P = 2), enable and wait for PLL
79
    RCC->PLLCFGR = (RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos) | (180 << RCC_PLLCFGR_PLLN_Pos));
80
    RCC->CR |= RCC_CR_PLLON;
81
    timeout = 1000000;
82
    do
83
    {
84
        timeout--;
85
    } while (((RCC->CR & RCC_CR_PLLRDY_Msk) != RCC_CR_PLLRDY) && (timeout > 0));
86
    
87
    // configure rest of clock tree
88
    RCC->CFGR &= ~(RCC_CFGR_PPRE2_Msk | RCC_CFGR_PPRE1_Msk | RCC_CFGR_HPRE_Msk);
89
    RCC->CFGR |= (RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1);
90
    
91
    // set PLL as clock source and wait until clock is ready
92
    RCC->CFGR &= ~(RCC_CFGR_SW_Msk);
93
    RCC->CFGR |= RCC_CFGR_SW_PLL;
94
    timeout = 1000000;
95
    do
96
    {
97
        timeout--;
98
    } while (((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) && (timeout > 0));
99
    
100
    SystemCoreClockUpdate();
101
    
102
    // enable GPIOA, ADC1, TIM1 and TIM2 clocks
103
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
104
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
105
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
106
}
107
108
void TimerInit(void)
109
{
110
    // counter direction down, generate update event only on underflow
111
    TIM2->CR1 |= (TIM_CR1_DIR | TIM_CR1_URS);
112
    // set update event as trigger source
113
    TIM2->CR2 &= ~TIM_CR2_MMS_Msk;
114
    TIM2->CR2 |= TIM_CR2_MMS_1;
115
    // enable update interrupt
116
    TIM2->DIER |= TIM_DIER_UIE;
117
    // set timer and reload value for update generation every 1000 ms
118
    TIM2->ARR = TIM2->CNT = 90000000;
119
}
120
121
void TimerStart(void)
122
{
123
    TIM2->CR1 |= TIM_CR1_CEN;
124
}
125
126
void AdcInit(void)
127
{
128
    // PA3 as analog input
129
    GPIOA->MODER |= GPIO_MODER_MODE3;
130
    // set clock prescaler to 4 -> 22,5 MHz
131
    ADC123_COMMON->CCR |= ADC_CCR_ADCPRE_0;
132
    // enable timer 2 trigger event as start trigger on rising edge and generate EOC interrupt after each conversion
133
    ADC1->CR2 |= (ADC_CR2_EXTSEL_2 | ADC_CR2_EXTSEL_1 | ADC_CR2_EXTEN_0 | ADC_CR2_EOCS);
134
    // set 480 cycles sample time for channel 3
135
    ADC1->SMPR2 |= ADC_SMPR2_SMP3;
136
    // set channel 3 as first (any only) regular channel
137
    ADC1->SQR3 |= (ADC_SQR3_SQ1_2 | ADC_SQR3_SQ1_1);
138
    // enable EOC interrupt
139
    ADC1->CR1 |= ADC_CR1_EOCIE;
140
    // enable ADC
141
    ADC1->CR2 |= ADC_CR2_ADON;
142
}
143
144
void InterruptInit(void)
145
{
146
    // Timer 2
147
    NVIC_SetPriority(TIM2_IRQn, 3);
148
    NVIC_ClearPendingIRQ(TIM2_IRQn);
149
    NVIC_EnableIRQ(TIM2_IRQn);
150
    // ADC
151
    NVIC_SetPriority(ADC_IRQn, 2);
152
    NVIC_ClearPendingIRQ(ADC_IRQn);
153
    NVIC_EnableIRQ(ADC_IRQn);
154
}
155
156
void TIM2_IRQHandler(void)
157
{
158
    SEGGER_SYSVIEW_RecordEnterISR();
159
    NVIC_ClearPendingIRQ(TIM2_IRQn);
160
    TIM2->SR &= ~TIM_SR_UIF;
161
}
162
163
void ADC_IRQHandler(void)
164
{
165
    uint16_t Value;
166
    SEGGER_SYSVIEW_RecordEnterISR();
167
    Value = ADC1->DR;
168
    NVIC_ClearPendingIRQ(ADC_IRQn);
169
}
170
171
int main(void)
172
{
173
    ClockInit();
174
    
175
    SEGGER_SYSVIEW_Conf();
176
    
177
    TimerInit();
178
    AdcInit();
179
    InterruptInit();
180
    
181
    TimerStart();
182
    while(1);
183
}
184
185
/*************************** End of file ****************************/

Edit Ein Kommentar war falsch (der TIM-Interrupt kommt jede Sekunde, 
nicht alle 10 ms)

: Bearbeitet durch User
von Michael K. (ampfing)


Lesenswert?

Hallo nochmal,

hm, 41 Ansichten des Screenshots und keiner eine Idee?
Ist meine Frage zu speziell oder schlecht gestellt? Oder ist einfach 
jeder der Meinung, dass der Code so passen sollte und hat keine Idee, 
warum der ADC so schnell ist?
Würde mich über Rückmeldung freuen :-)

von Uwe Bonnes (Gast)


Lesenswert?

Ist das nicht die gleiche Frage aus der ST Community? Und was war mit 
den falsch gesetzten Bits?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael K. schrieb:
> Kann mir das jemand erklären?
Was passiert denn, wenn du das Ganze mal ohne den ganzen 
Interruptklimbim so etwa 1000000 mal hintereinander mit Polling machst. 
Und dann jeweils eine LED toggelst?

> Da ich kein Oszilloskop besitze
Das ist ja schlimmer als Autofahren mit verbundenen Augen nach Gehör. 
Kauf dir für 10€ so einen billigen Logikanalyzer und du bist wenigstens 
einäugig unterwegs.

von Michael K. (ampfing)


Lesenswert?

Uwe Bonnes schrieb:
> Ist das nicht die gleiche Frage aus der ST Community?
Ja, das war die gleiche Frage. Hatte die ST-Community erst später 
entdeckt und dann gestern Abend dort noch gepostet. Meine erneute Frage 
hier war bevor ich den Tipp mit dem Kanal bekommen habe...

Uwe Bonnes schrieb:
> Und was war mit den falsch gesetzten Bits?
Das war die Lösung - wie auch schon unter 
https://community.st.com/s/question/0D73W000000Hm9t/conversion-time-adc-too-low 
erwähnt.
Man setzt die Sample-Zeit pro Kanal und wenn man dann natürlich den 
falschen Kanal wandelt hat der die Standard-Sample-Zeit von 3 Takten und 
braucht deswegen für eine Konvertierung natürlich deutlich kürzer als 
die 480 Takte...

Lothar M. schrieb:
> Kauf dir für 10€ so einen billigen Logikanalyzer und du bist wenigstens
> einäugig unterwegs
Der steht auf dem Wunschzettel - wenn auch evtl. etwas teurer als 10 €. 
In diesem Fall hätte mir der auch nichts anderes gesagt, davon abgesehen 
:-)

Danke auf jeden Fall für die Antworten und viele Grüße

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.