Forum: Mikrocontroller und Digitale Elektronik STM32F3 ADC (ohne STD-Lib)


von Daniel F. (franky55555)


Lesenswert?

Hi,
ich versuche mich gerade an einer Programmierung eines ADCs für das 
STM32F3. Soweit habe ich dies auch geschafft, jedoch funktioniert es 
nicht wie erwartet ^^ Mein Problem:
Der Code bleibt in dieser Zeile stecken:
1
while((ADC3->ISR & ADC_ISR_EOC)==0);// wait until conversion is complete

Hat irgendjemand eine Idee, warum dies passiert?
Ich möchte aber nicht auf die STD-Lib umsteigen, sondern auf 
Registerebene bleiben.

LG


Hier ist der gesamte Code:
1
/* Includes */
2
#include "stm32f30x.h"
3
#include "GPIO.h"
4
#include "clock.h"
5
6
uint32_t timerFlag=0;
7
uint16_t value=0;
8
9
10
int main(void)
11
{
12
  GPIO_CLKconfig();
13
  clock_config();
14
  //-----ADC_GPIO
15
  GPIOB->MODER |= GPIO_MODER_MODER1_1;
16
  GPIOB->MODER |= GPIO_MODER_MODER1_0; // Analoge MODE
17
  /* Analog mode 11
18
  *   Alternate   10
19
  *  GPIO     01
20
  *   Input       00
21
  */
22
23
 // GPIOB -> OSPEEDR |=  GPIO_OSPEEDER_OSPEEDR1_1| GPIO_OSPEEDER_OSPEEDR1_0;// 50 MHZ GPIO
24
  //------------
25
26
  //----LED_GPIO
27
  GPIOE->MODER |=GPIO_MODER_MODER8_0; // GPIO MODE
28
  GPIOE->MODER &=~GPIO_MODER_MODER8_1;
29
30
  /* Analog mode 11
31
  *   Alternate   10
32
  *  GPIO     01
33
  *   Input       00
34
  */
35
36
  GPIOE -> OSPEEDR |=  GPIO_OSPEEDER_OSPEEDR8_1| GPIO_OSPEEDER_OSPEEDR8_0;// 50 MHZ GPIO
37
38
  GPIOE->MODER |=GPIO_MODER_MODER9_0;
39
  GPIOE -> OSPEEDR |=  GPIO_OSPEEDER_OSPEEDR9_1| GPIO_OSPEEDER_OSPEEDR9_0;
40
  //--------
41
42
43
  // ADC init
44
  RCC -> AHBENR |= RCC_AHBENR_ADC34EN; //CLockenable for ADC 3 und 4
45
  ADC3 -> CR &= ~ ADC_CR_ADEN; //disable AD
46
  /*calibration*/
47
  ADC3 -> CR &=~ADC_CR_ADCALDIF;
48
  ADC3 -> CR |=(1<<28);// voltage regulator 01
49
       //voltage regulator
50
  ADC3 -> CR |= ADC_CR_ADCAL;     //starting calibration
51
52
  while((ADC3->CR & ADC_CR_ADCAL)==0); //wait until calibration is ready
53
  /*end calibration*/
54
55
56
57
58
  ADC3 -> CR |= ADC_CR_ADEN; //enable AD
59
  while((ADC3 -> ISR & ADC_ISR_ADRD)==1);//
60
  
61
  /*conversion and channel selection*/
62
  ADC3-> SQR1 = 0;
63
  ADC3-> SQR1 |=ADC_SQR1_SQ1_0; //channel 1
64
  ADC3-> CFGR &= ~ADC_CFGR_RES;
65
  ADC3-> CFGR |= ADC_CFGR_RES_0; // 10 bit resolution
66
  /*
67
   * 00 => 12 bit
68
   * 01 => 10 bit
69
   * 10 => 8 bit
70
   * 11 => 6 bit
71
   */
72
  while(1)
73
  {
74
  ADC3-> SMPR1 |= ADC_SMPR1_SMP1_2; //sampling time to 19.5 clock cycles
75
  //SMPR1....for channel 1
76
  ADC3-> CFGR &= ~ADC_CFGR_CONT;
77
  ADC3-> CR |= ADC_CR_ADSTART; // ADC start
78
  while((ADC3->ISR & ADC_ISR_EOC)==0);// wait until conversion is complete
79
  GPIOE-> BSRR = GPIO_Pin_9;
80
81
  value=ADC_DR_RDATA;        //get value of the ADC
82
  ADC3-> CR |= ADC_CR_ADSTP;    // stop conversion
83
84
  if(value>=512)
85
  {
86
  GPIOE-> BRR = GPIO_Pin_8;   // low
87
  }
88
  else
89
  {
90
  GPIOE-> BSRR = GPIO_Pin_8;   //high
91
  }
92
93
  }
94
  
95
  return 0;
96
}

Hier sind noch die oben eingebunden Bibliotheken:
1
#include "clock.h"
2
void clock_config(void)
3
{
4
  /*
5
   * ================================================================================
6
   * Initializing of PLL for using a higher internal clock-speed (64MHz)
7
   * ================================================================================
8
   */
9
  /* Enable Prefetch Buffer and set Flash Latency */
10
  /*These bits represent the ratio of the SYSCLK (system clock) period to the Flash
11
  access time. */
12
  /*Siehe RM0316 Seite 62 */
13
  FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1;
14
15
  /*configure prescaler */
16
  RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1 | //HCLK = SYSCLK
17
         (uint32_t)RCC_CFGR_PPRE1_DIV2 | // prescaler APB1 = 2
18
         (uint32_t)RCC_CFGR_PPRE2_DIV1; // prescaler APB2 =2
19
20
  /* PLL configuration */
21
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL));//clear register
22
  RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | //PLL gets HSI/2
23
              RCC_CFGR_PLLMULL16); //PLL-factor is 16 => 64MHz
24
25
  RCC->CR |= RCC_CR_PLLON; /* Enable PLL */
26
  while((RCC->CR & RCC_CR_PLLRDY) == 0);/* Wait till PLL is ready */
27
28
  /* Select PLL as system clock source */
29
  RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));//clear register
30
  RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
31
  /* Wait till PLL is used as system clock source */
32
  while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL);
33
}

zweite Bibliothek:
1
#include "GPIO.h"
2
void GPIO_CLKconfig()
3
{
4
  RCC -> AHBENR |= RCC_AHBENR_GPIOAEN | //enable clock for GPIOA
5
           RCC_AHBENR_GPIOBEN | //enable clock for GPIOB
6
           RCC_AHBENR_GPIOCEN | //enable clock for GPIOC
7
           RCC_AHBENR_GPIODEN | //enable clock for GPIOD
8
           RCC_AHBENR_GPIOEEN | //enable clock for GPIOE
9
           RCC_AHBENR_GPIOFEN ; //enable clock for GPIOF
10
}

von Kindergärtner (Gast)


Lesenswert?

Du hast den Interrupt überhaupt nicht eingeschaltet:
1
ADC3->IER |= ADC_IER_EOC;

von Daniel F. (franky55555)


Lesenswert?

Aber wird nicht die End of Conversion - Flag trotzdem gesetzt?
Weil ich ja nur die abfrage, und nicht auf den Interrupt reagiere.

von Kindergärtner (Gast)


Lesenswert?

Daniel Frank schrieb:
> Aber wird nicht die End of Conversion - Flag trotzdem gesetzt?
Die Doku schweigt dazu, aber bei vielen STM32-Peripherieeinheiten muss 
der Interrupt (im jeweiligen _IER) eingeschaltet sein, damit das 
Interruptflag (im _ISR) gesetzt wird; daher verhält es sich beim 
STM32F30x-ADC vermutlich genau so.
> Weil ich ja nur die abfrage, und nicht auf den Interrupt reagiere.
Doch, im ISR stehen Interrupt-Flags. Es wird lediglich keine ISR 
aufgerufen; dazu müsstest du den IRQ erst im Core über NVIC_* Funktionen 
aktivieren.

von Daniel F. (franky55555)


Lesenswert?

Ich habe die Codezeile hinzugefügt, jedoch hat sich an der Situation 
nichts geändert. Der Code bleibt weiterhin an dieser Stelle hängen...

Könnte ich noch etwas vergessen haben?

LG

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Hi, warum nimmst du nicht einfach das EOC-Flag im SR-Register?
1
while((ADC3->SR & ADC_SR_EOC)==0);// wait until conversion is complete

gruß
Christopher

von Daniel F. (franky55555)


Lesenswert?

Hi Christopher

diese Codezeile schluckt der Compiler nicht, da er dieses Register im 
Zusammenhang mit dem ADC nicht kennt.

LG

von Christopher B. (chrimbo) (Gast)


Lesenswert?

Hallo Daniel,

