OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Flshlite/] [serial/] [serial.c] - Blame information for rev 638

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 616 jeremybenn
/*
2
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
3
 
4
    ***************************************************************************
5
    *                                                                         *
6
    * If you are:                                                             *
7
    *                                                                         *
8
    *    + New to FreeRTOS,                                                   *
9
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
10
    *    + Looking for basic training,                                        *
11
    *    + Wanting to improve your FreeRTOS skills and productivity           *
12
    *                                                                         *
13
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
14
    *                                                                         *
15
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
16
    *                  http://www.FreeRTOS.org/Documentation                  *
17
    *                                                                         *
18
    * A pdf reference manual is also available.  Both are usually delivered   *
19
    * to your inbox within 20 minutes to two hours when purchased between 8am *
20
    * and 8pm GMT (although please allow up to 24 hours in case of            *
21
    * exceptional circumstances).  Thank you for your support!                *
22
    *                                                                         *
23
    ***************************************************************************
24
 
25
    This file is part of the FreeRTOS distribution.
26
 
27
    FreeRTOS is free software; you can redistribute it and/or modify it under
28
    the terms of the GNU General Public License (version 2) as published by the
29
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
30
    ***NOTE*** The exception to the GPL is included to allow you to distribute
31
    a combined work that includes FreeRTOS without being obliged to provide the
32
    source code for proprietary components outside of the FreeRTOS kernel.
33
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
34
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
35
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
36
    more details. You should have received a copy of the GNU General Public
37
    License and the FreeRTOS license exception along with FreeRTOS; if not it
38
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
39
    by writing to Richard Barry, contact details for whom are available on the
40
    FreeRTOS WEB site.
41
 
42
    1 tab == 4 spaces!
43
 
44
    http://www.FreeRTOS.org - Documentation, latest information, license and
45
    contact details.
46
 
47
    http://www.SafeRTOS.com - A version that is certified for use in safety
48
    critical systems.
49
 
50
    http://www.OpenRTOS.com - Commercial support, development, porting,
51
    licensing and training services.
52
*/
53
 
54
/*
55
Changes from V1.00:
56
 
57
        + Call to the more efficient portSWITCH_CONTEXT() replaces the call to
58
          taskYIELD() in the ISR.
59
 
60
Changes from V1.01:
61
 
62
        + The semaphore task is not operational.  This does nothing but check
63
          the semaphore from ISR functionality.
64
        + ISR modified slightly so only Rx or Tx is serviced per ISR - not both.
65
 
66
Changes from V1.2.0:
67
 
68
        + Change so Tx uses a DMA channel, and Rx uses an interrupt.
69
 
70
Changes from V1.2.3
71
 
72
        + The function xPortInitMinimal() has been renamed to
73
          xSerialPortInitMinimal() and the function xPortInit() has been renamed
74
          to xSerialPortInit().
75
 
76
Changes from V1.2.5
77
 
78
        + Reverted back to the non-DMA serial port driver, with a slightly modified
79
          ISR.  This is a better test of the scheduler mechanisms.
80
        + A critical section is now used in vInterruptOn().
81
        + Flag sTxInterruptOn has been added to the port structure.  This allows
82
          checking of the interrupt enable status without performing any IO.
83
 
84
Changes from V2.0.0
85
 
86
        + Use portTickType in place of unsigned pdLONG for delay periods.
87
        + Slightly more efficient vSerialSendString() implementation.
88
        + cQueueReieveFromISR() used in place of xQueueReceive() in ISR.
89
*/
90
 
91
#include <stdlib.h>
92
#include <dos.h>
93
#include "FreeRTOS.h"
94
#include "queue.h"
95
#include "task.h"
96
#include "portasm.h"
97
#include "semphr.h"
98
 
99
#define serMAX_PORTS                    ( ( unsigned short ) 2 )
100
 
101
#define serPORT_0_INT_REG               ( 0xff44 )
102
#define serPORT_0_BAUD_REG              ( 0xff88 )
103
#define serPORT_0_RX_REG                ( 0xff86 )
104
#define serPORT_0_TX_REG                ( 0xff84 )
105
#define serPORT_0_STATUS_REG    ( 0xff82 )
106
#define serPORT_0_CTRL_REG              ( 0xff80 )
107
#define serPORT_0_IRQ                   ( 0x14 )
108
 
109
#define serPORT_1_INT_REG               ( 0xff42 )
110
#define serPORT_1_BAUD_REG              ( 0xff18 )
111
#define serPORT_1_RX_REG                ( 0xff16 )
112
#define serPORT_1_TX_REG                ( 0xff14 )
113
#define serPORT_1_STATUS_REG    ( 0xff12 )
114
#define serPORT_1_CTRL_REG              ( 0xff10 )
115
#define serPORT_1_IRQ                   ( 0x11 )
116
 
117
#define serTX_EMPTY                             ( ( unsigned short ) 0x40 )
118
#define serRX_READY                             ( ( unsigned short ) 0x80 )
119
 
120
#define serRESET_PIC( usEOI_TYPE )      portOUTPUT_WORD( ( unsigned short ) 0xff22, usEOI_TYPE )
121
#define serTX_HOLD_EMPTY_INT            ( ( unsigned short ) 0x100 )
122
 
123
#define serENABLE_INTERRUPTS            ( ( unsigned short ) 0x80 )
124
#define serMODE                                         ( ( unsigned short ) 0x01 )
125
#define serENABLE_TX_MACHINES           ( ( unsigned short ) 0x40 )
126
#define serENABLE_RX_MACHINES           ( ( unsigned short ) 0x20 )
127
#define serINTERRUPT_MASK                       ( ( unsigned short ) 0x08 )
128
#define serCLEAR_ALL_STATUS_BITS        ( ( unsigned short ) 0x00 )
129
#define serINTERRUPT_PRIORITY           ( ( unsigned short ) 0x01 ) /*< Just below the scheduler priority. */
130
 
131
#define serDONT_BLOCK                           ( ( portTickType ) 0 )
132
 
133
typedef enum
134
{
135
        serCOM1 = 0,
136
        serCOM2,
137
        serCOM3,
138
        serCOM4,
139
        serCOM5,
140
        serCOM6,
141
        serCOM7,
142
        serCOM8
143
} eCOMPort;
144
 
145
typedef enum
146
{
147
        serNO_PARITY,
148
        serODD_PARITY,
149
        serEVEN_PARITY,
150
        serMARK_PARITY,
151
        serSPACE_PARITY
152
} eParity;
153
 
154
typedef enum
155
{
156
        serSTOP_1,
157
        serSTOP_2
158
} eStopBits;
159
 
160
typedef enum
161
{
162
        serBITS_5,
163
        serBITS_6,
164
        serBITS_7,
165
        serBITS_8
166
} eDataBits;
167
 
168
typedef enum
169
{
170
        ser50 = 0,
171
        ser75,
172
        ser110,
173
        ser134,
174
        ser150,
175
        ser200,
176
        ser300,
177
        ser600,
178
        ser1200,
179
        ser1800,
180
        ser2400,
181
        ser4800,
182
        ser9600,
183
        ser19200,
184
        ser38400,
185
        ser57600,
186
        ser115200
187
} eBaud;
188
 
189
/* Must be same order as eBaud definitions. */
190
static const unsigned short usBaudRateDivisor[] =
191
{
192
        0, /* Not sure if the first 6 are correct.  First cannot be used. */
193
        29127,
194
        19859,
195
        16302,
196
        14564,
197
        10923,
198
        6879,
199
        3437,
200
        1718,
201
        1145,
202
        859,
203
        429,
204
        214,
205
        107,
206
        54,
207
        35,
208
        18
209
};
210
 
211
 
212
typedef struct xCOM_PORT
213
{
214
        /* Hardware parameters for this port. */
215
        short sTxInterruptOn;
216
        unsigned short usIntReg;
217
        unsigned short usBaudReg;
218
        unsigned short usRxReg;
219
        unsigned short usTxReg;
220
        unsigned short usStatusReg;
221
        unsigned short usCtrlReg;
222
 
223
        unsigned short usIRQVector;
224
 
225
        /* Queues used for communications with com test task. */
226
        xQueueHandle xRxedChars;
227
        xQueueHandle xCharsForTx;
228
 
229
        /* This semaphore does nothing useful except test a feature of the
230
        scheduler. */
231
        xSemaphoreHandle xTestSem;
232
 
233
} xComPort;
234
 
235
static xComPort xPorts[ serMAX_PORTS ] =
236
{
237
        { pdFALSE, serPORT_0_INT_REG, serPORT_0_BAUD_REG, serPORT_0_RX_REG, serPORT_0_TX_REG, serPORT_0_STATUS_REG, serPORT_0_CTRL_REG, serPORT_0_IRQ, NULL, NULL, NULL },
238
        { pdFALSE, serPORT_1_INT_REG, serPORT_1_BAUD_REG, serPORT_1_RX_REG, serPORT_1_TX_REG, serPORT_1_STATUS_REG, serPORT_1_CTRL_REG, serPORT_1_IRQ, NULL, NULL, NULL }
239
};
240
 
