1 /*******************************************************************************
\r
2 * (c) Copyright 2007 Actel Corporation. All rights reserved.
\r
4 * SmartFusion Microcontroller Subsystem UART bare metal software driver
\r
7 * SVN $Revision: 1898 $
\r
8 * SVN $Date: 2009-12-21 17:27:57 +0000 (Mon, 21 Dec 2009) $
\r
10 #include "mss_uart.h"
\r
11 #include "../../CMSIS/mss_assert.h"
\r
17 /*******************************************************************************
\r
20 #define TX_READY 0x01U
\r
21 #define TX_COMPLETE 0U
\r
23 #define TX_FIFO_SIZE 16U
\r
25 #define FCR_TRIG_LEVEL_MASK 0xC0U
\r
27 #define IIRF_MASK 0x0FU
\r
29 /*******************************************************************************
\r
30 * Possible values for Interrupt Identification Register Field.
\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
38 /*******************************************************************************
\r
39 * Cortex-M3 interrupt handler functions implemented as part of the MSS UART
\r
42 #if defined(__GNUC__)
\r
43 __attribute__((__interrupt__)) void UART0_IRQHandler( void );
\r
45 void UART0_IRQHandler( void );
\r
48 #if defined(__GNUC__)
\r
49 __attribute__((__interrupt__)) void UART1_IRQHandler( void );
\r
51 void UART1_IRQHandler( void );
\r
54 /*******************************************************************************
\r
57 static void MSS_UART_isr( mss_uart_instance_t * this_uart );
\r
59 /*******************************************************************************
\r
62 mss_uart_instance_t g_mss_uart0;
\r
63 mss_uart_instance_t g_mss_uart1;
\r
65 /***************************************************************************//**
\r
67 * Initialises the UART with default configuration.
\r
72 mss_uart_instance_t* this_uart,
\r
77 uint16_t baud_value;
\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
84 /* Force the value of the CMSIS global variables holding the various system
\r
85 * clock frequencies to be updated. */
\r
86 SystemCoreClockUpdate();
\r
88 if ( this_uart == &g_mss_uart0 )
\r
90 this_uart->hw_reg = UART0;
\r
91 this_uart->hw_reg_bit = UART0_BITBAND;
\r
92 this_uart->irqn = UART0_IRQn;
\r
94 pclk_freq = g_FrequencyPCLK0;
\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
105 this_uart->hw_reg = UART1;
\r
106 this_uart->hw_reg_bit = UART1_BITBAND;
\r
107 this_uart->irqn = UART1_IRQn;
\r
109 pclk_freq = g_FrequencyPCLK1;
\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
119 /* disable interrupts */
\r
120 this_uart->hw_reg->IER = 0U;
\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
129 baud_value = (uint16_t)(pclk_freq / baud_rate);
\r
130 if ( baud_value & 0x00000008U )
\r
132 /* remainder above 0.5 */
\r
133 baud_value = (baud_value >> 4U) + 1U;
\r
137 /* remainder below 0.5 */
\r
138 baud_value = (baud_value >> 4U);
\r
141 /* set divisor latch */
\r
142 this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)1;
\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
149 /* reset divisor latch */
\r
150 this_uart->hw_reg_bit->LCR_DLAB = (uint32_t)0;
\r
152 /* set the line control register (bit length, stop bits, parity) */
\r
153 this_uart->hw_reg->LCR = line_config;
\r
155 /* FIFO configuration */
\r
156 this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE;
\r
158 /* disable loopback */
\r
159 this_uart->hw_reg_bit->MCR_LOOP = (uint32_t)0;
\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
166 this_uart->rx_handler = (mss_uart_rx_handler_t)0;
\r
169 /***************************************************************************//**
\r
170 * See mss_uart.h for details of how to use this function.
\r
175 mss_uart_instance_t * this_uart,
\r
176 const uint8_t * pbuff,
\r
183 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
185 for ( char_idx = 0U; char_idx < tx_size; char_idx++ )
\r
187 /* Wait for UART to become ready to transmit. */
\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
196 /***************************************************************************//**
\r
197 * See mss_uart.h for details of how to use this function.
\r
200 MSS_UART_polled_tx_string
\r
202 mss_uart_instance_t * this_uart,
\r
203 const uint8_t * p_sz_string
\r
209 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
213 while ( p_sz_string[char_idx] != 0U )
\r
215 /* Wait for UART to become ready to transmit. */
\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
225 /***************************************************************************//**
\r
226 * See mss_uart.h for details of how to use this function.
\r
231 mss_uart_instance_t * this_uart,
\r
232 const uint8_t * pbuff,
\r
236 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
238 if ( tx_size > 0U )
\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
245 /* enables TX interrupt */
\r
246 this_uart->hw_reg_bit->IER_ETBEI = (uint32_t)1;
\r
248 /* Enable UART instance interrupt in Cortex-M3 NVIC. */
\r
249 NVIC_EnableIRQ( this_uart->irqn );
\r
253 /***************************************************************************//**
\r
254 * See mss_uart.h for details of how to use this function.
\r
257 MSS_UART_tx_complete
\r
259 mss_uart_instance_t * this_uart
\r
262 int8_t ret_value = 0;
\r
263 uint32_t transmit_empty = this_uart->hw_reg_bit->LSR_TEMT;
\r
265 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
267 if ( ( TX_COMPLETE == this_uart->tx_buff_size ) && transmit_empty )
\r
276 /***************************************************************************//**
\r
277 * See mss_uart.h for details of how to use this function.
\r
282 mss_uart_instance_t * this_uart,
\r
287 size_t rx_size = 0U;
\r
289 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
291 while (( this_uart->hw_reg_bit->LSR_DR != 0U) && ( rx_size < buff_size ) )
\r
293 rx_buff[rx_size] = this_uart->hw_reg->RBR;
\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
312 mss_uart_instance_t * this_uart
\r
318 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
320 iirf = this_uart->hw_reg->IIR & IIRF_MASK;
\r
324 case IIRF_MODEM_STATUS:
\r
327 case IIRF_THRE: /* Transmitter Holding Register Empty */
\r
328 tx_empty = this_uart->hw_reg_bit->LSR_TEMT;
\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
337 fill_size = tx_remain;
\r
340 for ( i = 0U; i < fill_size; ++i )
\r
342 this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
\r
343 ++this_uart->tx_idx;
\r
348 this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx];
\r
349 ++this_uart->tx_idx;
\r
352 if ( this_uart->tx_idx == this_uart->tx_buff_size )
\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
360 case IIRF_RX_DATA: /* Received Data Available */
\r
361 case IIRF_DATA_TIMEOUT:
\r
362 if (this_uart->rx_handler != 0)
\r
364 (*(this_uart->rx_handler))();
\r
368 case IIRF_RX_LINE_STATUS:
\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
379 /***************************************************************************//**
\r
380 * See mss_uart.h for details of how to use this function.
\r
383 MSS_UART_set_rx_handler
\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
390 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
392 this_uart->rx_handler = handler;
\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
397 /* Enable receive interrupt. */
\r
398 this_uart->hw_reg_bit->IER_ERBFI = 1U;
\r
400 /* Enable UART instance interrupt in Cortex-M3 NVIC. */
\r
401 NVIC_EnableIRQ( this_uart->irqn );
\r
404 /***************************************************************************//**
\r
405 * See mss_uart.h for details of how to use this function.
\r
408 MSS_UART_set_loopback
\r
410 mss_uart_instance_t * this_uart,
\r
411 mss_uart_loopback_t loopback
\r
414 ASSERT( (this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1) );
\r
416 if ( loopback == MSS_UART_LOOPBACK_OFF )
\r
418 this_uart->hw_reg_bit->MCR_LOOP = 0U;
\r
422 this_uart->hw_reg_bit->MCR_LOOP = 1U;
\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
431 #if defined(__GNUC__)
\r
432 __attribute__((__interrupt__)) void UART0_IRQHandler( void )
\r
434 void UART0_IRQHandler( void )
\r
437 MSS_UART_isr( &g_mss_uart0 );
\r
438 NVIC_ClearPendingIRQ( UART0_IRQn );
\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
446 #if defined(__GNUC__)
\r
447 __attribute__((__interrupt__)) void UART1_IRQHandler( void )
\r
449 void UART1_IRQHandler( void )
\r
452 MSS_UART_isr( &g_mss_uart1 );
\r
453 NVIC_ClearPendingIRQ( UART1_IRQn );
\r