]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/mss_uart/mss_uart.c
Create directory structure to hold the (not yet created) Keil and IAR demo projects...
[freertos] / Demo / CORTEX_A2F200_IAR_and_Keil / MicroSemi_Code / drivers / mss_uart / mss_uart.c
1 /*******************************************************************************\r
2  * (c) Copyright 2007 Actel Corporation.  All rights reserved.\r
3  *\r
4  * SmartFusion Microcontroller Subsystem UART bare metal software driver\r
5  * implementation.\r
6  *\r
7  * SVN $Revision: 1898 $\r
8  * SVN $Date: 2009-12-21 17:27:57 +0000 (Mon, 21 Dec 2009) $\r
9  */\r
10 #include "mss_uart.h"\r
11 #include "../../CMSIS/mss_assert.h"\r
12 \r
13 #ifdef __cplusplus\r
14 extern "C" {\r
15 #endif \r
16 \r
17 /*******************************************************************************\r
18  * defines\r
19  */\r
20 #define TX_READY            0x01U\r
21 #define TX_COMPLETE             0U\r
22 \r
23 #define TX_FIFO_SIZE    16U\r
24 \r
25 #define FCR_TRIG_LEVEL_MASK     0xC0U\r
26 \r
27 #define IIRF_MASK   0x0FU\r
28 \r
29 /*******************************************************************************\r
30  * Possible values for Interrupt Identification Register Field.\r
31  */\r
32 #define IIRF_MODEM_STATUS   0x00U    \r
33 #define IIRF_THRE           0x02U\r
34 #define IIRF_RX_DATA        0x04U\r
35 #define IIRF_RX_LINE_STATUS 0x06U\r
36 #define IIRF_DATA_TIMEOUT   0x0CU\r
37 \r
38 /*******************************************************************************\r
39  * Cortex-M3 interrupt handler functions implemented as part of the MSS UART\r
40  * driver.\r
41  */\r
42 #if defined(__GNUC__)\r
43 __attribute__((__interrupt__)) void UART0_IRQHandler( void );\r
44 #else\r
45 void UART0_IRQHandler( void );\r
46 #endif\r
47 \r
48 #if defined(__GNUC__)\r
49 __attribute__((__interrupt__)) void UART1_IRQHandler( void );\r
50 #else\r
51 void UART1_IRQHandler( void );\r
52 #endif\r
53 \r
54 /*******************************************************************************\r
55  * Local functions.\r
56  */\r
57 static void MSS_UART_isr( mss_uart_instance_t * this_uart );\r
58 \r
59 /*******************************************************************************\r
60  *\r
61  */\r
62 mss_uart_instance_t g_mss_uart0;\r
63 mss_uart_instance_t g_mss_uart1;\r
64 \r
65 /***************************************************************************//**\r
66  * UART_init.\r
67  * Initialises the UART with default configuration.\r
68  */\r
69 void \r
70 MSS_UART_init\r
71 (\r
72         mss_uart_instance_t* this_uart, \r
73     uint32_t baud_rate,\r
74     uint8_t line_config\r
75 )\r
76 {\r
77     uint16_t baud_value;\r
78     uint32_t pclk_freq;\r
79 \r
80     /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only \r
81      * mss_uart_instance_t instances used to identfy UART0 and UART1. */\r
82     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
83     \r
84     /* Force the value of the CMSIS global variables holding the various system\r
85      * clock frequencies to be updated. */\r
86     SystemCoreClockUpdate();\r
87     \r
88     if ( this_uart == &g_mss_uart0 )\r
89     {\r
90         this_uart->hw_reg = UART0;\r
91         this_uart->hw_reg_bit = UART0_BITBAND;\r
92         this_uart->irqn = UART0_IRQn;\r
93 \r
94         pclk_freq = g_FrequencyPCLK0;\r
95         \r
96         /* reset UART0 */\r
97         SYSREG->SOFT_RST_CR |= SYSREG_UART0_SOFTRESET_MASK;\r
98         /* Clear any previously pended UART0 interrupt */\r
99         NVIC_ClearPendingIRQ( UART0_IRQn );\r
100         /* Take UART0 out of reset. */\r
101         SYSREG->SOFT_RST_CR &= ~SYSREG_UART0_SOFTRESET_MASK;\r
102     }\r
103     else\r
104     {\r
105         this_uart->hw_reg = UART1;\r
106         this_uart->hw_reg_bit = UART1_BITBAND;\r
107         this_uart->irqn = UART1_IRQn;\r
108 \r
109         pclk_freq = g_FrequencyPCLK1;\r
110         \r
111         /* Reset UART1 */\r
112         SYSREG->SOFT_RST_CR |= SYSREG_UART1_SOFTRESET_MASK;\r
113         /* Clear any previously pended UART1 interrupt */\r
114         NVIC_ClearPendingIRQ( UART1_IRQn );\r
115         /* Take UART1 out of reset. */\r
116         SYSREG->SOFT_RST_CR &= ~SYSREG_UART1_SOFTRESET_MASK;\r
117     }\r
118     \r
119     /* disable interrupts */\r
120     this_uart->hw_reg->IER = 0U;\r
121 \r
122     /*\r
123      * Compute baud value based on requested baud rate and PCLK frequency.\r
124      * The baud value is computed using the following equation:\r
125      *      baud_value = PCLK_Frequency / (baud_rate * 16)\r
126      * The baud value is rounded up or down depending on what would be the remainder\r
127      * of the divide by 16 operation.\r
128      */\r
129     baud_value = (uint16_t)(pclk_freq / baud_rate);\r
130     if ( baud_value & 0x00000008U )\r
131     {\r
132         /* remainder above 0.5 */\r
133         baud_value = (baud_value >> 4U) + 1U;\r
134     }\r
135     else\r
136     {\r
137         /* remainder below 0.5 */\r
138         baud_value = (baud_value >> 4U);\r
139     }\r
140 \r
141     /* set divisor latch */\r
142     this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)1;\r
143 \r
144     /* msb of baud value */\r
145     this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8);\r
146     /* lsb of baud value */\r
147     this_uart->hw_reg->DLR = (uint8_t)baud_value;\r
148 \r
149     /* reset divisor latch */\r
150     this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)0;\r
151 \r
152     /* set the line control register (bit length, stop bits, parity) */\r
153     this_uart->hw_reg->LCR = line_config;\r
154     \r
155     /* FIFO configuration */\r
156     this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE;\r
157     \r
158     /* disable loopback */\r
159     this_uart->hw_reg_bit->MCR_LOOP = (uint32_t)0;\r
160 \r
161     /* Instance setup */\r
162     this_uart->tx_buff_size = TX_COMPLETE;\r
163     this_uart->tx_buffer = (const uint8_t *)0;\r
164     this_uart->tx_idx = 0U;\r
165     \r
166     this_uart->rx_handler = (mss_uart_rx_handler_t)0;\r
167 }\r
168 \r
169 /***************************************************************************//**\r
170  * See mss_uart.h for details of how to use this function.\r
171  */\r
172 void \r
173 MSS_UART_polled_tx\r
174\r
175         mss_uart_instance_t * this_uart, \r
176         const uint8_t * pbuff,\r
177         uint32_t tx_size\r
178 )\r
179 {\r
180         uint32_t char_idx;\r
181         uint32_t status;\r
182 \r
183     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
184     \r
185     for ( char_idx = 0U; char_idx < tx_size; char_idx++ )\r
186     {\r
187         /* Wait for UART to become ready to transmit. */\r
188         do {\r
189             status = this_uart->hw_reg_bit->LSR_THRE;\r
190         } while ( (status & TX_READY) == 0U );\r
191         /* Send next character in the buffer. */\r
192         this_uart->hw_reg->THR = pbuff[char_idx];\r
193     }\r
194 }\r
195 \r
196 /***************************************************************************//**\r
197  * See mss_uart.h for details of how to use this function.\r
198  */\r
199 void \r
200 MSS_UART_polled_tx_string\r
201\r
202         mss_uart_instance_t * this_uart, \r
203         const uint8_t * p_sz_string\r
204 )\r
205 {\r
206         uint32_t char_idx;\r
207         uint32_t status;\r
208 \r
209     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
210     \r
211     char_idx = 0U;\r
212     \r
213     while ( p_sz_string[char_idx] != 0U )\r
214     {\r
215         /* Wait for UART to become ready to transmit. */\r
216         do {\r
217             status = this_uart->hw_reg_bit->LSR_THRE;\r
218         } while ( (status & TX_READY) == 0U);\r
219         /* Send next character in the buffer. */\r
220         this_uart->hw_reg->THR = p_sz_string[char_idx];\r
221         ++char_idx;\r
222     }\r
223 }\r
224 \r
225 /***************************************************************************//**\r
226  * See mss_uart.h for details of how to use this function.\r
227  */\r
228 void \r
229 MSS_UART_irq_tx\r
230\r
231         mss_uart_instance_t * this_uart, \r
232         const uint8_t * pbuff,\r
233         uint32_t tx_size\r
234 )\r
235 {\r
236     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
237     \r
238     if ( tx_size > 0U )\r
239     {\r
240         /*Initialise the transmit info for the UART instance with the arguments.*/\r
241         this_uart->tx_buffer = pbuff;\r
242         this_uart->tx_buff_size = tx_size;\r
243         this_uart->tx_idx = (uint16_t)0;\r
244                 \r
245         /* enables TX interrupt */\r
246         this_uart->hw_reg_bit->IER_ETBEI = (uint32_t)1;\r
247         \r
248         /* Enable UART instance interrupt in Cortex-M3 NVIC. */\r
249         NVIC_EnableIRQ( this_uart->irqn );\r
250     }\r
251 }\r
252 \r
253 /***************************************************************************//**\r
254  * See mss_uart.h for details of how to use this function.\r
255  */\r
256 int8_t \r
257 MSS_UART_tx_complete\r
258\r
259         mss_uart_instance_t * this_uart \r
260 )\r
261 {\r
262     int8_t ret_value = 0;\r
263     uint32_t transmit_empty = this_uart->hw_reg_bit->LSR_TEMT;\r
264     \r
265     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
266 \r
267     if ( ( TX_COMPLETE == this_uart->tx_buff_size ) && transmit_empty )\r
268     {\r
269         ret_value = 1;\r
270     }\r
271     \r
272     return ret_value;\r
273 }\r
274 \r
275 \r
276 /***************************************************************************//**\r
277  * See mss_uart.h for details of how to use this function.\r
278  */\r
279 size_t\r
280 MSS_UART_get_rx\r
281 (\r
282     mss_uart_instance_t * this_uart,\r
283     uint8_t * rx_buff,\r
284     size_t buff_size\r
285 )\r
286 {\r
287     size_t rx_size = 0U;\r
288     \r
289     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
290 \r
291     while (( this_uart->hw_reg_bit->LSR_DR != 0U) && ( rx_size < buff_size ) )\r
292     {\r
293         rx_buff[rx_size] = this_uart->hw_reg->RBR;\r
294         ++rx_size;\r
295     }\r
296                \r
297     return rx_size;\r
298 }\r
299 \r
300 /***************************************************************************//**\r
301  * Interrupt service routine triggered by the Transmitter Holding Register\r
302  * Empty (THRE) interrupt or Received Data Available (RDA). \r
303  * On THRE irq this routine will transmit the data from the transmit buffer. \r
304  * When all bytes are transmitted, this routine disables the THRE interrupt\r
305  * and resets the transmit counter.\r
306  * On RDA irq this routine will call the user's receive handler routine previously\r
307  * registered with the UART driver through a call to UART_set_rx_handler().\r
308  */\r
309 static void \r
310 MSS_UART_isr\r
311\r
312         mss_uart_instance_t * this_uart \r
313 )\r
314 {\r
315         uint8_t iirf;\r
316     uint32_t tx_empty;\r
317         \r
318     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
319 \r
320     iirf = this_uart->hw_reg->IIR & IIRF_MASK;\r
321    \r
322     switch ( iirf )\r
323     {\r
324     case IIRF_MODEM_STATUS:\r
325         break;\r
326         \r
327     case IIRF_THRE: /* Transmitter Holding Register Empty */\r
328         tx_empty = this_uart->hw_reg_bit->LSR_TEMT;\r
329         \r
330         if ( tx_empty )\r
331         {\r
332             uint32_t i;\r
333             uint32_t fill_size = TX_FIFO_SIZE;\r
334             uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx;\r
335             if ( tx_remain < TX_FIFO_SIZE )\r
336             {\r
337                 fill_size = tx_remain;\r
338             }\r
339             /* Fill up FIFO */\r
340             for ( i = 0U; i < fill_size; ++i )\r
341             {\r
342                 this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];\r
343                 ++this_uart->tx_idx;\r
344             }\r
345         }\r
346         else\r
347         {\r
348             this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];\r
349             ++this_uart->tx_idx;\r
350         }\r
351         \r
352         if ( this_uart->tx_idx == this_uart->tx_buff_size )\r
353         {\r
354             this_uart->tx_buff_size = TX_COMPLETE;\r
355             /* disables TX interrupt */\r
356             this_uart->hw_reg_bit->IER_ETBEI = 0U;\r
357         }\r
358         break;\r
359         \r
360     case IIRF_RX_DATA:          /* Received Data Available */\r
361     case IIRF_DATA_TIMEOUT:\r
362         if (this_uart->rx_handler != 0)\r
363         {\r
364             (*(this_uart->rx_handler))();\r
365         }\r
366         break;\r
367         \r
368     case IIRF_RX_LINE_STATUS:\r
369         break;\r
370         \r
371     default:\r
372         /* Disable other interrupts */\r
373         this_uart->hw_reg_bit->IER_ELSI = 0U;\r
374         this_uart->hw_reg_bit->IER_EDSSI = 0U;\r
375         break;\r
376     }\r
377 }\r
378 \r
379 /***************************************************************************//**\r
380  * See mss_uart.h for details of how to use this function.\r
381  */\r
382 void\r
383 MSS_UART_set_rx_handler\r
384 (\r
385         mss_uart_instance_t *       this_uart,\r
386     mss_uart_rx_handler_t       handler,\r
387     mss_uart_rx_trig_level_t    trigger_level\r
388 )\r
389 {\r
390     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
391     \r
392     this_uart->rx_handler = handler;\r
393     \r
394     /* Set the receive interrupt trigger level. */\r
395     this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | (uint8_t)trigger_level;\r
396     \r
397     /* Enable receive interrupt. */\r
398     this_uart->hw_reg_bit->IER_ERBFI = 1U;\r
399     \r
400     /* Enable UART instance interrupt in Cortex-M3 NVIC. */\r
401     NVIC_EnableIRQ( this_uart->irqn );\r
402 }\r
403 \r
404 /***************************************************************************//**\r
405  * See mss_uart.h for details of how to use this function.\r
406  */\r
407 void\r
408 MSS_UART_set_loopback\r
409 (\r
410         mss_uart_instance_t *   this_uart,\r
411         mss_uart_loopback_t     loopback\r
412 )\r
413 {\r
414     ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );\r
415     \r
416     if ( loopback == MSS_UART_LOOPBACK_OFF )\r
417     {\r
418         this_uart->hw_reg_bit->MCR_LOOP = 0U;\r
419     }\r
420     else\r
421     {\r
422         this_uart->hw_reg_bit->MCR_LOOP = 1U;\r
423     }\r
424 }\r
425 \r
426 /***************************************************************************//**\r
427  * UART0 interrupt service routine.\r
428  * UART0_IRQHandler is included within the Cortex-M3 vector table as part of the\r
429  * Fusion 2 CMSIS.\r
430  */\r
431 #if defined(__GNUC__)\r
432 __attribute__((__interrupt__)) void UART0_IRQHandler( void )\r
433 #else\r
434 void UART0_IRQHandler( void )\r
435 #endif\r
436 {\r
437     MSS_UART_isr( &g_mss_uart0 );\r
438     NVIC_ClearPendingIRQ( UART0_IRQn );\r
439 }\r
440 \r
441 /***************************************************************************//**\r
442  * UART1 interrupt service routine.\r
443  * UART2_IRQHandler is included within the Cortex-M3 vector table as part of the\r
444  * Fusion 2 CMSIS.\r
445  */\r
446 #if defined(__GNUC__)\r
447 __attribute__((__interrupt__)) void UART1_IRQHandler( void )\r
448 #else\r
449 void UART1_IRQHandler( void )\r
450 #endif\r
451 {\r
452     MSS_UART_isr( &g_mss_uart1 );\r
453     NVIC_ClearPendingIRQ( UART1_IRQn );\r
454 }\r
455 \r
456 #ifdef __cplusplus\r
457 }\r
458 #endif\r