Forum: Mikrocontroller und Digitale Elektronik Frage zu Multi-Processor-Commnication-Mode (MPCM)


von Humbold (Gast)


Lesenswert?

Hallo,

ich bin dabei ein seriellen Bus über USART aufzubauen. Dafür möchte ich 
dien MPCM benutzen um die angeschlossenen Controller adressieren zu 
können.

Irgendwie funktioniert der Mode aber nicht so richtig.

Ich habe das Format mit 9 Datenbits, 1 Parity, 2 Stoppbits gewählt. Das 
9. DB nur wegen dem MPCM.

Darum habe ich noch folgende Fragen:

Muss ich bei der MAster CPU das MPCM Bit auch setzten? (Habe ich jetzt 
nicht gemacht)
Wird automatisch beim Empfangen (Slave) geschaut ob das TXB8 Bit gestzte 
ist und dann entschieden ob es sich dabei um eine Adresse handelt?
Irgendwie verstehe ich das mit dem MPCM und TXB8 nicht so richtig, wann 
wird welches Bit automatisch gestzt und gelöscht?

Muss ich in der Receive Funktion noch irgendwelche Bits beachten bzw. 
setzten, löschen?

Ich habe das Senden folgender Maßen geschrieben (teilweise aus dem 
Datasheet übernommen):
1
void USART_Transmit_Data( uint16_t data )
2
{
3
  uint8_t byte;
4
  uint16_t word=data;
5
  byte=word;
6
  for(uint8_t i=0; i<=1; i++)
7
  {                  /* Wait for empty transmit buffer */
8
    
9
    while ( !( UCSRA & (1<<UDRE)) );
10
    UCSRB &= ~(1<<TXB8);      //TXB8: 0= Daten Senden                    /* Put data into buffer, sends the data */
11
    UDR = byte;
12
    while ( !( UCSRA & (1<<TXC)) );
13
    UCSRA |=(1<<TXC);
14
    byte=(word>>8);
15
  }
16
}
17
18
void USART_Transmit_Adress( uint8_t adress )
19
{
20
                /* Wait for empty transmit buffer */
21
    while ( !( UCSRA & (1<<UDRE)) );
22
    UCSRB |= (1<<TXB8);      //TXB8: 1=Adresse senden                    /* Put data into buffer, sends the data */
23
    UDR = adress;
24
    while ( !( UCSRA & (1<<TXC)) );
25
    UCSRA |=(1<<TXC);
26
  
27
}
28
29
unsigned char USART_Receive( void )
30
{
31
  unsigned char status, daten;
32
    
33
  while ( !(UCSRA & (1<<RXC)) );
34
  
35
  status=UCSRA;  //Flags sichern
36
  daten=UCSRB;  //Verwerfen des 9Bits 
37
  
38
  if(!(status & ((1<<FE)|(1<<DOR)|(1<<UPE))))
39
    return UDR;
40
  else
41
    return 0;
42
}

Also das Senden und Empfangen funktioniert ohne Probleme, nur es wird 
nicht automatisch zwischen Adresse und Daten unterschieden, d.h. beim 
senden von Daten antwortet der Slave was er aber nicht soll, da es sich 
ja um Daten handelt.

von Dieter W. (dds5)


Lesenswert?

> Ich habe das Format mit 9 Datenbits, 1 Parity, 2 Stoppbits gewählt.

Unterstützt denn der gewählte Controller dieses Format überhaupt?
Manche können nur insgesamt 11 Bit übertragen.

von Humbold (Gast)


Lesenswert?

Also ich hab jetzt nochmal mit 1 Stoppbit probiert, funktioniert auch 
nicht...

von spess53 (Gast)


Lesenswert?

Hi

Ich habe das vor kurzem in Assembler gemacht.

Bei dir vermisse ich in der Empfangsroutine einen Adressvergleich.

Am Anfang muss der Slave im MPC-Mode sein. Damit empfängt er nur Daten 
mit gesetzten Bit9. Wenn Daten empfangen wurden, muss ein Vergleich: UDR 
mit Slaveadresse stattfinden. Bei Nichübereinstimmung wird alles 
verworfen und der Slave kann weiterschlummern. Bei Übereinstimmung wird 
der Slave in den Normalmode versetzt und kann Daten mit Bit9=0 
empfangen. Wenn alle Daten übertragen sind, versetzt sich der Slave 
wieder in den MPC-Mode und spielt mit den empfangenen Daten.

MfG Spess

von Humbold (Gast)


Lesenswert?

Im Datenblatt auf Seite 132 steht folgendes:

"The following procedure should be used to exchange data in 
Multi-processor Communi-
cation mode:
1. All Slave MCUs are in Multi-processor Communication mode (MPCM in 
UCSRA
is set).
2. The Master MCU sends an address frame, and all slaves receive and 
read this
frame. In the Slave MCUs, the RXC flag in UCSRA will be set as normal.
3. Each Slave MCU reads the UDR Register and determines if it has been
selected. If so, it clears the MPCM bit in UCSRA, otherwise it waits for 
the next
address byte and keeps the MPCM setting.
4. The addressed MCU will receive all data frames until a new address 
frame is
received. The other Slave MCUs, which still have the MPCM bit set, will 
ignore
the data frames.
5. When the last data frame is received by the addressed MCU, the 
addressed
MCU sets the MPCM bit and waits for a new address frame from master. The
process then repeats from 2."


Besonders der Punkt 3 macht mir kopfzerbrechen.

Soll ich das so verstehen, wenn eine Adresse empfangen wird, dann wird 
das MCPM bit gelöscht, wenn es Daten sind dann bleibt es '1'. Also dann 
müsste ich warten bis das Bit gelöscht ist und mir dann die Adresse 
ansehen und schauen ob es die des jeweiligen Slave ist. ?
Aber wenn man das so manuell machen muss, dann wäre ja der Modus für den 
Ar***, dann könnte ich doch einfach das 9.DB dazu verwenden um zwischen 
Adresse und Daten zu unterscheiden. Für was also dann dass MPCM bit?

von Humbold (Gast)


Lesenswert?

@spess53

Also ich habe bei mir im Code es so gedacht, dass wenn der Slave eine 
Adresse Empängt diese dann von Receive() zurück gegeben wird und in der 
Main verglichen wird. Normalerweise sollte doch der Slave solange in der 
Receive() Funktion verharren bis eine Adresse kommt. Das ist doch der 
Sinn von MPCM, das automatisch die Daten gefiltert werden und erst wenn 
das erste mal eine Adresse kommt dann die Datendurchgelassen werden...

Hm wobei jetzt fällt mir beim schreiben auf, woher weiss der Controller 
das die gesendete Adresse jetzt seine ist und somit die nachkommenden 
Daten durchlässt?

von spess53 (Gast)


Lesenswert?

Hi

Wo du den Vergleich machst, ist eigentlich egal. Ich habe das gleich in 
die RX-ISR gepackt.

>Hm wobei jetzt fällt mir beim schreiben auf, woher weiss der Controller
>das die gesendete Adresse jetzt seine ist und somit die nachkommenden
>Daten durchlässt?

Die Adresse musst du ihm verpassen. Evtl. im EEPROM.

Was noch wichtig ist: Der Slave muss wissen, wann die Daten fertig 
übertragen sind. Damit er dann wieder zurückschalten kann.

MfG Spess

von Humbold (Gast)


Lesenswert?

Also muss ich quasi mit der Hand das RX8B auslesen und feststellen ob es 
sich um eine Adresse handelt oder es Daten sind?

wenn eine Adresse, dann vergleichen mit der Slave Adresse. -->Wenn die 
gleich sind muss ich das MPCM löschen, wenn nicht, dann nichts tun.?

Danach kann ich die Daten empfangen, nach dem Empfang aller Bytes muss 
ich MPCM wieder auf '1' setzen, d.h. der Slave muss genau wissen 
wieviele Frames als Daten gesendet werden!

Aber irgendwie raffe ich das mit dem Mode immer noch nicht, das ist doch 
dann alles per Software gelöst, nichts hardwaremäßig!

Und der Fall wenn die Adresse nicht übereinstimmt:
Der Slave muss doch trotzdem immer hören ob es sich um eine Adresse 
handelt, es könnte ja sein dass das nächste Byte wieder eine Adresse 
ist...

Ich blick es einfach nicht was jetzt der große Vorteil von MPCM ist, für 
mich ist das einfach nur ein Bit in einem register was man löschen und 
setzen kann und sonst keine funktion hat.

von spess53 (Gast)


Lesenswert?

Hi

>Also muss ich quasi mit der Hand das RX8B auslesen und feststellen ob es
>sich um eine Adresse handelt oder es Daten sind?

Nein. Im MPC-Mode empfängt der Slave nur 'Bytes' mit gesetzten Bit9. 
Also nur Adressen. Alles andere wird ignoriert.

>wenn eine Adresse, dann vergleichen mit der Slave Adresse. -->Wenn die
>gleich sind muss ich das MPCM löschen, wenn nicht, dann nichts tun.?

Ja.

>Und der Fall wenn die Adresse nicht übereinstimmt:
>Der Slave muss doch trotzdem immer hören ob es sich um eine Adresse
>handelt, es könnte ja sein dass das nächste Byte wieder eine Adresse
>ist...

Nein. Siehe oben.

MfG Spess

von Humbold (Gast)


Lesenswert?

Hm hab die Funktion jetzt umgeschrieben, aber es funktioniert immer noch 
nicht so richtig.
Woran könnte es noch liegen?


1
unsigned char USART_Receive( void )
2
{
3
  unsigned char status, daten;
4
  static unsigned char datenlaenge=0;  
5
  
6
  while ( !(UCSRA & (1<<RXC)) );
7
  status=UCSRA;  //Flags sichern
8
  daten=UCSRB;
9
  daten=UDR;  //Verwerfen des 9Bits
10
  
11
  if(status & ((1<<FE)|(1<<DOR)|(1<<UPE)))   //Auf Übertragungsfehler prüfen
12
    return 128;
13
  else if(UCSRA & (1<<MPCM) && UDR==SLAVE_ADRESSE ) //Richtige Slave Adresse?
14
  {  
15
    UCSRA &=~(1<<MPCM);  //MPCM ausschalten bereit für Datenempfang
16
    return 255;
17
  }
18
  else if(!(UCSRA & (1<<MPCM)) && datenlaenge<2) //MPCM Null und noch keine zwei Bytes empfangen?
19
  {
20
    datenlaenge++;
21
    if(datenlaenge>=2)
22
    {
23
      UCSRA |=(1<<MPCM); //MPCM wieder einschalten
24
      datenlaenge=0;
25
      
26
    }
27
    return daten;
28
  }
29
  
30
  return 1;
31
32
}

von Humbold (Gast)


Lesenswert?

Wird RXC eigentlich gestzt wenn kein Adressbyte kommt?

Wenn ich mir das Oszillogramm ansehe, wird auf ein empfangenes 
Datenbeyte eine 1 zurück gesendet.

in der Main() des Masters 2 DATEN Bytes gesendet, in der Slave Main() 
wird einfach nur das Empfangene zurückgesendet.
Da es sich um Datenbytes handelt dürfte der Slave garnicht senden.

Und wenn eine '1' zurück gesendet wird, muss das heißen dass die 
while(...) Warteschleife in der Receive Funktion beendet wurde, obwohl 
keine Adresse gesendet worden ist!

Ich versteh die Welt nicht mehr!?

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Also, ich bin notorischer Assemblerprogrammierer mit rudimentären 
C-Kenntnissen.

In der Testphase würde ich auf solche Sachen, wie Fehlerüberprüfung 
verzichten. Machen das Ganze nur unübersichtlicher und ist eine 
zusätzliche Fehlerquelle.

