static int32_t SSPx_Control()

in lib/cmsis/CMSIS/Pack/Example/CMSIS_Driver/SSP_LPC18xx.c [580:784]


static int32_t SSPx_Control (uint32_t control, uint32_t arg, SSP_RESOURCES *ssp) {
  uint32_t cpsr, scr, clk, data_bits;
  uint32_t best_cpsr = 2, best_scr = 0;

  if (!(ssp->info->state & SSP_POWERED))     return ARM_DRIVER_ERROR;
  if (  ssp->info->status.busy)              return ARM_DRIVER_ERROR_BUSY;

  switch (control & ARM_SPI_CONTROL_Msk) {
    default:
      return ARM_DRIVER_ERROR_UNSUPPORTED;

    case ARM_SPI_MODE_INACTIVE:             // SPI Inactive
      ssp->reg->CR1    &= ~SSPx_CR1_SSE;    // Disable SSP
      ssp->info->mode  &= ~ARM_SPI_CONTROL_Msk;
      ssp->info->mode  |=  ARM_SPI_MODE_INACTIVE;
      ssp->info->state &= ~SSP_CONFIGURED;
      return ARM_DRIVER_OK;

    case ARM_SPI_MODE_MASTER:               // SPI Master (Output on MOSI, Input on MISO); arg = Bus Speed in bps
      ssp->reg->CR1    &= ~SSPx_CR1_SSE;    // Disable SSP
      ssp->reg->CR1    &= ~SSPx_CR1_MS;     // Set master mode
      ssp->info->mode  &= ~ARM_SPI_CONTROL_Msk;
      ssp->info->mode  |=  ARM_SPI_MODE_MASTER;
      ssp->info->state |=  SSP_CONFIGURED;
      ssp->reg->CR1    |=  SSPx_CR1_SSE;    // Enable  SSP
      goto set_speed;

    case ARM_SPI_MODE_SLAVE:                // SPI Slave  (Output on MISO, Input on MOSI)
      ssp->reg->CR1    &= ~SSPx_CR1_SSE;    // Disable SSP
      ssp->reg->CR1    |=  SSPx_CR1_MS;     // Set slave mode
      ssp->info->mode  &= ~ARM_SPI_CONTROL_Msk;
      ssp->info->mode  |=  ARM_SPI_MODE_SLAVE;
      ssp->info->state |=  SSP_CONFIGURED;
      ssp->reg->CR1    |=  SSPx_CR1_SSE;    // Enable  SSP
      break;

    case ARM_SPI_MODE_MASTER_SIMPLEX:       // SPI Master (Output/Input on MOSI); arg = Bus Speed in bps
    case ARM_SPI_MODE_SLAVE_SIMPLEX:        // SPI Slave  (Output/Input on MISO)
      return ARM_SPI_ERROR_MODE;

    case ARM_SPI_SET_BUS_SPEED:             // Set Bus Speed in bps; arg = value
set_speed:
      clk = GetClockFreq(CLK_SRC_PLL1);
      for (cpsr = 2; cpsr < 255; cpsr+= 2) {// Loop through clock prescaler
        for (scr = 0; scr < 256; scr++) {   // Loop through bit prescaler
          if (clk == (arg * cpsr * (scr + 1))) {
            best_cpsr = cpsr;
            best_scr  = scr;
            goto found_best;
          } else if ((((clk % (best_cpsr * (best_scr + 1))) * 1024) / (best_cpsr * (best_scr + 1))) > 
                     (((clk % (     cpsr * (     scr + 1))) * 1024) / (     cpsr * (     scr + 1)))) {
            best_cpsr = cpsr;
            best_scr  = scr;
          }
        }
      }
found_best:
      ssp->reg->CPSR =  best_cpsr & SSPx_CPSR_CPSDVSR;
      ssp->reg->CR0 &= ~SSPx_CR0_SCR;
      ssp->reg->CR0 |= ((scr << 8) & SSPx_CR0_SCR);
      if ((control & ARM_SPI_CONTROL_Msk) == ARM_SPI_SET_BUS_SPEED) {
        return ARM_DRIVER_OK;
      }
      break;

    case ARM_SPI_GET_BUS_SPEED:             // Get Bus Speed in bps
      return (GetClockFreq(CLK_SRC_PLL1) / ((ssp->reg->CPSR & SSPx_CPSR_CPSDVSR) * ((ssp->reg->CR0 & SSPx_CR0_SCR) + 1)));

    case ARM_SPI_SET_DEFAULT_TX_VALUE:      // Set default Transmit value; arg = value
      ssp->xfer->def_val = (uint16_t)(arg & 0xFFFF);
      return ARM_DRIVER_OK;

    case ARM_SPI_CONTROL_SS:                // Control Slave Select; arg = 0:inactive, 1:active 
      if (((ssp->info->mode & ARM_SPI_CONTROL_Msk)        != ARM_SPI_MODE_MASTER)  ||
          ((ssp->info->mode & ARM_SPI_SS_MASTER_MODE_Msk) != ARM_SPI_SS_MASTER_SW)) {
        return ARM_DRIVER_ERROR;
      }
      if (arg == ARM_SPI_SS_INACTIVE)
        GPIO_PinWrite  (ssp->pin.ssel_gpio_port, ssp->pin.ssel_gpio_bit, 1);
      else
        GPIO_PinWrite  (ssp->pin.ssel_gpio_port, ssp->pin.ssel_gpio_bit, 0);
      return ARM_DRIVER_OK;

    case ARM_SPI_ABORT_TRANSFER:            // Abort current data transfer
      ssp->reg->CR1 &= ~SSPx_CR1_SSE;       // Disable SSP
      memset(ssp->xfer, 0, sizeof(SSP_TRANSFER_INFO));
      ssp->reg->IMSC =  0;                  // Disable interrupts
      ssp->info->status.busy = 0;
      ssp->reg->CR1 |=  SSPx_CR1_SSE;       // Enable  SSP
      return ARM_DRIVER_OK;
  }

  if (ssp->info->mode ==  ARM_SPI_MODE_MASTER) {
    switch (control & ARM_SPI_SS_MASTER_MODE_Msk) {
      case ARM_SPI_SS_MASTER_UNUSED:        // SPI Slave Select when Master: Not used (default)
        if (ssp->pin.ssel_en) SCU_PinConfigure (ssp->pin.ssel_port, ssp->pin.ssel_bit, 0);
        ssp->info->mode  &= ~ARM_SPI_SS_MASTER_MODE_Msk;
        ssp->info->mode  |=  ARM_SPI_SS_MASTER_UNUSED;
        break;

      case ARM_SPI_SS_MASTER_HW_INPUT:      // SPI Slave Select when Master: Hardware monitored Input
        ssp->info->mode  &= ~ARM_SPI_SS_MASTER_MODE_Msk;
        return ARM_SPI_ERROR_SS_MODE;

      case ARM_SPI_SS_MASTER_SW:            // SPI Slave Select when Master: Software controlled
        ssp->info->mode  &= ~ARM_SPI_SS_MASTER_MODE_Msk;
        if (ssp->pin.ssel_en) {
          SCU_PinConfigure (ssp->pin.ssel_port, ssp->pin.ssel_bit, ssp->pin.ssel_gpio_func             |
                                                                   SCU_PIN_CFG_PULLUP_DIS              |
                                                                   SCU_PIN_CFG_HIGH_SPEED_SLEW_RATE_EN );
          GPIO_SetDir      (ssp->pin.ssel_gpio_port, ssp->pin.ssel_gpio_bit, GPIO_DIR_OUTPUT);
          GPIO_PinWrite    (ssp->pin.ssel_gpio_port, ssp->pin.ssel_gpio_bit, 1);
          ssp->info->mode |= ARM_SPI_SS_MASTER_SW;
        } else {
          return ARM_SPI_ERROR_SS_MODE;
        }
        break;

      case ARM_SPI_SS_MASTER_HW_OUTPUT:     // SPI Slave Select when Master: Hardware controlled Output
        ssp->info->mode  &= ~ARM_SPI_SS_MASTER_MODE_Msk;
        if (ssp->pin.ssel_en) {
          SCU_PinConfigure (ssp->pin.ssel_port, ssp->pin.ssel_bit, ssp->pin.ssel_func                  |
                                                                   SCU_PIN_CFG_PULLUP_DIS              |
                                                                   SCU_PIN_CFG_HIGH_SPEED_SLEW_RATE_EN );
          ssp->info->mode |= ARM_SPI_SS_MASTER_HW_OUTPUT;
        } else {
          return ARM_SPI_ERROR_SS_MODE;
        }
        break;
    }
  }

  if (ssp->info->mode ==  ARM_SPI_MODE_SLAVE) {
    switch (control & ARM_SPI_SS_SLAVE_MODE_Msk) {
      case ARM_SPI_SS_SLAVE_HW:             // SPI Slave Select when Slave: Hardware monitored (default)
        ssp->info->mode  &= ~ARM_SPI_SS_SLAVE_MODE_Msk;
        if (ssp->pin.ssel_en) {
          SCU_PinConfigure (ssp->pin.ssel_port, ssp->pin.ssel_bit, ssp->pin.ssel_func                  |
                                                                   SCU_PIN_CFG_PULLUP_DIS              |
                                                                   SCU_PIN_CFG_HIGH_SPEED_SLEW_RATE_EN |
                                                                   SCU_PIN_CFG_INPUT_BUFFER_EN         |
                                                                   SCU_PIN_CFG_INPUT_FILTER_DIS        );
          ssp->info->mode |= ARM_SPI_SS_SLAVE_HW;
        } else {
          return ARM_SPI_ERROR_SS_MODE;
        }
        break;

      case ARM_SPI_SS_SLAVE_SW:             // SPI Slave Select when Slave: Software controlled
        ssp->info->mode  &= ~ARM_SPI_SS_SLAVE_MODE_Msk;
        return ARM_SPI_ERROR_SS_MODE;
    }
  }

  // Configure Frame Format
  switch (control & ARM_SPI_FRAME_FORMAT_Msk) {
    case ARM_SPI_CPOL0_CPHA0:
      ssp->reg->CR0 &=  ~SSPx_CR0_FRF;
      ssp->reg->CR0 &= ~(SSPx_CR0_CPOL | SSPx_CR0_CPHA);
      break;

    case ARM_SPI_CPOL0_CPHA1:
      ssp->reg->CR0 &=  ~SSPx_CR0_FRF;
      ssp->reg->CR0 &=  ~SSPx_CR0_CPOL;
      ssp->reg->CR0 |=   SSPx_CR0_CPHA;
      break;

    case ARM_SPI_CPOL1_CPHA0:
      ssp->reg->CR0 &=  ~SSPx_CR0_FRF;
      ssp->reg->CR0 |=   SSPx_CR0_CPOL;
      ssp->reg->CR0 &=  ~SSPx_CR0_CPHA;
      break;

    case ARM_SPI_CPOL1_CPHA1:
      ssp->reg->CR0 &=  ~SSPx_CR0_FRF;
      ssp->reg->CR0 |=  (SSPx_CR0_CPOL | SSPx_CR0_CPHA);
      break;

    case ARM_SPI_TI_SSI:
      ssp->reg->CR0  =  (ssp->reg->CR0 & (~SSPx_CR0_FRF)) | (1 << 4);
      break;

    case ARM_SPI_MICROWIRE:
      ssp->reg->CR0  =  (ssp->reg->CR0 & (~SSPx_CR0_FRF)) | (2 << 4);
      break;

    default:
      return ARM_SPI_ERROR_FRAME_FORMAT;
  }

  // Configure Number of Data Bits
  data_bits = ((control & ARM_SPI_DATA_BITS_Msk) >> ARM_SPI_DATA_BITS_Pos);
  if ((data_bits >= 4) && (data_bits <= 16)) {
    ssp->reg->CR0 = (ssp->reg->CR0 & (~SSPx_CR0_DSS)) | ((data_bits - 1) << 0);
  } else {
    return ARM_SPI_ERROR_DATA_BITS;
  }

  // Configure Bit Order
  if ((control & ARM_SPI_BIT_ORDER_Msk) == ARM_SPI_LSB_MSB) {
    return ARM_SPI_ERROR_BIT_ORDER;
  }

  return ARM_DRIVER_OK;
}