Forum: Projekte & Code Quellcode: DMX Empfänger Modul für ATxMega


von CeeKay (Gast)


Lesenswert?

Weil heute Freitag ist, quick und dirty eine DMX512 Empfangsrountine für 
ATxMega µC. Wer will kann das ganze noch besser absichern und mehr 
Abfragen zur Gültigkeit der Daten einbauen. Aber Empfangen klappt auch 
so schonmal. Jetzt müsste ihr nur noch was mit den Daten machen.
1
/*        _         _             _       _                  _          _            _            _   _            _
2
*         /\ \      /\ \         /\ \     /\_\               / /\       /\ \         /\ \         /\_\/\_\ _      /\ \
3
*        /  \ \     \_\ \       /  \ \   / / /         _    / /  \      \_\ \       /  \ \       / / / / //\_\   /  \ \
4
*       / /\ \ \    /\__ \     / /\ \ \  \ \ \__      /\_\ / / /\ \__   /\__ \     / /\ \ \     /\ \/ \ \/ / /__/ /\ \ \
5
*      / / /\ \_\  / /_ \ \   / / /\ \ \  \ \___\    / / // / /\ \___\ / /_ \ \   / / /\ \ \   /  \____\__/ //___/ /\ \ \
6
*     / / /_/ / / / / /\ \ \ / / /  \ \_\  \__  /   / / / \ \ \ \/___// / /\ \ \ / / /  \ \_\ / /\/________/ \___\/ / / /
7
*    / / /__\/ / / / /  \/_// / /    \/_/  / / /   / / /   \ \ \     / / /  \/_// / /   / / // / /\/_// / /        / / /
8
*   / / /_____/ / / /      / / /          / / /   / / /_    \ \ \   / / /      / / /   / / // / /    / / /        / / /    _
9
*  / / /\ \ \  / / /      / / /________  / / /___/ / //_/\__/ / /  / / /      / / /___/ / // / /    / / /         \ \ \__/\_\
10
* / / /  \ \ \/_/ /      / / /_________\/ / /____\/ / \ \/___/ /  /_/ /      / / /____\/ / \/_/    / / /           \ \___\/ /
11
* \/_/    \_\/\_\/       \/____________/\/_________/   \_____\/   \_\/       \/_________/          \/_/             \/___/_/
12
*
13
*
14
* DMX Receiver for ATxMega
15
* Tested with ATxMega256A3U
16
* Uses external 16 MHz oscillator together with internal PLL to generate 32MHz system clock
17
* 
18
* 
19
*
20
* Released under the "Don't care" license
21
* Feel free to use this code in any way you want
22
* Also no support will be given in any way
23
*
24
* Code V1.0 
25
* 25.09.2015
26
*/
27
28
#include <avr/io.h>
29
#include <stdio.h>
30
#include <avr/interrupt.h>
31
32
//Buffer to store the DMX stream (start code + 512 channels) 
33
volatile unsigned int dmx_buffer[513];
34
35
void Clock_init(void){
36
  //Xosc Bit 7&6 to 11 | Bit 3 to 0 as 1011
37
  OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
38
  //Bit 3 to 1 to enable external oscillator
39
  OSC.CTRL |= OSC_XOSCEN_bm;
40
  //wait for stable clock
41
  while(!(OSC.STATUS & OSC_XOSCRDY_bm));
42
  //Disable register protection for 4 clocks
43
  CCP = CCP_IOREG_gc;
44
  //Set Bit 2:0 to 011 for external oscillator
45
  CLK.CTRL = CLK_SCLKSEL_XOSC_gc;
46
}
47
48
void PLL_init(void){
49
  //Bit 7:0 to 11 for external oscillator as PLL source | 2 as multiplication value
50
  OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 0x02;
51
  //enable PLL
52
  OSC.CTRL |= OSC_PLLEN_bm;
53
  //wait for stable oscillation
54
  while (!(OSC.STATUS & OSC_PLLRDY_bm));
55
  //Disable register protection for 4 clocks
56
  CCP = CCP_IOREG_gc;
57
  //Set Bit 2:0 for PLL as clock source
58
  CLK.CTRL = CLK_SCLKSEL_PLL_gc;
59
}
60
61
void UART_init(void){
62
  // Pin from USARTC0 TxD C3 set to input
63
  PORTC.DIRCLR = PIN6_bm;
64
  // Asynchronous Modus
65
  USARTC1.CTRLC = (USARTC0.CTRLC & ~USART_CMODE_gm ) | USART_CMODE_ASYNCHRONOUS_gc;
66
  // No parity
67
  USARTC1.CTRLC = (USARTC0.CTRLC & ~USART_PMODE_gm ) | USART_PMODE_DISABLED_gc;
68
  // 8 data bits
69
  USARTC1.CTRLC = (USARTC0.CTRLC & ~USART_CHSIZE_gm ) | USART_CHSIZE_8BIT_gc;
70
  // 2 stop bits
71
  USARTC1.CTRLC = (USARTC0.CTRLC & ~USART_SBMODE_bm) | (0x01<<3);
72
  // 250 kBaud
73
  USARTC1.BAUDCTRLA = 07;
74
  // 250 kBaud
75
  USARTC1.BAUDCTRLB =(0 << USART_BSCALE0_bp)|(07 >> 8);
76
  // Set interrupt level of RX Int to low
77
  USARTC1.CTRLA = (USARTC1.CTRLA & ~USART_RXCINTLVL_gm) | USART_RXCINTLVL_LO_gc;
78
  // activate USARTC1
79
  USARTC1.CTRLB = USART_RXEN_bm;
80
  
81
}
82
83
int main (void){
84
  
85
  //Start-Up external crystal
86
  Clock_init();  
87
  //Use PLL to generate 32 MHz tact from external crystal                          
88
  PLL_init();    
89
  //Init UART                          
90
  UART_init();                            
91
  
92
  /* Enable LO interrupt level. */
93
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
94
  //Global Interrupts Enable
95
  sei();
96
  
97
  while (1)
98
  {
99
  }
100
  
101
  return 0;
102
}
103
104
//Interupt vector for USART C1 RX complete
105
ISR (USARTC1_RXC_vect){
106
    //Let's count the dmx channels
107
    static unsigned int dmx_channel_rx_count = 0;
108
    //And check if dmx is valid
109
    static unsigned char dmx_valid = 0;
110
    //Tmp is never wrong
111
    unsigned char tmp = 0;
112
    
113
    //Store currently received byte into tmp variable
114
    tmp =  USARTC1.DATA;
115
    
116
    //Check for framing error as start of dmx transmission
117
    if(USARTC1.STATUS & USART_FERR_bm)
118
    {
119
      //Start to count at first channel
120
      dmx_channel_rx_count = 0;
121
      //Copy tmp into our dmx buffer at position 0
122
      dmx_buffer[0] = tmp;
123
      //now check if this value was a 0 which is the start code for normal dmx transmissions
124
      if(dmx_buffer[0] == 0)
125
      {
126
        //ok dmx was valid
127
        dmx_valid = 1;
128
        //increase count to first dmx channel containing information
129
        dmx_channel_rx_count++;
130
      }
131
      else
132
      {
133
        //sorry but first byte was not a dmx start code, let's wait for the next frame error
134
        dmx_valid = 0;
135
      }
136
      return;
137
    }
138
    
139
    //yippy dmx was valid so we can process the other 512 channels
140
    if(dmx_valid)
141
    {
142
      //copy the received channel byte into the correct position of our dmx reception buffer
143
      dmx_buffer[dmx_channel_rx_count] = tmp;
144
      //repeat until we have gathered all 512 channels
145
      if(dmx_channel_rx_count < 513)
146
      {
147
        dmx_channel_rx_count++;
148
      }
149
      return;
150
    }
151
}

von Tester (Gast)


Lesenswert?

Danke für den Code, ist auch mal nett zu sehen wie man auf dem Xmega ein 
UART konfiguriert.

Wäre das hier
1
dmx_buffer[dmx_channel_rx_count] = tmp;
nicht perfekt für DMA? Also im Interrupt schauen wo ein Paket anfängt 
und alles weitere im Hintergrund in den Speicher schaufeln lassen?

von CeeKay (Gast)


Lesenswert?

Moin Tester,

DMA kann man an der Stelle anwenden. Allerdings wirst du nicht viel Zeit 
sparen, da ja immer nur ein einzelnes Byte kopiert wird. Ein kurzes wenn 
auch recht sinnfreies Beispiel für die DMA Konfiguration findest du im 
zugehörigen DMX Sendecode. Dort gibt es auch die entsprechende Nutzung 
des UART für Sendebetrieb.

von axeljaeger (unterwegs) (Gast)


Lesenswert?

Wo findet man denn den Sendecode?

Viele Grüße

Axel Jäger

von Falk B. (falk)


Lesenswert?


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.