Forum: Mikrocontroller und Digitale Elektronik STM8S ADC Problem


von Christoph R. (christoph_r463)


Lesenswert?

Hallo Zusammen,

Ich versuche gerade irgendwie einen random Seed für mein rand() auf 
einem STM8S003F3P6 zu erzeugen. Da mein Pin D3 noch nicht beschaltet ist 
(hängt in der Luft), dachte ich mir, ich könnte einfach das Rauschen des 
Pins via ADC messen und mir daraus den Seed generieren.
1
#define ADC_PORT                            GPIOD   
2
#define ADC_PIN                             GPIO_PIN_3
3
#define ADC_CHANNEL                         ADC1_CHANNEL_4
4
5
6
static void locADCConfig(void)
7
{
8
  /* initialize ADC pin */
9
  GPIO_Init(ADC_PORT, ADC_PIN, GPIO_MODE_IN_FL_NO_IT);
10
11
  /* De-Init ADC1 peripheral */
12
  ADC1_DeInit();   
13
14
  /* init */
15
  ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, 
16
            ADC1_CHANNEL_4,// AIN4 -> PD3
17
            ADC1_PRESSEL_FCPU_D2, 
18
            ADC1_EXTTRIG_TIM, 
19
            DISABLE, 
20
            ADC1_ALIGN_RIGHT, 
21
            ADC1_SCHMITTTRIG_CHANNEL4,
22
            DISABLE);  
23
    
24
  ADC1_StartConversion();       
25
        
26
  return;
27
}

Wenn ich nun in der main in einer Schleife den ADC Wert abfrage, bekomme 
ich immer den selben Wert.
1
locADCConfig();
2
3
while(1)
4
{
5
   wValue = ADC1_GetConversionValue();
6
   _delay_ms(1000);
7
}

Der Wert ist zum Beispiel 0x9C00, auch nach dem Neustart und wenn ich 
den Finger auf den ADC-Pin lege. Füge ich irgendwo Code hinzu und 
kompiliere, ist der Wert meist ein anderer, zum Beispiel 0x9500.

Was kann da falsch sein?
Grüße
Chris

von Max M. (maxmicr)


Lesenswert?

Hi,
wie sieht deine "GetConversion" aus? Oder ist das eine Funktion aus der 
stm8s_adc.h ?

von Christoph R. (christoph_r463)


Lesenswert?

Max M. schrieb:
> Hi,
> wie sieht deine "GetConversion" aus? Oder ist das eine Funktion aus der
> stm8s_adc.h ?

Hi Max,

ja genau, das ist eine Library Funktion vom STM
1
uint16_t ADC1_GetConversionValue(void)
2
{
3
  uint16_t temph = 0;
4
  uint8_t templ = 0;
5
  
6
  if ((ADC1->CR2 & ADC1_CR2_ALIGN) != 0) /* Right alignment */
7
  {
8
    /* Read LSB first */
9
    templ = ADC1->DRL;
10
    /* Then read MSB */
11
    temph = ADC1->DRH;
12
    
13
    temph = (uint16_t)(templ | (uint16_t)(temph << (uint8_t)8));
14
  }
15
  else /* Left alignment */
16
  {
17
    /* Read MSB first*/
18
    temph = ADC1->DRH;
19
    /* Then read LSB */
20
    templ = ADC1->DRL;
21
    
22
    temph = (uint16_t)((uint16_t)((uint16_t)templ << 6) | (uint16_t)((uint16_t)temph << 8));
23
  }
24
  
25
  return ((uint16_t)temph);
26
}

von Christoph R. (christoph_r463)


Lesenswert?

Hallo Zusammen,

mittlerweile habe ich es noch auf einem 2ten, identischen Board 
ausprobiert und dort bekomme ich die gleichen Werte wie beim ersten 
Board.

Auch habe ich mit den Flags getestet:
1
while(1)
2
{
3
4
  while(RESET == ADC1_GetFlagStatus(ADC1_FLAG_EOC));
5
  ADC1_ClearFlag(ADC1_FLAG_EOC);
6
  
7
  byLow = ADC1->DRL;
8
  byHigh =  ADC1->DRH;
9
  
10
  ADC1_StartConversion();
11
  
12
  _delay_ms(1000);
13
}

Auch am Mode (continuous und single) des ADC1 habe experimentiert, - 
alles unverändert.

Der ADC scheint einfach nicht zu wandeln.

Die Werte lese ich immer via Debugger aus, - kann es da evtl noch ein 
Problem geben, dass im Debug-Mode da etwas nicht eingeschaltet wird?

Grüße
Chris

von Ingo L. (corrtexx)


Lesenswert?

Muss man bei den STm8 auch den Clock für die Peripherie per Hand 
einschalten? Falls ja, sehe ich das nirgends...

von Christoph R. (christoph_r463)


Lesenswert?

Hallo Alle miteinander,

das Problem lag tatsächlich nicht am ADC... der läuft wunderbar. Das 
Problem lag an meiner Variablen, die ich mit dem Debugger abfrage...
Es kommt darauf an, wo ich die Variable wValue definiere. Definiere ich 
sie einmal und lasse sie immer wieder überschreiben, denkt der Kompiler 
scheinbar, er müsse die Variable nicht mit jedem Durchlauf der While(1) 
Schleife aktualisieren.

NOT OK:
1
unsigned int wValue = 0;
2
3
while(1)
4
{
5
   wValue = ADC1_GetConversionValue();
6
   _delay_ms(1000);
7
}

vs.

OK:
1
while(1)
2
{
3
   unsigned int wValue = ADC1_GetConversionValue();
4
   _delay_ms(1000);
5
}

volatile vor die Variable geht natürlich auch.

Grüße und Danke für den Input!
Chris

von Ingo L. (corrtexx)


Lesenswert?

Christoph R. schrieb:
> denkt der Kompiler
> scheinbar, er müsse die Variable nicht mit jedem Durchlauf der While(1)
> Schleife aktualisieren.
Nee, er optimiert dein Programm einfach gänzlich weg, da du die Variable 
nicht weiter benutzt und dein Programm nichts weiter tut. Macht er 
richtig so... Normalerweise spuckt er aber auch ne Warnung ala "unused 
Variable" aus, die du wahrscheinlich nicht beachtet hast.

von Christoph R. (christoph_r463)


Lesenswert?

In meinem Fall hat der Kompiler wegoptimiert, das der Wert meiner 
Variable mit dem tatsächlichen Wert in der Hardware synchronisiert wird 
(Unused ist sie nicht. Hinter dieser "Testschleife" kommt noch mein 
komplettes Programm und da wird mit der Variablen gerechnet.). Mit 
volatile "erzwingt" man das und dann gehts dann auch.

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.