/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterDeinit
 * Description   : Shuts down a SPI instance with DMA support.
 *
 * This function resets the SPI peripheral, gates its clock, disables any used interrupts to
 * the core, and releases any used DMA channels.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_DmaMasterDeinit(uint32_t instance)
{
    /* instantiate local variable of type spi_dma_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];
    SPI_Type *base = g_spiBase[instance];

    /* Restore the module to defaults which includes disabling the SPI then power it down.*/
    SPI_HAL_Init(base);

    /* destroy the interrupt sync object.*/
    OSA_SemaDestroy(&spiDmaState->irqSync);

    /* Disable SPI interrupt.*/
    INT_SYS_DisableIRQ(g_spiIrqId[instance]);

    /* Gate the clock for SPI.*/
    CLOCK_SYS_DisableSpiClock(instance);

    /* Free DMA channels */
    DMA_DRV_FreeChannel(&spiDmaState->dmaReceive);
    DMA_DRV_FreeChannel(&spiDmaState->dmaTransmit);

    /* Clear state pointer. */
    g_spiStatePtr[instance] = NULL;

    return kStatus_SPI_Success;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_MasterInit
 * Description   : Initialize a SPI instance for master mode operation.
 * This function uses a CPU interrupt driven method for transferring data.
 * This function initializes the run-time state structure to track the ongoing
 * transfers, ungates the clock to the SPI module, resets and initializes the module
 * to default settings, configures the IRQ state structure, enables
 * the module-level interrupt to the core, and enables the SPI module.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_MasterInit(uint32_t instance, spi_master_state_t * spiState)
{
    SPI_Type *base = g_spiBase[instance];

    /* Clear the state for this instance.*/
    memset(spiState, 0, sizeof(* spiState));

    /* Enable clock for SPI*/
    CLOCK_SYS_EnableSpiClock(instance);

    /* configure the run-time state struct with the source clock value */
    spiState->spiSourceClock = CLOCK_SYS_GetSpiFreq(instance);

    /* Reset the SPI module to it's default state, which includes SPI disabled */
    SPI_HAL_Init(base);

    /* Init the interrupt sync object.*/
    OSA_SemaCreate(&spiState->irqSync, 0);

    /* Set SPI to master mode */
    SPI_HAL_SetMasterSlave(base, kSpiMaster);

    /* Set slave select to automatic output mode */
    SPI_HAL_SetSlaveSelectOutputMode(base, kSpiSlaveSelect_AutomaticOutput);

    /* Set the SPI pin mode to normal mode */
    SPI_HAL_SetPinMode(base, kSpiPinMode_Normal);

#if FSL_FEATURE_SPI_FIFO_SIZE
    if (g_spiFifoSize[instance] != 0)
    {
        /* If SPI module contains a FIFO, enable it and set watermarks to half full/empty */
        SPI_HAL_SetFifoMode(base, true, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull);
    }
#endif
    /* Save runtime structure pointers to irq handler can point to the correct state structure*/
    g_spiStatePtr[instance] = spiState;

    /* Enable SPI interrupt.*/
    INT_SYS_EnableIRQ(g_spiIrqId[instance]);

    /* SPI system Enable*/
    SPI_HAL_Enable(base);

    return kStatus_SPI_Success;
}
Example #3
0
void SpiInit(Spi_t *obj, PinNames mosi, PinNames miso, PinNames sclk, PinNames nss)
{
    /* Check if a proper channel was selected */
    if (g_spiBase[obj->instance] == NULL) return;

    obj->Spi = g_spiBase[obj->instance];

    GpioInit(&obj->Mosi, mosi, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, 0);
    GpioInit(&obj->Miso, miso, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, 0);
    GpioInit(&obj->Sclk, sclk, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, 0);
    if (nss != NC) GpioInit(&obj->Nss, nss, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_PULL_DOWN, 1);

    /* Enable clock for SPI.*/
    CLOCK_SYS_EnableSpiClock(obj->instance);

    // Initialize the SPI module registers to default value, which disables the module
    SPI_HAL_Init(obj->Spi);

    // Set the SPI pin mode to normal mode
    SPI_HAL_SetPinMode(obj->Spi, kSpiPinMode_Normal);

#if FSL_FEATURE_SPI_FIFO_SIZE
    if (g_spiFifoSize[obj->instance] != 0)
    {
        // If SPI module contains a FIFO, disable it and set watermarks to half full/empty
        SPI_HAL_SetFifoMode(obj->Spi, false, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull);
    }
#endif

    if (!obj->isSlave) {
        // 8 bits, CPOL = 0, CPHA = 0, MASTER
        SpiFormat(obj, 8, 0, 0, 0);
    } else {
        // 8 bits, CPOL = 0, CPHA = 0, SLAVE
        SpiFormat(obj, 8, 0, 0, 1);
    }
    SpiFrequency(obj, 10000000);

    /* Enable Spi module */
    SPI_HAL_Enable(obj->Spi);
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaSlaveDeinit
 * Description   : De-initializes the device.
 * Clears the control register and turns off the clock to the module.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_DmaSlaveDeinit(uint32_t instance)
{
    spi_dma_slave_state_t * spiState = (spi_dma_slave_state_t *)g_spiStatePtr[instance];
    SPI_Type *base = g_spiBase[instance];

    assert(instance < SPI_INSTANCE_COUNT);

    /* Disable SPI interrupt */
    INT_SYS_DisableIRQ(g_spiIrqId[instance]);

    /* Reset the SPI module to its default settings including disabling SPI and its interrupts */
    SPI_HAL_Init(base);

#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    if (g_spiFifoSize[instance] != 0)
    {
        SPI_HAL_SetFifoIntCmd(base, kSpiRxFifoNearFullInt, false);
    }

    /* disable transmit interrupt */
    SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, false);
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */

    /* Free DMA channels */
    DMA_DRV_FreeChannel(&spiState->dmaReceive);
    DMA_DRV_FreeChannel(&spiState->dmaTransmit);

    /* Disable clock for SPI */
    CLOCK_SYS_DisableSpiClock(instance);

    /* Destroy the event */
    OSA_EventDestroy(&spiState->event);

    /* Clear state pointer */
    g_spiStatePtr[instance] = NULL;

    return kStatus_SPI_Success;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaSlaveInit
 * Description   : Initializes the SPI module for slave mode.
 * Saves the application callback info, turns on the clock to the module,
 * enables the device, and enables interrupts. Sets the SPI to a slave mode.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_DmaSlaveInit(uint32_t instance, spi_dma_slave_state_t * spiState,
                       const spi_dma_slave_user_config_t * slaveConfig)
{
    SPI_Type *base = g_spiBase[instance];
    assert(slaveConfig);
    assert(instance < SPI_INSTANCE_COUNT);
    assert(spiState);

#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    if (slaveConfig->bitCount > kSpi16BitMode)
    {
        /* bits/frame larger than hardware support */
        return kStatus_SPI_InvalidParameter;
    }
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */

    /* Check if the slave already initialized */
    if (g_spiStatePtr[instance])
    {
        return kStatus_SPI_AlreadyInitialized;
    }

    /* Clear the state for this instance. */
    memset(spiState, 0, sizeof(* spiState));

    spiState->hasExtraByte = false;

    /* Update dummy pattern value */
    spiState->dummyPattern = slaveConfig->dummyPattern;

    /* Enable clock for SPI */
    CLOCK_SYS_EnableSpiClock(instance);

    /* Reset the SPI module to its default settings including disabling SPI */
    SPI_HAL_Init(base);

    /* Initialize the event structure */
    if (OSA_EventCreate(&spiState->event, kEventAutoClear) != kStatus_OSA_Success)
    {
        return kStatus_SPI_Error;
    }

    /* Set SPI to slave mode */
    SPI_HAL_SetMasterSlave(base, kSpiSlave);

    /* Configure the slave clock polarity, phase and data direction */
    SPI_HAL_SetDataFormat(base, slaveConfig->polarity, slaveConfig->phase,
            slaveConfig->direction);

    /* Set the SPI pin mode to normal mode */
    SPI_HAL_SetPinMode(base, kSpiPinMode_Normal);

#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    SPI_HAL_Set8or16BitMode(base, slaveConfig->bitCount);
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */

#if FSL_FEATURE_SPI_FIFO_SIZE
    if (g_spiFifoSize[instance] != 0)
    {
        /* If SPI module contains a FIFO, enable it and set watermarks to half full/empty */
        SPI_HAL_SetFifoMode(base, true, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull);

        /* Set the interrupt clearing mechansim select for later use in driver to clear
         * status flags
         */
        SPI_HAL_SetIntClearCmd(base, true);
    }
#endif /* FSL_FEATURE_SPI_FIFO_SIZE */

    /*****************************************
     * Request DMA channel for RX and TX FIFO
     *****************************************/
    /* This channel transfers data from RX FIFO to receiveBuffer */
    if (instance == 0)
    {
        /* Request DMA channel for RX FIFO */
        if (kDmaInvalidChannel == DMA_DRV_RequestChannel(kDmaAnyChannel,
                                                         kDmaRequestMux0SPI0Rx,
                                                         &spiState->dmaReceive))
        {
            return kStatus_SPI_DMAChannelInvalid;
        }
        /* Request DMA channel for TX FIFO */
        if (kDmaInvalidChannel == DMA_DRV_RequestChannel(kDmaAnyChannel,
                                                         kDmaRequestMux0SPI0Tx,
                                                         &spiState->dmaTransmit))
        {
            return kStatus_SPI_DMAChannelInvalid;
        }
    }
#if (SPI_INSTANCE_COUNT > 1)
    else if (instance == 1)
    {
        /* Request DMA channel for RX FIFO */
        if (kDmaInvalidChannel == DMA_DRV_RequestChannel(kDmaAnyChannel,
                                                         kDmaRequestMux0SPI1Rx,
                                                         &spiState->dmaReceive))
        {
            return kStatus_SPI_DMAChannelInvalid;
        }
        /* Request DMA channel for TX FIFO */
        if (kDmaInvalidChannel == DMA_DRV_RequestChannel(kDmaAnyChannel,
                                                         kDmaRequestMux0SPI1Tx,
                                                         &spiState->dmaTransmit))
        {
            return kStatus_SPI_DMAChannelInvalid;
        }
    }
    else
    {
        return kStatus_SPI_OutOfRange;
    }
#endif

    /* Save runtime structure pointers to irq handler can point to the correct state structure */
    g_spiStatePtr[instance] = spiState;

    /* Enable SPI interrupt. The transmit interrupt should immediately cause an interrupt
     * which will fill in the transmit buffer and will be ready to send once the slave initiates
     * transmission.
     */
    INT_SYS_EnableIRQ(g_spiIrqId[instance]);

    /* SPI module enable */
    SPI_HAL_Enable(base);

    return kStatus_SPI_Success;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterInit
 * Description   : Initializes a SPI instance for master mode operation to work with DMA.
 * This function uses a dma driven method for transferring data.
 * this function initializes the run-time state structure to track the ongoing
 * transfers, ungates the clock to the SPI module, resets the SPI module, initializes the module
 * to user defined settings and default settings, configures the IRQ state structure, enables
 * the module-level interrupt to the core, and enables the SPI module.
 *
 * This initialization function also configures the DMA module by requesting channels for DMA
 * operation.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_DmaMasterInit(uint32_t instance, spi_dma_master_state_t * spiDmaState)
{
    SPI_Type *base = g_spiBase[instance];

    /* Clear the state for this instance.*/
    memset(spiDmaState, 0, sizeof(* spiDmaState));

    /* Enable clock for SPI*/
    CLOCK_SYS_EnableSpiClock(instance);

    /* configure the run-time state struct with the source clock value */
    spiDmaState->spiSourceClock = CLOCK_SYS_GetSpiFreq(instance);

    /* Reset the SPI module to it's default state, which includes SPI disabled */
    SPI_HAL_Init(base);

    /* Init the interrupt sync object.*/
    if (OSA_SemaCreate(&spiDmaState->irqSync, 0) != kStatus_OSA_Success)
    {
        return kStatus_SPI_Error;
    }

    /* Set SPI to master mode */
    SPI_HAL_SetMasterSlave(base, kSpiMaster);

    /* Set slave select to automatic output mode */
    SPI_HAL_SetSlaveSelectOutputMode(base, kSpiSlaveSelect_AutomaticOutput);

    /* Set the SPI pin mode to normal mode */
    SPI_HAL_SetPinMode(base, kSpiPinMode_Normal);

#if FSL_FEATURE_SPI_FIFO_SIZE
    if (g_spiFifoSize[instance] != 0)
    {
        /* If SPI module contains a FIFO, enable it and set watermarks to half full/empty */
        SPI_HAL_SetFifoMode(base, true, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull);

        /* Set the interrupt clearing mechansim select for later use in driver to clear
         * status flags
         */
        SPI_HAL_SetIntClearCmd(base, true);
    }
#endif
    /* Save runtime structure pointers to irq handler can point to the correct state structure*/
    g_spiStatePtr[instance] = spiDmaState;

    /*****************************************
     * Request DMA channel for RX and TX FIFO
     *****************************************/
    /* This channel transfers data from RX FIFO to receiveBuffer */
    if (instance == 0)
    {
        /* Request DMA channel for RX FIFO */
        DMA_DRV_RequestChannel(kDmaAnyChannel, kDmaRequestMux0SPI0Rx, &spiDmaState->dmaReceive);
        /* Request DMA channel for TX FIFO */
        DMA_DRV_RequestChannel(kDmaAnyChannel, kDmaRequestMux0SPI0Tx, &spiDmaState->dmaTransmit);
    }
#if (SPI_INSTANCE_COUNT > 1)
    else
    {
        /* Request DMA channel for RX FIFO */
        DMA_DRV_RequestChannel(kDmaAnyChannel, kDmaRequestMux0SPI1Rx, &spiDmaState->dmaReceive);
        /* Request DMA channel for TX FIFO */
        DMA_DRV_RequestChannel(kDmaAnyChannel, kDmaRequestMux0SPI1Tx, &spiDmaState->dmaTransmit);
    }
#endif

    /* Enable SPI interrupt.*/
    INT_SYS_EnableIRQ(g_spiIrqId[instance]);

    /* SPI system Enable */
    SPI_HAL_Enable(base);

    return kStatus_SPI_Success;
}
/*!
 * @brief SPI slave polling.
 *
 * This function sends back received buffer from master through SPI interface.
 */
int main (void)
{
    uint32_t j;
    SPI_Type * spiBaseAddr = g_spiBase[SPI_SLAVE_INSTANCE];

    // init the hardware, this also sets up up the SPI pins for each specific SoC
    hardware_init();

    OSA_Init();

    PRINTF("\r\nSPI board to board polling example");
    PRINTF("\r\nThis example run on instance %d", (uint32_t)SPI_SLAVE_INSTANCE);
    PRINTF("\r\nBe sure master's SPI%d and slave's SPI%d are connected",
                    (uint32_t)SPI_SLAVE_INSTANCE, (uint32_t)SPI_SLAVE_INSTANCE);

    // Enable clock for SPI
    CLOCK_SYS_EnableSpiClock(SPI_SLAVE_INSTANCE);

    // Reset the SPI module to its default settings including disabling SPI
    SPI_HAL_Init(spiBaseAddr);

    // Set SPI to slave mode
    SPI_HAL_SetMasterSlave(spiBaseAddr, kSpiSlave);

    // Set the SPI pin mode to normal mode
    SPI_HAL_SetPinMode(spiBaseAddr, kSpiPinMode_Normal);

#if FSL_FEATURE_SPI_FIFO_SIZE
    if (g_spiFifoSize[SPI_SLAVE_INSTANCE] != 0)
    {
        // If SPI module contains a FIFO, disable it and set watermarks to half full/empty
        SPI_HAL_SetFifoMode(spiBaseAddr, false, kSpiTxFifoOneHalfEmpty, kSpiRxFifoOneHalfFull);
    }
#endif

    //USER CONFIGURABLE OPTION FOR 8 or 16-BIT MODE (if applicable)
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    SPI_HAL_Set8or16BitMode(spiBaseAddr, kSpi8BitMode);
#endif
    // SPI system Enable
    SPI_HAL_Enable(spiBaseAddr);
    // Setup format as same as master
    SPI_HAL_SetDataFormat(spiBaseAddr, kSpiClockPolarity_ActiveHigh, kSpiClockPhase_FirstEdge, kSpiMsbFirst);

    while(1)
    {
        PRINTF("\r\nSlave example is running...\r\n");

        // Reset the sink buffer
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            s_spiSinkBuffer[j] = 0;
        }

        SPI_HAL_Disable(spiBaseAddr);
        SPI_HAL_Enable(spiBaseAddr);

        // Disable module to clear shift register
        for (j = 0; j <TRANSFER_SIZE; j++)
        {
            // Check if data received
            while(SPI_HAL_IsReadBuffFullPending(spiBaseAddr)==0){}

#if FSL_FEATURE_SPI_16BIT_TRANSFERS
            // Read data from data register
            s_spiSinkBuffer[j] = SPI_HAL_ReadDataLow(spiBaseAddr);
#else
            s_spiSinkBuffer[j] = SPI_HAL_ReadData(spiBaseAddr);
#endif
        }

        // Disable module to clear shift register
        SPI_HAL_Disable(spiBaseAddr);
        SPI_HAL_Enable(spiBaseAddr);

        // Send data back to master
        for (j = 0; j <TRANSFER_SIZE; j++)
        {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
            SPI_HAL_WriteDataBlocking(spiBaseAddr, kSpi8BitMode, 0, s_spiSinkBuffer[j]);
#else
            SPI_HAL_WriteDataBlocking(spiBaseAddr, s_spiSinkBuffer[j]);
#endif
        }

        // Print out receive buffer
        PRINTF("\r\nSlave receive:");
        for (j = 0; j < TRANSFER_SIZE; j++)
        {
            // Print 16 numbers in a line.
            if ((j & 0x0F) == 0)
            {
                PRINTF("\r\n    ");
            }
            PRINTF(" %02X", s_spiSinkBuffer[j]);
        }
    }
}