Attiny2313 - DMX-Receiver - eingestellte Startadresse != reale Startadresse

#3669014
Lesenswert?

Hallo,

im Moment sitze ich an einem kleinen DMX-Switchpack. Es besteht im 
Wesentlichen aus einem Attiny2313, einem 75176 und deine 
16MHz-Quarztoszillator. Die Startadresse habe ich im Quellcode fest auf 
1 einstellt.

Den DMX-Code habe ich von Hendrik Hölscher übernommen.

Als DMX-Sender verwende ich ein JMS-USB-Interface und DMXControl.

Grundsätzlich funktioniert die Schaltung. Allerdings ist mir folgendes 
aufgefallen.
Obwohl ich im Code eine 1 als Startadresse definiert habe, wird der 
"erste Ausgang" des Attiny durch den zweiten Kanal im DMXControl 
angesprochen.

Wird im DMXControl der Wert des ersten Kanals auf einen Wert > 0 
geändert, reagiert der Attiny auf Änderungen der anderen Kanäle nicht 
mehr. Erst wieder, wenn im DMXControl der Wert des ersten Kanals auf 0 
gestellt wird.


Kennt jemand so ein Verhalten?

Im Netz habe ich bislang noch nichts gefunden.

Danke
matt
Gast #3669029
Lesenswert?

Matt B. schrieb:
> Wird im DMXControl der Wert des ersten Kanals auf einen Wert > 0
> geändert, reagiert der Attiny auf Änderungen der anderen Kanäle nicht
> mehr. Erst wieder, wenn im DMXControl der Wert des ersten Kanals auf 0
> gestellt wird.

Dann würde ich doch mal einen Blick in den Quellcode werfen und mit dem 
Simulator ansehen, wo es denn hakt.

Matt B. schrieb:
> DMX-Code habe ich von Hendrik Hölscher