241
typedef xComPort * xComPortHandle;
242
 
243
/* These prototypes are repeated here so we don't have to include the serial header.  This allows
244
the xComPortHandle structure details to be private to this file. */
245
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
246
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
247
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
248
void vSerialClose( xComPortHandle xPort );
249
short sSerialWaitForSemaphore( xComPortHandle xPort );
250
/*-----------------------------------------------------------*/
251
 
252
static short xComPortISR( xComPort * const pxPort );
253
 
254
#define vInterruptOn( pxPort, usInterrupt )                                                                             \
255
{                                                                                                                                                               \
256
unsigned short usIn;                                                                                                            \
257
                                                                                                                                                                \
258
        portENTER_CRITICAL();                                                                                                           \
259
        {                                                                                                                                                       \
260
                if( pxPort->sTxInterruptOn == pdFALSE )                                                                 \
261
                {                                                                                                                                               \
262
                        usIn = portINPUT_WORD( pxPort->usCtrlReg );                                                     \
263
                        portOUTPUT_WORD( pxPort->usCtrlReg, usIn | usInterrupt );                       \
264
                                                                                                                                                                \
265
                        pxPort->sTxInterruptOn = pdTRUE;                                                                        \
266
                }                                                                                                                                               \
267
        }                                                                                                                                                       \
268
        portEXIT_CRITICAL();                                                                                                                    \
269
}
270
/*-----------------------------------------------------------*/
271
 
272
#define vInterruptOff( pxPort, usInterrupt )                                                                    \
273
{                                                                                                                                                               \
274
        unsigned short usIn = portINPUT_WORD( pxPort->usCtrlReg );                              \
275
        if( usIn & usInterrupt )                                                                                                        \
276
        {                                                                                                                                                       \
277
                portOUTPUT_WORD( pxPort->usCtrlReg, usIn & ~usInterrupt);                               \
278
                pxPort->sTxInterruptOn = pdFALSE;                                                                               \
279
        }                                                                                                                                                       \
280
}
281
/*-----------------------------------------------------------*/
282
 
283
 
284
/* Define an interrupt handler for each port */
285
#define COM_IRQ_WRAPPER(N)                                                                              \
286
        static void __interrupt COM_IRQ##N##_WRAPPER( void )            \
