Hallo zusammen, ich versuche nun schon seit einer Woche mit meinem STM32F030 meine Analogeingänge einzulesen. Ich habe erst ein paar kleinere Projekte realisiert und noch nicht mit Timern bzw DMA gearbeitet. Ich weiß nur grob was man damit anstellen kann und bin von den Konfigurationsmöglichkeiten der Timer beim STM32 etwas erschlagen worden... :-/ Nun zu meinem Anliegen. Ich möchte 6 Analogwerte einlesen, PA0 bis PA3 + TSC (Temperatur Sensor Channel) & Vref Channel. Die Abtastrate ist mir zuerst relativ egal. Wenn ich das richtig verstanden habe kann man mit DMA Werte direkt von der Peripherie in den Speicher schreiben lassen. Um das ganze Ressourcenschonend zu gestalten kann man den DMA Prozess intern bzw extern Triggern. Ich würde in meinem Fall gerne mit einem Timer zyklisch die Werte in den Speicher schreiben. Ich hoffe, dass ich das bis hierhin richtig verstanden habe… Habe mit Hilfe des refmanual und der ST Bibliothek unter CooCox einzelne Analogeingänge einlesen können. Jedoch bekomme ich das ganze nicht mit DMA und mehreren Kanälen realisiert. Infos: Ich konnte in den Registern beobachten, dass TIM1->CNT bis zum vorgeschriebenen Wert hochzählt und wieder von vorne beginnt. Das „Transfer Complete Flag“ vom DMA1 Channel 1 wird jedoch nie gesetzt. Ich weiß leider echt nicht mehr weiter und hoffe, dass jemand von euch mir ggf. ein paar Tipps geben kann. Gruß
:
Bearbeitet durch User
Servus, Frank C. schrieb: > Ich konnte in den Registern beobachten, dass TIM1->CNT bis zum > vorgeschriebenen Wert hochzählt und wieder von vorne beginnt. > Das „Transfer Complete Flag“ vom DMA1 Channel 1 wird jedoch nie gesetzt. wo ist dein:
1 | TIM1_IRQHandler(){ |
2 | und
|
3 | TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //hier den richtigen flag raussuchen |
4 | |
5 | //ADC val bearbeiten
|
6 | }
|
Du triggerst den ADC Port durch einen Timer. Du brauchst da nicht die DMA flags zu betrachten.
Benötigt man für DMA einen Interrupt? Ich dachte, dass das konfiguriert wird und dann der µC selbstständig im Hintergrund erledigt? Wenn ich den Interrupt benötigt stellt sich für mich nur die Frage was ich da rein programmieren soll um den ADC-DMA Prozess zu triggern...
:
Bearbeitet durch User
Also, beim starten werden die Analogwerte ein mal in das angelegte Array übertragen, danach nie wieder. Ich habe nun mal IRQ Handler vom TIM1 aktiviert, weiß jedoch nicht so genau was ich da machen soll. Ich kann mir trotz Bedienungsanleitung kein Bild davon machen was z.B. das "Capture Interrupt Flag" bzw "Update Interrupt Flag" bedeuten sollen. Bzw wann die genau gesetzt werden und was ich als Reaktion darauf im IRQHandler programmieren soll. Anscheinen habe ich noch nicht so ganz verstanden, wie der Prozess, ADC, DMA, TIM funktioniert. Mit der Bedienungsanleitung komme ich leider nicht so weit, weil ich mir unter den "Fachvokabeln" nicht viel vorstellen kann :-/ Ich glaube es stimmt etwas mit Timer <> ADC-triggerung nicht. Der Counter zählt zwar seine Runden, triggert jedoch nicht den Analogconvertierungsprozess. Hat vielleicht jemand eine Idee?
Frank C. schrieb: > Ich habe nun mal IRQ Handler vom TIM1 aktiviert, weiß jedoch nicht so > genau was ich da machen soll. aSma>> schrieb:
1 | TIM1_IRQHandler(){ |
2 | und
|
3 | TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //hier den richtigen flag raussuchen |
4 | |
5 | ===>DMA ADC val bearbeiten |
6 | }
|
Poste dein Tim1 Handler. > Anscheinen habe ich noch nicht so ganz verstanden, wie der Prozess, ADC, > DMA, TIM funktioniert. Ja, TIM1_IRQHandler() wird zyklisch aufgerufen, nur wenn der passende UIF gelöscht wurde. Dort tust du deine Daten bearbeiten. Also dein DMA Array umkopieren oder was auch immer.
Ich verstehe nur nicht so ganz was ich dann in dem IRQ-Handler machen soll. Die Daten sollen doch eigentlich direkt in "volatile uint16_t ADCReadBuffer[6];" geschrieben werden. Das würde mir erstmal reichen. Da ich nicht weiß was UIF ist und wie es funktioniert bzw was es bewirkt, kann ich damit nicht viel anfangen. Erstmal muss ja in den control registern konfiguriert werden was genau den interrupt auslösen soll. Hier habe ich einfach mal CC1IE (Capture/Compare 1 interrupt enable) aktiviert. Ich habe jedoch keine Ahnung was das bedeutet, ich vermute das er den IRQ Handler auslöst, wenn der Counter seinen Wert erreicht hat und wieder zurückgesetzt wird. Oder macht das der UIF? In meinem IRQ Handler mache ich gerade nicht besonderes, ich setze nur das Flag zurück. Demnach ist der ganze Interrupt aus meiner Sicht vorerst überflüssig. Ich könnte diesen zwar dazu nutzen um die Daten aus "ADCReadBuffer[6]" irgendwoanders hin zu kopieren. Jedoch würde das erst dann Sinn machen, wenn in "ADCReadBuffer[6]" auch endlich die Werte meiner Analogeingänge geschrieben werden. TIM1_IRQHandler() { TIM_ClearITPendingBit(TIM1, TIM_FLAG_CC1); }
:
Bearbeitet durch User
Fragen über fragen ==> Reference manual oder Beispiel Code angucken.
Siehe Anhang.
>TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
Das könnte durchaus stimmen. Muss du halt gucken, ob
1 | TIMx->SR &= ~0x0001 // Reset UIF |
Keine Ahnung, ob Bitbanging beim stm32f0 geht. Ich würde
1 | ADC_StartOfConversion(ADC1); |
erst nach der Initialisierung des Timers starten. Du könntest auch mal versuchen im Timer ADC_StartOfConversion zu starten:
1 | TIM1_IRQHandler(){ |
2 | TIM_ClearITPendingBit(TIM1, TIM_IT_Update); |
3 | Timer1_ADC_b=1; //volatile var fuer main |
4 | memcpy(&(DMA_ADC_BUFFER[0]) , &ADC_BUFFER, 12); //hier cpy 12 bytes, 6ADC val |
5 | ADC_StartOfConversion(ADC1); //start next conversation |
6 | }
|
7 | |
8 | //main
|
9 | if(Timer1_ADC_b) |
10 | {
|
11 | Timer1_ADC_b=0; |
12 | |
13 | x=ADC_BUFFER[0]; |
14 | y=ADC_BUFFER[1]; |
15 | //usw
|
16 | }
|
Du kannst auch pollen, oder Systick Handler fuer diese Aufgabe nutzen. Was ich nicht beantworten kann ist, ob bei dieser Methode die ADC Values beim Interrupt "frisch" sind oder "alt".
Erstmal möchte ich mich für die Unterstützung bedanken… aSma>> schrieb: >>TIM_ClearITPendingBit(TIM1, TIM_IT_Update); > Das könnte durchaus stimmen. Muss du halt gucken, obTIMx->SR &= ~0x0001 > // Reset UIF Habe schon alle Funktionen die in den Registern schreiben bzw lesen mit dem Handbuch abgeglichen und die Registern beobachtet. Es werden die richtigen Bits gesetzt... aSma>> schrieb: > Keine Ahnung, ob Bitbanging beim stm32f0 geht. Ich > würdeADC_StartOfConversion(ADC1);erst nach der Initialisierung des > Timers starten. Was bedeutet Bitbanging? Ich habe die Initialisierung mal an das Ende gesetzt. Jedoch ohne Erfolg. aSma>> schrieb: > Du kannst auch pollen, oder Systick Handler fuer diese Aufgabe nutzen. Pollen möchte ich vermeiden. Auf dem guten Stück muss noch RS485, I2C ans Laufen gebracht werden. aSma>> schrieb: > TIM1_IRQHandler(){ > TIM_ClearITPendingBit(TIM1, TIM_IT_Update); > Timer1_ADC_b=1; //volatile var fuer main > memcpy(&(DMA_ADC_BUFFER[0]) , &ADC_BUFFER, 12); //hier cpy 12 bytes, > 6ADC val > ADC_StartOfConversion(ADC1); //start next conversation > } Nicht wundern, ich habe in meinem Projekt andere Pins gewählt um mein Programm mit der Hardware komfortabler testen zu können. Beim aktuellen Code werden einmal beim Aufstarten die richten Werte in ADC_BUFFER bzw u16AnalogValue geschrieben. Danach leider nicht mehr. Wenn ich ADC_StartOfConversion(ADC1) im IRQ-Handler aufrufe werden die Eingänge immer noch nicht zyklisch abgefragt. Die Funktion wird zwar zyklisch aufgerufen, jedoch ändern sich nichts an den Werten im DMA Puffer.
:
Bearbeitet durch User
Ich habe nun ein lauffähiges Programm. Leider Funktioniert das selbstständige Triggern des ADC über einen Timer bei mir nicht :( Der Counter triggert zwar, jedoch wird keine Konvertierung ausgelöst. > ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; > ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; Ich löse nun mit TIM3 (100Hz) einen Interrupt aus und schaue in diesem Interrupt nach ob über DMA neue Daten eingetroffen sind. Wenn dies der Fall ist, kopiere ich die Daten aus dem DMA Speicherbereich und trigger eine neue ADC-Konvertierung. Für den Fall, dass jemand das Programm gebrauchen kann, habe ich es diesem Post abgehangene. Wenn jemand eine elegantere Lösung einfallen sollte, wäre ich über weitere Anregungen nicht abgeneigt. Gruß
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.