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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [WizNET_DEMO_GCC_ARM7/] [i2cISR.c] - Blame information for rev 623

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

Line No. Rev Author Line
1 585 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
/* Standard includes. */
56
#include <stdlib.h>
57
 
58
/* Scheduler include files. */
59
#include "FreeRTOS.h"
60
#include "task.h"
61
#include "queue.h"
62
#include "semphr.h"
63
 
64
/* Application includes. */
65
#include "i2c.h"
66
 
67
/*-----------------------------------------------------------*/
68
 
69
/* Bit definitions within the I2CONCLR register. */
70
#define i2cSTA_BIT              ( ( unsigned char ) 0x20 )
71
#define i2cSI_BIT               ( ( unsigned char ) 0x08 )
72
#define i2cSTO_BIT              ( ( unsigned char ) 0x10 )
73
#define i2cAA_BIT               ( ( unsigned char ) 0x04 )
74
 
75
/* Status codes for the I2STAT register. */
76
#define i2cSTATUS_START_TXED                    ( 0x08 )
77
#define i2cSTATUS_REP_START_TXED                ( 0x10 )
78
#define i2cSTATUS_TX_ADDR_ACKED                 ( 0x18 )
79
#define i2cSTATUS_DATA_TXED                             ( 0x28 )
80
#define i2cSTATUS_RX_ADDR_ACKED                 ( 0x40 )
81
#define i2cSTATUS_DATA_RXED                             ( 0x50 )
82
#define i2cSTATUS_LAST_BYTE_RXED                ( 0x58 )
83
 
84
/* Constants for operation of the VIC. */
85
#define i2cCLEAR_VIC_INTERRUPT  ( 0 )
86
 
87
/* Misc constants. */
88
#define i2cJUST_ONE_BYTE_TO_RX  ( 1 )
89
#define i2cBUFFER_ADDRESS_BYTES ( 2 )
90
 
91
/* End the current transmission and free the bus. */
92
#define i2cEND_TRANSMISSION( lStatus )                                  \
93
{                                                                                                               \
94
        I2C_I2CONCLR = i2cAA_BIT;                                                       \
95
        I2C_I2CONSET = i2cSTO_BIT;                                                      \
96
        eCurrentState = eSentStart;                                                     \
97
        lTransactionCompleted = lStatus;                                        \
98
}
99
/*-----------------------------------------------------------*/
100
 
101
/* Valid i2c communication states. */
102
typedef enum
103
{
104
        eSentStart,                             /*<< Last action was the transmission of a start bit. */
105
        eSentAddressForWrite,   /*<< Last action was the transmission of the slave address we are to write to. */
106
        eSentAddressForRead,    /*<< Last action was the transmission of the slave address we are to read from. */
107
        eSentData,                              /*<< Last action was the transmission of a data byte. */
108
        eReceiveData                    /*<< We expected data to be received. */
109
} I2C_STATE;
110
/*-----------------------------------------------------------*/
111
 
112
/* Points to the message currently being sent. */
113
volatile xI2CMessage *pxCurrentMessage = NULL;
114
 
115
/* The queue of messages waiting to be transmitted. */
116
static xQueueHandle xMessagesForTx;
117
 
118
/* Flag used to indicate whether or not the ISR is amid sending a message. */
119
unsigned long ulBusFree = ( unsigned long ) pdTRUE;
120
 
121
/* Setting this to true will cause the TCP task to think a message is
122
complete and thus restart.  It can therefore be used under error states
123
to force a restart. */
124
volatile long lTransactionCompleted = pdTRUE;
125
 
126
/*-----------------------------------------------------------*/
127
 
128
void vI2CISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxTxMessages, unsigned long **ppulBusFree )
129
{
130
        /* Create the queues used to hold Rx and Tx characters. */
131
        xMessagesForTx = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( xI2CMessage * ) );
132
 
133
        /* Pass back a reference to the queue and bus free flag so the I2C API file
134
        can post messages. */
135
        *pxTxMessages = xMessagesForTx;
136
        *ppulBusFree = &ulBusFree;
137
}
138
/*-----------------------------------------------------------*/
139
 
