This file is part of SimpleRTOS2
/*============================================================================*/ /*============================================================================*/ /*============================================================================*/ /* BASIC INTERRUPT DRIVEN SERIAL PORT DRIVER. NOTE: This driver is primarily to test the scheduler functionality. It does not effectively use the buffers or DMA and is therefore not intended to be an example of an efficient driver. */ /*============================================================================*/ /*============================================================================*/ /*============================================================================*/ /*============================================================================*/ /* Note: This file was severely modified from the original FreeRTOS version. */ /*============================================================================*/ /*============================================================================*/ /*============================================================================*/ /*============================================================================*/ #include <stdlib.h> #include <usart.h> #include <uart.h> #include <sysclk.h> #include <sam_gpio/sam_gpio.h> #include <pio.h> /*============================================================================*/ /* Scheduler include files. */ #include "Portable.h" #include "Queue.h" #include "PortSAM3Internals.h" #include "PortableInternals.h" #include "SimpleRTOSInternals.h" #include "SerialSAM3.h" /*============================================================================*/ #define SERIAL_PORTS 4 #define QUEUE_LENGTH 32 /*============================================================================*/ /* The queues used to communicate between tasks and ISR's. */ /*static*/ queue_t QueuesRX[SERIAL_PORTS]; /*static*/ unsigned char BuffersRX[SERIAL_PORTS][QUEUE_LENGTH]; /*static*/ queue_t QueuesTX[SERIAL_PORTS]; /*static*/ unsigned char BuffersTX[SERIAL_PORTS][QUEUE_LENGTH]; /*============================================================================*/ extern __attribute((weak)) void UserConfigUART1( void ); extern __attribute((weak)) void UserConfigUART2( void ); extern __attribute((weak)) void UserConfigUART3( void ); extern __attribute((weak)) void UserConfigUART4( void ); extern __attribute((weak)) void UserConfigUART5( void ); extern __attribute((weak)) void UserConfigUART6( void ); /*============================================================================*/ static IRQn_Type IRQn[] = { UART_IRQn, USART0_IRQn, USART1_IRQn, USART2_IRQn }; static int IDs[] = { ID_UART, ID_USART0, ID_USART1, ID_USART2 }; int SerialPortInitMinimal( unsigned int port, unsigned long BaudRate ) { sam_usart_opt_t usart_settings = { 115200, US_MR_CHRL_8_BIT, US_MR_PAR_NO, US_MR_NBSTOP_1_BIT, US_MR_CHMODE_NORMAL, 0 /* This field is only used in IrDA mode. */ }; if( port < 1 || port > SERIAL_PORTS ) return 0; /* Create the queues used by the com test task. */ QueueInit( &QueuesRX[port-1], sizeof( signed char ), QUEUE_LENGTH, &BuffersRX[port-1], QUEUE_SWITCH_IN_ISR ); QueueInit( &QueuesTX[port-1], sizeof( signed char ), QUEUE_LENGTH, &BuffersTX[port-1], QUEUE_SWITCH_NORMAL ); usart_settings.baudrate = BaudRate; /* Enable the peripheral clock in the PMC. */ sysclk_enable_peripheral_clock( IDs[port-1] ); switch( port ) { case 1: gpio_configure_pin( PIO_PA8_IDX, PIO_TYPE_PIO_PERIPH_A ); gpio_configure_pin( PIO_PA9_IDX, PIO_TYPE_PIO_PERIPH_A ); /* Enable the receiver and transmitter. */ uart_enable_tx( UART ); uart_enable_rx( UART ); /* Configure and enable interrupt of USART. */ irq_register_handler( IRQn[port-1], MAX_SYSCALL_INTERRUPT_PRIORITY ); NVIC_EnableIRQ( IRQn[port-1] ); uart_enable_interrupt( UART, US_IER_RXRDY ); if( UserConfigUART1 != NULL ) UserConfigUART1(); break; #if SERIAL_PORTS >= 2 case 2: gpio_configure_pin( PIO_PA10_IDX, PIO_TYPE_PIO_PERIPH_A ); gpio_configure_pin( PIO_PA11_IDX, PIO_TYPE_PIO_PERIPH_A ); /* Configure the USART. */ usart_init_rs232( USART0, &usart_settings, sysclk_get_cpu_hz() ); /* Enable the receiver and transmitter. */ usart_enable_tx( USART0 ); usart_enable_rx( USART0 ); /* Configure and enable interrupt of USART. */ irq_register_handler( IRQn[port-1], MAX_SYSCALL_INTERRUPT_PRIORITY ); NVIC_EnableIRQ( IRQn[port-1] ); usart_enable_interrupt( USART0, US_IER_RXRDY ); if( UserConfigUART2 != NULL ) UserConfigUART2(); break; #endif /* SERIAL_PORTS >= 2 */ #if SERIAL_PORTS >= 3 case 3: gpio_configure_pin( PIO_PA12_IDX, PIO_TYPE_PIO_PERIPH_A ); gpio_configure_pin( PIO_PA13_IDX, PIO_TYPE_PIO_PERIPH_A ); /* Configure the USART. */ usart_init_rs232( USART1, &usart_settings, sysclk_get_cpu_hz() ); /* Enable the receiver and transmitter. */ usart_enable_tx( USART1 ); usart_enable_rx( USART1 ); /* Configure and enable interrupt of USART. */ irq_register_handler( IRQn[port-1], MAX_SYSCALL_INTERRUPT_PRIORITY ); NVIC_EnableIRQ( IRQn[port-1] ); usart_enable_interrupt( USART1, US_IER_RXRDY ); if( UserConfigUART3 != NULL ) UserConfigUART3(); break; #endif /* SERIAL_PORTS >= 3 */ #if SERIAL_PORTS >= 4 case 4: gpio_configure_pin( PIO_PB21_IDX, PIO_TYPE_PIO_PERIPH_A ); gpio_configure_pin( PIO_PB20_IDX, PIO_TYPE_PIO_PERIPH_A ); /* Configure the USART. */ usart_init_rs232( USART2, &usart_settings, sysclk_get_cpu_hz() ); /* Enable the receiver and transmitter. */ usart_enable_tx( USART2 ); usart_enable_rx( USART2 ); /* Configure and enable interrupt of USART. */ irq_register_handler( IRQn[port-1], MAX_SYSCALL_INTERRUPT_PRIORITY ); NVIC_EnableIRQ( IRQn[port-1] ); usart_enable_interrupt( USART2, US_IER_RXRDY ); if( UserConfigUART4 != NULL ) UserConfigUART4(); break; #endif /* SERIAL_PORTS >= 4 */ } return 1; } /*============================================================================*/ int SerialReceive( unsigned int port, tickcount_t TimeToWait ) { unsigned char c; if( port < 1 || port > SERIAL_PORTS ) return -2; if( QueueRead( &QueuesRX[port-1], &c, TimeToWait )) return (unsigned int)c; else return -1; } /*============================================================================*/ int SerialWaitForTXCompletion( unsigned int port, tickcount_t TimeToWait ) { return 0; } /*============================================================================*/ int SerialTransmit( unsigned int port, signed char c, tickcount_t TimeToWait ) { if( port < 1 || port > SERIAL_PORTS ) return -2; /* Return false if after the block time there is no room on the Tx queue. */ if( QueueWrite( &QueuesTX[port-1], &c, TimeToWait ) == 0 ) return 0; else { if( port == 1 ) uart_enable_interrupt( UART, US_IER_TXRDY ); #if SERIAL_PORTS >= 2 else if( port == 2 ) usart_enable_interrupt( USART0, US_IER_TXRDY ); #endif /* SERIAL_PORTS >= 2 */ #if SERIAL_PORTS >= 3 else if( port == 3 ) usart_enable_interrupt( USART1, US_IER_TXRDY ); #endif /* SERIAL_PORTS >= 3 */ #if SERIAL_PORTS >= 4 else if( port == 4 ) usart_enable_interrupt( USART2, US_IER_TXRDY ); #endif /* SERIAL_PORTS >= 4 */ return 1; } return 0; } /*============================================================================*/ static void __attribute__((noinline)) UART_ISR( void ) { unsigned long Status; uint8_t Aux; int MustSwitch = 0; static char c; Status = uart_get_status( UART ) & uart_get_interrupt_mask( UART ); if( Status & US_CSR_RXRDY ) { while( uart_get_status( UART ) & US_CSR_RXRDY ) { /* Retrieve the received character and place it in the queue of received characters. */ uart_read( UART, &Aux ); c = (unsigned char)Aux; if( QueueWriteFromISR( &QueuesRX[0], &c ) > 1 ) MustSwitch = 1; } } /* Are any Tx interrupts pending? */ if( Status & US_CSR_TXRDY ) { while( uart_get_status( UART ) & US_CSR_TXRDY ) { int Result; Result = QueueReadFromISR( &QueuesTX[0], &c ); if( Result > 0 ) { /* Send the next character queued for Tx. */ uart_write( UART, c ); if( Result > 1 ) MustSwitch = 1; } else { /* Queue empty, nothing to send. */ uart_disable_interrupt( UART, US_IER_TXRDY ); break; } } } if( MustSwitch ) CurrentTask = ReadyTasks[HighestReadyPriority]; } /*============================================================================*/ void __attribute__((naked)) UART_Handler( void ) { SAVE_CONTEXT(); UART_ISR(); RESTORE_CONTEXT(); } /*============================================================================*/ #if SERIAL_PORTS >= 2 static void __attribute__((noinline)) USART_ISR( unsigned int usart ) { static Usart * const Usarts[] = { USART0, USART1, USART2 }; Usart *u; unsigned long Status; uint32_t Aux; int MustSwitch = 0; static char c; if( usart >= sizeof Usarts / sizeof Usarts[0] ) return; u = Usarts[usart]; Status = usart_get_status( u ) & usart_get_interrupt_mask( u ); if( Status & US_CSR_RXRDY ) { while( usart_get_status( u ) & US_CSR_RXRDY ) { /* Retrieve the received character and place it in the queue of received characters. */ usart_read( u, &Aux ); c = (unsigned char)Aux; if( QueueWriteFromISR( &QueuesRX[usart+1], &c ) > 1 ) MustSwitch = 1; } } /* Are any Tx interrupts pending? */ if( Status & US_CSR_TXRDY ) { while( usart_get_status( u ) & US_CSR_TXRDY ) { int Result; Result = QueueReadFromISR( &QueuesTX[usart+1], &c ); if( Result > 0 ) { /* Send the next character queued for Tx. */ usart_write( u, c ); if( Result > 1 ) MustSwitch = 1; } else { /* Queue empty, nothing to send. */ usart_disable_interrupt( u, US_IER_TXRDY ); break; } } } if( MustSwitch ) CurrentTask = ReadyTasks[HighestReadyPriority]; } /*============================================================================*/ void __attribute__((naked)) USART0_Handler( void ) { SAVE_CONTEXT(); USART_ISR( 0 ); RESTORE_CONTEXT(); } #endif /* SERIAL_PORTS >= 2 */ /*============================================================================*/ #if SERIAL_PORTS >= 3 void __attribute__((naked)) USART1_Handler( void ) { SAVE_CONTEXT(); USART_ISR( 1 ); RESTORE_CONTEXT(); } #endif /* SERIAL_PORTS >= 3 */ /*============================================================================*/ #if SERIAL_PORTS >= 4 void __attribute__((naked)) USART2_Handler( void ) { SAVE_CONTEXT(); USART_ISR( 2 ); RESTORE_CONTEXT(); } #endif /* SERIAL_PORTS >= 4 */ /*============================================================================*/