ups, sorry. Hab ins falsche RefMan geschaut.
Sonst seh ich leider keinen Fehler, der Interrupt muss für das Flag 
nicht eingschaltet sein, zumindest steht da kein besonderer Hinweis zu.

lg

von Daniel F. (franky55555)


Lesenswert?

Ich habe es geschafft die Fehlerquelle einzugrenzen.
Ich versuchte die vorgefertigte Funktion für das Abfragen des EOC-Flags 
zu verwenden und bemerkte, dass es nie zu dem Ende der Konvertierung 
kommt.
Das heißt es muss irgendein Fehler in der Initialisierung des gesamten 
ADCs sein.

Daher nochmal meine Frage: hat jemand eine Idee, was das Problem sein 
könnte?

MfG

von Kindergärtner (Gast)


Lesenswert?

Nimm den Beispielcode von ST mit Standard Periphal Library, und ersetze
ihn nach und nach durch die direkten Register-Zugriffe. Wenn es an einer
Stelle nicht mehr funktioniert weißt du warum.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Hi ich nochmal, schusss ins Blaue,
DISCEN = 1?

von Daniel F. (franky55555)


Lesenswert?

Danke für deine Hilfe, aber leider ist auch dies nicht der Fehler.

MfG

von geb (Gast)


Lesenswert?

Vor der Kalibration muss der ADC "enabelt" sein!

Grüsse

von geb (Gast)


Lesenswert?

Ich habs so gemacht:
/* ADC3 configuration 
------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC3, &ADC_InitStructure);
  // ADC3 regular channels configuration
  ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, 
ADC_SampleTime_239Cycles5);
   // Enable ADC3
  ADC_Cmd(ADC3, ENABLE);
  // Enable ADC3 reset calibaration register
  ADC_ResetCalibration(ADC3);
  // Check the end of ADC3 reset calibration register
  //ADC3->CR2 &=0xFF7FFFFF;
  // ADC3->CR2 |=0x00800000;
 while(ADC_GetResetCalibrationStatus(ADC3));


ADC_StartCalibration(ADC3);
while(ADC_GetCalibrationStatus(ADC3));

von Daniel F. (franky55555)


Lesenswert?

Dies war nicht der Fehler, aber danke für deine Antwort :)
Der ADC benötigt einen gesetzten Prescaler (scheint zumindest so, denn 
nachdem dieser gesetzt wurde funktionierte es :D )

Jedoch habe ich immer noch ein kleines Problem:
schreibe ich die Prescaler-configuration nicht dort, wo ich sie habe, so 
funktioniert der ADC nicht mehr
1
  
2
RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE34; //erase register
3
RCC->CFGR2 |= RCC_CFGR2_ADCPRE34_DIV2; // set precaler; division 2

ein weiteres Problem entsteht, wenn ich den ADC3 und den ADC4 verwenden 
möchte. Der ADC, der als "erster" initialisiert wird, funktioniert. Der 
zweite jedoch nicht. Verwende ich jedoch ADC2 und ADC3/ADC4 funktioniert 
es einwandfrei. Ich denke, dass sich somit ADC3 und ADC4 irgendwie 
gegeneinander behindern.

Hat jemand mögliche Lösungsvorschläge um die Probleme zu verhindert? :)
mfG

Hier ist der gesamte Init-Code:
1
void adc2_init()
2
{
3
  //**************************************************
4
  //--------ADC2 INIT-------------
5
  //**************************************************
6
  RCC -> AHBENR |= RCC_AHBENR_ADC12EN;
7
8
  ADC2 -> CR &= ~ (ADC_CR_ADEN);// ADEN disable
9
  ADC2 -> CR &=~(ADC_CR_ADVREGEN); // set reg to 00
10
  ADC2 -> CR |= ADC_CR_ADVREGEN_0; // ADVREGEN 01
11
12
  ADC2 -> CR &=~(ADC_CR_ADCALDIF);// single ended
13
  ADC2 -> CFGR |=(1<<13); //set to continous mode
14
  ADC2 -> CR |= ADC_CR_ADCAL; // calibration
15
16
  while((ADC2-> CR & ADC_CR_ADCAL) ==1);//wait until calibration is ready
17
18
  ADC2-> CR &=~ ADC_CR_ADSTART;// ADSTART disabled
19
  ADC2->IER |= ADC_IER_EOC;// enable end of conversion flag
20
  ADC2-> SQR1 &=~(ADC_SQR1_SQ1);
21
  ADC2->SQR1&=~(ADC_SQR1_L);// 1 sequenz
22
23
  ADC2-> SMPR1 &= (ADC_SMPR1_SMP1);
24
  ADC2-> SMPR1 |= ADC_SMPR1_SMP1_0;
25
  ADC2-> SMPR1 |= ADC_SMPR1_SMP1_1;
26
  //ADC2-> SMPR1 |= ADC_SMPR1_SMP1_2;
27
  /*
28
   * SMP = 000: 1.5 ADC clock cycles
29
   * SMP = 001: 2.5 ADC clock cycles
30
   * SMP = 010: 4.5 ADC clock cycles
31
   * SMP = 011: 7.5 ADC clock cycles => chosen
32
   * SMP = 100: 19.5 ADC clock cycles
33
   * SMP = 101: 61.5 ADC clock cycles
34
   * SMP = 110: 181.5 ADC clock cycles
35
   * SMP = 111: 601.5 ADC clock cycles
36
   */