287
        {                                                                                                                       \
288
        if( xComPortISR( &( xPorts[##N##] ) ) )                 \
289
        {                                                       \
290
                        portSWITCH_CONTEXT();                             \
291
                }                                                       \
292
        }
293
 
294
 
295
 
296
COM_IRQ_WRAPPER( 0 )
297
COM_IRQ_WRAPPER( 1 )
298
 
299
static pxISR xISRs[ serMAX_PORTS ] =
300
{
301
        COM_IRQ0_WRAPPER,
302
        COM_IRQ1_WRAPPER
303
};
304
 
305
/*-----------------------------------------------------------*/
306
 
307
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
308
{
309
unsigned short usPort;
310
xComPortHandle pxPort = NULL;
311
 
312
/* BAUDDIV = ( Microprocessor Clock / Baud Rate ) / 16 */
313
 
314
        /* Only n, 8, 1 is supported so these parameters are not required for this
315
        port. */
316
        ( void ) eWantedParity;
317
        ( void ) eWantedDataBits;
318
    ( void ) eWantedStopBits;
319
 
320
        /* Currently only n,8,1 is supported. */
321
 
322
        usPort = ( unsigned short ) ePort;
323
 
324
        if( usPort < serMAX_PORTS )
325
        {
326
                pxPort = &( xPorts[ usPort ] );
327
 
328
                portENTER_CRITICAL();
329
                {
330
                        unsigned short usInWord;
331
 
332
                        /* Create the queues used by the com test task. */
333
                        pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
334
                        pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
335
 
336
                        /* Create the test semaphore.  This does nothing useful except test a feature of the scheduler. */
337
                        vSemaphoreCreateBinary( pxPort->xTestSem );
338
 
339
                        /* There is no ISR here already to restore later. */
340
                        _dos_setvect( ( short ) pxPort->usIRQVector, xISRs[ usPort ] );
341
 
342
                        usInWord = portINPUT_WORD( pxPort->usIntReg );
343
                        usInWord &= ~serINTERRUPT_MASK;
344
                        usInWord |= serINTERRUPT_PRIORITY;
345
                        portOUTPUT_WORD( pxPort->usIntReg, usInWord );
346
 
347
                        portOUTPUT_WORD( pxPort->usBaudReg, usBaudRateDivisor[ eWantedBaud ] );
348
                        portOUTPUT_WORD( pxPort->usCtrlReg, serENABLE_INTERRUPTS | serMODE | serENABLE_TX_MACHINES | serENABLE_RX_MACHINES );
349
 
350
                        portOUTPUT_WORD( pxPort->usStatusReg, serCLEAR_ALL_STATUS_BITS );
351
                }
352
                portEXIT_CRITICAL();
353
        }
354
 
355
        return pxPort;
356
} /*lint !e715 Some parameters are not used as only a subset of the serial port functionality is currently implemented. */
357
/*-----------------------------------------------------------*/
358
 
359
void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
360
{
361
unsigned short usByte;
362
char *pcNextChar;
363
 
364
        pcNextChar = ( char * ) pcString;
365
 
366
        for( usByte = 0; usByte < usStringLength; usByte++ )
367
        {
368
                xQueueSend( pxPort->xCharsForTx, pcNextChar, serDONT_BLOCK );
369
                pcNextChar++;
370
        }
371
 
372
        vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
373
}
374
/*-----------------------------------------------------------*/
375
 
376
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
377
{
378
        /* Get the next character from the buffer, note that this routine is only
379
        called having checked that the is (at least) one to get */
380
        if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
381
        {
382
                return pdTRUE;
383
        }
384
        else
385
        {
386
                return pdFALSE;
387
        }
388
}
389
/*-----------------------------------------------------------*/
390
 
391
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
392
{
393
        if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
394
        {
395
                return pdFAIL;
396
        }
397
 
398
        vInterruptOn( pxPort, serTX_HOLD_EMPTY_INT );
399
 
400
        return pdPASS;
401
}
402
/*-----------------------------------------------------------*/
403
 
404
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
405
{
406
const portTickType xBlockTime = ( portTickType ) 0xffff;
407
 
408
        /* This function does nothing interesting, but test the
409
        semaphore from ISR mechanism. */
410
        return xSemaphoreTake( xPort->xTestSem, xBlockTime );
411
}
412
/*-----------------------------------------------------------*/
413
 
414
void vSerialClose( xComPortHandle xPort )
415
{
416
unsigned short usOutput;
417
 
418
        /* Turn off the interrupts.  We may also want to delete the queues and/or
419
        re-install the original ISR. */
420
 
421
        portENTER_CRITICAL();
422
        {
423
                usOutput = portINPUT_WORD( xPort->usCtrlReg );
424
 
425
                usOutput &= ~serENABLE_INTERRUPTS;
426
                usOutput &= ~serENABLE_TX_MACHINES;
427
                usOutput &= ~serENABLE_RX_MACHINES;
428
                portOUTPUT_WORD( xPort->usCtrlReg, usOutput );
429
 
430
                usOutput = portINPUT_WORD( xPort->usIntReg );
431
                usOutput |= serINTERRUPT_MASK;
432
                portOUTPUT_WORD( xPort->usIntReg, usOutput );
433
        }
434
        portEXIT_CRITICAL();
435
}
436
/*-----------------------------------------------------------*/
437
 
438
static portBASE_TYPE xComPortISR( xComPort * const pxPort )
439
{
440
unsigned short usStatusRegister;
441
char cChar;
442
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, xContinue = pdTRUE;
443
 
444
        /* NOTE:  THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
445
        THE SCHEDULER FUNCTIONALITY.  REAL APPLICATIONS SHOULD NOT USE THIS
446
        FUNCTION. */
447
 
448
 
449
        while( xContinue == pdTRUE )
450
        {
451
                xContinue = pdFALSE;
452
                usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );
453
 
454
                if( usStatusRegister & serRX_READY )
455
                {
456
                        cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
457
                        xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );
458
 
459
                        /* Also release the semaphore - this does nothing interesting and is just a test. */
460
                        xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
461
 
462
                        /* We have performed an action this cycle - there may be other to perform. */
463
                        xContinue = pdTRUE;
464
                }
465
 
466
                if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
467
                {
468
                        if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
469
                        {
470
                                portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
471
 
472
                                /* We have performed an action this cycle - there may be others to perform. */
473
                                xContinue = pdTRUE;
474
                        }
475
                        else
476
                        {
477
                                /* Queue empty, nothing to send */
478
                                vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
479
                        }
480
                }
481
        }
482
 
483
        serRESET_PIC( pxPort->usIRQVector );
484
 
485
        /* If posting to the queue woke a task that was blocked on the queue we may
486
        want to switch to the woken task - depending on its priority relative to
487
        the task interrupted by this ISR. */
488
        return xHigherPriorityTaskWoken;
489
}
490
 
491
 
492
 
493
 
494
 
495
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.