Guten Morgen zusammen, ich bin gerade auf der Suche nach einer etwas ausführlicheren Beschreibung der ADCs des STM32F103, als es das Reference Manual RM0008 bieten kann. Mein Anwendungsfall ist folgender: Ich habe eine PWM mit einer Pulslänge von 2-80µs und einem Duty Cycle von maximal 30%, d.h. nach jedem Puls ist mindestens 4µs Zeit. Ich will einen ADC-Kanal während des Pulses so oft wie möglich abtasten. In der Pause danach ist ja genügend Zeit, das zu verarbeiten. Weiter will ich die Pause nutzen, um noch mehrere andere ADC-Kanäle abzutasten, bei denen mir die Abtastrate fast egal ist (OK, 10Hz sollten es schon mindestens sein). Vermutlich brauche ich also zwei Interrupt-Routinen in der PWM, die den ADC zwischen einem interleaved-Messen beider ADCs mit DMA für die schnellen Kanäle und dem langsamen einzelnen Samplen der langsamen Kanäle umschalten. Leider habe ich noch keine schöne Beschreibung der Nutzung dieser Modi gefunden. RM0008 zeigt zwar schön, was geht, aber ich verstehe noch nicht, wie man es benutzt. Viele Grüße W.T.
:
Bearbeitet durch User
m m schrieb: > http://www.diller-technologies.de/stm32.html Naja, also ein Geheimtipp ist das aber nicht gerade. Freilaufend funktioniert der ADC schon lange. Ich suche eine Übersicht zu der Arbeit mit den injected channels.
Gibt es keine übersichtlichere Dokumentation der ADC-Funktionen als die "stm32f10x_stdperiph_lib_um.chm" ? Da muß man nach jedem Parameternamen den Quelltext mit dem RM0008 vergleichen oder Googlen, wenn man nicht sicher ist, ob er nur das bedeutet, was der Name suggeriert.
OK, wenn hier keine sinnvollen Antworten kommen, dokumentiere ich das, was ich finde mal selbst - für den Fall, daß jemand per Google hierhingestoßen wird, weil er dasselbe sucht. Eine gut lesebare Übersicht über die ADC-Modi liefert die Application Note AN3116 "STM32's ADC modes and their applications". Damit kennt man die Namen, die ST benutzt. Damit wiederum ist dann in der "stm32f10x_stdperiph_lib_um.chm"-Doku das Beispiel "STM32F10x_StdPeriph_Examples/ADC/3ADCs_DMA/main.c" ganz gut lesbar.
In fast allen ADC-Beispielen mit DMA steht das folgende Define:
1 | #define ADC1_DR_Address ((uint32_t)0x4001244C)
|
Was bedeutet diese Adresse? Man kann sich in der stm32f10x.h entlanghangeln zu: PERIPH_BASE -> APB2PERIPH_BASE -> ADC1_BASE + 0x4C Aber was ist der Offset von 4C?
> Aber was ist der Offset von 4C?
Abschnitt 11.12.13 im REF-2011
ADC injected data register x (ADC_JDRx) (x= 1..4)
Address offset: 0x3C - 0x48
Bits 31:16 Reserved, must be kept at reset value.
Bits 15:0 JDATA[15:0]: Injected data
These bits are read only. They contain the conversion result from
injected channel x. The data is left or right-aligned as shown in Figure
27 and Figure 28.
Danke für die Antwort. Allerdings bin ich jetzt etwas aufgeschmissen. Ich war bis jetzt davon ausgegangen, den Regular Mode mit DMA zu nutzen. Momentan sieht mein Plan (mit noch nicht ganz der Zielfunktionalität) so aus, alle Kanäle per DMA in ein Array zu bringen und nach der Wandlung des letzten Wertes per Interrupt zur Weiterverarbeitung zu kopieren. So habe ich zwar noch nicht die ganze maximale ADC-Rate, aber immerhin schon ein Viertel. Sozusagen zum kennenlernen.
Ist doch auch möglich 11.12.14 ADC regular data register (ADC_DR) Address offset: 0x4C RM0008 Seite 247... ja ist ein wenig verwirrend, aber es geht schon. Viel Erfolg Gruß Ert
Nils P. schrieb: > 0x4C Stimmt, das hatte ich überlesen. Aus irgendeinem Grund funktioniert das Ganze allerdings noch immer nicht; aus dem struct gls_adc werden alle Werte als 0 ausgelesen. Und beim zweiten Aufruf von edm_adc_init() bleibt sie in einer Endlosschleife hängen.
Ich habe die Interrupt-Routine mal auf einen Pin gelegt: Sie wird nie aufgerufen:
1 | void ADC1_IRQHandler (void) { |
2 | GPIO_SetBits(SPARE1_GPIO,SPARE1_Pin); |
3 | |
4 | if(ADC1->SR & ADC_SR_EOC) { |
5 | gls_adc.sensep = (ADC1ConvertedValues[0] |
6 | + ADC1ConvertedValues[2] \ |
7 | + ADC1ConvertedValues[4] \ |
8 | + ADC1ConvertedValues[6] \ |
9 | + ADC1ConvertedValues[8] \ |
10 | + 3*gls_adc.sensep)/8; |
11 | |
12 | gls_adc.sensem = (ADC1ConvertedValues[1] + 3*gls_adc.sensep)/4; |
13 | |
14 | gls_adc.updwn = (uint8_t) (ADC1ConvertedValues[3] >> 4); |
15 | gls_adc.iSet = (uint8_t) (ADC1ConvertedValues[5] >> 4); |
16 | gls_adc.tOff = (uint8_t) (ADC1ConvertedValues[7] >> 4); |
17 | gls_adc.tOn = (uint8_t) (ADC1ConvertedValues[9] >> 4); |
18 | |
19 | |
20 | }
|
21 | GPIO_ResetBits(SPARE1_GPIO,SPARE1_Pin); |
22 | }
|
Müssen Interrupts vielleicht noch irgendwo global eingeschaltet werden? Und fängt die Liste der ADC-RegularChannel wirklich mit 1 an?
:
Bearbeitet durch User
OK, den DMA1-Clock hatte ich vergessen. Und in keinem Tutorial finde ich noch eine extra-Aktivierung der Interrupts. Dummerweise funktioniert der IRQ immer noch nicht.
:
Bearbeitet durch User
Die ADC-Wandlung läuft und der IRQ für die fertige Wandlung wird mit der richtigen Taktfrequenz aufgerufen. Vorher hatte ich einige Fehler gemacht: Es wird nicht der ADC-Interrupt sondern der DMA-Interrupt gebraucht. Durch die Display-Darstellung sieht man, daß das Array "ADC1ConvertedValues[10]" mit plausiblen Werten gefüllt wird. Allerdings ergeben sich beim Kopieren in das struct "gls_adc" im DMA1_Channel1_IRQHandler total inplausible Werte - so als hätte das Array zum Zeitpunkt des IRQs komplett andere Werte, als wenn es in der Hauptschleife aufgerufen wird. Wird im IRQHandler der Wert hart gesetzt (z.B. gls_adc.tOn = 3;) stimmt alles. "gls_adc" ist wie folgt deklariert und definiert:
1 | typedef struct { |
2 | uint16_t sensep; |
3 | uint16_t sensem; |
4 | uint8_t iSet; |
5 | uint8_t tOn; |
6 | uint8_t tOff; |
7 | uint8_t updwn; |
8 | } gls_adc_t; |
9 | |
10 | volatile gls_adc_t gls_adc; |
11 | |
12 | ...
|
13 | // In *.c-Datei:
|
14 | volatile gls_adc_t gls_adc = {0xAAAA,0xAAAA,0xAA,0xAA,0xAA,0xAA}; |
Gibt es die Möglichkeit, in einen IRQ zu debuggen? Viele Grüße W.T.
Es ist wie verhext. Der IRQ-Handler scheint sehr empfindlich gegenüber Veränderungen zu sein: Werden zwei zusätzliche Variablen "gl_a" und "gl_b" einkommentiert, hängt sich das Programm auf. Der Inhalt des globalen Structs "gls_adc" scheint nichts mit dem Inhalt von ADC1ConvertedValues zu tun zu haben (siehe obiges Bild);
1 | extern volatile uint16_t gl_a; |
2 | extern volatile uint16_t gl_b; |
3 | void DMA1_Channel1_IRQHandler(void) { |
4 | gls_adc.sensep = (ADC1ConvertedValues[0] |
5 | + ADC1ConvertedValues[2] \ |
6 | + ADC1ConvertedValues[4] \ |
7 | + ADC1ConvertedValues[6] \ |
8 | + ADC1ConvertedValues[8] \ |
9 | + 3*gls_adc.sensep)/8; |
10 | |
11 | gls_adc.sensem = (ADC1ConvertedValues[1] + 3*gls_adc.sensem)/4; |
12 | |
13 | gls_adc.updwn = (ADC1ConvertedValues[3] >> 4 ); |
14 | gls_adc.iSet = (uint8_t) (ADC1ConvertedValues[5] >> 4); |
15 | gls_adc.tOff = (uint8_t) (ADC1ConvertedValues[7] >> 4); |
16 | gls_adc.tOn = (uint8_t) (ADC1ConvertedValues[9] >> 4); |
17 | |
18 | //gl_a = ADC1ConvertedValues[3];
|
19 | //gl_b = ADC1ConvertedValues[5];
|
20 | |
21 | DMA_ClearFlag(DMA1_FLAG_TC1); |
22 | }
|
Definiert und deklariert sind die globalen Variablen hier:
1 | volatile uint16_t gl_a; |
2 | volatile uint16_t gl_b; |
3 | /* Test der ADC-Routinen (Multiplex und Interrupt-Aufruf) */
|
4 | void edm_test_adc(void) { |
5 | printf_P(PSTR("\fTest EDM-ADC \n" |
6 | "Beenden durch Knopfdruck\a")); |
7 | |
8 | edm_adc_init(); |
9 | printf_P(PSTR("Init OK\n\a")); |
10 | |
11 | edm_adc_start(); |
12 | printf_P(PSTR("Start OK\n\a")); |
13 | |
14 | while(!key_getstroke()) { |
15 | //togglespare2();
|
16 | |
17 | printf_P(PSTR("\fTest EDM-ADC \n"\ |
18 | "Beenden mit Taster\n"\ |
19 | "Sen+=%5u\t"\ |
20 | "Sen-=%5u\t"\ |
21 | "iSet=%5u\t"\ |
22 | "tOn =%5u\t"\ |
23 | "tOff=%5u\t"\ |
24 | "updo=%5u\n"),\ |
25 | gls_adc.sensep,gls_adc.sensem,gls_adc.iSet,gls_adc.tOn,gls_adc.tOff,\ |
26 | gls_adc.updwn); |
27 | printf_P(PSTR("Roh:"\ |
28 | "%4u,%4u,%4u,%4u,%4u,%4u,%4u,%4u,%4u,%4u"),\ |
29 | ADC1ConvertedValues[0],ADC1ConvertedValues[1], |
30 | ADC1ConvertedValues[2],ADC1ConvertedValues[3], |
31 | ADC1ConvertedValues[4],ADC1ConvertedValues[5], |
32 | ADC1ConvertedValues[6],ADC1ConvertedValues[7], |
33 | ADC1ConvertedValues[8],ADC1ConvertedValues[9]); |
34 | |
35 | printf_P(PSTR("|%4u,%u|"),gl_a,gl_b); |
36 | printf_P(PSTR("\n\a")); |
37 | }
|
38 | }
|
Warum steht in "gl_a" 19? Nirgendwo wird hineingeschrieben, die Variable kommt in keiner anderen Datei vor und globale Variablen werden implizit mit 0 initialisiert. Es sieht aus, als wären in den IRQ-Handlern Reste vorheriger Builds - oder als ob Zeiger marodierten.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.