STM32G4: minimale Sequenz zum Einschalten des ADC1

OP #7435049
Lesenswert?

Hallo zusammen,

ich möchte den ADC1 eines Nucleo32G4-Boards mit dem G431 in Betrieb nehmen.

Dazu habe ich folgendes Vorgehen bisher (ohne HAL):

1
            RCC->AHB2ENR |= RCC_AHB2ENR_ADC12EN;
2
            
3
            MODIFY_REG(ADC1->CR, ADC_CR_DEEPPWD_Msk, 0x00 << ADC_CR_DEEPPWD_Pos); 
4
            ADC1->CR |= ADC_CR_ADVREGEN;
5
            
6
            wait_us(100);
7

8
            ADC1->ISR |= ADC_ISR_ADRDY; // clear flag
9
            
10
            // VREF ?
11
            
12
            ADC12_COMMON->CCR |= (0x0b << ADC_CCR_PRESC_Pos); // prescaler 256
13
            MODIFY_REG(ADC1->CFGR , ADC_CFGR_RES_Msk, (0x00 << ADC_CFGR_RES_Pos)); // 12 bit
14
            
15
            // temp sensor channel select (ADC1 INP16)
16
            
17
            ADC1->SQR1 = (0x00 << ADC_SQR1_L_Pos) | (16 << ADC_SQR1_SQ1_Pos);
18
            
19
            ADC1->CR |= ADC_CR_ADEN;
20
            
21
          while(!(ADC1->ISR & ADC_ISR_ADRDY)); //  ????

Das ADC_ISR_ADRDY geht allerding nie auf true.

Der Systemtakt und AHB Takt ist 170MHz.

Was mache ich falsch?

#7435068
Lesenswert?

Wenn ich von STM alles so mundgerecht serviert bekomme dann gebe ich mich als faulen Sack und lasse CubeMX den Code generieren.

Wenn ich das beispielhaft für einen G431 mache bekome ich den folgenden übersichtlichen Code der (vermutlich doch) alles beinhaltet. Und das ohne HAL-Funktionen zu verwenden.

Daran könntest du dich orientieren wenn du wirklich auf Registerebene alles zu Fuss machen möchtest. Das kann jedoch

  • wie so oft - stark fehlerbehaftet sein. Also viel Erfolg, welchen Weg du auch immer beschreiten willst .....
1
/* ADC1 init function */
2
void MX_ADC1_Init(void)
3
{
4
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
5
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
6
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
7

8
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
9

10
  /* Peripheral clock enable */
11
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC12);
12
  
13
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
14
  /**ADC1 GPIO Configuration  
15
  PA0   ------> ADC1_IN1 
16
  */
17
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
18
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
19
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
20
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
21

22
  /* ADC1 interrupt Init */
23
  NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
24
  NVIC_EnableIRQ(ADC1_2_IRQn);
25

26
  /** Common config 
27
  */
28
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
29
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
30
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
31
  LL_ADC_Init(ADC1, &ADC_InitStruct);
32

33
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
34
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
35
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
36
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
37
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
38
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;
39
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
40

41
  LL_ADC_SetGainCompensation(ADC1, 0);
42
  LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
43
  LL_ADC_DisableDeepPowerDown(ADC1);
44
  LL_ADC_EnableInternalRegulator(ADC1);
45
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
46
  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
47
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
48
  LL_ADC_EnableIT_EOC(ADC1);
49
  LL_ADC_DisableIT_EOS(ADC1);
50
  /** Configure Regular Channel 
51
  */
52
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_1);
53
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_2CYCLES_5);
54
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_1, LL_ADC_SINGLE_ENDED);
55
}
(Firma: egal) #7435088
Lesenswert?

Raoul D. schrieb:

1
> 0x00 << ADC_CR_DEEPPWD_Pos
2
> (0x00 << ADC_CFGR_RES_Pos)
3
> (0x00 << ADC_SQR1_L_Pos)

Kann mir mal jemand erklären was das sein soll? Ich hätte eigentlich gedacht das hier eine Null n mal nach links geschiftet wird und dann immer noch Null ist. Aber zusammen mit dem mir unbekannten Makro "MODIFY_REG" scheint das wohl was anderes zu bewirken, sonst wäre es ja sinnlos und verwirrend?

OP #7435116
Lesenswert?

Niklas G. schrieb:

Versuch mal:

