Forum: Mikrocontroller und Digitale Elektronik MSP430 ADS7888 RS232


von rico (Gast)


Angehängte Dateien:

Lesenswert?

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

von Stefan (Gast)


Lesenswert?

>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
                                                 Samples pro sekunde
Was hast Du denn für'n Super-MSP erwischt ;-)
Mein Timer_A hat nur 16-bit, also maximal 65535

von rico (Gast)


Angehängte Dateien:

Lesenswert?

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;

von Christian R. (supachris)


Lesenswert?

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.

von rico (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Stefan (Gast)


Lesenswert?

>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"

von Stefan (Gast)


Lesenswert?

>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...

von rico (Gast)


Angehängte Dateien:

Lesenswert?

>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?

von rico (Gast)


Lesenswert?

habe den letzten kommentar nicht gelesen, dann hat sich meine frage 
erledigt. denke ich. ich glaube ich habe es gerafft...

von Christian R. (supachris)


Lesenswert?

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.

von rico (Gast)


Lesenswert?

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

von Stefan (Gast)


Lesenswert?

1
Error: main5.c missing

von Christian R. (supachris)


Lesenswert?

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.

von rico (Gast)


Angehängte Dateien:

Lesenswert?

dauerte ein wenig, da ich die datei zerstörte und noch mal schreiben 
musste.....

von Stefan (Gast)


Lesenswert?

1
do 
2
{
3
  IFG2 &=~ URXIFG1;                    // URXIFG1 = 0 in IFG2 register
4
} while (URXIFG1 & IFG2);       
5
ADC_Byte1=RXBUF1;
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
3
ADC_Byte1=RXBUF1;

von rico (Gast)


Angehängte Dateien:

Lesenswert?

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 ....

von Stefan (Gast)


Lesenswert?

>hiermit funktioniert es.
Ganz ehrliche Antwort?
Glaub ich nicht!

Übrigens, ich korrigiere mein letzes Posting:
1
while (!(IFG2 & UTXIFG1));   // USART1 TX buffer ready?
2
IFG2 &=~ URXIFG1;            // RX-Flag löschen
3
TXBUF1 = 0x00;               // Byte senden
4
while (~(URXIFG1 & IFG2));   // solange warten, bis Byte komplett empfangen     
5
ADC_results[2*(sample_count)]=RXBUF1;

von rico (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Christian R. (supachris)


Lesenswert?

Ich mach das immer so: (für einen LTC1864L)
1
volatile UINT16 ActualSample;
2
volatile unsigned char* pRawSampleHigh = (unsigned char*)&ActualSample;
3
volatile unsigned char* pRawSampleLow = (unsigned char*)(&ActualSample)+1;
4
5
void SPIGetData(void)
6
{
7
      while (!(IFG2 & UTXIFG1));                // USART1 TX buffer ready?
8
        TXBUF1 = 0x00;
9
        do
10
        {
11
          IFG2 &=~ URXIFG1;
12
        }
13
        while (URXIFG1 & IFG2); 
14
15
        *pRawSampleHigh = RXBUF1;
16
        
17
        while (!(IFG2 & UTXIFG1));                // USART1 TX buffer ready?  
18
        TXBUF1 = 0x00;      
19
        
20
        do
21
        {
22
          IFG2 &=~ URXIFG1;
23
        }
24
        while (URXIFG1 & IFG2);
25
    
26
        *pRawSampleLow = RXBUF1;
27
28
}

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.

von Stefan (Gast)


Lesenswert?

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

von rico (Gast)


Lesenswert?

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?

von rico (Gast)


Angehängte Dateien:

Lesenswert?

jetzt dauert der prozess seine 1ms. bin aber mit dem programm (main7.c) 
wieder in die isr gewandert :/. toll finde ich das auch nicht.

von Stefan (Gast)


Lesenswert?

>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!

von rico (Gast)


Lesenswert?

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:

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.