Forum: Mikrocontroller und Digitale Elektronik Cortex M3 - Wie funktioniert das mapping eines Pins zum ADC-Channel


von Ulf (Gast)


Lesenswert?

Hallo zusammen,

ich kann ich Datanblatt und der CMSIS Lib nicht nachvollziehen, wie man 
einen GPIO-Pin eines beliebigen Ports mit einem ADC-Kanal verbindet.

Gibt es eine feste Zuordnung, dass bestimmte Pins nur mit bestimmten 
Kanälen funktionieren?

Hier mein Beispielcode:

/* enable ADC1 clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
                               RCC_APB2Periph_ADC1, ENABLE);

        /* GPIOA: ADC Channel 0, 1, 2, 3 as analog input
         * Ch 3 -> Battery Voltage
         * Ch 4 -> Current
         * Ch 5 -> Temperature
         */
        GPIO_InitStructure.GPIO_Pin =
                GPIO_Pin_3 |
                GPIO_Pin_4 |
                GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure ADC1 */
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
        ADC_InitStructure.ADC_ExternalTrigConv = 
ADC_ExternalTrigConv_None;
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_NbrOfChannel = 0;
        ADC_Init(ADC1, &ADC_InitStructure);

        ADC_InjectedSequencerLengthConfig(ADC1, 3);

        ADC_InjectedChannelConfig(ADC1, ADC_Channel_11, 1,
                                  ADC_SampleTime_239Cycles5);
        ADC_InjectedChannelConfig(ADC1, ADC_Channel_12, 2,
                                  ADC_SampleTime_239Cycles5);
        ADC_InjectedChannelConfig(ADC1, ADC_Channel_13, 3,
                                  ADC_SampleTime_239Cycles5);

        /* ADC1 injected external trigger configuration */
        ADC_ExternalTrigInjectedConvConfig(ADC1, 
ADC_ExternalTrigInjecConv_None);





Mir fehlt praktisch das Verständnis, welches Pin sich hinter den Kanalen 
"andockt".

        ADC_InjectedChannelConfig(ADC1, ADC_Channel_11, 1,
                                  ADC_SampleTime_239Cycles5);
        ADC_InjectedChannelConfig(ADC1, ADC_Channel_12, 2,
                                  ADC_SampleTime_239Cycles5);
        ADC_InjectedChannelConfig(ADC1, ADC_Channel_13, 3,
                                  ADC_SampleTime_239Cycles5);


vielen Dank für eure Unterstützung!
Ulf

von Antwort (Gast)


Lesenswert?

Du hast die wichtigste Angabe vergessen: Welcher Cortex M3?

von Ulf (Gast)


Lesenswert?

Sorry, STM32107VCT6!

von Michael G. (let)


Lesenswert?

Ein STM32F1xx würde ich mal sagen. Aber wer das am Code nicht
erkennt wird die Frage kaum beantworten können ;)

Die Pinzuordnung steht im Datenblatt (nicht das "Reference Manual")
unter "Pinouts and pin assignment". Beim STM32F100 ist das Kapitel 3.
Such mal nach z. B. "ADC1_IN4".

Interessant an dieser "Peripherial Lib" finde ich das jeder
STM32 Fan sie einerseits lobt (leichter Einstieg usw.), sie
andererseits aber kaum verwendet wird. So ist zumindest mein
Eindruck.

von Antwort (Gast)


Lesenswert?

Welcher Pin zu welchen Kanälen gehört findet man im Datasheet:

ADC_Channel_11: PC1
ADC_Channel_12: PC2
ADC_Channel_13: PC3

Hinter PA3/4/5 stecken ADC_Channel_3/4/5

Datasheet Seite 27:
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00220364.pdf

Du hast also die Falschen kanäle eingelesen/die Falschen pins 
Konfiguriert.

btw. Ein grauenhaftes Datenblatt/User Manual...Sehr unübersichtlich und 
die Pin Configuration ist im User Manual gar nicht zu finden. Zumindest 
habe ich sie nicht gefunden.

von (prx) A. K. (prx)


Lesenswert?

Ulf schrieb:

> ich kann ich Datanblatt und der CMSIS Lib nicht nachvollziehen, wie man
> einen GPIO-Pin eines beliebigen Ports mit einem ADC-Kanal verbindet.

Soweit mir erinnerlich tut man das überhaupt nicht, das hat ST für dich 
schon erledigt. Nur eben nicht "beliebig", sondern ein bestimmter 
ADC-Kanal sitzt auf einem bestimmten Portpin.

von (prx) A. K. (prx)


Lesenswert?

Antwort schrieb:

> btw. Ein grauenhaftes Datenblatt/User Manual...Sehr unübersichtlich und
> die Pin Configuration ist im User Manual gar nicht zu finden. Zumindest
> habe ich sie nicht gefunden.

Apropos übersichtlich: Seit sie die Webseite neu definiert haben finde 
ich nicht einmal mehr die Datasheets wieder. In der Reference können die 
Pinout allerdings auch nicht drinstehen, die sind immerhin 
modellspezifisch.

Man muss schon einiges virtuelle Papier zusammenkratzen um die ganze 
Doku zu haben: Reference, Datasheet, Programming Manual und das vom 
Cortex.

von Antwort (Gast)


Lesenswert?

A. K. schrieb:
> Apropos übersichtlich: Seit sie die Webseite neu definiert haben finde
> ich nicht einmal mehr die Datasheets wieder. In der Reference können die
> Pinout allerdings auch nicht drinstehen, die sind immerhin
> modellspezifisch.
>
> Man muss schon einiges virtuelle Papier zusammenkratzen um die ganze
> Doku zu haben: Reference, Datasheet, Programming Manual und das vom
> Cortex.

Hm, also die Aufteilung gefällt mir überhaupt nicht. Da Lobe ich mir die 
User Manuals von NXP/Atmel. Da steht immer alles in einem Dokument und 
ist auch auf der Seite elicht zu finden.
Aber das hat mit dem Problem des Thread-Autors nichts zu tuen. Daher 
würde ich diese Absschweifung gerne an dieser Stelle beenden und zum 
eigentlich Problem zurückkehren.

von Ulf (Gast)


Lesenswert?

Leute! Super geil!

Ich bin auch total am verzweifeln mit diesem - tschuldigung - 
DRECKS-MANUAL.
Jeder Atmega hat ein bessere Doc. Bin bisher mit der Doku von Freescale 
(S12X...) ganz gut ausgekommen und kann mich mit der von ST nich 
anfreunden.

Vielen lieben Dank und einen schönen Abend euch.
Ulf

von Ulf (Gast)


Lesenswert?

P.S.: der Oberwitz ist ja, dass dieses im Vergleich zum "Reference 
Manual" sehr sinnvolle Dokument nicht mal einen anständigen Namen hat, 
sodass man es chance hätte es wieder zu finden. Ich muss es jetzt unter 
"STM32F107xx.pdf" speichern...

---> Und die Hompepage von ST ist an Unübersichtlichkeit kaum zu 
übertreffen. Grauenhaft.

bye

von Ulf (Gast)


Lesenswert?

So, jetzt habe ich meine ganzen ADC Einstellungen hinter mir.

Mein System zur Motorsteuerung hat ein Shunt, an dem ich zweimal pro PWM 
zyklus per Injection die Spannung messen möchte, und 5 weitere Kanäle, 
die einfach im autoscan-mode gewandelt werden sollten.

Die Injections starte ich ja per Software durch den Befehl:

ADC_SoftwareStartInjectedConvCmd(ADC1, ENABLE);

Bekomme ich dann sofort nach Ende der ersten Conversion einen Interrupt, 
oder erst wenn beide Messungen durch sind? Ich habe gelesen, dass man 
den DMA-Controller nutzen muss... stimmt das? Muss ich da aktiv was 
machen oder ist dieser per default aktiv?

mein ADC-Interrupt sieht im Moment so aus:

ADC_ClearFlag(ADC1, ADC_FLAG_JEOC);
Shunt_Messung1 = 
ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
Shunt_Messung2 = 
ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2);



Bei der regular channels muss ich doch bestimmt noch ein paar Befehle 
ausführen um die Conversion zu starten, oder?

Und wie mache ich den Zugriff auf die kontinuierlich gewandelten 
Messwerte? Würde diese gerne im Pollingmodus abholen.


Anbei aktueller Code zur Initialisierung der ADC Kanäle nach dem Studium 
des "guten" Dokuments...

/* Configure ADC */


/* enable ADC1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
                       RCC_APB2Periph_ADC1, ENABLE);

/* ADC Channel Mapping Port A
  Pin A1: Onboard Poti  --> ADC Channel 1
  Pin A3: U_Shunt    --> ADC Channel 3
  Pin A6: U_DC_BUS  --> ADC Channel 6
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* ADC Channel Mapping Port B
  Pin B0: Current Phase A  --> ADC Channel 8

      */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* ADC Channel Mapping Port C
  Pin C4: Temperature LOW SIDE  --> ADC Channel 14
  Pin C5: Current Phase B    --> ADC Channel 15
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);


/* Configure ADC1 */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 5;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_InjectedSequencerLengthConfig(ADC1, 2);

ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 1, 
ADC_SampleTime_7Cycles5);
ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 2, 
ADC_SampleTime_7Cycles5);


/* ADC1 injected external trigger configuration */
ADC_ExternalTrigInjectedConvConfig(ADC1, 
ADC_ExternalTrigInjecConv_None);


/* Enable ADC1 JEOC interrupt */
ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);

/* Check the end of ADC1 reset calibration */
while (ADC_GetResetCalibrationStatus(ADC1) == SET) ;

/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);

/* Check the end of ADC1 calibration */
while (ADC_GetCalibrationStatus(ADC1) == SET) ;

/* Start ADC1 Software Conversion */
ADC_SoftwareStartInjectedConvCmd(ADC1, ENABLE);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/* Enable the ADC Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);


Danke für die Mithilfe und guten Abend!

von J. S. (grooc)


Lesenswert?

Hallo ich muss diesen Beitrag nochmal aufgreiben weil mir eine sache 
nicht klar ist. Mit der Konfiguration:
1
ADC_InjectedChannelConfig(ADC1, ADC_FB_VOLTAGE, 1, 
2
ADC_SampleTime_7Cycles5);
3
ADC_InjectedChannelConfig(ADC1, ADC_BAT_VOLTAGE, 2, 
4
ADC_SampleTime_7Cycles5);

In diesem Abschnitt werden die InjectedChannel konfiguriert. Bekommt man 
mit dem Befehl,
1
 ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
dann den Wert von "ADC_FB_VOLTAGE" oder von dem ADC_Channel_1 ? Also 
bezieht sich der Index der InjectedChannel auf das Ranking der CHannels 
oder muss man das noch irgendwo mappen?

von Michael M. (eos400dman)


Lesenswert?

Hallo,

also meines Wissen nach funktioniert das so wie du es beschrieben hast 
also mit:
1
  ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
 bekommst du denn Wert von ADC_FB_VOLTAGE.

Allerdings habe ich auch eine Frage zu:
Ulf schrieb:
> ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 1,
> ADC_SampleTime_7Cycles5);
> ADC_InjectedChannelConfig(ADC1, ADC_Channel_3, 2,
> ADC_SampleTime_7Cycles5);

Funktioniert das bei dir wenn du zwei InjectedChannel auf den gleichen 
ADC_Channel definiert? Bei mir funktioniert die Messung zwar, allerdings 
bekomme ich dann immer Ergebnisse die sehr nahe beieinander liegen 
obwohl sie völlig verschieden sein sollten. Und da nirgends definitiv 
steh ob das geht oder nicht bin ich mir unsicher.

Vielen Dank für die Hilfe und viele Grüße
Michael

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.