37
38
  ADC2-> CFGR &=~ (ADC_CFGR_RES);
39
  //clock prescaler, must be there!!
40
  RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE12;
41
  RCC->CFGR2 |= RCC_CFGR2_ADCPRE12_DIV2;
42
43
  ADC2 -> CR |= ADC_CR_ADEN;// enable ADC
44
  while((ADC2 -> ISR & ADC_ISR_ADRD)==0);//wait until ADC is ready
45
}
46
void adc3_init()
47
{
48
49
  //**************************************
50
  //--------ADC3 Init------------
51
  //**************************************
52
  RCC -> AHBENR |= RCC_AHBENR_ADC34EN;
53
54
  ADC3 -> CR &= ~ (ADC_CR_ADEN);// ADEN disable
55
  ADC3 -> CR &=~(ADC_CR_ADVREGEN); // set reg to 00
56
  ADC3 -> CR |= ADC_CR_ADVREGEN_0; // ADVREGEN 0
57
58
  ADC3 -> CR &=~(ADC_CR_ADCALDIF);// single ended
59
  ADC3 -> CFGR |=(1<<13); //set to continous mode
60
  ADC3 -> CR |= ADC_CR_ADCAL; // calibration
61
62
  while((ADC3-> CR & ADC_CR_ADCAL) ==1);//wait until calibration is ready
63
64
  ADC3-> CR &=~ ADC_CR_ADSTART;// ADSTART disabled
65
  ADC3->IER |= ADC_IER_EOC;// enable end of conversion flag
66
  ADC3-> SQR1 &=~(ADC_SQR1_SQ1);
67
  ADC3->SQR1&=~(ADC_SQR1_L);// 1 sequenz
68
69
  ADC3-> SMPR1 &= (ADC_SMPR1_SMP1);
70
  ADC3-> SMPR1 |= ADC_SMPR1_SMP1_0;
71
  ADC3-> SMPR1 |= ADC_SMPR1_SMP1_1;
72
  //ADC3-> SMPR1 |= ADC_SMPR1_SMP1_2;
73
  /*
74
   * SMP = 000: 1.5 ADC clock cycles
75
   * SMP = 001: 2.5 ADC clock cycles
76
   * SMP = 010: 4.5 ADC clock cycles
77
   * SMP = 011: 7.5 ADC clock cycles => chosen
78
   * SMP = 100: 19.5 ADC clock cycles
79
   * SMP = 101: 61.5 ADC clock cycles
80
   * SMP = 110: 181.5 ADC clock cycles
81
   * SMP = 111: 601.5 ADC clock cycles
82
   */
83
84
85
  ADC3-> CFGR &=~ (ADC_CFGR_RES); //data resolution
86
  //clock prescaler, must be there!!
87
  RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE34; //erase register
88
  RCC->CFGR2 |= RCC_CFGR2_ADCPRE34_DIV2; // set precaler; division 2
89
  //RCC->CFGR2 |= RCC_CFGR2_ADCPRE34_NO;//use AHB clock
90
91
  ADC3 -> CR |= ADC_CR_ADEN;// enable ADC
92
  while((ADC3 -> ISR & ADC_ISR_ADRD)==0);//wait until ADC is ready
93
94
}
95
void adc4_init()
96
{
97
  //**************************************************
98
  //--------ADC4 INIT-------------
99
  //**************************************************
100
  RCC -> AHBENR |= RCC_AHBENR_ADC34EN;
101
102
  ADC4 -> CR &= ~ (ADC_CR_ADEN);// ADEN disable
103
  ADC4 -> CR &=~(ADC_CR_ADVREGEN); // set reg to 00
104
  ADC4 -> CR |= ADC_CR_ADVREGEN_0; // ADVREGEN 0
105
106
  ADC4 -> CR &=~(ADC_CR_ADCALDIF);// single ended
107
  ADC4 -> CFGR |=(1<<13); //set to continous mode
108
  ADC4 -> CR |= ADC_CR_ADCAL; // calibration
109
110
  while((ADC4-> CR & ADC_CR_ADCAL) ==1);//wait until calibration is ready
111
112
  ADC4-> CR &=~ ADC_CR_ADSTART;// ADSTART disabled
113
  ADC4->IER |= ADC_IER_EOC;// enable end of conversion flag
114
  ADC4-> SQR1 &=~(ADC_SQR1_SQ1);
115
  ADC4->SQR1&=~(ADC_SQR1_L);// 1 sequenz
116
117
  ADC4-> SMPR1 &= (ADC_SMPR1_SMP1);
118
  ADC4-> SMPR1 |= ADC_SMPR1_SMP1_0;
119
  ADC4-> SMPR1 |= ADC_SMPR1_SMP1_1;
120
  //ADC3-> SMPR1 |= ADC_SMPR1_SMP1_2;
121
  /*
122
   * SMP = 000: 1.5 ADC clock cycles
123
   * SMP = 001: 2.5 ADC clock cycles
124
   * SMP = 010: 4.5 ADC clock cycles
125
   * SMP = 011: 7.5 ADC clock cycles => chosen
126
   * SMP = 100: 19.5 ADC clock cycles
127
   * SMP = 101: 61.5 ADC clock cycles
128
   * SMP = 110: 181.5 ADC clock cycles
129
   * SMP = 111: 601.5 ADC clock cycles
130
   */
131
132
  ADC4-> CFGR &=~ (ADC_CFGR_RES);
133
  //clock prescaler, must be there!!
134
  RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE34;
135
  RCC->CFGR2 |= RCC_CFGR2_ADCPRE34_DIV2;
136
137
138
  ADC4 -> CR |= ADC_CR_ADEN;// enable ADC
139
  while((ADC4 -> ISR & ADC_ISR_ADRD)==0);//wait until ADC is ready
140
141
}

Ich habe auch eigene Funktionen für das Auslesen der ADC-Werte:
1
int adc3_value(uint8_t channel)
2
{
3
  uint16_t value=0;
4
  ADC3-> SQR1 |= (channel<<6);
5
  //ADC3-> SQR1 |=ADC_SQR1_SQ1_3|ADC_SQR1_SQ1_2; //set channel 12
6
  ADC3-> CR |= ADC_CR_ADSTART; // ADC start
7
    while((ADC3 -> ISR & ADC_ISR_EOC) == 0); //wait until ADC conversion is ready
8
  value=ADC3 -> DR;// write into buffer
9
    ADC3->CR |= ADC_CR_ADSTP;//stopping ADC
10
    return value;
11
}
12
13
int adc2_value(uint8_t channel)
14
{
15
  uint16_t value=0;
16
  ADC2-> SQR1 |= (channel<<6);
17
  //ADC3-> SQR1 |=ADC_SQR1_SQ1_3|ADC_SQR1_SQ1_2; //set channel 12
18
  ADC2-> CR |= ADC_CR_ADSTART; // ADC start
19
    while((ADC2 -> ISR & ADC_ISR_EOC) == 0); //wait until ADC conversion is ready
20
  value=ADC2 -> DR;// write into buffer
21
    ADC2->CR |= ADC_CR_ADSTP;//stopping ADC
22
    return value;
23
}
24
25
int adc4_value(uint8_t channel)
26
{
27
  uint16_t value=0;
28
  ADC4-> SQR1 |= (channel<<6);
29
  //ADC3-> SQR1 |=ADC_SQR1_SQ1_3|ADC_SQR1_SQ1_2; //set channel 12
30
  ADC4-> CR |= ADC_CR_ADSTART; // ADC start
31
    while((ADC4 -> ISR & ADC_ISR_EOC) == 0); //wait until ADC conversion is ready
32
  value=ADC4 -> DR;// write into buffer
33
    ADC4->CR |= ADC_CR_ADSTP;//stopping ADC
34
    return value;
35
}

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.