Project

General

Profile

Sample uPP Device Driver » DspUpp.cpp

DSP based uPP Driver .cpp source - Thomas Catalino, 01/26/2012 01:40 AM

 
1
/**
2
 * 	\file 	tcDspUpp.cpp
3
 * 
4
 * 	\brief 	DSP uPP driver source
5
 *
6
 *     o  0
7
 *     | /       Copyright (c) 2005-2011
8
 *    (CL)---o   Critical Link, LLC
9
 *      \
10
 *       O
11
 */
12

    
13
#include "DspUpp.h"
14
#include "memorymap.h"
15
#include "core/DspSyscfg.h"
16
#include "core/DspLpsc.h"
17

    
18
#include <tsk.h>
19
#include <assert.h>
20
#include <hwi.h>
21
#include <c62.h>
22

    
23
using namespace MityDSP;
24

    
25
SEM_Handle tcDspUpp::mhGetInstSem = SEM_create(1, NULL);
26

    
27
tcDspUpp* tcDspUpp::mpDspUpp = NULL;
28

    
29
/**
30
 * Get instance of tcDspUpp.
31
 */
32
tcDspUpp* 
33
tcDspUpp::getInstance()
34
{
35
	// Pend on the static mutex so that we do not accidentally 
36
	// init too many objects
37
	SEM_pend(mhGetInstSem, SYS_FOREVER);
38

    
39
	// Check if the singleton need initialization
40
	if (NULL == mpDspUpp)
41
	{
42
		mpDspUpp = new tcDspUpp();
43
	}
44

    
45
	// Safe to return the mutex now
46
	SEM_post(mhGetInstSem);
47

    
48
	// Return pointer to singleton
49
	return mpDspUpp;
50
}
51

    
52
/**
53
 * Intiailize the uPP device.
54
 */
55
int 
56
tcDspUpp::initialize(tsDspUppConfig const* apDspUppConfig)
57
{
58
	// ISR attributes
59
	HWI_Attrs hwi_attrs = {0, 0, (Arg)this};
60

    
61
	TSK_Attrs tsk_attrs = TSK_ATTRS;
62

    
63
	tuUppcrReg luUppcrReg = {0};
64
	tuUpctlReg luUpctlReg = {0};
65
	tuUpicrReg luUpicrReg = {0};
66
	tuUpivrReg luUpivrReg = {0};
67
	tuUptcrReg luUptcrReg = {0};
68
	tuUpiesReg luUpiesReg = {0};
69

    
70
	// Pin Mux functions to make sure uPP is enabled properly for Channel A
71
	tePinFunc laPinFuncCHA[] = 
72
		{
73
			UPP_CH1_WAIT,
74
			UPP_CH1_ENABLE,
75
			UPP_CH1_START,
76
			UPP_CH1_CLK,
77
			PINFUNC_LIST_TERMINATE
78
		};	
79

    
80
	// Pin Mux functions to make sure uPP is enabled properly for Channel B
81
	tePinFunc laPinFuncCHB[] = 
82
		{
83
			UPP_CH0_WAIT,
84
			UPP_CH0_ENABLE, 
85
			UPP_CH0_START,
86
			UPP_CH0_CLK,
87
			PINFUNC_LIST_TERMINATE
88
		};
89

    
90
	// Pin Mux functions for DATA[15:8]
91
	tePinFunc laPinFuncData15_8[] = 
92
		{
93
			UPP_D8,
94
			UPP_D9,
95
			UPP_D10,
96
			UPP_D11,
97
			UPP_D12,
98
			UPP_D13, 
99
			UPP_D14,
100
			UPP_D15,
101
			PINFUNC_LIST_TERMINATE
102
		};
103

    
104
	// Pin Mux functions for DATA[7:0]
105
	tePinFunc laPinFuncData7_0[] = 
106
		{
107
			UPP_D0,
108
			UPP_D1,
109
			UPP_D2,	
110
			UPP_D3,
111
			UPP_D4, 
112
			UPP_D5, 
113
			UPP_D6,
114
			UPP_D7,
115
			PINFUNC_LIST_TERMINATE
116
		};
117
		
118
	// Pin Mux functions for XDATA[15:8]
119
	tePinFunc laPinFuncXData15_8[] = 
120
		{	
121
			UPP_XD8,
122
			UPP_XD9,
123
		    UPP_XD10,
124
			UPP_XD11,
125
			UPP_XD12,
126
			UPP_XD13, 
127
			UPP_XD14, 
128
			UPP_XD15,
129
			PINFUNC_LIST_TERMINATE
130
		};			 
131
			
132
	// Pin Mux functions for XDATA[7:0]
133
	tePinFunc laPinFuncXData7_0[] = 
134
		{
135
			UPP_XD0, 
136
			UPP_XD1,
137
			UPP_XD2, 
138
			UPP_XD3,
139
			UPP_XD4,
140
			UPP_XD5,
141
			UPP_XD6,
142
			UPP_XD7,	
143
			PINFUNC_LIST_TERMINATE
144
		};
145

    
146
	// MbxA attributes //TODO: non-default attributes?
147
	MBX_Attrs lsMbxAttrsA = MBX_ATTRS;
148
	// MbxB attributes //TODO: non-default attributes?
149
	MBX_Attrs lsMbxAttrsB = MBX_ATTRS;
150

    
151
	// Length of Chan A MBXs
152
	uint32_t lnMbxLenA = apDspUppConfig->nMbxLenA;
153
	// Length of Chan B MBXs
154
	uint32_t lnMbxLenB = apDspUppConfig->nMbxLenB;
155

    
156

    
157
	// Configuration sanity checks
158
	if (eeDisabled == apDspUppConfig->eChanADir &&
159
		eeDisabled == apDspUppConfig->eChanBDir)
160
		return -1;
161

    
162
	if (apDspUppConfig->nHWInterruptLevel > 15 || 
163
		apDspUppConfig->nHWInterruptLevel < 4) 
164
	{
165
		return -1;
166
	}
167

    
168
	// TODO: Additional checks?
169
	
170

    
171
	// Check if we've already been initialized
172
	if (false == mbFirstInit)
173
	{
174
		// TODO: any necessary shutdown before the re-init	
175

    
176
		// Reset all pin config to default? (need to? Make sense?)
177
	}
178

    
179
	mbFirstInit = false;
180

    
181
	// Reset channels to disabled in case there is a failure
182
	meChanADir = eeDisabled;
183
	meChanADir = eeDisabled;
184

    
185
	// Set uPP DMA Master Priority
186
	tcDspSyscfg::SetMasterPriority(tcDspSyscfg::eeUPP, 
187
		apDspUppConfig->nDmaMasterPriority);
188

    
189
	// Apply the appropriate pin mux settings to enable the uPP 
190
	// (based on configuration)
191
	if (eeTransmit == apDspUppConfig->eChanADir || 
192
		eeTransmit == apDspUppConfig->eChanBDir)
193
	{
194
		// Select the appropriate Transmit Clock
195
		if (eeUPP_2xTXCLK == apDspUppConfig->eTxClockSel)
196
		{
197
			tcDspSyscfg::SetChipConfig(UPP_TX_CLKSRC_2xTXCLK);
198

    
199
			// Enable 2xTXCLK pin 
200
			if (tcDspSyscfg::SetPinMuxConfig(UPP_2xTXCLK) < 0)
201
				return -1;
202
		}
203
		else if (eePLL0_SYSCLK2 == apDspUppConfig->eTxClockSel)
204
		{
205
			tcDspSyscfg::SetChipConfig(ASYNC3_CLKSRC_PLL0_SYSCLK2);
206
			tcDspSyscfg::SetChipConfig(UPP_TX_CLKSRC_ASYNC3);
207
		}
208
		else if (eePLL1_SYSCLK2 == apDspUppConfig->eTxClockSel)
209
		{
210
			tcDspSyscfg::SetChipConfig(ASYNC3_CLKSRC_PLL1_SYSCLK2);
211
			tcDspSyscfg::SetChipConfig(UPP_TX_CLKSRC_ASYNC3);
212
		}
213
	}	
214

    
215
	if (eeDisabled != apDspUppConfig->eChanADir)
216
	{
217
		// Enable Channel A pins if it is not disabled
218
		if (tcDspSyscfg::SetPinMuxConfig(laPinFuncCHA) < 0)
219
			return -1;
220
	}
221

    
222
	if (eeDisabled != apDspUppConfig->eChanBDir)
223
	{
224
		// Enable Channel B pins if it is not disabled
225
		if (tcDspSyscfg::SetPinMuxConfig(laPinFuncCHB) < 0)
226
			return -1;
227
	}
228

    
229
	if (eeDisabled == apDspUppConfig->eChanBDir &&
230
		eeDisabled != apDspUppConfig->eChanADir)
231
	{
232
		// Enable lower 8 bits for Channel A
233
		if (tcDspSyscfg::SetPinMuxConfig(laPinFuncData7_0) < 0)
234
			return -1;
235

    
236
		if (ee8Bit != apDspUppConfig->eChanBitWidthA)
237
		{
238
			// Enable upper 8 bits for Channel A
239
			if (true == apDspUppConfig->bChanAUseXData)
240
			{
241
				if (tcDspSyscfg::SetPinMuxConfig(laPinFuncXData7_0) < 0)
242
					return -1;
243
			}
244
			else
245
			{
246
				if (tcDspSyscfg::SetPinMuxConfig(laPinFuncData15_8) < 0)
247
					return -1;
248
			}
249
		}
250
	}
251
	else
252
	{
253
		if (eeDisabled != apDspUppConfig->eChanADir)
254
		{
255
			// Enable lower 8 bits for Channel A
256
			if (tcDspSyscfg::SetPinMuxConfig(laPinFuncData7_0) < 0)
257
				return -1;
258
		
259
			if (ee8Bit != apDspUppConfig->eChanBitWidthA)
260
			{
261
				// Enable upper 8 bits for Channel A
262
				if (tcDspSyscfg::SetPinMuxConfig(laPinFuncXData7_0) < 0)
263
					return -1;
264
			}
265
		}
266

    
267
		if (eeDisabled != apDspUppConfig->eChanBDir)
268
		{
269
			// Enable lower 8 bits for Channel B
270
			if (tcDspSyscfg::SetPinMuxConfig(laPinFuncData15_8) < 0)
271
				return -1;
272

    
273
			if (ee8Bit != apDspUppConfig->eChanBitWidthB)
274
			{
275
				// Enable upper 8 bits for Channel B
276
				if (tcDspSyscfg::SetPinMuxConfig(laPinFuncXData15_8) < 0)
277
					return -1;
278
			}
279
		}
280

    
281
	}		
282
	
283
	// make sure to enable the power and clocks to the uPP device
284
	tcDspLpsc::ConfigPeripheral(tcDspLpsc::eeUPP, tcDspLpsc::eeENABLE);
285

    
286
	// Delete Chan A MBXs if they exists
287
	if (NULL != mhMbxDoneA)
288
		MBX_delete(mhMbxDoneA);
289

    
290
	if (NULL != mhMbxIntA)
291
		MBX_delete(mhMbxIntA);
292

    
293
	if (NULL != mhMbxQueueA)
294
		MBX_delete(mhMbxQueueA);
295

    
296
	// Delete Chan B MBXs if they exists
297
	if (NULL != mhMbxDoneB)
298
		MBX_delete(mhMbxDoneB);
299
	
300
	if (NULL != mhMbxIntB)
301
		MBX_delete(mhMbxIntB);
302

    
303
	if (NULL != mhMbxQueueB)
304
		MBX_delete(mhMbxQueueB);
305

    
306

    
307
	// Initialize Chan A MBXs if Chan A is enabled
308
	if (eeDisabled != apDspUppConfig->eChanADir) 
309
	{
310
		lsMbxAttrsA.name = "mhMbxDoneA";
311
		mhMbxDoneA = MBX_create(sizeof(tsMbxMsg), lnMbxLenA, 
312
			&lsMbxAttrsA);
313
		if (NULL == mhMbxDoneA)
314
			return -1;
315

    
316
		lsMbxAttrsA.name = "mhMbxIntA";
317
		mhMbxIntA = MBX_create(sizeof(tsMbxMsg), 2, &lsMbxAttrsA);
318
		if (NULL == mhMbxIntA)
319
			return -1;
320

    
321
		lsMbxAttrsA.name = "mhMbxQueueA";
322
		mhMbxQueueA = MBX_create(sizeof(tsMbxMsg), lnMbxLenA, 
323
			&lsMbxAttrsA);
324
		if (NULL == mhMbxQueueA)
325
			return -1;
326
	}
327

    
328
	// Initialize Chan B MBXs if Chan B is enabled
329
	if (eeDisabled != apDspUppConfig->eChanBDir) 
330
	{
331
		lsMbxAttrsB.name = "mhMbxDoneB";
332
		mhMbxDoneB = MBX_create(sizeof(tsMbxMsg), lnMbxLenB, 
333
			&lsMbxAttrsB);
334
		if (NULL == mhMbxDoneB)
335
			return -1;
336

    
337
		lsMbxAttrsB.name = "mhMbxIntB";
338
		mhMbxIntB = MBX_create(sizeof(tsMbxMsg), 2, &lsMbxAttrsB);
339
		if (NULL == mhMbxIntB)
340
			return -1;
341

    
342
		lsMbxAttrsB.name = "mhMbxQueueB";
343
		mhMbxQueueB = MBX_create(sizeof(tsMbxMsg), lnMbxLenB, 
344
			&lsMbxAttrsB);
345
		if (NULL == mhMbxQueueB)
346
			return -1;
347
	}
348

    
349
	// Reset the uPP
350
	reset();
351

    
352
	// Program UPCTL reg (mode, data width/format, etc.)
353
	if (eeTransmit == apDspUppConfig->eChanADir &&
354
		eeReceive == apDspUppConfig->eChanBDir)
355
	{
356
		luUpctlReg.sRegBits.MODE = eeAXmitBRcv; // Xmit/Rcv Mode
357
	}	
358
	else if (eeReceive == apDspUppConfig->eChanADir &&
359
			 eeTransmit == apDspUppConfig->eChanBDir)
360
	{
361
		luUpctlReg.sRegBits.MODE = eeARcvBXmit; // Xmit/Rcv Mode
362
	}
363
	else if (eeTransmit == apDspUppConfig->eChanADir ||
364
			 eeTransmit == apDspUppConfig->eChanBDir)
365
	{
366
		luUpctlReg.sRegBits.MODE = eeAllXmit; // Xmit/Rcv Mode
367
	}
368
	else if (eeReceive == apDspUppConfig->eChanADir ||
369
			 eeReceive == apDspUppConfig->eChanBDir)
370
	{
371
		luUpctlReg.sRegBits.MODE = eeAllRcv; // Xmit/Rcv Mode
372
	}
373
	
374
	if (eeDisabled != apDspUppConfig->eChanBDir || 
375
		true == apDspUppConfig->bChanAUseXData)
376
	{
377
		// Must "enable" both channels if B is active
378
		// Though if it's just B active, we do not enable A's pinmuxing
379
		// Or in case where only Channel A is active, but we want CHN=1
380
		// data bit assignments
381
		luUpctlReg.sRegBits.CHN = 1; // Only Chan A active, or Chan A/B active
382
	}
383

    
384
	luUpctlReg.sRegBits.SDRTXIL = 0; // Not supported... yet
385
	luUpctlReg.sRegBits.DDRDEMUX = 0; // Not supported... yet
386
	
387
	luUpctlReg.sRegBits.DRA = 0; // Chan A single/double data rate
388
	
389
	if (ee8Bit != apDspUppConfig->eChanBitWidthA)
390
	{
391
		luUpctlReg.sRegBits.IWA = 1; // Chan A 8/16-bit interface
392
	}
393

    
394
	// Mod 8 because 8 and 16 bit = 0
395
	luUpctlReg.sRegBits.DPWA = (apDspUppConfig->eChanBitWidthA)%8; 
396
	luUpctlReg.sRegBits.DPFA = eeRJSE; // Chan A data packing format
397

    
398
	luUpctlReg.sRegBits.DRB = 0; // Chan B single/double data rate
399
	
400
	if (ee8Bit != apDspUppConfig->eChanBitWidthB)
401
	{
402
		luUpctlReg.sRegBits.IWB = 1; // Chan B 8/16-bit interface
403
	}
404

    
405
	// Mod 8 because 8 and 16 bit = 0
406
	luUpctlReg.sRegBits.DPWB = (apDspUppConfig->eChanBitWidthB)%8; 
407
	luUpctlReg.sRegBits.DPFB = eeRJSE; // Chan B data packing format
408
	mpUppRegs->UPCTL = luUpctlReg.nRegWord;
409

    
410
	// Program UPICR reg (signal enable, clock rate)
411
	luUpicrReg.sRegBits.STARTPOLA = 0; 
412
	luUpicrReg.sRegBits.ENAPOLA = 0;
413
	luUpicrReg.sRegBits.WAITPOLA = 0;
414
	luUpicrReg.sRegBits.STARTA = apDspUppConfig->bChanAUseStart;
415
	luUpicrReg.sRegBits.ENAA = 1;
416
	luUpicrReg.sRegBits.WAITA = 1;
417
	luUpicrReg.sRegBits.CLKDIVA = apDspUppConfig->nChanAClkDiv;
418
	luUpicrReg.sRegBits.CLKINVA = 0;	
419
	luUpicrReg.sRegBits.TRISA = 0; // Chan A high-impedence state
420

    
421
	luUpicrReg.sRegBits.STARTPOLB = 0;
422
	luUpicrReg.sRegBits.ENAPOLB = 0;
423
	luUpicrReg.sRegBits.WAITPOLB = 0;
424
	luUpicrReg.sRegBits.STARTB = apDspUppConfig->bChanBUseStart;
425
	luUpicrReg.sRegBits.ENAB = 1;
426
	luUpicrReg.sRegBits.WAITB = 1;
427
	luUpicrReg.sRegBits.CLKDIVB = apDspUppConfig->nChanBClkDiv;
428
	luUpicrReg.sRegBits.CLKINVB = 0;	
429
	luUpicrReg.sRegBits.TRISB = 0; // Chan B high-impedence state
430

    
431
	mpUppRegs->UPICR = luUpicrReg.nRegWord;
432

    
433
	// Program UPIVR reg (idle xmit value)
434
	luUpivrReg.sRegBits.VALA = 0xFFFF; // Chan A idle value, if TRISA==0
435
	luUpivrReg.sRegBits.VALB = 0xFFFF; // Chan B idle value, if TRISB==0
436

    
437
	mpUppRegs->UPIVR = luUpivrReg.nRegWord;
438

    
439
	// Program UPTCR reg (i/o threshold)
440
	luUptcrReg.sRegBits.RDSIZEI = apDspUppConfig->eThresholdRxA;
441
	luUptcrReg.sRegBits.RDSIZEQ = apDspUppConfig->eThresholdRxB;
442
	
443
	luUptcrReg.sRegBits.TXSIZEA = apDspUppConfig->eThresholdTxA;
444
	luUptcrReg.sRegBits.TXSIZEB = apDspUppConfig->eThresholdTxB;
445

    
446
	mpUppRegs->UPTCR = luUptcrReg.nRegWord;
447

    
448
	// Program UPDLB reg (digital loopback)
449
	mpUppRegs->UPDLB = 0; // TODO: support internal loopback?
450

    
451
	// Clear all interrupts using UPIEC
452
	mpUppRegs->UPIEC = 0x1F1F;
453

    
454
	// Program uPP interrupt enable reg (UPIES)
455
	luUpiesReg.nRegWord = 0;
456
	// DMA I interrupts
457
	if (eeDisabled != apDspUppConfig->eChanADir) 
458
	{
459
		luUpiesReg.sRegBits.EOWI = 1;
460
		luUpiesReg.sRegBits.DPEI = 1;
461
		luUpiesReg.sRegBits.UORI = 1;
462
		luUpiesReg.sRegBits.ERRI = 1;
463
		// No need to service end of line interrupt
464
		luUpiesReg.sRegBits.EOLI = 0; 
465
	}
466
	// DMA Q interrupts
467
	if (eeDisabled != apDspUppConfig->eChanBDir) 
468
	{
469
		luUpiesReg.sRegBits.EOWQ = 1;
470
		luUpiesReg.sRegBits.DPEQ = 1;
471
		luUpiesReg.sRegBits.UORQ = 1;
472
		luUpiesReg.sRegBits.ERRQ = 1;
473
		// No need to service end of line interrupt	
474
		luUpiesReg.sRegBits.EOLQ = 0; 
475
	}
476
	
477
	mpUppRegs->UPIES = luUpiesReg.nRegWord;
478
 
479

    
480
	// Register ISR (if enabled)
481
	// Setup interrupt handling function
482
	// TODO: Failure codes for these functions?
483
	HWI_dispatchPlug(apDspUppConfig->nHWInterruptLevel, 
484
					(Fxn)isr, 
485
					-1, 
486
					&hwi_attrs);
487
	HWI_eventMap(apDspUppConfig->nHWInterruptLevel, 
488
				 94);
489
	C62_enableIER(1 << apDspUppConfig->nHWInterruptLevel);
490

    
491
	
492
	// Store directionality of channels
493
	meChanADir = apDspUppConfig->eChanADir;
494
	meChanBDir = apDspUppConfig->eChanBDir;
495

    
496
	// Turn on the uPP and other final UPPCR config
497
	luUppcrReg.sRegBits.FREE = 1; // Emulation will not halt uPP
498
	luUppcrReg.sRegBits.EN = 1; // Enable uPP device
499
	mpUppRegs->UPPCR = luUppcrReg.nRegWord;
500

    
501
	// Start the Chan A thread for handling the DMA
502
	if (eeDisabled != apDspUppConfig->eChanADir)
503
	{
504
		if (NULL != mhDmaTskA)
505
			TSK_delete(mhDmaTskA);
506

    
507
		tsk_attrs = TSK_ATTRS;
508
		tsk_attrs.name = "DmaTskA";
509
		tsk_attrs.stacksize = 1024;
510
		tsk_attrs.priority  = apDspUppConfig->nTskPriorityChanA;
511
		mhDmaTskA = TSK_create((Fxn)programDMA, &tsk_attrs, this, 
512
				eeChanA);
513

    
514
		// Check that task creation was successful
515
		if (NULL == mhDmaTskA)
516
			return -1;
517
	}
518

    
519
	// Start the Chan B thread for handling the DMA
520
	if (eeDisabled != apDspUppConfig->eChanBDir)
521
	{
522
		if (NULL != mhDmaTskB)
523
			TSK_delete(mhDmaTskB);
524

    
525
		tsk_attrs = TSK_ATTRS;
526
		tsk_attrs.name = "DmaTskB";
527
		tsk_attrs.stacksize = 1024;
528
		tsk_attrs.priority  = apDspUppConfig->nTskPriorityChanB;
529
		mhDmaTskB = TSK_create((Fxn)programDMA, &tsk_attrs, this,
530
				eeChanB);
531

    
532
		// Check that task creation was successful
533
		if (NULL == mhDmaTskB)
534
			return -1;
535
	}
536

    
537
	return 0;
538
}
539

    
540
/**
541
* Perform software reset of the uPP.
542
*
543
* @return None.
544
*/
545
void 
546
tcDspUpp::reset()
547
{
548
	tuUppcrReg luUppcrReg = {0};
549

    
550
	// Read current contents of the register
551
	luUppcrReg.nRegWord = mpUppRegs->UPPCR;
552

    
553
	// Place the uPP in SW reset
554
	luUppcrReg.sRegBits.SWRST = 1; // SW reset enabled
555
	mpUppRegs->UPPCR = luUppcrReg.nRegWord;
556

    
557
	// Wait at least 200 cycles 
558
	TSK_sleep(200);
559

    
560
	// Clear the SW reset bit
561
	luUppcrReg.sRegBits.SWRST = 0; // SW reset disabled
562
	mpUppRegs->UPPCR = luUppcrReg.nRegWord;
563
}
564

    
565
/**
566
 * Get handle to mailbox for associated channel where info on
567
 */