> unsigned char status, daten;
>  static unsigned char datenlaenge=0;

Sitzt das nicht an der falschen Stelle? Meinesachtens löscht du 
Datenlänge damit bei jedem Aufruf.

Hast du auch mit unterschiedlich gesetzten Bit9 gesendet und die 
richtige Adresse benutzt?

Hab dir mal mein Assenblerprogramm angehängt (kleine Rache). Der erste 
Teil ist für den Master, der Zweite für den Slave.

MfG Spess

von Humbold (Gast)


Lesenswert?

>> unsigned char status, daten;
>>  static unsigned char datenlaenge=0;

>Sitzt das nicht an der falschen Stelle? Meinesachtens löscht du
>Datenlänge damit bei jedem Aufruf.

Also ich glaube dass bei "static" die variable beim Aufruf nur einaml 
deklariert wird und beim beenden der Funktion erhalten bleibt.

Mit Fehlerüberprüfung meinst du FE, UPE?
Das ist eigentlich kein Problem, eine 128 wird nie zurück gesendet.

>Hast du auch mit unterschiedlich gesetzten Bit9 gesendet und die
>richtige Adresse benutzt?

Also wie im erstn Post setzte ich TXB8 auf 1 wenn ich Adresse sende und 
0 wenn ich Daten senden möchte.

Die Slave Adresse stimmt, aber ist ja eigentlich egal da ich diesen MPCM 
Mode teste in dem ich gar keine Adresse sende! Einfach nur um zu 
überprüfen ob der Receiver vom Slave die empfangenen Bytes verwirft, da 
es ja hier nicht um eine Adresse handelt.

Genau das ist ja das Problem, der Receiver verwirft bzw. ignoriert das 
nicht!

PS die Rache ist dir geglückt. ;-)

von spess53 (Gast)


Lesenswert?

Hi

>Also ich glaube dass bei "static" die variable beim Aufruf nur einaml
>deklariert wird und beim beenden der Funktion erhalten bleibt.

Mag sein. Aber du setzt sie jedesmal auf 0.

>Genau das ist ja das Problem, der Receiver verwirft bzw. ignoriert das
>nicht!

Zeig mal die Initialisierung der Slave UART. Wie realisiert du das 
Senden?

MfG Spess

von Humbold (Gast)


Lesenswert?

>Mag sein. Aber du setzt sie jedesmal auf 0.

Ich glaube nicht, zumindest wenn man dieser Beschreibung glauben darf
http://tutorial.schornboeck.net/static.htm

Slave USART Initalieserung:
1
void USART_Init( unsigned int baud )
2
{
3
  UBRRH = (unsigned char)(baud>>8);    //Baudrate festlegen
4
  UBRRL = (unsigned char)baud;  
5
  UCSRA |= (1<<MPCM);            //Multi-Processor-Mode
6
  UCSRB = (1<<RXEN)|(1<<TXEN)|(UCSZ2);      //Transimitter und Receiver einschalten
7
  UCSRC = (1<<UCSZ0)|(1<<UCSZ1)|(1<<UPM1);  //Frame-Format festlegen: 9 Datenbits, 1 Stoppbits, Paritybit even
8
}

Beim Master ist es das gleiche, bis auf das der MPCM nicht auf '1' 
gesetzt wird.

>Wie realisiert du das Senden?

in der Main vom Master einfach so:
1
USART_Transmit_Data(4444); //4444 hat keine Bedeutung, einfach mal was senden

Dazu die Funktion:
1
void USART_Transmit_Data( uint16_t data )
2
{
3
  uint8_t byte;
4
  uint16_t word=data;
5
  byte=word;
6
7
  for(uint8_t i=0; i<=1; i++)
8
  {                  /* Wait for empty transmit buffer */
9
    
10
    while ( !( UCSRA & (1<<UDRE)) );
11
    UCSRB &= ~(1<<TXB8);      //TXB8: 0= Daten Senden                    /* Put data into buffer, sends the data */
12
    UDR = byte;
13
    while ( !( UCSRA & (1<<TXC)) );
14
    UCSRA |=(1<<TXC);
15
    byte=(word>>8);
16
  }
17
}

von spess53 (Gast)


Lesenswert?

Hi

>void USART_Transmit_Data( uint16_t data )

Irgendwie herrscht bei dir ein Durcheinander von Datentypen. Wieso 
benutzt du  beim Senden 'uint16_t data' und beim Empfangen 'unsigned 
char'. Das Ganze kommt mir sehr unsystematisch vor.

>Ich glaube nicht, zumindest wenn man dieser Beschreibung glauben darf

Du denkst noch dran, das ich Assemblerprogrammierer bin. Ich bewege mich 
hier auf sehr unsicheren Terrain.

MfG Spess

von Steffen (Gast)


Lesenswert?

>Irgendwie herrscht bei dir ein Durcheinander von Datentypen. Wieso
>benutzt du  beim Senden 'uint16_t data' und beim Empfangen 'unsigned
>char'. Das Ganze kommt mir sehr unsystematisch vor.

Das Ganze hat aber ein System:

Ich verwende 1Byte beim Senden von Adressen und 2Bytes beim Senden von 
Daten. 1Byte Adresse langt völlig aus um alle  Slaves zu Adressieren. 
Bei den Daten habe ich mich auf eine Paketgröße von 2Byte festgelegt 
weil ich immer 16Bit große Wörter verschicke. Das macht die Main auch 
übersichtlicher, denn dann brauch ich nicht jedesmal die Word to Byte 
umwandlung hinschreiben.

Zum empfangen langt die funktion mit dem return von 1Byte. Ich schreib 
dann in der Main einfach zwei Receive() Aufrufe hintereinander.

Aber all das dürfte eigentlich nichts mit meinem Problem zu tun haben.
In der USART_Transmit_Adress(...) setze ich TXB8 auf '1' und bei 
USART_Transmit_data(...) wird TXB8 auf '0' gesetzt.

Wenn also TXB8='0' ist müsster der Slave (MPCM=1) erkennen, dass es sich 
dabei nicht um eine Adresse handelt und die Empfangenen Daten 
ignorieren, das macht er aber nicht!!!
Ich werd nochmal verrückt mit diesem Modus. :-( Ist irgendwie schlecht 
beschrieben im Datenblatt.

von spess53 (Gast)


Lesenswert?

Hi

Dann liegt der Fehler möglicherweise in anderen Codeteilen. Hast du dir 
mal meinen Code angesehen. Der funktioniert 100%-tig (JTAG 
ICE-getestet).

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Sieh dir diese Zeile aus deinem Post weiter oben mal an:

UCSRB = (1<<RXEN)|(1<<TXEN)|(UCSZ2);

Dämmert was?

MfG Spess

von Steffen (Gast)


Lesenswert?

Hm, es dämmert nicht.

Receiver und Transmiter eingeschaltet, 9 DatenBits

???

von spess53 (Gast)


Lesenswert?

HI

|(UCSZ2);

Und jetzt?

MfG Spess

von Steffen (Gast)


Lesenswert?

Was ist damit? UCSZ2 ist gestzt um 9 Bits zu versenden. Das neunte ist 
TXB8.

von spess53 (Gast)


Lesenswert?

Hi

>Was ist damit? UCSZ2 ist gestzt um 9 Bits zu versenden. Das neunte ist
>TXB8.

Nein!

  UCSZ2   = 2
  1<<UCS2 = 4

mit  |(UCSZ2) versuchst du RXB8 zu beschreiben.

MfG Spess

von Steffen (Gast)


Lesenswert?

Ah! jetzt fällt es mir auf! Oh man was ein blöder Fehler. schähm Ob es 
wirklich daran liegt werd ich allerdings erst Montag erfahren.
Danke.

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.