[PATCH] arm/tms570: sci context has to be writable because it holds state variable.

Martin Galvan martin.galvan at tallertechnologies.com
Wed Feb 4 18:49:31 UTC 2015


On Wed, Feb 4, 2015 at 2:20 PM, Pavel Pisa <pisa at 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).

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.galvan at tallertechnologies.com>
+ * Marcos Diaz      <marcos.diaz at tallertechnologies.com>
+ * Eduardo Sanchez  <eduardo.sanchez at 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.galvan at tallertechnologies.com>
+ * Marcos Diaz      <marcos.diaz at tallertechnologies.com>
+ * Eduardo Sanchez  <eduardo.sanchez at 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.galvan at tallertechnologies.com>
+ * Marcos Diaz      <marcos.diaz at tallertechnologies.com>
+ * Eduardo Sanchez  <eduardo.sanchez at 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.galvan at tallertechnologies.com>
+ * Marcos Diaz      <marcos.diaz at tallertechnologies.com>
+ * Eduardo Sanchez  <eduardo.sanchez at 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.galvan at tallertechnologies.com>
+ * Marcos Diaz      <marcos.diaz at tallertechnologies.com>
+ * Eduardo Sanchez  <eduardo.sanchez at 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 */


-- 

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



More information about the devel mailing list