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;
}