static int32_t USART_Control()

in lib/cmsis/CMSIS/Pack/Example/CMSIS_Driver/USART_LPC18xx.c [1244:1670]


static int32_t USART_Control (uint32_t          control,
                              uint32_t          arg,
                              USART_RESOURCES  *usart) {
  uint32_t val, mode;
  uint32_t syncctrl, hden, icr, scictrl, lcr, mcr;

  if ((usart->info->flags & USART_FLAG_POWERED) == 0) {
    // USART not powered
    return ARM_DRIVER_ERROR;
  }

  syncctrl = 0;
  hden     = 0;
  icr      = 0;
  scictrl  = 0;
  lcr      = 0;

  switch (control & ARM_USART_CONTROL_Msk) {
    case ARM_USART_MODE_ASYNCHRONOUS:
      mode = ARM_USART_MODE_ASYNCHRONOUS;
      break;
    case ARM_USART_MODE_SYNCHRONOUS_MASTER:
      if (usart->capabilities.synchronous_master) {
        // Enable synchronous master (SCLK out) mode
        syncctrl = USART_SYNCCTRL_SYNC | USART_SYNCCTRL_CSRC;
      } else return ARM_USART_ERROR_MODE;
      mode = ARM_USART_MODE_SYNCHRONOUS_MASTER;
      break;
    case ARM_USART_MODE_SYNCHRONOUS_SLAVE:
      if (usart->capabilities.synchronous_slave) {
        // Enable synchronous slave (SCLK in) mode
        syncctrl = USART_SYNCCTRL_SYNC;
      } else return ARM_USART_ERROR_MODE;
      mode = ARM_USART_MODE_SYNCHRONOUS_SLAVE;
      break;
    case ARM_USART_MODE_SINGLE_WIRE:
      // Enable Half duplex
      hden = USART_HDEN_HDEN;
      mode = ARM_USART_MODE_SINGLE_WIRE;
      break;
    case ARM_USART_MODE_IRDA:
      if (usart->capabilities.irda) {
        // Enable IrDA mode
        icr = USART_ICR_IRDAEN;
      } else return ARM_USART_ERROR_MODE;
      mode = ARM_USART_MODE_IRDA;
      break;
    case ARM_USART_MODE_SMART_CARD:
      if (usart->capabilities.smart_card) {
        // Enable Smart card mode
        scictrl = USART_SCICTRL_SCIEN;
      } else return ARM_USART_ERROR_MODE;
      mode = ARM_USART_MODE_SMART_CARD;
      break;

    // Default TX value
    case ARM_USART_SET_DEFAULT_TX_VALUE:
      usart->info->xfer.tx_def_val = arg;
      return ARM_DRIVER_OK;

    // IrDA pulse
    case ARM_USART_SET_IRDA_PULSE:
      if (usart->capabilities.irda) {
        if (arg == 0) {
          usart->reg->ICR &= ~(USART_ICR_FIXPULSEEN);
        } else {
          val = 1000000000 / (GetClockFreq (((*usart->clk.base_clk >> 24) & 0x1F)));
          icr = usart->reg->ICR & ~USART_ICR_PULSEDIV_MSK;
          if      (arg <= (2   * val)) icr |= (0 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (4   * val)) icr |= (1 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (8   * val)) icr |= (2 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (6   * val)) icr |= (3 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (2   * val)) icr |= (4 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (64  * val)) icr |= (5 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (128 * val)) icr |= (6 << USART_ICR_PULSEDIV_POS);
          else if (arg <= (256 * val)) icr |= (7 << USART_ICR_PULSEDIV_POS);
          else return ARM_DRIVER_ERROR;
          usart->reg->ICR = icr | USART_ICR_FIXPULSEEN;
        }
      } else return ARM_DRIVER_ERROR;
      return ARM_DRIVER_OK;

    // SmartCard guard time
    case ARM_USART_SET_SMART_CARD_GUARD_TIME:
      if (usart->capabilities.smart_card) {
        if (arg > 0xFF) return ARM_DRIVER_ERROR;
        usart->reg->SCICTRL &= ~USART_SCICTRL_GUARDTIME_MSK;
        usart->reg->SCICTRL |= (arg << USART_SCICTRL_GUARDTIME_POS);
      } else return ARM_DRIVER_ERROR;
      return ARM_DRIVER_OK;

    // SmartCard clock
    case ARM_USART_SET_SMART_CARD_CLOCK:
      if (usart->capabilities.smart_card == 0) return ARM_DRIVER_ERROR;
      if (arg == 0)                            return ARM_DRIVER_OK;
      if (usart->capabilities.smart_card_clock) {
        if ((usart->info->baudrate * 372) != arg)
          return ARM_DRIVER_ERROR;
      } else return ARM_DRIVER_ERROR;
      return ARM_DRIVER_OK;

     // SmartCard NACK
    case ARM_USART_CONTROL_SMART_CARD_NACK:
      if (usart->capabilities.smart_card) {
        if (arg) usart->reg->SCICTRL &= ~USART_SCICTRL_NACKDIS;
        else     usart->reg->SCICTRL |=  USART_SCICTRL_NACKDIS;
      } else return ARM_DRIVER_ERROR;
      return ARM_DRIVER_OK;

    // Control TX
    case ARM_USART_CONTROL_TX:
      if (arg) {
        if (usart->info->mode != ARM_USART_MODE_SMART_CARD) {
          // USART TX pin function selected
          SCU_PinConfigure(usart->pins.tx->port, usart->pins.tx->num,
                           SCU_PIN_CFG_PULLUP_DIS | SCU_PIN_CFG_INPUT_FILTER_DIS |
                           SCU_PIN_CFG_MODE(usart->pins.tx->config_val));
        }
        usart->info->flags |= USART_FLAG_TX_ENABLED;
        usart->reg->TER |= USART_TER_TXEN;
      } else {
        usart->info->flags &= ~USART_FLAG_TX_ENABLED;
        usart->reg->TER &= ~USART_TER_TXEN;
        if (usart->info->mode != ARM_USART_MODE_SMART_CARD) {
          // GPIO pin function selected
          SCU_PinConfigure(usart->pins.tx->port, usart->pins.tx->num,
                           SCU_PIN_CFG_PULLUP_DIS | SCU_PIN_CFG_INPUT_FILTER_DIS |
                           SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0));
        }
      }
      return ARM_DRIVER_OK;

    // Control RX
    case ARM_USART_CONTROL_RX:
      // RX Line interrupt enable (overrun, framing, parity error, break)
      if (arg) {
        if ((usart->info->mode != ARM_USART_MODE_SMART_CARD)   &&
            (usart->info->mode != ARM_USART_MODE_SINGLE_WIRE )) {
          // USART RX pin function selected
          SCU_PinConfigure(usart->pins.rx->port, usart->pins.rx->num,
                           SCU_PIN_CFG_INPUT_BUFFER_EN | SCU_PIN_CFG_INPUT_FILTER_DIS |
                           SCU_PIN_CFG_PULLUP_DIS | SCU_PIN_CFG_MODE(usart->pins.rx->config_val));
        }
        usart->info->flags |= USART_FLAG_RX_ENABLED;
        usart->reg->RS485CTRL &= ~USART_RS485CTRL_RXDIS;
        usart->reg->IER |= USART_IER_RXIE;
      } else {
        usart->info->flags &= ~USART_FLAG_RX_ENABLED;
        usart->reg->RS485CTRL |= USART_RS485CTRL_RXDIS;
        usart->reg->IER &= ~USART_IER_RXIE;
        if ((usart->info->mode != ARM_USART_MODE_SMART_CARD)   &&
            (usart->info->mode != ARM_USART_MODE_SINGLE_WIRE )) {
          // GPIO pin function selected
          SCU_PinConfigure(usart->pins.rx->port, usart->pins.rx->num,
                           SCU_PIN_CFG_PULLUP_DIS | SCU_PIN_CFG_INPUT_FILTER_DIS |
                           SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0));
        }
      }
      return ARM_DRIVER_OK;

    // Control break
    case ARM_USART_CONTROL_BREAK:
      if (arg) usart->reg->LCR |=  USART_LCR_BC;
      else     usart->reg->LCR &= ~USART_LCR_BC;
      return ARM_DRIVER_OK;

    // Abort Send
    case ARM_USART_ABORT_SEND:
      // Disable transmit holding register empty interrupt
      usart->reg->IER &= ~USART_IER_THREIE;

      // Set trigger level
      val  = (usart->trig_lvl & USART_FCR_RXTRIGLVL_MSK) |
              USART_FCR_FIFOEN;
      if (usart->dma_rx || usart->dma_tx)
        val |= USART_FCR_DMAMODE;

      // Transmit FIFO reset
      val |= USART_FCR_TXFIFORES;
      usart->reg->FCR = val;

      // If DMA mode - disable DMA channel
      if ((usart->dma_tx) && (usart->info->flags & USART_FLAG_SEND_ACTIVE)) {
        GPDMA_ChannelDisable (usart->dma_tx->channel);
      }

      // Clear Send active flag
      usart->info->flags &= ~USART_FLAG_SEND_ACTIVE;
      return ARM_DRIVER_OK;

    // Abort receive
    case ARM_USART_ABORT_RECEIVE:
      // Disable receive data available interrupt
      usart->reg->IER &= ~USART_IER_RBRIE;

      // Set trigger level
      val  = (usart->trig_lvl & USART_FCR_RXTRIGLVL_MSK) |
              USART_FCR_FIFOEN;
      if (usart->dma_rx || usart->dma_tx)
        val |= USART_FCR_DMAMODE;

      // Transmit FIFO reset
      val |= USART_FCR_RXFIFORES;
      usart->reg->FCR = val;

      // If DMA mode - disable DMA channel
      if ((usart->dma_rx) && (usart->info->status.rx_busy)) {
        GPDMA_ChannelDisable (usart->dma_tx->channel);
      }

      // Clear RX busy status
      usart->info->status.rx_busy = 0;
      return ARM_DRIVER_OK;

    // Abort transfer
    case ARM_USART_ABORT_TRANSFER:
      // Disable transmit holding register empty and 
      // receive data available interrupts
      usart->reg->IER &= ~(USART_IER_THREIE | USART_IER_RBRIE);

      // If DMA mode - disable DMA channel
      if ((usart->dma_tx) && (usart->info->flags & USART_FLAG_SEND_ACTIVE)) {
        GPDMA_ChannelDisable (usart->dma_tx->channel);
      }
      if ((usart->dma_rx) && (usart->info->status.rx_busy)) {
        GPDMA_ChannelDisable (usart->dma_tx->channel);
      }

      // Set trigger level
      val  = (usart->trig_lvl & USART_FCR_RXTRIGLVL_MSK) |
              USART_FCR_FIFOEN;
      if (usart->dma_rx || usart->dma_tx)
        val |= USART_FCR_DMAMODE;

      // Transmit FIFO reset
      val |= USART_FCR_TXFIFORES | USART_FCR_RXFIFORES;
      usart->reg->FCR = val;

      // Clear busy statuses
      usart->info->status.rx_busy = 0;
      usart->info->flags &= ~USART_FLAG_SEND_ACTIVE;
     
      return ARM_DRIVER_OK;

    // Unsupported command
    default: return ARM_DRIVER_ERROR_UNSUPPORTED;
  }

  // Check if Receiver/Transmitter is busy
  if ( usart->info->status.rx_busy ||
      (usart->info->flags & USART_FLAG_SEND_ACTIVE)) {
    return ARM_DRIVER_ERROR_BUSY;
  }

  // USART Data bits
  switch (control & ARM_USART_DATA_BITS_Msk) {
    case ARM_USART_DATA_BITS_5: lcr |= (0 << USART_LCR_WLS_POS); break;
    case ARM_USART_DATA_BITS_6: lcr |= (1 << USART_LCR_WLS_POS); break;
    case ARM_USART_DATA_BITS_7: lcr |= (2 << USART_LCR_WLS_POS); break;
    case ARM_USART_DATA_BITS_8: lcr |= (3 << USART_LCR_WLS_POS); break;
    default: return ARM_USART_ERROR_DATA_BITS;
  }

  // USART Parity
  switch (control & ARM_USART_PARITY_Msk) {
    case ARM_USART_PARITY_NONE:                                  break;
    case ARM_USART_PARITY_EVEN: lcr |= (1 << USART_LCR_PS_POS) |
                                             USART_LCR_PE;       break;
    case ARM_USART_PARITY_ODD:  lcr |= USART_LCR_PE;             break;
  }

  // USART Stop bits
  switch (control & ARM_USART_STOP_BITS_Msk) {
    case ARM_USART_STOP_BITS_1:                       break;
    case ARM_USART_STOP_BITS_2: lcr |= USART_LCR_SBS; break;
    default: return ARM_USART_ERROR_STOP_BITS;
  }

  // USART Flow control (RTS and CTS lines are only available on USART1)
  if (usart->uart_reg) {
    mcr = usart->uart_reg->MCR & ~(UART_MCR_RTSEN | UART_MCR_CTSEN);
    switch (control & ARM_USART_FLOW_CONTROL_Msk) {
      case ARM_USART_FLOW_CONTROL_NONE:
        break;
      case ARM_USART_FLOW_CONTROL_RTS:
        if (usart->capabilities.flow_control_rts)
          mcr |= UART_MCR_RTSEN;
        else return ARM_USART_ERROR_FLOW_CONTROL;
        break;
      case ARM_USART_FLOW_CONTROL_CTS:
        if (usart->capabilities.flow_control_cts)
          mcr |= UART_MCR_CTSEN;
        else return ARM_USART_ERROR_FLOW_CONTROL;
        break;
      case ARM_USART_FLOW_CONTROL_RTS_CTS:
        if (usart->capabilities.flow_control_rts && 
            usart->capabilities.flow_control_cts) {
          mcr |= (UART_MCR_RTSEN | UART_MCR_CTSEN);
        } else return ARM_USART_ERROR_FLOW_CONTROL;
        break;
      default:
        return ARM_USART_ERROR_FLOW_CONTROL;
    }
  }

  // Clock setting for synchronous mode
  if ((mode == ARM_USART_MODE_SYNCHRONOUS_MASTER) ||
      (mode == ARM_USART_MODE_SYNCHRONOUS_SLAVE )) {

    // Only CPOL0 - CPHA1 combination available

    // USART clock polarity
    if ((control & ARM_USART_CPOL_Msk) != ARM_USART_CPOL0)
      return ARM_USART_ERROR_CPOL;

    // USART clock phase
    if ((control & ARM_USART_CPHA_Msk) != ARM_USART_CPHA1)
      return ARM_USART_ERROR_CPHA;
  }

  // USART Baudrate
  if (USART_SetBaudrate (arg, usart) == -1)
    return ARM_USART_ERROR_BAUDRATE;

  // Configuration is OK - Mode is valid
  usart->info->mode = mode;

  // Configure TX pin regarding mode and transmitter state
  val = SCU_PIN_CFG_INPUT_FILTER_DIS | SCU_PIN_CFG_PULLUP_DIS;
  switch (usart->info->mode) {
    case ARM_USART_MODE_SMART_CARD:
      // Pin function = USART TX
      val |= SCU_PIN_CFG_MODE(usart->pins.tx->config_val);
      break;
    default:
      // Synchronous master/slave, asynchronous, single-wire and IrDA mode
      if (usart->info->flags & USART_FLAG_TX_ENABLED) {
        // Pin function = USART TX
        val |= SCU_PIN_CFG_MODE(usart->pins.tx->config_val);
      } else {
        // Pin function = GPIO
        val |= SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0);
      }
  }
  SCU_PinConfigure(usart->pins.tx->port, usart->pins.tx->num, val);

  // Configure RX pin regarding mode and receiver state
  val = SCU_PIN_CFG_INPUT_FILTER_DIS | SCU_PIN_CFG_PULLUP_DIS;
  switch (usart->info->mode) {
    case ARM_USART_MODE_SINGLE_WIRE:
    case ARM_USART_MODE_SMART_CARD:
      // Pin function = GPIO
      val |= SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0);
      break;
    default:
      // Synchronous master/slave, asynchronous and  IrDA mode
       if (usart->info->flags & USART_FLAG_TX_ENABLED) {
        // Pin function = USART RX
        val |= SCU_PIN_CFG_INPUT_BUFFER_EN | 
               SCU_PIN_CFG_MODE(usart->pins.tx->config_val);
       } else {
        // Pin function = GPIO
        val |= SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0);
       }
      break;
  }
  SCU_PinConfigure(usart->pins.rx->port, usart->pins.rx->num, val);

  // Configure CLK pin regarding mode
  if (usart->pins.clk) {
    val = SCU_PIN_CFG_PULLUP_DIS | SCU_PIN_CFG_INPUT_FILTER_DIS;
    switch (usart->info->mode) {
      case ARM_USART_MODE_SMART_CARD:
      case ARM_USART_MODE_SYNCHRONOUS_MASTER:
        // Pin function = USART UCLK (output)
        val |= SCU_PIN_CFG_MODE(usart->pins.clk->config_val);
        break;
      case ARM_USART_MODE_SYNCHRONOUS_SLAVE:
        // Pin function = USART UCLK (input)
        val |= SCU_PIN_CFG_INPUT_BUFFER_EN |
               SCU_PIN_CFG_MODE(usart->pins.clk->config_val);
        break;
      default:
        // Asynchronous, Single-wire and IrDA mode
        // Pin function = GPIO
        val |= SCU_PIN_CFG_INPUT_BUFFER_EN |
               SCU_PIN_CFG_MODE(SCU_CFG_MODE_FUNC0);
    }
    SCU_PinConfigure(usart->pins.clk->port, usart->pins.clk->num, val);
  }

  // Configure SYNCCRTL register (only in synchronous mode)
  if (usart->capabilities.synchronous_master ||
      usart->capabilities.synchronous_slave) {
    usart->reg->SYNCCTRL = USART_SYNCCTRL_FES    |
                           USART_SYNCCTRL_SSSDIS |
                           syncctrl;
  }

  // Configure HDEN register (only in single wire mode)
  if (usart->capabilities.single_wire)
    usart->reg->HDEN = hden;

  // Configure ICR register (only in IrDA mode)
  if (usart->capabilities.irda)
    usart->reg->ICR = (usart->reg->ICR & ~USART_ICR_IRDAEN) | icr;

  // Configure SCICTRL register (only in Smart Card mode)
  if (usart->capabilities.smart_card) {
    usart->reg->SCICTRL = (usart->reg->SCICTRL & ~USART_SCICTRL_SCIEN) |
                           scictrl;
  }

  // Configure MCR register (modem line for USART1)
  if (usart->uart_reg) {
    usart->uart_reg->MCR = ((usart->uart_reg->MCR & ~(UART_MCR_RTSEN |
                             UART_MCR_CTSEN))) | mcr;
  }

  // Configure Line control register
  usart->reg->LCR = ((usart->reg->LCR & (USART_LCR_BC | USART_LCR_DLAB)) | lcr);

  // Set configured flag
  usart->info->flags |= USART_FLAG_CONFIGURED;

  return ARM_DRIVER_OK;
}