root/webserver/example/EnergyMeters/Source/serial.c

Revision 72, 12.9 kB (checked in by phil, 14 years ago)

- switched baud rate to 2400 (try to minimize errors)
- corrected binary coded hex number conversion algorithm for yield calculation

Line 
1 /*
2         FreeRTOS.org V5.0.2 - Copyright (C) 2003-2008 Richard Barry.
3
4         This file is part of the FreeRTOS.org distribution.
5
6         FreeRTOS.org is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; either version 2 of the License, or
9         (at your option) any later version.
10
11         FreeRTOS.org is distributed in the hope that it will be useful,
12         but WITHOUT ANY WARRANTY; without even the implied warranty of
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14         GNU General Public License for more details.
15
16         You should have received a copy of the GNU General Public License
17         along with FreeRTOS.org; if not, write to the Free Software
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20         A special exception to the GPL can be applied should you wish to distribute
21         a combined work that includes FreeRTOS.org, without being obliged to provide
22         the source code for any proprietary components.  See the licensing section
23         of http://www.FreeRTOS.org for full details of how and when the exception
24         can be applied.
25
26     ***************************************************************************
27     ***************************************************************************
28     *                                                                         *
29     * SAVE TIME AND MONEY!  We can port FreeRTOS.org to your own hardware,    *
30     * and even write all or part of your application on your behalf.          *
31     * See http://www.OpenRTOS.com for details of the services we provide to   *
32     * expedite your project.                                                  *
33     *                                                                         *
34     ***************************************************************************
35     ***************************************************************************
36
37         Please ensure to read the configuration and relevant port sections of the
38         online documentation.
39
40         http://www.FreeRTOS.org - Documentation, latest information, license and
41         contact details.
42
43         http://www.SafeRTOS.com - A version that is certified for use in safety
44         critical systems.
45
46         http://www.OpenRTOS.com - Commercial support, development, porting,
47         licensing and training services.
48 */
49
50
51 /*
52         BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0.
53 */
54
55 /* Standard includes. */
56 #include <stdlib.h>
57
58 /* Scheduler includes. */
59 #include "FreeRTOS.h"
60 #include "queue.h"
61 #include "task.h"
62
63 #include "semphr.h"
64
65 /* Demo application includes. */
66 #include "serial.h"
67
68
69 /*-----------------------------------------------------------*/
70
71 /* Constants to setup and access the UART. */
72 #define serDLAB                                                 ( ( unsigned portCHAR ) 0x80 )
73 #define serENABLE_INTERRUPTS                    ( ( unsigned portCHAR ) 0x03 )
74 #define serNO_PARITY                                    ( ( unsigned portCHAR ) 0x00 )
75 #define ser1_STOP_BIT                                   ( ( unsigned portCHAR ) 0x00 )
76 #define ser8_BIT_CHARS                                  ( ( unsigned portCHAR ) 0x03 )
77 #define serFIFO_ON                                              ( ( unsigned portCHAR ) 0x01 )
78 #define serCLEAR_FIFO                                   ( ( unsigned portCHAR ) 0x06 )
79 #define serWANTED_CLOCK_SCALING                 ( ( unsigned portLONG ) 16 )
80
81 /* Constants to setup and access the VIC. */
82 #define serU3VIC_CHANNEL                                ( ( unsigned portLONG ) 0x0006 )
83 #define serU3VIC_CHANNEL_BIT                    ( ( unsigned portLONG ) 0x0040 )
84 #define serU3VIC_ENABLE                                 ( ( unsigned portLONG ) 0x0020 )
85 #define serCLEAR_VIC_INTERRUPT                  ( ( unsigned portLONG ) 0 )
86
87 /* Constants to determine the ISR source. */
88 #define serSOURCE_THRE                                  ( ( unsigned portCHAR ) 0x02 )
89 #define serSOURCE_RX_TIMEOUT                    ( ( unsigned portCHAR ) 0x0c )
90 #define serSOURCE_ERROR                                 ( ( unsigned portCHAR ) 0x06 )
91 #define serSOURCE_RX                                    ( ( unsigned portCHAR ) 0x04 )
92 #define serINTERRUPT_SOURCE_MASK                ( ( unsigned portCHAR ) 0x0f )
93
94 /* Misc. */
95 #define serINVALID_QUEUE                                ( ( xQueueHandle ) 0 )
96 #define serHANDLE                                               ( ( xComPortHandle ) 1 )
97 #define serNO_BLOCK                                             ( ( portTickType ) 0 )
98
99 /*-----------------------------------------------------------*/
100
101 /* Queues used to hold received characters, and characters waiting to be
102 transmitted. */
103 static xQueueHandle xRxedChars;
104 static xQueueHandle xCharsForTx;
105 static volatile portLONG lTHREEmpty = pdFALSE;
106
107 /*-----------------------------------------------------------*/
108
109 /* The ISR.  Note that this is called by a wrapper written in the file
110 SerialISR.s79.  See the WEB documentation for this port for further
111 information. */
112 void vSerialISR( void );
113
114
115 extern void ( vUART3_ISR_Wrapper )( void );
116 extern unsigned int uart3TxRunning;
117
118
119
120
121 /* The interrupt entry point. */
122 void vUART3_ISR_Wrapper( void ) __attribute__((naked));
123
124 /* The function that actually performs the interrupt processing.  This must be
125 separate to the wrapper to ensure the correct stack frame is set up. */
126 void vSerialISR( void );
127
128
129 void vSerialISR( void )
130 {
131 signed portCHAR cChar;
132 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
133
134         /* What caused the interrupt? */
135         switch( U3IIR & serINTERRUPT_SOURCE_MASK )
136         {
137                 case serSOURCE_ERROR :  /* Not handling this, but clear the interrupt. */
138                                                                 cChar = U3LSR;
139                                                                 break;
140
141                 case serSOURCE_THRE     :       /* The THRE is empty.  If there is another
142                                                                 character in the Tx queue, send it now. */
143
144                                   if (uart3TxRunning == 0)
145                                   {
146                                     RXD_RS485(); /* we are done sending, we have to receive now. */
147                                   }
148                                   else
149                                   {
150                                     TXD_RS485(); /* we are still sending */
151                                   }
152 #if 0                                                     
153                                                                 if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
154                                                                 {
155                                                                         //TXD_RS485();  /* send */
156                                                                         U3THR = cChar;
157                                                                         RXD_RS485();   
158                                                                 }
159                                                                 else
160                                                                 {
161                                                                         /* There are no further characters
162                                                                         queued to send so we can indicate
163                                                                         that the THRE is available. */
164                                                                         lTHREEmpty = pdTRUE;
165
166                                                                         /* the queue is empty, the FIFO is empty. switch to RXD,
167                                                                          * so we can receive the response from the network.
168                                                                          */
169                                                                         RXD_RS485();
170
171                                                                 }
172                                                                 break;
173
174 #endif
175
176
177                 case serSOURCE_RX_TIMEOUT :
178                 case serSOURCE_RX       :       /* A character was received.  Place it in
179                                                                 the queue of received characters. */
180                                                                 cChar = U3RBR;
181                                                                 xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
182                                                                 break;
183
184                 default                         :       /* There is nothing to do, leave the ISR. */
185                                                                 break;
186         }
187
188
189         /* Clear the ISR in the VIC. */
190         VICVectAddr = serCLEAR_VIC_INTERRUPT;       
191
192
193         /* Exit the ISR.  If a task was woken by either a character being received
194         or transmitted then a context switch will occur. */
195
196         portYIELD_FROM_ISR();
197         //portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
198
199
200 }
201 /*-----------------------------------------------------------*/
202
203 void vUART3_ISR_Wrapper( void )
204 {
205         /* Save the context of the interrupted task. */
206         portSAVE_CONTEXT();
207
208         /* Call the handler function.  This must be separate from the wrapper
209         function to ensure the correct stack frame is set up. */
210         vSerialISR();
211
212         /* Restore the context of whichever task is going to run next. */
213         portRESTORE_CONTEXT();
214 }
215
216
217
218
219
220 /*-----------------------------------------------------------*/
221
222 xComPortHandle xSerialPortInitMinimal( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
223 {
224
225
226   unsigned int baud = 2400;
227   unsigned int divisor = get_uart_clk(3, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud);
228
229
230
231 unsigned portLONG ulDivisor, ulWantedClock;
232 xComPortHandle xReturn = serHANDLE;
233 extern void ( vSerialISREntry) ( void );
234
235         /* Create the queues used to hold Rx and Tx characters. */
236         xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
237         xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
238
239         /* Initialise the THRE empty flag. */
240         lTHREEmpty = pdTRUE;
241
242         if(
243                 ( xRxedChars != serINVALID_QUEUE ) &&
244                 ( xCharsForTx != serINVALID_QUEUE ) &&
245                 ( ulWantedBaud != ( unsigned portLONG ) 0 )
246           )
247         {
248                 portENTER_CRITICAL();
249                 {
250                   /* Setup the baud rate:  Calculate the divisor value. */
251                   ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
252                   ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
253
254
255                   // xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx
256                   PCONP   |= 0x02000000;                                                                        // UART3 Power-ON
257                
258                
259                
260                 /* Configure UART */
261                
262                
263                  U3LCR = 0x83;                                                                  // 8 bits, no Parity, 1 Stop bit
264                
265                  U3DLL = divisor & 0xFF;
266                
267                  U3DLM = (divisor >> 8) & 0xFF;
268                
269                   /* Turn on the FIFO's and clear the buffers. */
270                   U3FCR = ( serFIFO_ON | serCLEAR_FIFO );
271                
272                  
273                  U3LCR = 0x03; 
274                
275                   /* Setup the VIC for the UART. */
276                   VICVectAddr29 = (portLONG) vUART3_ISR_Wrapper; /* UART3 interrupt handler */
277                   VICIntEnable |= (1<<29); /* Enable VIC index-29 (sUART3) */
278                  
279                   /* Enable UART3 interrupts. */
280                   U3IER |= serENABLE_INTERRUPTS;
281                 }
282                 portEXIT_CRITICAL();
283
284                 xReturn = ( xComPortHandle ) 1;
285         }
286         else
287         {
288                 xReturn = ( xComPortHandle ) 0;
289         }
290
291         return xReturn;
292 }
293 /*-----------------------------------------------------------*/
294
295 signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime )
296 {
297         /* The port handle is not required as this driver only supports UART3. */
298         ( void ) pxPort;
299
300         /* Get the next character from the buffer.  Return false if no characters
301         are available, or arrive before xBlockTime expires. */
302         if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )
303         {
304                 return pdTRUE;
305         }
306         else
307         {
308                 return pdFALSE;
309         }
310 }
311 /*-----------------------------------------------------------*/
312
313 void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )
314 {
315 signed portCHAR *pxNext;
316
317         /* NOTE: This implementation does not handle the queue being full as no
318         block time is used! */
319
320         /* The port handle is not required as this driver only supports UART0. */
321         ( void ) pxPort;
322         ( void ) usStringLength;
323
324         /* Send each character in the string, one at a time. */
325         pxNext = ( signed portCHAR * ) pcString;
326         while( *pxNext )
327         {
328                 xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );
329                 pxNext++;
330         }
331 }
332 /*-----------------------------------------------------------*/
333
334 signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )
335 {
336 signed portBASE_TYPE xReturn;
337
338         /* The port handle is not required as this driver only supports UART3. */
339         ( void ) pxPort;
340
341         portENTER_CRITICAL();
342         {
343                 /* Is there space to write directly to the UART? */
344                 if( lTHREEmpty == ( portLONG ) pdTRUE )
345                 {
346                         /* We wrote the character directly to the UART, so was
347                         successful. */
348                         lTHREEmpty = pdFALSE;
349                         //TXD_RS485(); 
350                         U3THR = cOutChar;
351                         //RXD_RS485(); 
352                         xReturn = pdPASS;
353                 }
354                 else
355                 {
356                         /* We cannot write directly to the UART, so queue the character.
357                         Block for a maximum of xBlockTime if there is no space in the
358                         queue.  It is ok to block within a critical section as each
359                         task has it's own critical section management. */
360                         xReturn = xQueueSend( xCharsForTx, &cOutChar, xBlockTime );
361
362                         /* Depending on queue sizing and task prioritisation:  While we
363                         were blocked waiting to post interrupts were not disabled.  It is
364                         possible that the serial ISR has emptied the Tx queue, in which
365                         case we need to start the Tx off again. */
366                         if( lTHREEmpty == ( portLONG ) pdTRUE )
367                         {
368                                 xQueueReceive( xCharsForTx, &cOutChar, serNO_BLOCK );
369                                 lTHREEmpty = pdFALSE;
370                                 //TXD_RS485(); 
371                                 U3THR = cOutChar;
372                                 //RXD_RS485();
373                         }
374                 }
375         }
376         portEXIT_CRITICAL();
377
378         return xReturn;
379 }
380 /*-----------------------------------------------------------*/
381
Note: See TracBrowser for help on using the browser.