1
RCC->AHB2ENR |= RCC_AHB2ENR_ADC12EN;
2
> __DSB ();
3
> ADC1->CR = ADC_CR_ADVREGEN;
4
> 
5
> wait_us(100);
6
> ADC1->ISR = ADC_ISR_ADRDY; // clear flag
7
> 
8
>

Schau auch mal im Debugger was jeweils in den Registern steht (CR1, ISR).

CR1 gibt es ja nicht, Du meinst sicher CR

Die Bits in ISR sind "rc_w1", also geht löschen wie oben gezeigt (kein OR).

Danke, das habe ich übersehen.

Die MB mit __DSB() ist m.E. unnötig und führt auch nicht zum Erfolg.

#7435119
Lesenswert?

Irgend W. schrieb:

Kann mir mal jemand erklären was das sein soll?

Vermutlich spuckt der Code Generator immer den gleichen Code aus und trägt falls notwendig nur eine 1 ein.

Irgend W. schrieb:

Ich hätte eigentlich gedacht das hier eine Null n mal nach links geschiftet wird und dann immer noch Null ist.

Ja, würde ich auch sagen.

Irgend W. schrieb:

Aber zusammen mit dem mir unbekannten Makro "MODIFY_REG" scheint das wohl was anderes zu bewirken, sonst wäre es ja sinnlos und verwirrend?

Man könnte sagen es ist sinnlos. Man könnte auch sagen dass man dadurch direkt sieht was auf dem entsprechenden Bit steht. Manche Bit sind Default 0, manche 1. Ich denke also das ist Ansichtssache.

#7435227
Lesenswert?

Hm, erstens fehlt die Kalibrierungsphase und zweitens ist der notwendige Ablauf im RM genau beschrieben, ADC on-off control 21.4.9. Beim G0 geht es bei mir so, wie im (zugehörigen) RM beschrieben (ohne diesen ganzen HAL-Krempel), und soweit ich auf den ersten Blick sehe, gibt's da auch keine wesentlichen Unterschiede zw. G0 und G4.

#7435254
Lesenswert?

Andreas B. schrieb:

wie im (zugehörigen) RM beschrieben (ohne diesen ganzen HAL-Krempel),

Dieser ganz "HAL-Krempel" funktioniert aber i.d.R und bis auf ganz, ganz wenige Ausnahmen zuverlässig, frei von Nebenwirkungen und das sogar unter Berücksichtigung der letzten Eratas.

Während die Superchecker, die sich für schlauer halten als die Ings bei ST noch an ihrer Initialisierung herumfrickeln kann man sich HAL-sei-Dank bereits auf die eigentliche Aufgabe/Anwendung konzentrieren.

#7435267
Lesenswert?

Harry L. schrieb:

Dieser ganz "HAL-Krempel" funktioniert aber i.d.R und bis auf ganz, ganz wenige Ausnahmen zuverlässig, frei von Nebenwirkungen und das sogar unter Berücksichtigung der letzten Eratas.

Während die Superchecker, die sich für schlauer halten als die Ings bei ST noch an ihrer Initialisierung herumfrickeln kann man sich HAL-sei-Dank bereits auf die eigentliche Aufgabe/Anwendung konzentrieren.

Ach Gottchen, da regt sich mal wieder einer auf. Sei's drum, wer es so machen will (und für die simple GPIO-Init. gleich wer weiß wieviel Flash verbraten will), soll's doch gerne machen, was juckt's mich? Wenn jemand nicht mal die ADC-Initialisierung nach RM hin bekommt, ist das Ganze ohnehin ziemlich akademisch ...

#7435271
Lesenswert?

Andreas B. schrieb:

und für die simple GPIO-Init. gleich wer weiß wieviel Flash verbraten will

Allein mit diesem Satz hast du dich vollkommen disqualifiziert. Man sollte nicht über Dinge schwadronieren, die man nicht kennt/von denen man keine Ahnung hat/ die man nicht verstanden hat.

Flash ist i.d.R auch reichlich vorhanden, und für ungenutzten Speicher gibts auch kein Geld zurück, und auch, wenn der generierte Code etwas länger erscheint, gilt das nicht zwangläufig für das, was der Compiler/Linker daraus macht.

Der generierte Code ist jedenfalls gut verständlich und dokumentiert - im Gegensatz zu den meisten Frickler-Ejakulaten.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren