changing circuitry to disable RTC, update initialization to match
[fw/openalt] / uart / uart.c
1 /* 
2    INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0 and UART1. 
3
4    This file contains all the serial port components that can be compiled to
5    either ARM or THUMB mode.  Components that must be compiled to ARM mode are
6    contained in serialISR.c.
7  */
8
9 //
10 //  Standard includes
11 //
12 #include <stdlib.h>
13
14 //
15 //  Scheduler includes
16 //
17 #include "FreeRTOS.h"
18 #include "queue.h"
19 #include "task.h"
20
21 //
22 //  Demo application includes
23 //
24 #include "uart.h"
25 #include "uartISR.h"
26
27 //
28 //  Constants to setup and access the UART
29 //
30 #define serWANTED_CLOCK_SCALING   ((unsigned portLONG) 16)
31
32 //
33 //  Constants to setup and access the VIC
34 //
35 #define serINVALID_QUEUE                                  ((xQueueHandle) 0)
36 #define serHANDLE                                               ((xComPortHandle) 1)
37 #define serNO_BLOCK                                           ((portTickType) 0)
38
39 //
40 //  Queues used to hold received characters, and characters waiting to be transmitted
41 //
42 static xQueueHandle xRX0Queue; 
43 static xQueueHandle xTX0Queue; 
44 static xQueueHandle xRX1Queue; 
45 static xQueueHandle xTX1Queue; 
46
47 //
48 //  Communication flag between the interrupt service routine and serial API
49 //
50 static volatile portLONG *plTHREEmpty;
51 static volatile portLONG *plTHREEmpty1;
52
53 //
54 //
55 //
56 xComPortHandle uartInit (portCHAR pxPort, unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength)
57 {
58   unsigned portLONG ulDivisor;
59   unsigned portLONG ulWantedClock;
60   xComPortHandle xReturn = serHANDLE;
61
62   switch (pxPort)
63   {
64     case 0 :    
65       {
66         uartISRCreateQueues (0, uxQueueLength, &xRX0Queue, &xTX0Queue, &plTHREEmpty);
67
68         if ((xRX0Queue != serINVALID_QUEUE) && 
69             (xTX0Queue != serINVALID_QUEUE) && 
70             (ulWantedBaud != (unsigned portLONG) 0) 
71            )
72         {
73           portENTER_CRITICAL ();
74
75           {
76             SCB_PCONP |= SCB_PCONP_PCUART0;
77
78             //
79             //  Setup the baud rate:  Calculate the divisor value
80             //
81             ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
82             ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
83
84             //
85             //  Set the DLAB bit so we can access the divisor
86             //
87             UART0_LCR |= UART_LCR_DLAB;
88
89             //
90             //  Setup the divisor
91             //
92             UART0_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
93             ulDivisor >>= 8;
94             UART0_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
95
96             //
97             //  Turn on the FIFO's and clear the buffers
98             //
99             UART0_FCR = UART_FCR_EN | UART_FCR_CLR;
100
101             //
102             //  Setup transmission format
103             //
104             UART0_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
105
106             //
107             //  Setup the VIC for the UART
108             //
109             VIC_IntSelect &= ~VIC_IntSelect_UART0;
110             VIC_VectAddr2 = (portLONG) uartISR0;
111             VIC_VectCntl2 = VIC_VectCntl_ENABLE | VIC_Channel_UART0;
112             VIC_IntEnable = VIC_IntEnable_UART0;
113
114             //
115             //  Enable UART0 interrupts
116             //
117             UART0_IER |= UART_IER_EI;
118           }
119
120           portEXIT_CRITICAL ();
121         }
122         else
123           xReturn = (xComPortHandle) 0;
124       }
125       break;
126
127     case 1:
128       {
129         uartISRCreateQueues (1, uxQueueLength, &xRX1Queue, &xTX1Queue, &plTHREEmpty1);
130
131         if ((xRX1Queue != serINVALID_QUEUE) && 
132             (xTX1Queue != serINVALID_QUEUE) && 
133             (ulWantedBaud != (unsigned portLONG) 0) 
134            )
135         {
136           portENTER_CRITICAL ();
137
138           {
139             SCB_PCONP |= SCB_PCONP_PCUART1;
140
141             //
142             //  Setup the baud rate:  Calculate the divisor value
143             //
144             ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
145             ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
146
147             //
148             //  Set the DLAB bit so we can access the divisor
149             //
150             UART1_LCR |= UART_LCR_DLAB;
151
152             //
153             //  Setup the divisor
154             //
155             UART1_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
156             ulDivisor >>= 8;
157             UART1_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
158
159             //
160             //  Turn on the FIFO's and clear the buffers
161             //
162             UART1_FCR = UART_FCR_EN | UART_FCR_CLR;
163
164             //
165             //  Setup transmission format
166             //
167             UART1_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
168
169             //
170             //  Setup the VIC for the UART
171             //
172             VIC_IntSelect &= ~VIC_IntSelect_UART1;
173             VIC_VectAddr3 = (portLONG) uartISR1;
174             VIC_VectCntl3 = VIC_VectCntl_ENABLE | VIC_Channel_UART1;
175             VIC_IntEnable = VIC_IntEnable_UART1;
176
177             //
178             //  Enable UART0 interrupts//
179             //
180             UART1_IER |= UART_IER_EI;
181           }
182
183           portEXIT_CRITICAL ();
184         }
185         else
186           xReturn = (xComPortHandle) 0;
187       }
188       break;
189   }
190
191   return xReturn;
192 }
193
194 signed portBASE_TYPE uartGetChar (portCHAR pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime)
195 {
196   switch (pxPort)
197   {
198     //
199     //  Get the next character from the buffer.  Return false if no characters are available, or arrive before xBlockTime expires
200     //
201     case 0:    
202       {
203         if (xQueueReceive (xRX0Queue, pcRxedChar, xBlockTime))
204           return pdTRUE;
205         else
206           return pdFALSE;
207       }
208       break;
209
210       //
211       //  Get the next character from the buffer.  Return false if no characters are available, or arrive before xBlockTime expires
212       //
213     case 1:
214       {
215         if (xQueueReceive (xRX1Queue, pcRxedChar, xBlockTime))
216           return pdTRUE;
217         else
218           return pdFALSE;
219       }
220       break;
221   }
222
223   return pdFALSE;
224 }
225
226 //
227 //
228 //
229 void uartPutString (portCHAR pxPort, const signed portCHAR * const pcString, portTickType xBlockTime)
230 {
231   signed portCHAR *pxNext;
232
233   pxNext = (signed portCHAR *) pcString;
234
235   while (*pxNext)
236   {
237     uartPutChar (pxPort, *pxNext, xBlockTime);
238     pxNext++;
239   }
240 }
241
242 //
243 //
244 //
245 signed portBASE_TYPE uartPutChar (portCHAR pxPort, signed portCHAR cOutChar, portTickType xBlockTime)
246 {
247   signed portBASE_TYPE xReturn = 0;
248
249   switch (pxPort)
250   {
251     case 0 :    
252       {
253         portENTER_CRITICAL ();
254
255         {
256           //
257           //  Is there space to write directly to the UART?
258           //
259           if (*plTHREEmpty == (portLONG) pdTRUE)
260           {
261             *plTHREEmpty = pdFALSE;
262             UART0_THR = cOutChar;
263             xReturn = pdPASS;
264           }
265           else 
266           {
267             //
268             //  We cannot write directly to the UART, so queue the character.  Block for a maximum of 
269             //  xBlockTime if there is no space in the queue.
270             //
271             xReturn = xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
272
273             //
274             //  Depending on queue sizing and task prioritisation:  While we were blocked waiting to post 
275             //  interrupts were not disabled.  It is possible that the serial ISR has emptied the Tx queue, 
276             //  in which case we need to start the Tx off again.
277             //
278             if ((*plTHREEmpty == (portLONG) pdTRUE) && (xReturn == pdPASS))
279             {
280               xQueueReceive (xTX0Queue, &cOutChar, serNO_BLOCK);
281               *plTHREEmpty = pdFALSE;
282               UART0_THR = cOutChar;
283             }
284           }
285         }
286
287         portEXIT_CRITICAL ();
288       }
289       break;
290
291     case 1 :
292       {
293         portENTER_CRITICAL ();
294
295         {
296           //
297           //  Is there space to write directly to the UART?
298           //
299           if (*plTHREEmpty1 == (portLONG) pdTRUE)
300           {
301             *plTHREEmpty1 = pdFALSE;
302             UART1_THR = cOutChar;
303             xReturn = pdPASS;
304           }
305           else 
306           {
307             //
308             //  We cannot write directly to the UART, so queue the character.  Block for a maximum of 
309             //  xBlockTime if there is no space in the queue.
310             //
311             xReturn = xQueueSend (xTX1Queue, &cOutChar, xBlockTime);
312
313             //
314             //  Depending on queue sizing and task prioritisation:  While we were blocked waiting to post 
315             //  interrupts were not disabled.  It is possible that the serial ISR has emptied the Tx queue, 
316             //  in which case we need to start the Tx off again.
317             //
318             if ((*plTHREEmpty1 == (portLONG) pdTRUE) && (xReturn == pdPASS))
319             {
320               xQueueReceive (xTX1Queue, &cOutChar, serNO_BLOCK);
321               *plTHREEmpty1 = pdFALSE;
322               UART1_THR = cOutChar;
323             }
324           }
325         }
326
327         portEXIT_CRITICAL ();   
328       }
329       break;
330
331     default:
332       return xReturn;
333       break;
334   }
335
336   return xReturn;
337 }
338
339 //
340 //
341 //
342 void uart0GetRxQueue (xQueueHandle *qh)
343 {
344   *qh = xRX0Queue;
345 }
346
347 void uart1GetRxQueue (xQueueHandle *qh)
348 {
349   *qh = xRX1Queue;
350 }