Hallo,
ich habe da ein paar Fragen.
Benutzt wird der MSP430F149, Takt 7,3728 MHz (ACLK), IAR Software.
ADS7888 (8bit ADC)
Funktionsweise des Programms:
Programm soll den Timerwert hochzählen und danach jeweils die Daten aus
dem ADC auslesen und dann zum PC über RS232 schicken.
Das Programm (siehe Anhang) läuft durch, wenn man segmentweise
durchgeht, aber nicht, wenn es alleine durchlaufen soll (run). Leider
wird kein Fehler angezeigt, deswegen bin ich aufgeschmissen. Kann jemand
helfen
Danke im Voraus
Rico
>Das Programm (siehe Anhang) läuft durch, wenn man segmentweise>durchgeht, aber nicht, wenn es alleine durchlaufen soll (run).
Was heißt segmentweise?
Debug-Modus Einzelschritt oder mit Breakpoints oder was?
Überprüfe Deinen Code nochmal auf "groben Unfug" oder bei der
Formatierung ist was schiefgelaufen...
Einige Ungereimtheiten:
1
//Timereinstellungen
2
CCR0=0;// z�hlt bis 500
3
TACTL=TASSEL_1+MC_2;// ACLK, upmode
4
CCTL0=CCIE;// CCR0 timer interrupt enabled
das zählt alles mögliche aber bestimmt nicht 500 !
1
//Wenn interrups nicht zur�ckgesetzt werden l�uft die ISR immer weiter
2
{
3
4
TACCR0+=7372800;// ACLK/1000 = ca 7372 f�r 1000
5
Samplesprosekunde
Was hast Du denn für'n Super-MSP erwischt ;-)
Mein Timer_A hat nur 16-bit, also maximal 65535
Was heißt segmentweise?
Damit ist das Schrittweise weitergehen im Debug-Modus gemeint. Das mit
den Zählerständen habe ich gestern Abend geändert, natürlich ist es
ziemlicher Unfug, aber ich denke nicht, dass es wirklich daran liegt.
Sondern irgendwas mit den Interrupts nicht funktioniert.
Im Debug-Modus liest er die gewandelten U-Werte aus dem ADC und schickt
sie danach zum PC.
Der MSP soll, solange wie er funktionstüchtig ist, in der ISR bleiben
und nur das eine machen.... (erstmal)
Mittlerweile habe ich das Programm umgeändert und habe jetzt die Stelle
an der es "stockt" und zwar sendet er immer noch nicht und ich glaube es
hat was mit den folgenden Zeilen zu tun. Oder muss ich irgendwelche
Zeiten einhalten oder noch andere Register umschreiben?
hier >>UCTL0 &= ~SWRST; // USART freigeben
IE1 |= UTXIE0; // + UTXIE0 TX- und
RX-interrupts anschalten
zeigerText = & (ADC_results[(sample_count)]);
while (!(IFG1 & UTXIFG0));
TXBUF0 = (*zeigerText++);
UCTL0 = 0x11;
IE1 = 0x00;
Also ich wette mal, dass deine ISR so lange dauert, dass in der
Zwischenzeit schon wieder der Timer rumgekommen ist. Wenn ich das
richtig sehe, hast du jetzt 7,3728MHz / 65000, das bedeutet, dein
Timer-Int kommt alle 8,8ms.
Und woher soll deine UART-Sende-Routine eigentlich wissen, wieviele
Bytes sie versenden soll? Da dieht irgendwie kein Schwein durch. Der
Kompiler müsste doch auch zumindest jede Menge Warnungen ausspucken, was
soll bitte "volatile unsigned transmit" darstellen?
Alles in die ISR zu packen, ist grober Unsinn, sowas macht man indem man
in der ISR ein Flag setzt, und in der Hauptschleife dann schaut, was zu
tun ist.
Das Bitegeschiebe kannst du dir sparen, wenn du gleich 2 Pointer auf ein
Result-Register machst und die direkt beschreibst. Und dann aus dem
Result-Register in das Array kopieren. Geht viel schneller. Mit viel
Glück optimiert das der Compiler so hin, aber nur mit Glück.
Miss mal nach, wie lange deine ISR dauert.
Volantine:
Zur Optimierung von Rechenprozessen versucht der Compiler, so viele
Werte wie moeglich in den Prozessor-Registern zu halten. Das kann unter
Umstaenden in die Hose gehen, weil sich Speicherinhalte auch ohne Wissen
des Compilers aendern koennen (z.B. Timer). Mit "volatile" wird der
Compiler angewiesen, einen Code zu erzeugen, der jedesmal bei Benutzung
der volatile-Variablen direkt auf die Speicheradresse zugreift und diese
niemals in einem Prozessor-Register haelt
Fehler/Warnungen wurden nicht angezeigt!
Ich kürzte mal mein Programm und grenzte den Fehler ein. Dieser löst
aus, wenn diese beiden Befehle
1. _BIS_SR(GIE);
2. IE1 |= UTXIE0 ;
zusammentreffen.
Irgendwie vertragen die beiden sich nicht. Wenn der 1. gesetzt ist dann
unterbricht das Programm, wenn der 2. Befehl ausgeführt wird....
wenn ich 2. raus nehme dann funktioniert es (siehe main3).
Wie misst man die Dauer eines Programmdurchlaufs? Mache das gerade mit
dem Oszilloskop. Wieviel Takte benötigen eigentlich die einzelnen
Befehle? Kann das irgendwo nachgelesen werden?
>1. _BIS_SR(GIE);>2. IE1 |= UTXIE0 ;>Irgendwie vertragen die beiden sich nicht.
Hä?
2. aktiviert den USART Transmit-Interrupt
1. ist die globale Interruptfreigabe, ohne die geht 2. auch nicht!
Die müssen sich vertragen und tun das auch, weil's so gewollt ist!
Der Fehler liegt wo anders!
>Wie misst man die Dauer eines Programmdurchlaufs? Mache das gerade mit>dem Oszilloskop.
GPIO an Anfang des Programabschnitts setzen und am Ende zurücksetzen.
Impulsbreite mit Oszi messen = Dauer
>Wieviel Takte benötigen eigentlich die einzelnen>Befehle? Kann das irgendwo nachgelesen werden?
Sicher doch! Im User-Guide am Ende des Kapitels "Instruction Set"
>2. IE1 |= UTXIE0 ;>Irgendwie vertragen die beiden sich nicht. Wenn der 1. gesetzt ist dann>unterbricht das Programm, wenn der 2. Befehl ausgeführt wird....
Hmm... und wo ist die ISR für UTXIFG ?
Vergessen zu posten oder keine definiert?
Falls nicht definiert, ist klar dass sich der µC aufhängt, weil er ins
Nirwana springt...
>Hä?
Hä?
habe ja nicht so viel code geschrieben. ging daher nochmals die register
im datenblatt durch. habe keinen weiteren fehler gefunden.
ich habe noch eine frage und zwar, wenn IE1 |= UTXIE0; nicht gesetzt
ist, kann dann der msp überhaupt daten über die uart senden? was macht
der UTXIE0 interrupt?
rico wrote:
> Zur Optimierung von Rechenprozessen versucht der Compiler, so viele> Werte wie moeglich in den Prozessor-Registern zu halten. Das kann unter> Umstaenden in die Hose gehen, weil sich Speicherinhalte auch ohne Wissen> des Compilers aendern koennen (z.B. Timer). Mit "volatile" wird der> Compiler angewiesen, einen Code zu erzeugen, der jedesmal bei Benutzung> der volatile-Variablen direkt auf die Speicheradresse zugreift und diese> niemals in einem Prozessor-Register haelt
Das weiß ich selbst. Ich meinte eher das Weglassen des eigentlichen
Typs. "volatile unsigned transmit" wird laut C-Standard als int
angenommen, aber willst du das?
Und was willst denn mit dem TX-Interrupt? Der kommt, wenn ein Byte
fertig über die USART geschickt wurde. Wenn du da keine ISR deklariert
hast, und du aktiviert den GIE, krachts natürlich beim Eintreffen des
TX-Interrupts.
volatile nutzte wegen des flags, welches ich in der ISR setzte, aber
durch den fehlerhaften Interrup "IE1 |= UTXIE0;" kam der flag nicht wie
erwartet und das wollte ich mit "volatile unsigned transmit"
erschlagen....
aber ich habe noch ein anderes porblem und zwar bezieht sich das auf den
ADS7888. das im programm (main5.c) läut im debug-modus einwandfrei
durch, aber im run-modus kommen am µC nur 0x00 an. Wieso?
ich schrieb noch ein anderes programm , welches nur 100 werte
hintereinander aus dem ADC lies und speichert. das funktioniert!
komisch, weil ich ja auch nicht unbedingt was anderes mache.
vielleicht durchen die beiden uart, die nicht gleichzeitig initaliliert
sein dürfen oder?????
Gruß R
rico wrote:
> aber ich habe noch ein anderes porblem und zwar bezieht sich das auf den> ADS7888. das im programm (main5.c) läut im debug-modus einwandfrei> durch, aber im run-modus kommen am µC nur 0x00 an. Wieso?
Hmmm...meine Glaskugel sagt immer noch, dass deine ISR viel zu lange
dauert und in der Zwischenzeit der Timer noch paar mal überläuft. Aber
meine Glaskugel kann sich auch täuschen.
Man kann problemlos beide USARTs nutzen, man muss nur aufpassen, dass
man sich mit den ISRs nicht verhaspelt.
Was soll das machen?
Du setzt URXIFG1 zurück und überprüfst in while (URXIFG1 & IFG2)
praktisch sofort danach, ob's schon wieder gesetzt wurde. Wenn nicht,
wird do-while beendet! D.h. Du wartest nicht wirklich auf die Antwort
vom ADS7888!
Besser:
1
IFG2&=~URXIFG1;
2
while(~(URXIFG1&IFG2));// solange warten, bis Byte komplett empfangen
hiermit funktioniert es. habe das programm genommen, welches die daten
hintereinander ausliest und so umgemodelt.... (main6.c)
Wieso es jetzt funktiniert, dass weiß ich nicht. ich denkemal, ein bit
in einem register oder so.
wäre gut zu wissen wo der fehler lag.
danke für die hilfen und antworen :) hilft ja immer weiter, wenn mal
andere gedanken ins hirn kommen ....
habe es gerade nochmal ausprobiert und es geht immer noch. ich
verkleiner die Spannung am ADC input und der gewandelte wert ändert sich
wie erwartet .....
was soll ich tun?
Das aktuelle 16-Bit Sample steht dann in ActualSample.
Diese komische do while Schleife ist schon wichtig, ist auch in den
TI-Beispielen so. Interessiert aber nur, wenn man das Chip-Select dann
wieder bedienen muss. Das CS ist beim LTC1864 gleichzeitig der
Sample-Start, das bediene ich mit dem Timer A und einer geschickten
Verknüpfung der Output-unit mit 2 CCR Registern und dem CCR-Interrupt.
Somit hab ich eine äquidistante Abtastung, weil das CS in Hardware
generiert wird.
Arrghhhhh!!!!
Jaja...SPI ist ja synchron, war irgendwie bei UART....
Sicher braucht man eine Abfrage, ob die Daten schon komplett empfangen
wurden, aber diese ominöse do-while Schleife halte ich nach wie vor für
falsch, auch wenn TI sie postuliert! Oder steh ich jetzt total auf'm
Schlauch???
1
do
2
{
3
IFG2&=~URXIFG1;
4
}while(URXIFG1&IFG2);
Zuerst lösche ich URXIFG1 und frage gleich danach ab, ob's wieder
gesetzt wurde. Wenn der Code schneller durchläuft, als die
SPI-Datenübertragung braucht, dann bin ich in der while-Abfrage, bevor
die Daten komplett übertragen wurden, URXIFG1 ist dann noch nicht
gesetzt und ich verlasse do-while --> Fehler!
Ich glaube das Programm funktioniert trotzdem, weil die SPI mit hoher
Baudrate betrieben wird und do-while einfach als Delay wirkt... wäre
aber genausogut durch ein paar NOP's erledigt!
Die für mich richtige Implementierung ist immer noch:
1
TXBUF1=0x00;// Byte senden
2
while(~(URXIFG1&IFG2));// solange warten, bis Byte komplett empfangen
Zeit:
Habe jetzt die zeiten durchgemessen: 11,3 µs für ads_results, 10,3 µs
für bitoperatonen,fürden der rest der if schleife kommen ca .9µs drauf.
insgesamt braucht der prozess aber 9"ms" wieso dauert der teil so lange.
bekommt der µC die ISR und die if (k == 1){..} nicht schneller hin? Was
passiert in der Zeit? Hat man da irgedwelchen einfluss, dass schneller
zu machen?
>jetzt dauert der prozess seine 1ms.
Nö, der "Prozess" (was auch immer Du damit genau meinst) ist
wesentlich schneller!
Überschlagsmäßig dauert Deine SPI-Kommunikation 16Bit*2/7,3728MHz =
4,34µs.
Die UART zum PC (8+2)Bit/115200 = 86,8µs
"Echte" Wartezeiten in den while-Schleifen dürfte es nicht geben, da die
Kommunikation ja ansonsten nicht stattfindet. Und der Rest ist
Krims-Krams (10-20µs vielleicht). Kommst'de insgesamt auf ca. 100µs.
Aber das Toggeln der LED (dessen Periodendauer Du wahrscheinlich misst)
geschieht ja auch in Deiner ISR und die wird von Dir genau alle 1ms
aufgerufen!
>bin aber mit dem programm (main7.c)>wieder in die isr gewandert :/. toll finde ich das auch nicht.
Was spricht dagegen?
Bei ISR's muss man sich nur darüber im Klaren sein, dass das was man
darin ausführt erledigt sein muss, bevor der nächste IRQ die ISR
startet!
OK,
dann lasse ich es so wie es ist....
Die Zeit, die das Programm (Prozess) "main6.c" für einen Durchlauf,
sprich das Auslösen des Interrupts und abarbeiten der Befehle, dauert
über 9 ms. Und das verstehe ich nicht ganz. Nur weil ich das Programm
nicht in der ISR durchführe?
Danke nochmals an alle Mitwirkende
Rico: