On Wed, Feb 4, 2015 at 3:49 PM, Martin Galvan <martin.gal...@tallertechnologies.com> wrote: > On Wed, Feb 4, 2015 at 2:20 PM, Pavel Pisa <p...@cmp.felk.cvut.cz> wrote: >> The structure tms570_sci_context holds state variable >> tx_chars_in_hw which holds if and how many characters >> (in the optional FIFO support for some Ti SCIs) are submitted >> into hardware. >> >> When field is not writable then code breaks when RTEMS >> is build for Flash area. >> >> The problem found and analyzed by Martin Galvan from tallertechnologies. > > Thanks for the patch. In addition, we've developed a refactored > version of the driver which, besides being const-correct, addresses a > number of other issues present in the current driver. Namely, it > improves the coding style, fixes what seems to be an erroneous check > for ctx->regs->SCIRD != 0 and uses the correct formula for the SCI > prescaler value. I'm attaching it here so that it can be commited > before us and Premek add further changes. > > Notice, however, that my driver sets BSP_PLL_OUT_CLOCK to 180 MHz in > bsp.h and divides it by 2 when it's setting the prescaler, so the > value of VCLK for the formula is 90 MHz. This may vary from board to > board (I noticed the original code used 160 MHz instead of 90); we > used 90 MHz because it's what HALCoGen generates by default. Notice as > well that this code still relies on the device having been set up > already (as Pavel said, right now we're using HALCoGen-generated code > for that).
It appears my mail client wrapped the lines after 80 characters, so the patch won't apply if you copy it directly from the e-mail. I'm attaching it here as a separate file. Sorry for the inconvenience.
diff --git a/c/src/lib/libbsp/arm/tms570/console/printk-support.c b/c/src/lib/libbsp/arm/tms570/console/printk-support.c index 241ca9b..8009e74 100644 --- a/c/src/lib/libbsp/arm/tms570/console/printk-support.c +++ b/c/src/lib/libbsp/arm/tms570/console/printk-support.c @@ -3,7 +3,9 @@ * * @ingroup tms570 * - * @brief definitions of serial line for debugging. + * @brief Functions needed for using printk. + * + * Premysl: Debug functions always use serial dev 0 peripheral. */ /* @@ -15,6 +17,11 @@ * 166 36 Praha 6 * Czech Republic * + * Copyright (c) 2015 Taller Technologies + * Martin Galvan <martin.gal...@tallertechnologies.com> + * Marcos Diaz <marcos.d...@tallertechnologies.com> + * Eduardo Sanchez <eduardo.sanc...@tallertechnologies.com> + * * Based on LPC24xx and LPC1768 BSP * by embedded brains GmbH and others * @@ -28,11 +35,8 @@ #include <bsp/tms570-sci.h> #include <bsp/tms570-sci-driver.h> - /** - * @brief Puts chars into peripheral - * - * debug functions always use serial dev 0 peripheral + * @brief Puts chars into the peripheral. * * @retval Void */ @@ -41,44 +45,43 @@ static void tms570_putc(char ch) rtems_interrupt_level level; rtems_interrupt_disable(level); - while ( ( driver_context_table[0].regs->SCIFLR & 0x100 ) == 0) { + + while (!(driver_context_table[0].regs->SCIFLR & TXRDY)) { rtems_interrupt_flash(level); } + driver_context_table[0].regs->SCITD = ch; rtems_interrupt_enable(level); } /** - * @brief debug console output + * @brief Debug console output. * - * debug functions always use serial dev 0 peripheral + * This function is called by the kernel's generic putk() to output a char. * * @retval Void */ static void tms570_uart_output(char c) { - if ( c == '\n' ) { - char r = '\r'; - tms570_putc(r); + if (c == '\n') { + tms570_putc('\r'); } + tms570_putc(c); } /** - * @brief debug console input + * @brief Debug console input. * - * debug functions always use serial dev 0 peripheral + * Is called by the kernel's generic getchark() to read a char. * - * @retval x Read char - * @retval -1 No input character available + * @retval x Read char. + * @retval -1 No input character available. */ -static int tms570_uart_input( void ) +static int tms570_uart_input(void) { - if ( driver_context_table[0].regs->SCIFLR & (1<<9) ) { - return driver_context_table[0].regs->SCIRD; - } else { - return -1; - } + return driver_context_table[0].regs->SCIFLR & RXRDY ? + driver_context_table[0].regs->SCIRD : -1; } BSP_output_char_function_type BSP_output_char = tms570_uart_output; diff --git a/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c b/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c index 56ed04e..de45cc6 100644 --- a/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c +++ b/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c @@ -3,7 +3,7 @@ * * @ingroup tms570 * - * @brief Serial communication interface (SCI) functions definitions. + * @brief Serial Communication Interface (SCI) function definitions. */ /* @@ -15,6 +15,11 @@ * 166 36 Praha 6 * Czech Republic * + * Copyright (c) 2015 Taller Technologies + * Martin Galvan <martin.gal...@tallertechnologies.com> + * Marcos Diaz <marcos.d...@tallertechnologies.com> + * Eduardo Sanchez <eduardo.sanc...@tallertechnologies.com> + * * Based on LPC24xx and LPC1768 BSP * by embedded brains GmbH and others * @@ -33,14 +38,14 @@ #include <bsp/fatal.h> #include <bsp/irq.h> -#define TMS570_SCI_BUFFER_SIZE 1 +#define TMS570_SCI_BUFFER_SIZE 1u /** * @brief Table including all serial drivers * * Definitions of all serial drivers */ -const tms570_sci_context driver_context_table[] = { +tms570_sci_context driver_context_table[] = { { .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("TMS570 SCI1"), .device_name = "/dev/console", @@ -58,20 +63,20 @@ const tms570_sci_context driver_context_table[] = { /** * @brief Serial drivers init function * - * Initialize all serial drivers specified in driver_context_table + * Initialize all the serial drivers specified in driver_context_table. * * @param[in] major * @param[in] minor * @param[in] arg * @retval RTEMS_SUCCESSFUL Initialization completed */ -rtems_device_driver console_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) +rtems_device_driver console_initialize(rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) { - rtems_status_code sc; + rtems_status_code status; + tms570_sci_context *ctx; + #if CONSOLE_USE_INTERRUPTS const rtems_termios_device_handler *handler = &tms570_sci_handler_interrupt; #else @@ -86,12 +91,8 @@ rtems_device_driver console_initialize( rtems_termios_initialize(); /* Initialize each device */ - for ( - minor = 0; - minor < RTEMS_ARRAY_SIZE(driver_context_table); - ++minor - ) { - const tms570_sci_context *ctx = &driver_context_table[minor]; + for (minor = 0; minor < RTEMS_ARRAY_SIZE(driver_context_table); ++minor) { + ctx = &driver_context_table[minor]; /* * Install this device in the file system and Termios. In order @@ -99,152 +100,106 @@ rtems_device_driver console_initialize( * on stdin, stdout and stderr), one device must be registered as * "/dev/console" (CONSOLE_DEVICE_NAME). */ - sc = rtems_termios_device_install( - ctx->device_name, - major, - minor, - handler, - NULL, - RTEMS_DECONST(rtems_termios_device_context *, &ctx->base) - ); - if ( sc != RTEMS_SUCCESSFUL ) { + status = rtems_termios_device_install(ctx->device_name, major, minor, + handler, NULL, &ctx->base); + + if (status != RTEMS_SUCCESSFUL) { bsp_fatal(BSP_FATAL_CONSOLE_NO_DEV); } } + return RTEMS_SUCCESSFUL; } /** - * @brief Reads chars from HW + * @brief Set the SCI parity control. * - * Reads chars from HW peripheral specified in driver context. - * TMS570 does not have HW buffer for serial line so this function can - * return only 0 or 1 char + * Sets the SCIGCR1 parity bits according to the current Termios settings. * - * @param[in] ctx context of the driver - * @param[out] buf read data buffer - * @param[in] N size of buffer - * @retval x Number of read chars from peripherals + * @param[in] ctx Context of the driver. + * @param[in] c_cflag Termios control flag. + * @retval void. */ -static int tms570_sci_read_received_chars( - tms570_sci_context * ctx, - char * buf, - int N) + +static void tms570_sci_set_parity(tms570_sci_context *const ctx, + const tcflag_t c_cflag) { - if ( N < 1 ) { - return 0; - } - if ( ctx->regs->SCIRD != 0 ) { - buf[0] = ctx->regs->SCIRD; - return 1; + if (c_cflag & PARENB) { + ctx->regs->SCIGCR1 |= PARITY_ENA; + + if (c_cflag & PARODD) { /* Odd parity */ + ctx->regs->SCIGCR1 &= ~(EVEN_PARITY); + } else { /* Even parity */ + ctx->regs->SCIGCR1 |= EVEN_PARITY; + } + } else { /* No Parity */ + ctx->regs->SCIGCR1 &= ~(PARITY_ENA); } - return 0; } /** - * @brief Enables RX interrupt + * @brief Set the SCI prescaler. * - * Enables RX interrupt source of SCI peripheral - * specified in the driver context. + * Sets the value of the BRS corresponding to the desired baud rate. * - * @param[in] ctx context of the driver - * @retval Void + * @param[in] ctx Context of the driver. + * @param[in] terminal Termios driver. + * @retval void. */ -static void tms570_sci_enable_interrupts(tms570_sci_context * ctx) +static void tms570_sci_set_prescaler(tms570_sci_context *const ctx, + const struct termios *terminal) { - ctx->regs->SCISETINT = (1<<9); -} + uint32_t factor; + uint32_t vclk; + rtems_termios_baud_t baudrate; + rtems_termios_baud_t prescaler; -/** - * @brief Disables RX interrupt - * - * Disables RX interrupt source of SCI peripheral specified in the driver - * context. - * - * @param[in] ctx context of the driver - * @retval Void - */ -static void tms570_sci_disable_interrupts(tms570_sci_context * ctx) -{ - ctx->regs->SCICLEARINT = (1<<9); -} + vclk = BSP_PLL_OUT_CLOCK / 2u; -/** - * @brief Check whether driver has put char in HW - * - * Check whether driver has put char in HW. - * This information is read from the driver context not from a peripheral. - * TMS570 does not have write data buffer asociated with SCI - * so the return can be only 0 or 1. - * - * @param[in] ctx context of the driver - * @retval x - */ -static int tms570_sci_transmitted_chars(tms570_sci_context * ctx) -{ - int ret; + /* Determine whether we're in synchronous or asynchronous mode, and select + the appropriate divider factor. */ + factor = ctx->regs->SCIGCR1 & TIMING_MODE ? 16u : 1u; - ret = ctx->tx_chars_in_hw; - if ( ret == 1 ) { - ctx->tx_chars_in_hw = 0; - return 1; - } - return ret; + /* Set the prescaler for the desired baud rate. + * According to the datasheet, the formula for the baudrate is: + * baudrate = vclk / (factor * (prescaler + 1)) + */ + baudrate = rtems_termios_baud_to_number(cfgetospeed(terminal)); + prescaler = (vclk / (factor * baudrate)) - 1; + ctx->regs->BRS = prescaler; } /** - * @brief Set attributes of the HW peripheral + * @brief Set the attributes of the SCI peripheral. * - * Sets attributes of the HW peripheral (parity, baud rate, etc.) + * Sets the attributes of the SCI peripheral (parity, baud rate, etc.). * - * @param[in] base context of the driver - * @param[in] t termios driver - * @retval true peripheral setting is changed + * @param[in] base Context of the driver. + * @param[in] terminal Termios driver. + * @retval true Peripheral settings are changed. */ -static bool tms570_sci_set_attributes( - rtems_termios_device_context *base, - const struct termios *t -) +static bool tms570_sci_set_attributes(rtems_termios_device_context *base, + const struct termios *terminal) { - tms570_sci_context *ctx = (tms570_sci_context *) base; + tms570_sci_context *ctx = (tms570_sci_context *)base; rtems_interrupt_lock_context lock_context; - int32_t bauddiv; - int32_t baudrate; rtems_termios_device_lock_acquire(base, &lock_context); - ctx->regs->SCIGCR1 &= ~( (1<<7) | (1<<25) | (1<<24) ); - - ctx->regs->SCIGCR1 &= ~(1<<4); /*one stop bit*/ - ctx->regs->SCIFORMAT = 0x7; - - switch ( t->c_cflag & ( PARENB|PARODD ) ) { - case ( PARENB|PARODD ): - /* Odd parity */ - ctx->regs->SCIGCR1 &= ~(1<<3); - ctx->regs->SCIGCR1 |= (1<<2); - break; - - case PARENB: - /* Even parity */ - ctx->regs->SCIGCR1 |= (1<<3); - ctx->regs->SCIGCR1 |= (1<<2); - break; - - default: - case 0: - case PARODD: - /* No Parity */ - ctx->regs->SCIGCR1 &= ~(1<<2); - } + /* Put the SCI into reset state, and disable transmissions and receptions. */ + ctx->regs->SCIGCR1 &= ~(SWnRST | RXENA | TXENA); - /* Baud rate */ - baudrate = rtems_termios_baud_to_number(cfgetospeed(t)); - baudrate *= 2 * 16; - bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate; - ctx->regs->BRS = bauddiv; + ctx->regs->SCIGCR1 &= ~(STOP); /* One stop bit */ + ctx->regs->SCIFORMAT = 0x7u; /* Characters are 8 bits long */ - ctx->regs->SCIGCR1 |= (1<<7) | (1<<25) | (1<<24); + /* Set the parity control bits. */ + tms570_sci_set_parity(ctx, terminal->c_cflag); + + /* Set the prescaler register. */ + tms570_sci_set_prescaler(ctx, terminal); + + /* Put the SCI into ready state, and enable transmissions and receptions. */ + ctx->regs->SCIGCR1 |= (SWnRST | RXENA | TXENA); rtems_termios_device_lock_release(base, &lock_context); @@ -252,200 +207,150 @@ static bool tms570_sci_set_attributes( } /** - * @brief sci interrupt handler + * @brief SCI interrupt handler. * - * Handler checks which interrupt occured and provides nessesary maintenance - * dequeue characters in termios driver whether character is send succesfully - * enqueue characters in termios driver whether character is recieved + * The handler checks which interrupt occured and acts accordingly. + * - If a character was sent, remove it from the Termios queue. + * - If a character was received, add it to the Termios queue. * - * @param[in] arg rtems_termios_tty + * @param[in] arg The rtems_termios_tty * @retval Void */ -static void tms570_sci_interrupt_handler(void * arg) +static void tms570_sci_interrupt_handler(void *arg) { rtems_termios_tty *tty = arg; tms570_sci_context *ctx = rtems_termios_get_device_context(tty); - char buf[TMS570_SCI_BUFFER_SIZE]; - size_t n; + char buffer[TMS570_SCI_BUFFER_SIZE]; + + /* Check if we've received something. */ + if (ctx->regs->SCIFLR & RXRDY) { + buffer[0] = (char)ctx->regs->SCIRD; + /* + * Hand the data over to the Termios infrastructure. + * We send 1 as the "len" value because we can read only one byte at a time. + */ + rtems_termios_enqueue_raw_characters(tty, buffer, 1u); + } /* else, we didn't receive anything. */ /* - * Check if we have received something. - */ - if ( (ctx->regs->SCIFLR & (1<<9) ) == (1<<9) ) { - n = tms570_sci_read_received_chars(ctx, buf, TMS570_SCI_BUFFER_SIZE); - if ( n > 0 ) { - /* Hand the data over to the Termios infrastructure */ - rtems_termios_enqueue_raw_characters(tty, buf, n); - } - } - /* - * Check if we have something transmitted. + * Check if we transmitted something and are ready to transmit again. + * We need to check ctx->wrote_data because the TXRDY flag is set + * at system reset. If we were to reset the system and then handle an RX interrupt, + * TXRDY would be set and the interrupt handler would think we transmitted something. */ - if ( (ctx->regs->SCIFLR & (1<<8) ) == (1<<8) ) { - n = tms570_sci_transmitted_chars(ctx); - if ( n > 0 ) { - /* - * Notify Termios that we have transmitted some characters. It - * will call now the interrupt write function if more characters - * are ready for transmission. - */ - rtems_termios_dequeue_characters(tty, n); - } - } + + if ((ctx->regs->SCIFLR & TXRDY) && ctx->wrote_data) { + ctx->wrote_data = false; + /* + * Notify Termios that we have transmitted some characters. + * It'll call the interrupt write function if more characters + * are ready for transmission. + * We send 1 as the "len" value because we can transmit only one byte at a time. + */ + rtems_termios_dequeue_characters(tty, 1u); + } /* else, we either didn't transmit anything or aren't ready to transmit yet. */ } /** - * @brief sci write function called from interrupt + * @brief SCI write function called from the interrupt handler. * - * Nonblocking write function. Writes characters to HW peripheral - * TMS570 does not have write data buffer asociated with SCI - * so only one character can be written. + * Nonblocking write function. Writes characters to HW peripheral. + * As SCITD only has 8 bits for its transmit data buffer, we can only transmit + * one byte at the time. * - * @param[in] base context of the driver - * @param[in] buf buffer of characters pending to send - * @param[in] len size of the buffer + * @param[in] base Context of the driver. + * @param[in] buffer Buffer of characters pending to be transmitted. + * @param[in] length Buffer size. * @retval Void */ -static void tms570_sci_interrupt_write( - rtems_termios_device_context *base, - const char *buf, - size_t len -) +static void tms570_sci_interrupt_write(rtems_termios_device_context *base, + const char *buffer, size_t length) { - tms570_sci_context *ctx = (tms570_sci_context *) base; - - if ( len > 0 ) { - /* start UART TX, this will result in an interrupt when done */ - ctx->regs->SCITD = *buf; - /* character written - raise count*/ - ctx->tx_chars_in_hw = 1; - /* Enable TX interrupt (interrupt is edge-triggered) */ - ctx->regs->SCISETINT = (1<<8); - - } else { - /* No more to send, disable TX interrupts */ - ctx->regs->SCICLEARINT = (1<<8); - /* Tell close that we sent everything */ + tms570_sci_context *ctx = (tms570_sci_context *)base; + + if (length) { + /* Start UART TX, this will result in an interrupt when done. */ + ctx->regs->SCITD = *buffer; + /* Let the interrupt handler know that we wrote something. */ + ctx->wrote_data = true; + /* Enable TX interrupts (these are edge-triggered). */ + ctx->regs->SCISETINT = TX_INT; + } else { /* No more to send, disable TX interrupts. */ + ctx->regs->SCICLEARINT = TX_INT; } } /** - * @brief sci write function + * @brief SCI poll write function. * - * Blocking write function. Waits until HW peripheral is ready and then writes - * character to HW peripheral. Writes all characters in the buffer. + * Blocking write function. Waits until the HW peripheral is ready and then writes + * a character to it. Writes all the characters in the buffer. * - * @param[in] base context of the driver - * @param[in] buf buffer of characters pending to send - * @param[in] len size of the buffer + * @param[in] base Context of the driver. + * @param[in] buffer Buffer of characters pending to be transmitted. + * @param[in] length Size of the buffer. * @retval Void */ -static void tms570_sci_poll_write( - rtems_termios_device_context *base, - const char *buf, - size_t n -) +static void tms570_sci_poll_write(rtems_termios_device_context *base, + const char *buffer, size_t length) { - tms570_sci_context *ctx = (tms570_sci_context *) base; + const tms570_sci_context *const ctx = (tms570_sci_context *)base; size_t i; - /* Write */ - - for ( i = 0; i < n; ++i ) { - while ( (ctx->regs->SCIFLR & (1<<11) ) == 0) { - ; + for (i = 0; i < length; ++i) { + while (!(ctx->regs->SCIFLR & TX_EMPTY)) { + continue; /* Wait until the transmitter's buffer registers are empty. */ } - ctx->regs->SCITD = buf[i]; - } -} - -/** - * @brief See if there is recieved charakter to read - * - * read the RX flag from peripheral specified in context - * - * @param[in] ctx context of the driver - * @retval 0 No character to read - * @retval x Character ready to read - */ -static int TMS570_sci_can_read_char( - tms570_sci_context * ctx -) -{ - return ctx->regs->SCIFLR & (1<<9); -} -/** - * @brief reads character from peripheral - * - * reads the recieved character from peripheral specified in context - * - * @param[in] ctx context of the driver - * @retval x Character - */ -static char TMS570_sci_read_char( - tms570_sci_context * ctx -) -{ - return ctx->regs->SCIRD; + ctx->regs->SCITD = buffer[i]; + } } /** - * @brief sci read function + * @brief SCI poll read function. * - * check if there is recieved character to be read and reads it. + * Check if there's data available in SCIRD, and read it. * - * @param[in] base context of the driver - * @retval -1 No character to be read - * @retval x Read character + * @param[in] base Context of the driver. + * @retval -1 No data available to read. + * @retval x Read character. */ static int tms570_sci_poll_read(rtems_termios_device_context *base) { - tms570_sci_context *ctx = (tms570_sci_context *) base; + const tms570_sci_context *const ctx = (tms570_sci_context *)base; - /* Check if a character is available */ - if ( TMS570_sci_can_read_char(ctx) ) { - return TMS570_sci_read_char(ctx); - } else { - return -1; - } + return ctx->regs->SCIFLR & RXRDY ? + ctx->regs->SCIRD : -1; } /** - * @brief initialization of the driver + * @brief Driver initialization function (polling mode). * - * initialization of the HW peripheral specified in contex of the driver. + * This function performs the necessary HW intialization for the polling mode. * This function is called only once when opening the driver. * - * @param[in] tty Termios control - * @param[in] ctx context of the driver - * @param[in] term Termios attributes + * @param[in] tty Termios control. + * @param[in] ctx Context of the driver. + * @param[in] terminal Termios attributes. * @param[in] args - * @retval false Error occured during initialization - * @retval true Driver is open and ready + * @retval false Error occured during initialization. + * @retval true Driver is open and ready. */ -static bool tms570_sci_poll_first_open( - rtems_termios_tty *tty, - rtems_termios_device_context *ctx, - struct termios *term, - rtems_libio_open_close_args_t *args -) +static bool tms570_sci_poll_first_open(rtems_termios_tty *tty, + rtems_termios_device_context *ctx, + struct termios *terminal, + rtems_libio_open_close_args_t *args) { - bool ok; - - rtems_termios_set_best_baud(term, TMS570_SCI_BAUD_RATE); - ok = tms570_sci_set_attributes(ctx, term); - if ( !ok ) { - return false; - } - return true; + rtems_termios_set_best_baud(terminal, TMS570_SCI_BAUD_RATE); + return tms570_sci_set_attributes(ctx, terminal); } /** - * @brief initialization of the interrupt driven driver + * @brief Driver initialization function (interrupt mode). * - * calls tms570_sci_poll_first_open function. - * install and enables interrupts. + * This function performs the necessary HW intialization for the interrupt-driven mode. + * It installs an interrupt handler and enables interrupts. + * This function is called only once when opening the driver. * * @param[in] tty Termios control * @param[in] base context of the driver @@ -453,99 +358,74 @@ static bool tms570_sci_poll_first_open( * @retval false Error occured during initialization * @retval true Driver is open and ready */ -static bool tms570_sci_interrupt_first_open( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - struct termios *term, - rtems_libio_open_close_args_t *args -) -{ - tms570_sci_context *ctx = (tms570_sci_context *) base; - rtems_status_code sc; - bool ret; - - ret = tms570_sci_poll_first_open(tty, base, term, args); - if ( ret == false ) { - return false; - } - ctx->regs->SCISETINTLVL = 0; - /* Register Interrupt handler */ - sc = rtems_interrupt_handler_install(ctx->irq, - ctx->device_name, - RTEMS_INTERRUPT_SHARED, - tms570_sci_interrupt_handler, - tty - ); - if ( sc != RTEMS_SUCCESSFUL ) { - return false; - } - tms570_sci_enable_interrupts(ctx); - return true; -} -/** - * @brief closes sci peripheral - * - * @param[in] tty Termios control - * @param[in] base context of the driver - * @param[in] args - * @retval false Error occured during initialization - * @retval true Driver is open and ready - */ -static void tms570_sci_poll_last_close( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - rtems_libio_open_close_args_t *args -) +static bool tms570_sci_interrupt_first_open(rtems_termios_tty *tty, + rtems_termios_device_context *base, + struct termios *terminal, + rtems_libio_open_close_args_t *args) { - ; + tms570_sci_context *ctx = (tms570_sci_context *)base; + rtems_status_code status; + bool success = true; + + success = tms570_sci_poll_first_open(tty, base, terminal, args); + + if (success) { + /* Register Interrupt handler */ + status = rtems_interrupt_handler_install(ctx->irq, ctx->device_name, + RTEMS_INTERRUPT_SHARED, + tms570_sci_interrupt_handler, tty); + if (status == RTEMS_SUCCESSFUL) { + /* Enable RX interrupts */ + ctx->regs->SCISETINT = RX_INT; + } else { /* We couldn't install the interrupt handler. */ + success = false; + } + } /* else, we couldn't set up the hardware. */ + + return success; } /** - * @brief closes sci peripheral of interrupt driven driver + * @brief Closes the SCI driver in the interrupt-driven mode. * - * calls tms570_sci_poll_last_close and disables interrupts + * Calls tms570_sci_poll_last_close and disables interrupts. * - * @param[in] tty Termios control - * @param[in] base context of the driver + * @param[in] tty Termios control. + * @param[in] base Context of the driver. * @param[in] args - * @retval false Error occured during initialization - * @retval true Driver is open and ready + * @retval Void */ -static void tms570_sci_interrupt_last_close( - rtems_termios_tty *tty, - rtems_termios_device_context *base, - rtems_libio_open_close_args_t *args -) +static void tms570_sci_interrupt_last_close(rtems_termios_tty *tty, + rtems_termios_device_context *base, + rtems_libio_open_close_args_t *args) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; - /* Turn off RX interrupts */ + /* Disable RX interrupts. */ rtems_termios_device_lock_acquire(base, &lock_context); - tms570_sci_disable_interrupts(ctx); + ctx->regs->SCICLEARINT = RX_INT; rtems_termios_device_lock_release(base, &lock_context); - /* Flush device */ - while ( ( ctx->regs->SCIFLR & (1<<11) ) > 0 ) { - ;/* Wait until all data has been sent */ + /* Flush device. */ + while (ctx->regs->SCIFLR & TX_EMPTY) { + continue; /* Wait until all data has been sent. */ } - /* uninstall ISR */ + /* Uninstall interrupt handler. */ rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty); - - tms570_sci_poll_last_close(tty, base, args); } /** * @brief Struct containing definitions of polled driver functions. * * Encapsulates polled driver functions. - * Use of this table is determited by not defining TMS570_USE_INTERRUPTS + * Use of this table is determited by not defining TMS570_USE_INTERRUPTS. */ const rtems_termios_device_handler tms570_sci_handler_polled = { .first_open = tms570_sci_poll_first_open, - .last_close = tms570_sci_poll_last_close, + .last_close = NULL, .poll_read = tms570_sci_poll_read, .write = tms570_sci_poll_write, .set_attributes = tms570_sci_set_attributes, @@ -556,7 +436,7 @@ const rtems_termios_device_handler tms570_sci_handler_polled = { * @brief Struct containing definitions of interrupt driven driver functions. * * Encapsulates interrupt driven driver functions. - * Use of this table is determited by defining TMS570_USE_INTERRUPTS + * Use of this table is determited by defining TMS570_USE_INTERRUPTS. */ const rtems_termios_device_handler tms570_sci_handler_interrupt = { .first_open = tms570_sci_interrupt_first_open, diff --git a/c/src/lib/libbsp/arm/tms570/include/bsp.h b/c/src/lib/libbsp/arm/tms570/include/bsp.h index 81bc4cd..5453d16 100644 --- a/c/src/lib/libbsp/arm/tms570/include/bsp.h +++ b/c/src/lib/libbsp/arm/tms570/include/bsp.h @@ -15,6 +15,11 @@ * 166 36 Praha 6 * Czech Republic * + * Copyright (c) 2015 Taller Technologies + * Martin Galvan <martin.gal...@tallertechnologies.com> + * Marcos Diaz <marcos.d...@tallertechnologies.com> + * Eduardo Sanchez <eduardo.sanc...@tallertechnologies.com> + * * Based on LPC24xx and LPC1768 BSP * * The license and distribution terms for this file may be @@ -36,11 +41,13 @@ #include <rtems/clockdrv.h> #include <bsp/default-initial-extension.h> -#define BSP_OSCILATOR_CLOCK 8000000 -#define BSP_PLL_OUT_CLOCK 160000000 +#define BSP_OSCILATOR_CLOCK 8000000u + +/* This is the output of the main PLL, and the source of the Global Clock Module (GCM). */ +#define BSP_PLL_OUT_CLOCK 180000000u /** Define operation count for Tests */ -#define OPERATION_COUNT 4 +#define OPERATION_COUNT 4u #ifdef __cplusplus extern "C" { diff --git a/c/src/lib/libbsp/arm/tms570/include/tms570-sci-driver.h b/c/src/lib/libbsp/arm/tms570/include/tms570-sci-driver.h index f32eaea..10fb134 100644 --- a/c/src/lib/libbsp/arm/tms570/include/tms570-sci-driver.h +++ b/c/src/lib/libbsp/arm/tms570/include/tms570-sci-driver.h @@ -3,7 +3,7 @@ * * @ingroup tms570 * - * @brief Declaration of serial's driver inner structure. + * @brief Declaration of the serial's driver inner structure. */ /* @@ -15,6 +15,11 @@ * 166 36 Praha 6 * Czech Republic * + * Copyright (c) 2015 Taller Technologies + * Martin Galvan <martin.gal...@tallertechnologies.com> + * Marcos Diaz <marcos.d...@tallertechnologies.com> + * Eduardo Sanchez <eduardo.sanc...@tallertechnologies.com> + * * Based on LPC24xx and LPC1768 BSP * by embedded brains GmbH and others * @@ -39,7 +44,7 @@ typedef struct { rtems_termios_device_context base; const char *device_name; volatile tms570_sci_t *regs; - int tx_chars_in_hw; + bool wrote_data; rtems_vector_number irq; } tms570_sci_context; @@ -47,7 +52,7 @@ extern const rtems_termios_device_handler tms570_sci_handler_polled; extern const rtems_termios_device_handler tms570_sci_handler_interrupt; -extern const tms570_sci_context driver_context_table[]; +extern tms570_sci_context driver_context_table[]; /** @} */ diff --git a/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h b/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h index 6ed68e2..c0506e5 100644 --- a/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h +++ b/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h @@ -15,6 +15,11 @@ * 166 36 Praha 6 * Czech Republic * + * Copyright (c) 2015 Taller Technologies + * Martin Galvan <martin.gal...@tallertechnologies.com> + * Marcos Diaz <marcos.d...@tallertechnologies.com> + * Eduardo Sanchez <eduardo.sanc...@tallertechnologies.com> + * * Based on LPC24xx and LPC1768 BSP * by embedded brains GmbH and others * @@ -36,41 +41,57 @@ extern "C" { #endif /* __cplusplus */ typedef struct { - uint32_t SCIGCR0; /*SCIGlobalControlRegister0*/ - uint32_t SCIGCR1; /*SCIGlobalControlRegister1*/ - uint32_t reserved1 [0x4/4]; - uint32_t SCISETINT; /*SCISetInterruptRegister*/ - uint32_t SCICLEARINT; /*SCIClearInterruptRegister*/ - uint32_t SCISETINTLVL; /*SCISetInterruptLevelRegister*/ - uint32_t SCICLEARINTLVL; /*SCIClearInterruptLevelRegister*/ - uint32_t SCIFLR; /*SCIFlagsRegister*/ - uint32_t SCIINTVECT0; /*SCIInterruptVectorOffset0*/ - uint32_t SCIINTVECT1; /*SCIInterruptVectorOffset1*/ - uint32_t SCIFORMAT; /*SCIFormatControlRegister*/ - uint32_t BRS; /*BaudRateSelectionRegister*/ - uint32_t SCIED; /*ReceiverEmulationDataBuffer*/ - uint32_t SCIRD; /*ReceiverDataBuffer*/ - uint32_t SCITD; /*TransmitDataBuffer*/ - uint32_t SCIPIO0; /*SCIPinI/OControlRegister0*/ - uint32_t SCIPIO1; /*SCIPinI/OControlRegister1*/ - uint32_t SCIPIO2; /*SCIPinI/OControlRegister2*/ - uint32_t SCIPIO3; /*SCIPinI/OControlRegister3*/ - uint32_t SCIPIO4; /*SCIPinI/OControlRegister4*/ - uint32_t SCIPIO5; /*SCIPinI/OControlRegister5*/ - uint32_t SCIPIO6; /*SCIPinI/OControlRegister6*/ - uint32_t SCIPIO7; /*SCIPinI/OControlRegister7*/ - uint32_t SCIPIO8; /*SCIPinI/OControlRegister8*/ - uint32_t reserved2 [0x30/4]; - uint32_t IODFTCTRL; /*Input/OutputErrorEnableRegister*/ -}tms570_sci_t; + uint32_t SCIGCR0; /* SCI Global Control Register 0 */ + uint32_t SCIGCR1; /* SCI Global Control Register 1 */ + uint32_t reserved1; + uint32_t SCISETINT; /* SCI Set Interrupt Register */ + uint32_t SCICLEARINT; /* SCI Clear Interrupt Register */ + uint32_t SCISETINTLVL; /* SCI Set Interrupt Level Register */ + uint32_t SCICLEARINTLVL; /* SCI Clear Interrupt Level Register */ + uint32_t SCIFLR; /* SCI Flags Register */ + uint32_t SCIINTVECT0; /* SCI Interrupt Vector Offset 0 */ + uint32_t SCIINTVECT1; /* SCI Interrupt Vector Offset 1 */ + uint32_t SCIFORMAT; /* SCI Format Control Register */ + uint32_t BRS; /* Baud Rate Selection Register */ + uint32_t SCIED; /* Receiver Emulation Data Buffer */ + uint32_t SCIRD; /* Receiver Data Buffer */ + uint32_t SCITD; /* Transmit Data Buffer */ + uint32_t SCIPIO0; /* SCI Pin I/O Control Register 0 */ + uint32_t SCIPIO1; /* SCI Pin I/O Control Register 1 */ + uint32_t SCIPIO2; /* SCI Pin I/O Control Register 2 */ + uint32_t SCIPIO3; /* SCI Pin I/O Control Register 3 */ + uint32_t SCIPIO4; /* SCI Pin I/O Control Register 4 */ + uint32_t SCIPIO5; /* SCI Pin I/O Control Register 5 */ + uint32_t SCIPIO6; /* SCI Pin I/O Control Register 6 */ + uint32_t SCIPIO7; /* SCI Pin I/O Control Register 7 */ + uint32_t SCIPIO8; /* SCI Pin I/O Control Register 8 */ + uint32_t reserved2[12]; + uint32_t IODFTCTRL; /* I/O Error Enable Register */ +} tms570_sci_t; + +#define TMS570_SCI (*(volatile tms570_sci_t *)0xFFF7E400u) +#define TMS570_SCI2 (*(volatile tms570_sci_t *)0xFFF7E500u) + +/* SCI Global Control Register 1 (SCIGCR1) */ +#define TIMING_MODE (1u << 1u) /* 0: Synchronous; 1: Asynchronous */ +#define PARITY_ENA (1u << 2u) /* 0: Parity is disabled; 1: Parity is enabled */ +#define EVEN_PARITY (1u << 3u) /* 0: Odd parity; 1: Even parity */ +#define STOP (1u << 4u) /* 0: One stop bit; 1: Two stop bits */ +#define SWnRST (1u << 7u) /* 0: SCI/LIN is in reset state; 1: SCI/LIN is in ready state */ +#define RXENA (1u << 24u) /* 0: Receive disabled; 1: Receive enabled */ +#define TXENA (1u << 25u) /* 0: Transmit disabled; 1: Transmit enabled */ -#define TMS570_SCI (*(volatile tms570_sci_t*)0xFFF7E400U) -#define TMS570_SCI2 (*(volatile tms570_sci_t*)0xFFF7E500U) +/* SCI Flags Register (SCIFLR) */ +#define TXRDY (1u << 8u) /* 0: SCITD is full; 1: SCITD is ready to receive the next character */ +#define RXRDY (1u << 9u) /* 0: No new data in SCIRD; 1: New data is ready to be read from SCIRD */ +#define TX_EMPTY (1u << 11u) /* 0: Transmit buffers are loaded; 1: Transmit buffers are empty */ -/** @} */ +/* Interrupt bits (SCISETINT and SCICLEARINT) */ +#define TX_INT (1u << 8u) /* TX interrupts */ +#define RX_INT (1u << 9u) /* RX interrupts */ #ifdef __cplusplus } #endif /* __cplusplus */ -#endif +#endif /* LIBBSP_ARM_TMS570_SCI_H */
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel