Sorry for the late answer. On Wed, Jan 14, 2015 at 6:50 PM, Pavel Pisa <p...@cmp.felk.cvut.cz> wrote: > Hello Martin, > > On Wednesday 14 of January 2015 18:27:41 Martin Galvan wrote: >> Hi everyone! We're currently working on improving the TMS570 BSP, and >> in the process we discovered an important bug caused by a misuse of >> the RTEMS_DECONST macro. Said macro seems to be used in a few other >> places throughout the code to bypass const restrictions. > > Please, can you provide more details? > I have contributed to RTEMS_DECONST and TMS570 BSP - directly > and as GSoC menthor. So bugs can fall to my head.
Sure. We're working with a TMS570 USB Development kit, with both RTEMS and the HALCogen-generated code placed the board's ROM (I understand you were loading RTEMS in RAM). What happened was that, in the SCI driver, driver_context_table was declared as const and it included a variable called tx_chars_in_hw which is used by the interrupt handler as a flag to mark that we just wrote a character. tx_chars_in_hw was supposed to be set to 1 in tms570_sci_interrupt_write; however because driver_context_table was declared as const it was being placed inside the board's ROM. Therefore, tx_chars_in_hw couldn't be written into, and the console got locked after writing the first character. RTEMS_DECONST was being misused in console_initialize to cast &driver_context_table.base to rtems_termios_device_context *, thus masking out the source of the bug. The only reason it was working for you is that RTEMS was loaded in RAM. Right now we're facing a different bug where we can't use printf to print a 2-digit integer because the system hangs somewhere inside printf. This happens in both interrupt-driven and polled mode, but it doesn't happen with puts or printk (which leads us to think it's either a printf or a driver issue). Any pointers on this would be welcome. >> What's the purpose of having something like this in the codebase? >> Should it be removed to maintain const-correctness throughout the >> code? > > The RTEMS_DECONST is the tool how to suppress warning when > the target function can cope with const and non-constant > pointer, can distinguish if it is non-const case from some > data in from the poited to structure or other parameter > and it needs to change some data/reference counts in non-const > case for example. Such cases cannot be solved cleanly with > C in some specific cases and programmer has to take responsibility > into his/her own hands. But there could be bug for sure. I noticed that. It's unfortunate we have to have something like this in the codebase; we should at least add a few comments to the macro definition to avoid having people using it unless it's completely necessary. > As for TMS570 BSP, Premysl Houdek is due to finish some > things in the BSP in the next months. He needs to complete > his master thesis and submit it. > > I have spent considerable time with him to negotiate > and prepare format and way to extend coverage of TMS570 header > files. I have communicated with Ti representatives about > releasing files under RTEMS compatible license but they are > not able to change that for more reasons. So we work on preparation > of RTEMS license and format friendly header files from PDF manual. I don't understand what you meant by that. Right now we're using the HALCogen code for testing purposes only; is there any way to incorporate them into the BSP code? > Premek has promised to complete ETHERNET support in frame > of his thesis. My other colleague finished work on TMS570 ETHERNET > for Ti provided FreeRTOS to really work. So we have knowledge > now how the EMAC works. We work on Matlab/Simulink support > in our other industrial partner paid non-RTEMS TMS570 and RM48 > project based on Ti provided CodeComposer support. So I would be happy > if we can one day extend TMS570 to support RM48 as well but that > is far far future without contract. But I hope that TMS570 > will be extended in next months. That's great. We're not planning to use ethernet with the TMS right now so we won't be able to test it, but any improvements to the BSP are welcome. > So please, if you plan to introduce more changes, please, send > plan of your work in advance to coordinate things. We're probably gonna have to refactor a few of the existing files and add CAN support. > If you want to text TMS570 for real application which is computational intensive > then you probably want to try change board configuration files to specify > hat FPU should be used for math. We have used soft-float > for initial porting but thanks to Sebastian Huber generic > ARM work, TMS570 float is supported too. Right now we're not using the FPU, but we'll definitely need it in the near future so that's great. > As for RTEMS_DECONST, its definition should not be removed for sure. > But it is possible that it is used in incorrect place or even that > that macro has bug. So please, specify in more detail what is > the problem and what are your planes. I'm attaching a patch with the refactored driver. It should work with the tms570ls3137_hdk configuration. Notice we had to add some calls to HALCogen-generated functions inside the RTEMS initialization code in order for everything to work. We also changed the value of the BSP_PLL_OUT_CLOCK macro from 160 MHz to 180 MHz. -- Martín Galván Software Engineer Taller Technologies Argentina San Lorenzo 47, 3rd Floor, Office 5 Córdoba, Argentina Phone: 54 351 4217888 / +54 351 4218211
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..91fba22 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. */ /* @@ -28,11 +30,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 +40,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 36d62e4..b56ac24 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. */ /* @@ -33,14 +33,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 +58,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 +86,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 +95,115 @@ 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) -{ - if ( N < 1 ) { - return 0; - } - if ( ctx->regs->SCIRD != 0 ) { - buf[0] = ctx->regs->SCIRD; - return 1; - } - return 0; -} -/** - * @brief Enables RX interrupt - * - * Enables RX interrupt source of SCI peripheral - * specified in the driver context. - * - * @param[in] ctx context of the driver - * @retval Void - */ -static void tms570_sci_enable_interrupts(tms570_sci_context * ctx) +static void tms570_sci_set_parity(tms570_sci_context *const ctx, + const tcflag_t c_cflag) { - ctx->regs->SCISETINT = (1<<9); -} + if (c_cflag & PARENB) { + ctx->regs->SCIGCR1 |= PARITY_ENA; -/** - * @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); + 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); + } } /** - * @brief Check whether driver has put char in HW + * @brief Set the SCI prescaler. * - * 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. + * Sets the value of the BRS corresponding to the desired baud rate. * - * @param[in] ctx context of the driver - * @retval x + * @param[in] ctx Context of the driver. + * @param[in] terminal Termios driver. + * @retval void. */ -static int tms570_sci_transmitted_chars(tms570_sci_context * ctx) +static void tms570_sci_set_prescaler(tms570_sci_context *const ctx, + const struct termios *terminal) { - int ret; - - ret = ctx->tx_chars_in_hw; - if ( ret == 1 ) { - ctx->tx_chars_in_hw = 0; - return 1; - } - return ret; + uint32_t factor; + uint32_t VCLK; + rtems_termios_baud_t baudrate; + rtems_termios_baud_t prescaler; + + VCLK = BSP_PLL_OUT_CLOCK / 2u; + + /* Determine whether we're in synchronous or asynchronous mode, and select + the appropriate divider factor. */ + factor = ctx->regs->SCIGCR1 & TIMING_MODE ? 16u : 1u; + + /* Set the prescaler for the desired baud rate. + * According to the datasheet, the formula for the baudrate is: + * baudrate = VCLK / (factor * (prescaler + 1)) + * + * Solving for prescaler: + * prescaler = (VCLK / (factor * baudrate)) - 1 + * + * If we use that formula, however, we'll end up having rounding issues such as + * using a prescaler of 47 for 115200 (should be 48). To avoid this we'll + * use the formula HALCogen generates, which gives us similar values for + * the prescaler but without the rounding issues. + */ + baudrate = rtems_termios_baud_to_number(cfgetospeed(terminal)); + /*prescaler = VCLK / (factor * (baudrate + 1u));*/ + 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 +211,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 +362,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 +440,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/tms570-sci-driver.h b/c/src/lib/libbsp/arm/tms570/include/tms570-sci-driver.h index f32eaea..565ff50 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. */ /* @@ -39,7 +39,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 +47,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 25c02e5..9c59774 100644 --- a/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h +++ b/c/src/lib/libbsp/arm/tms570/include/tms570-sci.h @@ -1,9 +1,9 @@ /** - * @file tms570-rti.h + * @file tms570-sci.h * * @ingroup tms570 * - * @brief Real Time Interrupt module (RTI) header file. + * @brief Serial Communication Interface (SCI) header file. */ /* @@ -23,11 +23,12 @@ * http://www.rtems.org/license/LICENSE. */ -#ifndef LIBBSP_ARM_TMS570_RTI_H -#define LIBBSP_ARM_TMS570_RTI_H +#ifndef LIBBSP_ARM_TMS570_SCI_H +#define LIBBSP_ARM_TMS570_SCI_H -#ifndef ASM +#include <libchip/serial.h> +#include <rtems.h> #include <stdint.h> #ifdef __cplusplus @@ -35,61 +36,57 @@ extern "C" { #endif /* __cplusplus */ typedef struct { - uint32_t RTIGCTRL; /* RTIGlobalControlRegister */ - uint32_t RTITBCTRL; /* RTITimebaseControlRegister */ - uint32_t RTICAPCTRL; /* RTICaptureControlRegister */ - uint32_t RTICOMPCTRL; /* RTICompareControlRegister */ - uint32_t RTIFRC0; /* RTIFreeRunningCounter0Register */ - uint32_t RTIUC0; /* RTIUpCounter0Register */ - uint32_t RTICPUC0; /* RTICompareUpCounter0Register */ - uint32_t reserved1 [0x4/4]; - uint32_t RTICAFRC0; /* RTICaptureFreeRunningCounter0Register */ - uint32_t RTICAUC0; /* RTICaptureUpCounter0Register */ - uint32_t reserved2 [0x8/4]; - uint32_t RTIFRC1; /* RTIFreeRunningCounter1Register */ - uint32_t RTIUC1; /* RTIUpCounter1Register */ - uint32_t RTICPUC1; /* RTICompareUpCounter1Register */ - uint32_t reserved3 [0x4/4]; - uint32_t RTICAFRC1; /* RTICaptureFreeRunningCounter1Register */ - uint32_t RTICAUC1; /* RTICaptureUpCounter1Register */ - uint32_t reserved4 [0x8/4]; - uint32_t RTICOMP0; /* RTICompare0Register */ - uint32_t RTIUDCP0; /* RTIUpdateCompare0Register */ - uint32_t RTICOMP1; /* RTICompare1Register */ - uint32_t RTIUDCP1; /* RTIUpdateCompare1Register */ - uint32_t RTICOMP2; /* RTICompare2Register */ - uint32_t RTIUDCP2; /* RTIUpdateCompare2Register */ - uint32_t RTICOMP3; /* RTICompare3Register */ - uint32_t RTIUDCP3; /* RTIUpdateCompare3Register */ - uint32_t RTITBLCOMP; /* RTITimebaseLowCompareRegister */ - uint32_t RTITBHCOMP; /* RTITimebaseHighCompareRegister */ - uint32_t reserved5 [0x8/4]; - uint32_t RTISETINTENA; /* RTISetInterruptEnableRegister */ - uint32_t RTICLEARINTENA; /* RTIClearInterruptEnableRegister */ - uint32_t RTIINTFLAG; /* RTIInterruptFlagRegister */ - uint32_t reserved6 [0x4/4]; - uint32_t RTIDWDCTRL; /* DigitalWatchdogControlRegister */ - uint32_t RTIDWDPRLD; /* DigitalWatchdogPreloadRegister */ - uint32_t RTIWDSTATUS; /* WatchdogStatusRegister */ - uint32_t RTIWDKEY; /* RTIWatchdogKeyRegister */ - uint32_t RTIDWDCNTR; /* RTIDigitalWatchdogDownCounterRegister */ - uint32_t RTIWWDRXNCTRL; /* DigitalWindowedWatchdogReactionControlRegister */ - uint32_t RTIWWDSIZECTRL; /* DigitalWindowedWatchdogWindowSizeControlRegister */ - uint32_t RTIINTCLRENABLE;/* RTICompareInterruptClearEnableRegister */ - uint32_t RTICOMP0CLR; /* RTICompare0ClearRegister */ - uint32_t RTICOMP1CLR; /* RTICompare1ClearRegister */ - uint32_t RTICOMP2CLR; /* RTICompare2ClearRegister */ - uint32_t RTICOMP3CLR; /* RTICompare3ClearRegister */ -}tms570_rti_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_RTI (*(volatile tms570_rti_t*)0xFFFFFC00) +#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 */ + +/* 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 /* ASM */ - -#endif /* LIBBSP_ARM_TMS570_IRQ_H */ +#endif /* LIBBSP_ARM_TMS570_SCI_H */
_______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel