-
Notifications
You must be signed in to change notification settings - Fork 0
/
DmxDue.cpp
319 lines (249 loc) · 6.71 KB
/
DmxDue.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
//#include <string.h>
//#include <arduino.h>
#include "DmxDue.h"
// Constructors
DmxDue::DmxDue(Usart* pUsart, IRQn_Type dwIrq, uint32_t dwId, uint8_t *pRx_buffer, uint8_t *pTx_buffer)
{
_rx_buffer = pRx_buffer;
_pUsart = pUsart;
_dwIrq = dwIrq;
_dwId = dwId;
_tx_buffer = pTx_buffer;
_txReadyEvent = NULL;
_rxReadyEvent = NULL;
_rxCnt=0;
_rxLength=0;
clrTxBuffer();
setTxMaxChannels(DMX_TX_MAX);
_rxState = RX_OFF;
_txState = TX_OFF;
}
/* --------- transmitter ---------- */
// clear transmit buffer
void DmxDue::clrTxBuffer()
{
for (uint16_t i = 0; i < DMX_TX_MAX; i++) {
_tx_buffer[i] = 0;
}
}
// set max transmit channels
void DmxDue::setTxMaxChannels(uint16_t maxChannels)
{
if (maxChannels > DMX_TX_MAX)
_maxTxChannels = DMX_TX_MAX;
else
_maxTxChannels = maxChannels;
}
// write value to transmit buffer
void DmxDue::write(uint16_t channel, uint8_t value)
{
// sanity check
if (channel == 0 || channel > DMX_TX_MAX) return;
_tx_buffer[channel - 1] = value;
}
// get value from transmit buffer
uint8_t DmxDue::getTx(uint16_t channel)
{
// sanity check
if (channel == 0 || channel > DMX_TX_MAX) return 0;
return _tx_buffer[channel - 1];
}
/* --------- receiver ---------- */
// return dmx value from channel
uint8_t DmxDue::read(uint16_t channel)
{
// sanity check
if (channel == 0 || channel > DMX_RX_MAX) return 0;
return _rx_buffer[channel];
}
uint16_t DmxDue::getRxLength()
{
return _rxLength;
}
// initialise hardware
void DmxDue::begin()
{
// Configure PMC
pmc_enable_periph_clk( _dwId ) ;
// Disable PDC channel
_pUsart->US_PTCR = US_PTCR_RXTDIS | US_PTCR_TXTDIS ;
// Reset and disable receiver and transmitter
_pUsart->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS ;
// Configure mode
_pUsart->US_MR = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK | US_MR_CHRL_8_BIT | US_MR_PAR_NO |
US_MR_NBSTOP_2_BIT | US_MR_CHMODE_NORMAL;
// Configure baudrate, asynchronous no oversampling
_pUsart->US_BRGR = (SystemCoreClock / (250000 *16)) ;
// Configure interrupts
_pUsart->US_IDR = 0xFFFFFFFF;
// _pUsart->US_IER = US_IER_RXRDY | US_IER_OVRE| US_IER_FRAME | US_IER_RXBRK | US_IER_TXRDY | US_IER_TXEMPTY;
_pUsart->US_IER = US_IER_RXRDY | US_IER_RXBRK | US_IER_TXRDY;
//
// first thing to do is generate break
_txState = TX_BREAK;
_rxState = IDLE;
// Enable receiver and transmitter
_pUsart->US_CR = US_CR_RXEN | US_CR_TXEN;
// Enable UART interrupt in NVIC
NVIC_EnableIRQ( _dwIrq ) ;
}
void DmxDue::setRxEvent(Fptr f)
{
_rxReadyEvent = f;
}
void DmxDue::setBreakEvent(Fptr f)
{
_txReadyEvent = f;
}
void DmxDue::markAfterBreak()
{
// stop brake
_pUsart->US_CR |= US_CR_STPBRK;
}
// Send start code
void DmxDue::beginWrite()
{
_pUsart->US_THR = 0;
_txCnt = 0;
_txState = TX_DATA; // next state
}
void DmxDue::setInterruptPriority(uint32_t priority)
{
NVIC_SetPriority(_dwIrq, priority & 0x0F);
}
// all usartX interupts together
void DmxDue::IrqHandler(void)
{
if (_rxState == RX_OFF && _txState == TX_OFF) return;
uint32_t status = _pUsart->US_CSR; // get state before data!
// Did we receive data ?
if (status & US_CSR_RXRDY) {
uint8_t dmxByte =_pUsart->US_RHR; // get data
switch (_rxState) {
case BREAK:
// first byte is the start code
_rx_buffer[0] = dmxByte;
if (dmxByte == 0) {
_rxState = DATA; // normal DMX start code detected
_rxCnt = 1; // start with channel # 1
} else {
;//_rxState = IDLE; // wait for next BREAK !
}
break;
case DATA:
_rx_buffer[_rxCnt] = dmxByte; // store received data into dmx data buffer
if (_rxCnt < DMX_RX_MAX) {
_rxCnt++; // next channel
} else {
_rxState = IDLE; // wait for next break
}
break;
case IDLE:
default:
break;
}
}
// Receiver Break = frame error
if (status & US_CSR_RXBRK) { //check for break
_rxState = BREAK; // break condition detected.
if (_rxCnt>1) _rxLength = _rxCnt-2; // store dmx length
else _rxLength =0;
_pUsart->US_CR |= US_CR_RSTSTA;
if (_rxReadyEvent && _rxLength) _rxReadyEvent();
}
// tx ready
if (status & US_CSR_TXRDY) {
switch (_txState) {
case TX_DATA:
// Send character
_pUsart->US_THR = _tx_buffer[_txCnt];
if (_txCnt < _maxTxChannels - 1) {
_txCnt++;
} else {
_txState = TX_BREAK;// next state
}
break;
case TX_BREAK:
// send first break byte
_pUsart->US_CR |= US_CR_STTBRK;
_pUsart->US_THR=0;
_txState = TX_BREAK1;
break;
case TX_BREAK1:
// send 2-nd break byte
_pUsart->US_THR=0;
_txState = TX_BREAK2;
break;
case TX_BREAK2:
// send 3-th break byte
_pUsart->US_THR=0;
// break must be at leat 88 uSec so , 44 uSec to go
if (_txReadyEvent) _txReadyEvent();
_txState = TX_START;
break;
case TX_START:
_pUsart->US_CR |= US_CR_STPBRK; //Stop Break. 2 stop bits from break bytes will working as Mark After Break
_pUsart->US_THR = 0; // Send INIT
_txCnt = 0;
_txState = TX_DATA; // next state
case TX_DISABLE:
default:
// Mask off transmit interrupt so we don't get it anymore
//_pUsart->USART_IDR = USART_IDR_TXRDY;
break;
}
}
/*
// Acknowledge errors
if (status & US_CSR_OVRE)
{
// TODO: error reporting outside ISR
_pUsart->US_CR |= US_CR_RSTSTA;
}
*/
}
// ----------------------------------------------------------------------------
/*
* USART objects
*/
// Array of DMX values (raw).
// Entry 0 will never be used for DMX data but will store the startbyte (0 for DMX mode).
#ifdef DMX1
uint8_t dmx_rx_buffer1[DMX_RX_MAX + 1];
uint8_t dmx_tx_buffer1[DMX_TX_MAX];
// Create class instances
DmxDue DmxDue1(USART0, USART0_IRQn, ID_USART0, dmx_rx_buffer1, dmx_tx_buffer1);
// IT handlers
void USART0_Handler( void )
{
DmxDue1.IrqHandler() ;
}
#endif
#ifdef DMX2
uint8_t dmx_rx_buffer2[DMX_RX_MAX + 1];
uint8_t dmx_tx_buffer2[DMX_TX_MAX];
DmxDue DmxDue2(USART1, USART1_IRQn, ID_USART1, dmx_rx_buffer2, dmx_tx_buffer2);
void USART1_Handler( void )
{
DmxDue2.IrqHandler() ;
}
#endif
#ifdef DMX3
uint8_t dmx_rx_buffer3[DMX_RX_MAX + 1];
uint8_t dmx_tx_buffer3[DMX_TX_MAX];
DmxDue DmxDue3(USART3, USART3_IRQn, ID_USART3, dmx_rx_buffer3, dmx_tx_buffer3);
void USART3_Handler( void )
{
DmxDue3.IrqHandler() ;
}
#endif
#ifdef DMX4
//Spare unlisted USART on the board
uint8_t dmx_rx_buffer4[DMX_RX_MAX + 1];
uint8_t dmx_tx_buffer4[DMX_TX_MAX];
DmxDue DmxDue4(USART2, USART2_IRQn, ID_USART2, dmx_rx_buffer4, dmx_tx_buffer4);
void USART2_Handler( void )
{
DmxDue4.IrqHandler() ;
}
#endif