140
/* The ISR entry point. */
141
void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));
142
 
143
/* The ISR function to perform the actual work.  This must be a separate
144
function from the wrapper to ensure the correct stack frame is set up. */
145
void vI2C_ISR_Handler( void );
146
 
147
/*-----------------------------------------------------------*/
148
 
149
void vI2C_ISR_Wrapper( void )
150
{
151
        /* Save the context of the interrupted task. */
152
        portSAVE_CONTEXT();
153
 
154
        /* Call the handler to perform the actual work.  This must be a
155
        separate function to ensure the correct stack frame is set up. */
156
        vI2C_ISR_Handler();
157
 
158
        /* Restore the context of whichever task is going to run next. */
159
        portRESTORE_CONTEXT();
160
}
161
/*-----------------------------------------------------------*/
162
 
163
void vI2C_ISR_Handler( void )
164
{
165
/* Holds the current transmission state. */
166
static I2C_STATE eCurrentState = eSentStart;
167
static long lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
168
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
169
long lBytesLeft;
170
 
171
        /* The action taken for this interrupt depends on our current state. */
172
        switch( eCurrentState )
173
        {
174
                case eSentStart :
175
 
176
                                /* We sent a start bit, if it was successful we can
177
                                go on to send the slave address. */
178
                                if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
179
                                {
180
                                        /* Send the slave address. */
181
                                        I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;
182
 
183
                                        if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
184
                                        {
185
                                                /* We are then going to read bytes back from the
186
                                                slave. */
187
                                                eCurrentState = eSentAddressForRead;
188
 
189
                                                /* Initialise the buffer index so the first byte goes
190
                                                into the first buffer position. */
191
                                                lMessageIndex = 0;
192
                                        }
193
                                        else
194
                                        {
195
                                                /* We are then going to write some data to the slave. */
196
                                                eCurrentState = eSentAddressForWrite;
197
 
198
                                                /* When writing bytes we first have to send the two
199
                                                byte buffer address so lMessageIndex is set negative,
200
                                                when it reaches 0 it is time to send the actual data. */
201
                                                lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
202
                                        }
203
                                }
204
                                else
205
                                {
206
                                        /* Could not send the start bit so give up. */
207
                                        i2cEND_TRANSMISSION( pdFAIL );
208
                                }
209
 
210
                                I2C_I2CONCLR = i2cSTA_BIT;
211
 
212
                                break;
213
 
214
                case eSentAddressForWrite :
215
 
216
                                /* We sent the address of the slave we are going to write to.
217
                                If this was acknowledged we     can go on to send the data. */
218
                                if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
219
                                {
220
                                        /* Start the first byte transmitting which is the
221
                                        first byte of the buffer address to which the data will
222
                                        be sent. */
223
                                        I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
224
                                        eCurrentState = eSentData;
225
                                }
226
                                else
227
                                {
228
                                        /* Address was not acknowledged so give up. */
229
                                        i2cEND_TRANSMISSION( pdFAIL );
230
                                }
231
                                break;
232
 
233
                case eSentAddressForRead :
234
 
235
                                /* We sent the address of the slave we are going to read from.
236
                                If this was acknowledged we can go on to read the data. */
237
                                if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
238
                                {
239
                                        eCurrentState = eReceiveData;
240
                                        if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
241
                                        {
242
                                                /* Don't ack the last byte of the message. */
243
                                                I2C_I2CONSET = i2cAA_BIT;
244
                                        }
245
                                }
246
                                else
247
                                {
248
                                        /* Something unexpected happened - give up. */
249
                                        i2cEND_TRANSMISSION( pdFAIL );
250
                                }
251
                                break;
252
 
253
                case eReceiveData :
254
 
255
                                /* We have just received a byte from the slave. */
256
                                if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
257
                                {
258
                                        /* Buffer the byte just received then increment the index
259
                                        so it points to the next free space. */
260
                                        pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
261
                                        lMessageIndex++;
262
 
263
                                        /* How many more bytes are we expecting to receive? */
264
                                        lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
265
                                        if( lBytesLeft == ( unsigned long ) 0 )
266
                                        {
267
                                                /* This was the last byte in the message. */
268
                                                i2cEND_TRANSMISSION( pdPASS );
269
 
270
                                                /* If xMessageCompleteSemaphore is not null then there
271
                                                is a task waiting for this message to complete and we
272
                                                must 'give' the semaphore so the task is woken.*/
273
                                                if( pxCurrentMessage->xMessageCompleteSemaphore )
274
                                                {
275
                                                        xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
276
                                                }
277
 
278
                                                /* Are there any other messages to transact? */
279
                                                if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
280
                                                {
281
                                                        /* Start the next message - which was
282
                                                        retrieved from the queue. */
283
                                                        I2C_I2CONSET = i2cSTA_BIT;
284
                                                }
285
                                                else
286
                                                {
287
                                                        /* No more messages were found to be waiting for
288
                                                        transaction so the bus is free. */
289
                                                        ulBusFree = ( unsigned long ) pdTRUE;
290
                                                }
291
                                        }
292
                                        else
293
                                        {
294
                                                /* There are more bytes to receive but don't ack the
295
                                                last byte. */
296
                                                if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
297
                                                {
298
                                                        I2C_I2CONCLR = i2cAA_BIT;
299
                                                }
300
                                        }
301
                                }
302
                                else
303
                                {
304
                                        /* Something unexpected happened - give up. */
305
                                        i2cEND_TRANSMISSION( pdFAIL );
306
                                }
307
 
308
                                break;
309
 
310
                case eSentData  :
311
 
312
                                /* We sent a data byte, if successful send the  next byte in
313
                                the message. */
314
                                if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
315
                                {
316
                                        /* Index to the next byte to send. */
317
                                        lMessageIndex++;
318
                                        if( lMessageIndex < 0 )
319
                                        {
320
                                                /* lMessage index is still negative so we have so far
321
                                                only sent the first byte of the buffer address.  Send
322
                                                the second byte now, then initialise the buffer index
323
                                                to zero so the next byte sent comes from the actual
324
                                                data buffer. */
325
                                                I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
326
                                        }
327
                                        else if( lMessageIndex < pxCurrentMessage->lMessageLength )
328
                                        {
329
                                                /* Simply send the next byte in the tx buffer. */
330
                                                I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];
331
                                        }
332
                                        else
333
                                        {
334
                                                /* No more bytes in this message to be send.  Finished
335
                                                sending message - send a stop bit. */
336
                                                i2cEND_TRANSMISSION( pdPASS );
337
 
338
                                                /* If xMessageCompleteSemaphore is not null then there
339
                                                is a task waiting for this message to be sent and the
340
                                                semaphore must be 'given' to wake the task. */
341
                                                if( pxCurrentMessage->xMessageCompleteSemaphore )
342
                                                {
343
                                                        xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
344
                                                }
345
 
346
                                                /* Are there any other messages to transact? */
347
                                                if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
348
                                                {
349
                                                        /* Start the next message from the Tx queue. */
350
                                                        I2C_I2CONSET = i2cSTA_BIT;
351
                                                }
352
                                                else
353
                                                {
354
                                                        /* No more message were queues for transaction so
355
                                                        the bus is free. */
356
                                                        ulBusFree = ( unsigned long ) pdTRUE;
357
                                                }
358
                                        }
359
                                }
360
                                else
361
                                {
362
                                        /* Something unexpected happened, give up. */
363
                                        i2cEND_TRANSMISSION( pdFAIL );
364
                                }
365
                                break;
366
 
367
                default :
368
 
369
                                /* Should never get here. */
370
                                eCurrentState = eSentStart;
371
                                break;
372
        }
373
 
374
        /* Clear the interrupt. */
375
        I2C_I2CONCLR = i2cSI_BIT;
376
        VICVectAddr = i2cCLEAR_VIC_INTERRUPT;
377
 
378
        if( xHigherPriorityTaskWoken )
379
        {
380
                portYIELD_FROM_ISR();
381
        }
382
}
383
/*-----------------------------------------------------------*/
384
 

powered by: WebSVN 2.1.0

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