568
MBX_Handle 
569
tcDspUpp::getMBX(teUppChan aeChan)
570
{
571
	return (eeChanB == aeChan)?mhMbxDoneB:mhMbxDoneA;
572
}
573

    
574
/**
575
 * Queue transmit of given data buffer. Use getMBX() to get corresponding
576
 * mailbox where pointer info will be posted once data has been tramsmitted.
577
 */
578
int 
579
tcDspUpp::transmit(teUppChan aeChan,
580
		 		   const uint8_t* apXmitData,
581
		 		   uint16_t anByteCnt,
582
		 		   uint16_t anLineCnt,
583
		 		   uint16_t anLineOffset)
584
{
585
	// MBX Queue msg
586
	tsMbxMsg lsMbxMsg;
587
	// Queue MBX
588
	MBX_Handle lhMbxQueue = (eeChanB == aeChan)?mhMbxQueueB:mhMbxQueueA; 
589

    
590
	// Check aeChan directionality...
591
	if (eeChanA == aeChan)
592
	{
593
		if (eeTransmit != meChanADir)
594
		{
595
			return -1;
596
		}
597
	}
598
	else if (eeChanB == aeChan)
599
	{
600
		if (eeTransmit != meChanBDir)
601
		{
602
			return -1;
603
		}
604
	}
605
	else
606
	{
607
		return -1;
608
	}
609

    
610
	// Check if apXmitData is on 64-bit aligned
611
	if (0 != (((uint32_t)apXmitData)&0x7))
612
		return -1;
613
		
614
	// Check that anByteCnt is even
615
	if (0 != (anByteCnt&0x1))
616
		return -1;
617
		
618
	// Check that anLineOffset is 64-bit aligned
619
	if (0 != (anLineOffset&0x7))
620
		return -1;
621
	
622
	//TODO: Check restrictions on other inputs
623

    
624
	// Setup the request
625
	lsMbxMsg.pBufPtr = (uint8_t*)apXmitData;
626
	lsMbxMsg.nByteCnt = anByteCnt;
627
	lsMbxMsg.nLineCnt = anLineCnt;
628
	lsMbxMsg.nLineOffset = anLineOffset;
629
	lsMbxMsg.pOptArg = NULL;
630

    
631
	// Add the request to the queue mailbox
632
	if (false == MBX_post(lhMbxQueue, &lsMbxMsg, SYS_FOREVER))
633
	{
634
		return -1;
635
	}
636

    
637
	return 0;
638
	// TODO: failure conditions!
639
}
640

    
641
/**
642
* Add buffer to receive queue. Use getMBX() to get corresponding
643
* mailbox where pointer info will be posted once data has been received. 				
644
*/
645
int 
646
tcDspUpp::receive(teUppChan aeChan,
647
				  uint8_t* apRcvData,
648
				  uint16_t anByteCnt,
649
				  uint16_t anLineCnt,
650
				  uint16_t anLineOffset)
651
{
652
	// MBX Queue msg
653
	tsMbxMsg lsMbxMsg;
654
	// Queue MBX
655
	MBX_Handle lhMbxQueue = (eeChanB == aeChan)?mhMbxQueueB:mhMbxQueueA; 
656

    
657
	// Check aeChan directionality...
658
	if (eeChanA == aeChan)
659
	{
660
		if (eeReceive != meChanADir)
661
		{
662
			return -1;
663
		}
664
	}
665
	else if (eeChanB == aeChan)
666
	{
667
		if (eeReceive != meChanBDir)
668
		{
669
			return -1;
670
		}
671
	}
672
	else
673
	{
674
		return -1;
675
	}
676

    
677
	// Check if apXmitData is on 64-bit aligned
678
	if (0 != (((uint32_t)apRcvData)&0x7))
679
		return -1;
680
		
681
	// Check that anByteCnt is even
682
	if (0 != (anByteCnt&0x1))
683
		return -1;
684
		
685
	// Check that anLineOffset is 64-bit aligned
686
	if (0 != (anLineOffset&0x7))
687
		return -1;
688

    
689

    
690
	// Setup the request
691
	lsMbxMsg.pBufPtr = apRcvData;
692
	lsMbxMsg.nByteCnt = anByteCnt;
693
	lsMbxMsg.nLineCnt = anLineCnt;
694
	lsMbxMsg.nLineOffset = anLineOffset;
695
	lsMbxMsg.pOptArg = NULL;
696

    
697
	// Add the request to the queue mailbox
698
	if (false == MBX_post(lhMbxQueue, &lsMbxMsg, SYS_FOREVER))
699
	{
700
		return -1;
701
	}
702

    
703
	return 0;
704
	//TODO: failure conditions!
705
}
706

    
707
/**
708
 * Thread for programming the DMA for the specified channel.
709
 */