Den kennt ja auch jeder und der hat auch nur einen veröffentlicht ...
:-(
#3669049
Lesenswert?

> Die Startadresse habe ich im Quellcode fest auf 1 einstellt.

Ist das die interne Adresse oder die DMX Adresse?

Hintergrund:
Die DMX Adressierung beginnt grundsätzlich bei 1.
C Programmierer beginnen allerdings bei 0 zu zählen.
D.h. für einen C Programmierer trägt das erste Datenbyte einer Sequenz 
die Nummer 0. Aus DMX Sicht ist das aber das Byte mit der Nummer 1.

Also ganz einfach im Code nachsehen, was mit dieser Einstellung gemacht 
wird. Dann ist man schlauer.
#3669056
Lesenswert?

Hier noch die Codes zum DMX-Empfang.

Initialisierung:
1
void init_DMX_RX(void)
2
{
3
  DDRD  |= (1<<PD2);
4
  PORTD &= ~(1<<PD2);                
5
  UBRRH  = 0;                    //enable reception
6
  UBRRL  = ((F_OSC/4000)-1);            //250kbaud, 8N2
7
  UCSRC  = (3<<UCSZ0)|(1<<USBS);
8
  UCSRB  = (1<<RXEN)|(1<<RXCIE);
9
  gDmxState= IDLE;
10
}

UART-ISR:
1
ISR (USART_RX_vect)
2
{
3
  static  uint16_t DmxCount;
4
  uint8_t  USARTstate= UCSRA;            //get state before data!
5
  uint8_t  DmxByte   = UDR;            //get data
6
  uint8_t  DmxState  = gDmxState;          //just load once from SRAM to increase speed
7
 
8
  if (USARTstate &(1<<FE))            //check for break
9
  {
10
    UCSRA &= ~(1<<FE);              //reset flag (necessary for simulation in AVR Studio)
11
    DmxCount = DmxAddress;            //reset channel counter (count channels before start address)
12
    gDmxState = BREAK;
13
  }
14

15
  else if (DmxState == BREAK)
16
  {
17
    if (DmxByte == 0) gDmxState = STARTB;    //normal start code detected
18
    else        gDmxState = IDLE;
19
  }
20
  
21
  else if (DmxState == STARTB)
22
  {
23
    if (--DmxCount == 0)            //start address reached?
24
    {
25
      DmxCount = 1;              //set up counter for required channels
26
      DmxRxField[0] = DmxByte;        //get 1st DMX channel of device
27
      gDmxState = STARTADR;
28
    }
29
  }
30

31
  else if (DmxState == STARTADR)
32
  {
33
    DmxRxField[DmxCount++] = DmxByte;      //get channel
34
    if (DmxCount >= sizeof(DmxRxField))     //all ch received?
35
    {
36
      gDmxState = IDLE;            //wait for next break
37
    }
38
  }              
39
}

Die von mir einstellte Startadresse ist tatsächlich '1'. Der Wert des 
ersten Kanals wird im ersten Element des Arrays 'DmxRxField' abgelegt ( 
DmxRxField[0]).

Es ist so, dass der als Startkanal eingestellte Kanal als Startbyte 
verwendet wird. Besitzt der einen Wert ungleich 0, erkennt der Empfänger 
kein Startbyte und setzt "gDmxState = IDLE". Es werden kann keine 
weiteren Kanäle eingelesen.

Aber im Code konnte ich bislang nichts finden, das so eine Funktion 
erklärt.
#3669095
Lesenswert?

Matt B. schrieb:
> Hier noch die Codes zum DMX-Empfang.

Hmm.
Der Code sieht gut aus.
Wenn ich mich im Kopf nicht vertan habe, dann entspricht er der DMX 
Spezifikation, in dem er die über die UART reinkommenden Bytes korrekt 
verteilt.


> Es ist so, dass der als Startkanal eingestellte Kanal als Startbyte
> verwendet wird.

Das entspricht dann aber nicht der DMX Spezifikation. Die verlangt 
zwingend, dass nach dem langen Puls (der über den Frame Error 
ausgewertet wird) erst mal ein Byte mit dem Wert 0 kommen muss.

> Besitzt der einen Wert ungleich 0, erkennt der Empfänger
> kein Startbyte und setzt "gDmxState = IDLE". Es werden kann keine
> weiteren Kanäle eingelesen.

Logisch. So ist das im Empfänger programmiert.

Im Moment deutet für mich vieles darauf hin, dass sich zwar dieser 
Empfangscode an den DMX Standard hält, aber anscheinend dieses 
DMXControl nicht.
Hast du eine Möglichkeit, dir die übergebenen Werte anzusehen (LCD, 
Terminal?)
>
> Aber im Code konnte ich bislang nichts finden, das so eine Funktion
> erklärt.
#3669111
Lesenswert?

Ich glaube nicht, dass der Fehler beim DMXControl liegt. Dann wäre ich 
bestimmt nicht der einzige, der damit Probleme hat. Die aktuelle Version 
von dem Programm habe ich übrigens installiert.

Wenn ich die Startadresse im Attiny z.B. auf 10 umstelle, dann wird der 
10. Kanal als Startbyte und der 11. Kanal als tatsächlicher Startkanal 
verwendet. Die Kanäle 1 bis 9 haben dann keinen Einfluss auf den 
Attiny...

Ein Gerät um die vom Interface ausgegebenen Werte anzuzeigen kann ich 
auf die Schnelle nicht auftreiben.
Für die Darstellung von Werte am Attiny habe ich insgesamt 10 LEDs zur 
Verfügung. Darüber kann also auch 8-Bit-Werte (oder auch 10-Bit-Werte) 
darstellen
#3669119
Lesenswert?

Matt B. schrieb:
> Ich glaube nicht, dass der Fehler beim DMXControl liegt. Dann wäre ich
> bestimmt nicht der einzige, der damit Probleme hat. Die aktuelle Version
> von dem Programm habe ich übrigens installiert.
>
> Wenn ich die Startadresse im Attiny z.B. auf 10 umstelle, dann wird der
> 10. Kanal als Startbyte und der 11. Kanal als tatsächlicher Startkanal
> verwendet. Die Kanäle 1 bis 9 haben dann keinen Einfluss auf den
> Attiny...
>
> Ein Gerät um die vom Interface ausgegebenen Werte anzuzeigen kann ich
> auf die Schnelle nicht auftreiben.

Dann sehe ich eigentlich nur noch die Möglichkeit, dass der Code für 2 
hintereinander folgende Byte einen Frame Error bekommt. Er also das 
0-Startbyte als weiteres 'Synchronisationsbyte'-Break ansieht, welches 
über den generierten Frame Error alles weitere ins Rollen bringt, 
wodurch sich die ganze Zählung verschiebt.
#3669137
Lesenswert?

Nach dem "langen Puls bzw. Frame-Error" kommt laut DMX-Specs ein 
Type-Byte, danach folgen die Daten. Type=0x00 bedeutet "Dimmer", der 
verwendete code ist vermutlich dafür ausgelegt auch andere Typen 
weiterzuverarbeiten:
Also: Frame Error - 1 Byte 0x00 für Dimmer - 1 bis 512 Bytes für die 
Kanäle 1 bis 512.
Hoffe die Info hilft weiter!
PS.: und DMX-Control ist als Fehlerrquelle zu 99,9% auszuschließen ;-)
#3669145
Lesenswert?

Karl Heinz schrieb:
> Dann sehe ich eigentlich nur noch die Möglichkeit, dass der Code für 2
> hintereinander folgende Byte einen Frame Error bekommt. Er also das
> 0-Startbyte als weiteres 'Synchronisationsbyte'-Break ansieht, welches
> über den generierten Frame Error alles weitere ins Rollen bringt,
> wodurch sich die ganze Zählung verschiebt.

Sowas in der Art stelle ich mir auch vor...
Aber wie gehe das Problem an?

@Klaus:
Das von dir erwähnte Type-Byte ist doch das allgemeine Startbyte, das 
immer den Wert 0 besitzt!?
#3669235
Lesenswert?

Was mit gerade noch einfällt:
Ist es möglich, dass das DMXControl davon ausgeht, dass das Interface 
selbstständig ein Startbyte vor die Datenbytes stellt, das JMS Interface 
aber davon ausgeht, dass die vom DMX-Programm erhaltenen Bytes mit einem 
Startbyte beginnen und die Datenbytes diesem folgen?

Dann wäre zumindest das Verhalten bei mir plausibel. Leider habe ich 
momentan keine anderen DMX-Geräte da um das prüfen zu können...
#3669344
Lesenswert?

Hallo matt!

In den Standards DMX512, DMX512/1990 und dem deutschen Standard nach DIN 
56930-2 wird noch von Startbyte (=0x00) gesprochen.
Seit DMX512A, bzw. E1.11-2008, USITT DMX512-A gibt es zwei gravierende 
Änderungen:
Mark-After-Break von 4 auf 8µs verlängert.
Start-Byte (=0x00) zu Start-Code erklärt:
0x00 dimmers and lighting fixtures
0x17 text packets
0xCF system information packets
0xCC RDM extension

grüße leo
#3669350
Lesenswert?

@Klaus:
danke für die Info.



Gerade konnte ich den Attiny an einem ArtNet und einer anderen Software 
betreiben. Der Fehler lag weiterhin vor. Deswegen gehe ich jetzt 
tatsächlich von einem Fehler im Programm aus...

Edit:
Ich habe die ISR etwas angepasst. Die Abfrage auf das Startbyte habe ich 
komplett weggelassen. Seither funktioniert es. Das Startbyte/Type-Byte 
kommt bei mir irgendwie gar nicht an.

Hier die ISR:
1
ISR (USART_RX_vect)
2
{
3
  static  uint16_t DmxCount;
4
  uint8_t  USARTstate= UCSRA;            //get state before data!
5
  uint8_t  DmxByte   = UDR;            //get data
6
  uint8_t  DmxState  = gDmxState;          //just load once from SRAM to increase speed
7
 
8
  if (USARTstate &(1<<FE))            //check for break
9
  {
10
    UCSRA &= ~(1<<FE);              //reset flag (necessary for simulation in AVR Studio)
11
    DmxCount = 0;            //reset channel counter (count channels before start address)
12
    gDmxState = BREAK;
13
  }
14

15
  else if (DmxState == BREAK)
16
  {
17
    if(DmxCount >= DmxAddress - 1)
18
      DmxRxField[DmxCount - (DmxAddress - 1)] = DmxByte;
19

20
    DmxCount++;
21
    if(DmxCount > DmxAddress + sizeof(DmxRxField))
22
      DmxState = IDLE;
23
  }    
24
}
#3669999
Lesenswert?

Hallo matt,

liest du für Kanal 1 DmxRxField[0] oder DmxRxField[1] aus?
wenn ich die ISR richtig lese steht mit DmxAddress = 1 in
DmxRxField[0] .. DMX Slot 0 (=0x00 für Licht und Dimmer)
DmxRxField[1] .. DMX Slot 1 = Kanal 1
usw.

bei der letzten if-Abfrage sollte wohl
  gDmxState = IDLE;
stehen?

Slot 0 nicht auszulesen halte ich für mutig, über kurz oder lang
wird sich RDM durchsetzen und dann blinkt dein Empfänger lustig vor
sich hin.

Grüße leo
#3670022
Lesenswert?

Hallo Klaus,

deine Bedenken bezüglich RDM verstehe ich.

Bislang bin ich immer davon ausgegangen, dass in DmxRxField[0] der Wert 
des ersten Datenbytes (1. Kanal) liegt. Das habe ich gerade auch nochmal 
nachvollzogen. Das ist wirklich so. In DmxRxField[2] liegt 
dementsprechend der Wert des zweiten Datenbytes (2. Kanal), usw.

Der Originalcode betrachtet aber tatsächlich das 1. Datenbyte als 
Startbyte. Das ist das Symptom. Aber wie schon erwähnt, kann ich nicht 
nachvollziehen, warum das so ist. Es scheint, als ob kein Startbyte 
ausgesendet wird. Aber das kann ich  mitlerweile ausschließen!

Braucht der UART eventuell nach einem Frame Error eine gewisse Zeit, bis 
er wieder Daten einlesen kann und das Startbyte eventuell "zu schnell" 
kommt?

In der letzten If-Abfrage muss tatsächlich
1
gDmxState = IDLE
stehen!

Danke für eure Hilfe!!!
#3670040
Lesenswert?

Hier mal noch die restlichen Informationen die eventuell interessant 
sein könnten:

- externer 16MHz-Oszillator: laut Datenblatt bei 250k ein Fehler von 
0,0%
- Fuse CKDIV8:     deaktiviert
- Fuse SUT_CKSEL:  EXTCLK_14CK_65MS


Edit:
Wird wenn ein Frame Error erkannt wurde ein Interrupt ausgelöst? Im 
Datenblatt konnte ich nichts konkretes finden...
#3670090
Lesenswert?

> Braucht der UART eventuell nach einem Frame Error eine gewisse Zeit,
> bis er wieder Daten einlesen kann und das Startbyte eventuell
> "zu schnell" kommt?

Das frage ich mich auch schon die ganze Zeit.

Kannst du mal verifizieren, ob tatsächlich 2 Bytes hintereinander mit 
einem Frame-Error klassifiziert werden?
D.h. hier
1
  if (USARTstate &(1<<FE))            //check for break
2
  {
3
    UCSRA &= ~(1<<FE);              //reset flag (necessary for simulation in AVR Studio)
4
    DmxCount = DmxAddress;            //reset channel counter (count channels before start address)
5
    gDmxState = BREAK;
6
  }

mitzählen, bzw.
1
  if (USARTstate &(1<<FE))            //check for break
2
  {
3
    UCSRA &= ~(1<<FE);              //reset flag (necessary for simulation in AVR Studio)
4
    DmxCount = DmxAddress;            //reset channel counter (count channels before start address)
5

6
 // .............
7

8
    if( gDMXState == BREAK )
9
      mach was
10
    else
11
      nimms zurück, alles ok
12

13
// ..............
14

15
    gDmxState = BREAK;
16
  }

irgendeine Form von Kennung /zb. Fehler-LED einschalten 
dazwischenhängen.

Bis lang ist das ja nur eine Hypothese, dass das Startbyte 
fälschlicherweise als Break angesehen wird, auch wenn es IMHO sehr 
plausibel ist und auch zum Fehlerbild passen würde.
#3670101
Lesenswert?

Hier der Code den ich hierfür verwende:
1
if (USARTstate &(1<<FE))            //check for break
2
  {
3
    if(DmxState == BREAK)
4
      LED_red(1);
5

6
    UCSRA &= ~(1<<FE);              //reset flag (necessary for simulation in AVR Studio)
7
    DmxCount =  DmxAddress;            //reset channel counter (count channels before start address)
8
    gDmxState= BREAK;
9
  }

Die Ansteuerung der "roten LED" habe ich in eine Funktion gepackt. Ist 
der Parameter 1, wird die LED eingeschaltet, bei 0 entsprechend 
ausgeschaltet.

Im Falle von zwei aufeinanderfolgenden Breaks wird die LED eingeschaltet 
und bleibt dann dauerhaft an.

Aber die LED bleibt aus. Das heisst keine zwei aufeinanderfolgenden 
Breaks.
#3670115
Lesenswert?

Nochmal zu meiner vorherigen Frage (etwas ausführlicher):
Über die UART wird dem Controller ein Break gesendet. Wird durch den 
damit verbundenen Frame Error der RX-Interrupt ausgelöst? Im Datenblatt 
konnte ich nichts konkretes finden.

Falls nicht, dann wird der Break erst beim nächsten korrekt empfangenen 
Byte vom Programm erkannt. Dieses korrekt empfangene Byte wäre in 
unserem Fall das Start-/Type-Byte. In der If-Abfrage zur Prüfung des 
Breaks wird dieses aber nicht ausgewertet. Erst das nächste empfangene 
Byte wird als Start-/Type-Byte ausgewertet...

Könnte da was dran sein?
#3670137
Lesenswert?

Matt B. schrieb:
> Nochmal zu meiner vorherigen Frage (etwas ausführlicher):
> Über die UART wird dem Controller ein Break gesendet. Wird durch den
> damit verbundenen Frame Error der RX-Interrupt ausgelöst?


Müsste eigentlich.
Wenn dem nicht so wäre, wäre das extrem unlogisch.

> Könnte da was dran sein?

Ich kanns mir nicht recht vorstellen, dass in so einem Fall ein Receive 
Interrupt nicht ausgelöst werden würde. Das würde Interrupts de facto 
unbrauchbar machen, wenn da nur einwandfrei empfangene Bytes durchkommen 
würden.
#3670153
Lesenswert?

@ Matt B. (mattb)

>- externer 16MHz-Oszillator: laut Datenblatt bei 250k ein Fehler von
>0,0%

Aber nur, wenn dein RC-Oszillator 0,0% Fehler hat. Die 0,0% beziehen 
sich auf dein systemtisch Fehler durch Frequenzteilung. Bei einem 
ganzzahligen Teiler ist der logischerweise 0 ;-)
Ich wäre da vorsichtig. Ein 8 oder 16 MHz Quarz(oszillator) bringt hier 
auf jeden Fall Sicherheit.

