Hallo,
ich habe ein Problem mit dem ADC12 des MSP430FG4618 DevBoard.
Ich habe eine Interruptroutine für den ADC-Conversion Vorgang
programmiert, die allerdings nicht mehr verlassen wird, d.h. es wird
nicht mehr in den Main-Loop des Programms zurückgekehrt. Hat jemand eine
Idee, woran das liegen könnte?
Hier erst mal meine init-routine:
1
voidinit_adc(){
2
P6SEL=0x0F;
3
ADC12CTL0=ADC12ON+MSC+SHT0_2;// Turn on ADC12, set sampling time
4
ADC12CTL1=SHP+CONSEQ_1;// Use sampling timer, single sequ
5
ADC12MCTL0=INCH_0;// ref+=AVcc, channel = A0
6
ADC12MCTL1=INCH_1;// ref+=AVcc, channel = A1
7
ADC12MCTL2=INCH_2;// ref+=AVcc, channel = A2
8
ADC12MCTL3=INCH_3+EOS;// ref+=AVcc, channel = A3, end seq
9
ADC12IE=0x08;// Enable interrupt
10
ADC12CTL0|=ENC;// Conversion enabled
11
}
Die wird aufgerufen durch:
1
WDTCTL=WDTPW+WDTHOLD;// Stop watchdog timer
2
FLL_CTL0|=XCAP18PF;// Set LoadCap
3
init_adc();
4
_BIS_SR(CPUOFF+GIE);
und hier jetzt die Routine selbst - die aber eigentlich nicht viel
macht, außer eine Ausgabe auf die Serielle Schnittstelle zu schreiben:
1
__interruptvoidADC_ISR(void);
2
ADC12_ISR(ADC_ISR)
3
__interruptvoidADC_ISR(void){
4
printUART("ADC-IR\r\n",sizeof("ADC-IR\r\n"));
5
_BIC_SR_IRQ(CPUOFF);
6
_NOP();
7
}
Im Main-Loop steht noch folgendes:
1
while(true){
2
P2OUT^=0x02;
3
DC12CTL0|=ADC12SC;
4
for(i=0;i<20000;i++);
5
}
Hat vielleicht jemand eine Idee? Wie gesagt - wird die
Interrupt-Routine, des ADCs nicht verlassen, bzw. dauert so lange, dass
bevor ins Hauptprogramm zurückgesprungen werden kann, wieder die Routine
aufgerufen wird.
Ich kenn mich leider mit dem TI nicht so gut aus, daher wäre - falls es
ein Zeitproblem wäre - die Frage, wie ich die Aufrufzeit der ISR
bestimmen kann. Also wie kann ich einstellen, mit welcher Frequenz der
Interrupt "gefeuert" wird?
Danke GALDO
Mir ist schon bewusst, dass "sowas" ewíg dauert, allerdings - macht es
auch keinen Unterschied, wenn ich das nicht verwende.
Das Problem ist in meinen Augen, dass der Interrupt viel zu hoch
frequentiert ist und ich nicht weiß, wie ich das vernünftig einstellen
kann. Ich habe den Code stellenweiße aus den Beispielen von TI - aber
die Informationen dazu sind sehr gering :(
Er kommt - ob mit oder ohne UART - nicht mehr aus der ISR rauß - somit
wird nur noch eine Wandlung abgearbeitet, ich habe aber auch noch
anderen Code, der mal verarbeitet werden müsste - somit brauch ich
unbedingt noch Ausführungszeit für den Main-Loop.
Hat jemand noch ne Idee?
Danke GALDO
Ich antworte mir mal selbst:
Ich habe jetzt eine BruteForce-Lösung programmiert, allerdings wäre eure
Meinung dazu nicht schlecht.
Ich schalte einfach
1
ADC12IE=0x00;
in der ADC12_ISR, mit einem Timer von etwa 4Hz bis 6Hz (müsste man mal
mim Oszi plotten), schalte ich jetzt einfach mit dieser Frequenz die
1
ADC12IE=0x0F;
und damit ein.
Das funktioniert soweit ganz gut - allerdings habe ich damit noch keine
tatsächliche Wandlung versucht - das werde ich demnächst mal testen.
Aber das wäre - sofern es funktioniert - genau das was ich brauche, AD
auslesen, wandeln, zurückschicken - warten - AD auslesen, wandeln,
zurückschicken - warte - etc.
Wie würdet ihr obige Anforderung implementieren?
Danke für weitere Anregungen und Hinweise
GALDO
Andreas del Galdo wrote:
> Aber das wäre - sofern es funktioniert - genau das was ich brauche, AD> auslesen, wandeln, zurückschicken - warten - AD auslesen, wandeln,> zurückschicken - warte - etc.>> Wie würdet ihr obige Anforderung implementieren?
Nicht so.
Eher so:
Interrupt kommt
ADC wird ausgelesen
Wert wird in einer globalen Variablen bereitgestellt
zusätzliche globale Variable auf 1 setzen (das sog. Jobflag)
um der ganzen Welt anzuzeigen, dass ein ADC Wert verfügbar ist
und etwas damit gemacht werden müsste.
Interrupt fertig
In der Hauptschleife in main()
while( 1 ) {
das Jobflag für den ADC abfragen
ist es 0 -> kein Wert da, weiter wie bisher
ist es 1 ->
Interrupt sperren
Wert von der globalen Variablen wegholen
Jobflag wieder auf 0 setzen.
Interrupt freigeben
Wert formatieren und über UART ausgeben
}
Auf die Art ist die Interrupt Routine so kurz wie es nur
irgendwie geht und lässt noch jede Menge Rechenzeit für
anderes übrig.
Ist das ein Schreibfehler? Da fehlt das A. Außerdem: Sobald das SC Bit
gesetzt wird, startet der Sequenzer und wandelt die 4 Werte und löst den
Int aus.
Außerdem muss man soweit ich mich erinnere, das ADC12IFG Register selber
löschen, weiß nich ob das nen Bug ist oder gewollt....
Ich hab jetzt mal ein Netzgerät angeschlossen (den Pluspol an einen
Kanal) und siehe da - es kommt Käse rauß...
Ohne Irgendwas dran hätte doch eigentlich als 0 1,25V raußkommen sollen
- und was bekomme ich:
1
Result: 0.318V, 0.923V, 0.001V, 0.732V
Sobald ich dann das Netzgerät - eingestellt auf etwa 3V anschließe
bekomme ich so abstruße Werte wie 0V, oder 4,2V nur nicht drei - und es
kommt auch drauf an, wo ich das Netzgerät anschließe - die Werte ändern
sich an jedem Kanal anders.
Hier nochmal der Init-Code:
1
voidinit_adc(){
2
P6SEL=0x0F;
3
ADC12CTL0=ADC12ON+MSC+SHT0_2;
4
ADC12CTL1=SHP+CONSEQ_1;// Use sampling timer, single sequ