710
void 
711
tcDspUpp::programDMA(tcDspUpp* apDspUpp, teUppChan aeChan)
712
{
713
	// Pointer to the tcDspUpp object
714
	tcDspUpp* lpDspUpp = apDspUpp;
715
        // Queue MBX
716
	MBX_Handle lhMbxQueue = (eeChanB == aeChan)? 
717
        lpDspUpp->mhMbxQueueB:lpDspUpp->mhMbxQueueA; 
718
	// Intermediate MBX (for buffers being DMAed)
719
	MBX_Handle lhMbxInt = (eeChanB == aeChan)?
720
        lpDspUpp->mhMbxIntB:lpDspUpp->mhMbxIntA;
721
	// Local MBX message for copying and setting DMA
722
	tsMbxMsg lsMbxMsg;
723
	// Used for checking DMA status
724
	tuUpiqs2Reg luUpiqs2Reg = {0};
725
	// Used for setting the DMA reg 0
726
	tuUpiqd1Reg luUpiqd1Reg = {0};
727

    
728
    // This thread runs continuously
729
    while(1)
730
    {
731

    
732
        // Pend on mhMbxQueue waiting for a new message that can be
733
        // used to program the DMA
734
        MBX_pend(lhMbxQueue, &lsMbxMsg, SYS_FOREVER);
735

    
736
        // Post to mhMbxInt waiting for space to open up in DMA 
737
        MBX_post(lhMbxInt, &lsMbxMsg, SYS_FOREVER);
738

    
739
        // Now we should be able to safely program the DMA
740

    
741
        // Read the appropriate DMA status register
742
        if (eeChanB == aeChan)
743
        {
744
            luUpiqs2Reg.nRegWord = lpDspUpp->mpUppRegs->UPQS2;
745
        }
746
        else
747
        {
748
            luUpiqs2Reg.nRegWord = lpDspUpp->mpUppRegs->UPIS2;
749
        }
750

    
751
        // Check if the DMA can be programmed
752
        while (1 == luUpiqs2Reg.sRegBits.PEND)
753
        {
754
            // The DMA is busy, this should not happen
755
            if (NULL != lpDspUpp->mpErrorCallback)
756
		        lpDspUpp->mpErrorCallback(0xDEADBEEF);
757

    
758
            // Maybe it will fix itself?
759
            TSK_sleep(100);
760
        }
761

    
762
        // Program the DMA
763
        luUpiqd1Reg.sRegBits.BCNT = lsMbxMsg.nByteCnt;
764
        luUpiqd1Reg.sRegBits.LNCNT = lsMbxMsg.nLineCnt;
765

    
766
        if (eeChanB == aeChan)
767
        {
768
            lpDspUpp->mpUppRegs->UPQD0 = (uint32_t)lsMbxMsg.pBufPtr;
769
            lpDspUpp->mpUppRegs->UPQD1 = luUpiqd1Reg.nRegWord;
770
            lpDspUpp->mpUppRegs->UPQD2 = lsMbxMsg.nLineOffset;
771
        }
772
        else
773
        {
774
            lpDspUpp->mpUppRegs->UPID0 = (uint32_t)lsMbxMsg.pBufPtr;
775
            lpDspUpp->mpUppRegs->UPID1 = luUpiqd1Reg.nRegWord;
776
            lpDspUpp->mpUppRegs->UPID2 = lsMbxMsg.nLineOffset;
777
        }
778

    
779
    }
780
}
781

    
782
/**
783
 * Handle any uPP related interrupts that might occur.
784
 *
785
 * \return 0 on success, negative on failure. 
786
 */
787
int 
788
tcDspUpp::isr(tcDspUpp* apDspUpp)
789
{
790
	// Return value
791
	int retval = 0;
792
	// Pointer to the tcDspUpp object
793
	tcDspUpp* lpDspUpp = apDspUpp;
794
	// Local copy of uPP registers so that we don't have to 
795
	// dereference lpDspUpp so many times
796
	volatile tsUppRegs* const lpUppRegs = lpDspUpp->mpUppRegs;
797
	// Value of the UPIER register, which tells us which interrupts occurred
798
	tuUpierReg luUpierReg = {0};
799
	// Used to clear the UPIER register interrupts once processed
800
	tuUpierReg luUpierRegClr = {0};
801
	// Used to update the Done MBX
802
	tsMbxMsg lsMbxMsg;
803

    
804
	// Check for interrupts
805
	luUpierReg.nRegWord = lpUppRegs->UPIER;
806

    
807
	// Process all pending interrupts. 
808
	while (0 != luUpierReg.nRegWord)
809
	{
810
		// Check for Channel I programming error interrupt
811
		if (luUpierReg.sRegBits.DPEI == 1)
812
		{
813
			// Clear the interrupt
814
			luUpierRegClr.nRegWord = 0;
815
			luUpierRegClr.sRegBits.DPEI = 1;
816
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
817
			
818
			// Handle the interrupt
819
			if (NULL != lpDspUpp->mpErrorCallback)
820
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
821
		}
822

    
823
		// Check for Channel I underrun/overflow interrupt
824
		if (luUpierReg.sRegBits.UORI == 1)
825
		{
826
			// Clear the interrupt
827
			luUpierRegClr.nRegWord = 0;
828
			luUpierRegClr.sRegBits.UORI = 1;
829
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
830

    
831
			// Handle the interrupt
832
			if (NULL != lpDspUpp->mpErrorCallback)
833
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
834
		}
835

    
836
		// Check for Channel I error interrupt
837
		if (luUpierReg.sRegBits.ERRI == 1)
838
		{
839
			// Clear the interrupt
840
			luUpierRegClr.nRegWord = 0;
841
			luUpierRegClr.sRegBits.ERRI = 1;
842
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
843
			
844
			// Handle the interrupt
845
			if (NULL != lpDspUpp->mpErrorCallback)
846
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
847
		}
848

    
849
		// Check for Channel I End-of-Window interrupt
850
		if (luUpierReg.sRegBits.EOWI == 1)
851
		{
852
			// Clear the interrupt
853
			luUpierRegClr.nRegWord = 0;
854
			luUpierRegClr.sRegBits.EOWI = 1;
855
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
856

    
857
			// Handle the interrupt
858
			
859
			// Get the DMAed data info
860
			if (true == MBX_pend(lpDspUpp->mhMbxIntA,
861
								 &lsMbxMsg,
862
								 0))
863
			{
864
				// Update the done MBX
865
				if (false == MBX_post(lpDspUpp->mhMbxDoneA,
866
					   				  &lsMbxMsg,
867
								  	  0))
868
				{
869
					// Return queue overflow!
870
					retval = -1;
871
				}	
872
			}
873
			else
874
			{
875
				// No data in the intermediate mailbox, but we received
876
				// an interrupt, this is a problem
877
				retval = -1;
878
			}			
879
		}
880

    
881
		// Check for Channel I End-of-Line interrupt
882
		if (luUpierReg.sRegBits.EOLI == 1)
883
		{
884
			// Clear the interrupt
885
			luUpierRegClr.sRegBits.EOLI = 1;
886
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
887
			luUpierRegClr.nRegWord = 0;
888

    
889
			// Handle the interrupt
890

    
891
		}	
892

    
893
		// Check for Channel Q programming error interrupt
894
		if (luUpierReg.sRegBits.DPEQ == 1)
895
		{
896
			// Clear the interrupt
897
			luUpierRegClr.nRegWord = 0;
898
			luUpierRegClr.sRegBits.DPEQ = 1;
899
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
900
			
901
			// Handle the interrupt
902
			if (NULL != lpDspUpp->mpErrorCallback)
903
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
904
		}
905

    
906
		// Check for Channel Q underrun/overflow interrupt
907
		if (luUpierReg.sRegBits.UORQ == 1)
908
		{
909
			// Clear the interrupt
910
			luUpierRegClr.nRegWord = 0;
911
			luUpierRegClr.sRegBits.UORQ = 1;
912
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
913
			
914
			// Handle the interrupt
915
			if (NULL != lpDspUpp->mpErrorCallback)
916
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
917
		}
918

    
919
		// Check for Channel Q error interrupt
920
		if (luUpierReg.sRegBits.ERRQ == 1)
921
		{
922
			// Clear the interrupt
923
			luUpierRegClr.nRegWord = 0;
924
			luUpierRegClr.sRegBits.ERRQ = 1;
925
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
926
			
927
			// Handle the interrupt
928
			if (NULL != lpDspUpp->mpErrorCallback)
929
				lpDspUpp->mpErrorCallback(luUpierRegClr.nRegWord);
930
		}	
931

    
932
		// Check for Channel Q End-of-Window interrupt
933
		if (luUpierReg.sRegBits.EOWQ == 1)
934
		{
935
			// Clear the interrupt
936
			luUpierRegClr.nRegWord = 0;
937
			luUpierRegClr.sRegBits.EOWQ = 1;
938
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
939
			
940
			// Handle the interrupt
941
			
942
			// Get the DMAed data info
943
			if (true == MBX_pend(lpDspUpp->mhMbxIntB,
944
								 &lsMbxMsg,
945
								 0))
946
			{
947
				// Update the done MBX
948
				if (false == MBX_post(lpDspUpp->mhMbxDoneB,
949
					   				  &lsMbxMsg,
950
								  	  0))
951
				{
952
					// Return queue overflow!
953
					retval = -1;
954
				}	
955
			}
956
			else
957
			{
958
				// No data in the intermediate mailbox, but we received
959
				// an interrupt, this is a problem
960
				retval = -1;
961
			}
962
		}
963

    
964
		// Check for Channel Q End-of-Line interrupt
965
		if (luUpierReg.sRegBits.EOLQ == 1)
966
		{
967
			// Clear the interrupt
968
			luUpierRegClr.nRegWord = 0;
969
			luUpierRegClr.sRegBits.EOLQ = 1;
970
			lpUppRegs->UPIER = luUpierRegClr.nRegWord;
971
			
972
			// Handle the interrupt
973

    
974
		}
975

    
976
		// Check for more interrupts
977
		luUpierReg.nRegWord = lpUppRegs->UPIER;
978
	}
979

    
980
	// Write end of interrupt vector to allow future calls
981
	lpUppRegs->UPEOI = 0;
982

    
983
	return retval;
984
}
985

    
986
/**
987
 * Set the error callback function.
988
 */
989
void 
990
tcDspUpp::registerErrorCallback(tfErrorCallback afErrorCallback)
991
{
992
	mpErrorCallback = afErrorCallback;
993
}
994

    
995
/**
996
 * Private constructor.
997
 */
998
tcDspUpp::tcDspUpp()
999
: mpUppRegs((tsUppRegs*)UPP_REG_BASE)
1000
, mhDmaTskA(NULL)
1001
, mhDmaTskB(NULL)
1002
, mhMbxDoneA(NULL)
1003
, mhMbxDoneB(NULL)
1004
, mhMbxIntA(NULL)
1005
, mhMbxIntB(NULL)
1006
, mhMbxQueueA(NULL)
1007
, mhMbxQueueB(NULL)
1008
, mpErrorCallback(NULL)
1009
, mbFirstInit(true)
1010
, meChanADir(eeDisabled)
1011
, meChanBDir(eeDisabled)
1012
{
1013

    
1014
}
1015

    
1016
/**
1017
 * Private destructor.
1018
 */
1019
tcDspUpp::~tcDspUpp()
1020
{
1021

    
1022
}
1023

    
(1-1/3) Go to top
Add picture from clipboard (Maximum size: 1 GB)