>Wird wenn ein Frame Error erkannt wurde ein Interrupt ausgelöst?

Sicher.

>Falls nicht, dann wird der Break erst beim nächsten korrekt empfangenen
>Byte vom Programm erkannt.

Nein. Der wird im fehlerhaft empfangenen BYte sofort erkannt.

>Breaks wird dieses aber nicht ausgewertet. Erst das nächste empfangene
>Byte wird als Start-/Type-Byte ausgewertet...

DMX ist doch eigentlich nicht so schwer.

Schau dir mal das Beispiel an, das funktioniert sogar ohne explizite 
statemachine.

Beitrag "DMX512 Empfänger mit Relaisansteuerung für 20 Kanäle"
#3670155
Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>> Über die UART wird dem Controller ein Break gesendet. Wird durch den
>> damit verbundenen Frame Error der RX-Interrupt ausgelöst?

>Müsste eigentlich.

Wird auch.

>Wenn dem nicht so wäre, wäre das extrem unlogisch.

Eben.
#3670164
Lesenswert?

Es ist ein Quarzoszillator verbaut, kein RC-Oszillator.

Den Quellcode von deinem DMX-Empfänger habe ich gerade vor mir:

Hier ein Ausschnitt aus der ISR:
1
if (status & (1<<FE)) {          // frame error
2
    if (data==0) {            // break -> DMX Reset
3
      dmx_channel=0;
4
      dmx_base = (~PINB & 0xFF)+1;  // read dip switches which define DMX base address
5
      if (~PIND & (1<<PD6)) dmx_base +=256;
6
      flag=1;              // trigger update
7
    }
8
    else                // rx error
9
      dmx_channel++;
10
  }

Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du 
mit der Zeile
1
if (data==0)
das Startbyte prüfst?
#3670192
Lesenswert?

Matt B. schrieb:

> Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du
> mit der Zeile
>
1
> if (data==0)
2
>
> das Startbyte prüfst?


Die ganze Sequenz sieht ja so aus
1
  if (status & (1<<FE)) {          // frame error
2
    if (data==0) {            // break -> DMX Reset
3
      dmx_channel=0;
4
      dmx_base = (~PINB & 0xFF)+1;  // read dip switches which define DMX base address
5
      if (~PIND & (1<<PD6)) dmx_base +=256;
6
      flag=1;              // trigger update
7
    }
8
    else                // rx error
9
      dmx_channel++;
10
  }
11
  else {
12
    index = dmx_channel-dmx_base;
13
    if (index>=0 && index<dmx_size)
14
      dmx_array[index]=data;
15
    dmx_channel++;
16
  }

Das übergehen des Startbytes ist implizit hier
1
    index = dmx_channel-dmx_base;
2
    if (index>=0 && index<dmx_size)
mit enthalten. Beim ersten Startbyte nach dem Break hat dmx_channel den 
Wert 0, während dmx_base zb 1 ist. index wird zu -1 und damit wird das 
Byte übersprungen.


Das hier
1
  if (status & (1<<FE)) {          // frame error
2
    if (data==0) {            // break -> DMX Reset
ist eigentlich der Normalfall. Denn so wie der Break erzeugt wird, 
mündet er automatisch darin, dass sich an der UART ein Byte-Wert von 0 
ergibt.
#3670222
Lesenswert?

Matt B. (mattb)

>Verstehe ich das richtig, dass wenn ein Frame Error erkannt wurde, du
>mit der Zeile

>if (data==0)

>das Startbyte prüfst?

Nein. Schon mal den Kommentar angeschaut?

BREAK = FE && data==0

Das Startbyte interssiert diesen Empfänger gar nicht, es wird wie jedes 
andere DMX-Byte einfach im Array abgelegt und fertig.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren