openmv/lib/alif/drivers/source/spi.c
iabdalkader daf2bb30da misc: Restructure repo.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2025-04-13 08:28:34 +02:00

1502 lines
44 KiB
C

/* Copyright (C) 2023 Alif Semiconductor - All Rights Reserved.
* Use, distribution and modification of this code is permitted under the
* terms stated in the Alif Semiconductor Software License Agreement
*
* You should have received a copy of the Alif Semiconductor Software
* License Agreement with this file. If not, please write to:
* contact@alifsemi.com, or visit: https://alifsemi.com/license
*
*/
/**************************************************************************//**
* @file spi.c
* @author Girish BN, Manoj A Murudi
* @email girish.bn@alifsemi.com, manoj.murudi@alifsemi.com
* @version V1.0.0
* @date 20-04-2023
* @brief Low Level Source File for SPI.
* @bug None.
* @Note None
******************************************************************************/
#include "spi.h"
/**
\fn void spi_set_mode(SPI_Type *spi, SPI_MODE mode)
\brief Set the SPI mode for the SPI instance.
\param[in] spi Pointer to the SPI register map
\param[in] mode The mode to be set.
\return none
*/
void spi_set_mode(SPI_Type *spi, SPI_MODE mode)
{
uint32_t val;
spi_disable(spi);
val = spi->SPI_CTRLR0;
val &= ~(SPI_CTRLR0_SCPOL_HIGH | SPI_CTRLR0_SCPH_HIGH);
switch (mode)
{
/* Clock Polarity 0, Clock Phase 0 */
case SPI_MODE_0:
break;
/* Clock Polarity 0, Clock Phase 1 */
case SPI_MODE_1:
val |= (SPI_CTRLR0_SCPOL_LOW | SPI_CTRLR0_SCPH_HIGH);
break;
/* Clock Polarity 1, Clock Phase 0 */
case SPI_MODE_2:
val |= (SPI_CTRLR0_SCPOL_HIGH | SPI_CTRLR0_SCPH_LOW);
break;
/* Clock Polarity 1, Clock Phase 1 */
case SPI_MODE_3:
val |= (SPI_CTRLR0_SCPOL_HIGH | SPI_CTRLR0_SCPH_HIGH);
break;
}
spi->SPI_CTRLR0 = val;
spi_enable(spi);
}
/**
\fn void spi_set_protocol(SPI_Type *spi, SPI_PROTO format)
\brief Set the protocol format for the SPI instance.
\param[in] spi Pointer to the SPI register map
\param[in] format The protocol to be set
\return none
*/
void spi_set_protocol(SPI_Type *spi, SPI_PROTO format)
{
uint32_t val;
spi_disable(spi);
val = spi->SPI_CTRLR0;
val &= ~(SPI_CTRLR0_FRF_MASK);
switch(format)
{
case SPI_PROTO_SPI:
break;
case SPI_PROTO_SSP:
val |= SPI_CTRLR0_FRF_TI;
break;
case SPI_PROTO_MICROWIRE:
val |= SPI_CTRLR0_FRF_MICROWIRE;
break;
}
spi->SPI_CTRLR0 = val;
spi_enable(spi);
}
/**
\fn void spi_set_dfs(SPI_Type *spi, uint8_t dfs)
\brief Set the data frame size for the SPI instance.
\param[in] spi Pointer to the SPI register map
\param[in] dfs The data frame size
\return none
*/
void spi_set_dfs(SPI_Type *spi, uint8_t dfs)
{
uint32_t val = 0;
spi_disable(spi);
val = spi->SPI_CTRLR0;
val &= ~SPI_CTRLR0_DFS_MASK;
val |= (dfs - 1);
spi->SPI_CTRLR0 = val;
spi_enable(spi);
}
/**
\fn void spi_set_tmod(SPI_Type *spi, SPI_TMOD tmod)
\brief Set the transfer mode for the SPI instance.
\param[in] spi Pointer to the SPI register map
\param[in] tmod Transfer mode
\return none
*/
void spi_set_tmod(SPI_Type *spi, SPI_TMOD tmod)
{
uint32_t val = 0;
spi_disable(spi);
val = spi->SPI_CTRLR0;
val &= ~(SPI_CTRLR0_TMOD_MASK);
switch(tmod)
{
case SPI_TMOD_TX_AND_RX:
val |= SPI_CTRLR0_TMOD_TRANSFER;
break;
case SPI_TMOD_TX:
val |= SPI_CTRLR0_TMOD_SEND_ONLY;
break;
case SPI_TMOD_RX:
val |= SPI_CTRLR0_TMOD_RECEIVE_ONLY;
break;
case SPI_TMOD_EEPROM_READ:
val |= SPI_CTRLR0_TMOD_EEPROM_READ_ONLY;
break;
default:
break;
}
spi->SPI_CTRLR0 = val;
spi_enable(spi);
}
/**
\fn SPI_TMOD spi_get_tmod(SPI_Type *spi)
\brief Get the transfer mode of the SPI instance.
\param[in] spi Pointer to the SPI register map
\return The current transfer mode
*/
SPI_TMOD spi_get_tmod(SPI_Type *spi)
{
uint32_t val = spi->SPI_CTRLR0;
if ((val & SPI_CTRLR0_TMOD_MASK) == SPI_CTRLR0_TMOD_SEND_ONLY)
{
return SPI_TMOD_TX;
}
else if ((val & SPI_CTRLR0_TMOD_MASK) == SPI_CTRLR0_TMOD_RECEIVE_ONLY)
{
return SPI_TMOD_RX;
}
else if ((val & SPI_CTRLR0_TMOD_MASK) == SPI_CTRLR0_TMOD_TRANSFER)
{
return SPI_TMOD_TX_AND_RX;
}
else
{
return SPI_TMOD_EEPROM_READ;
}
}
/**
\fn void spi_set_tx_threshold(SPI_Type *spi, uint8_t threshold)
\brief Set Transmit FIFO interrupt threshold for the SPI instance
\param[in] spi Pointer to the SPI register map
\param[in] threshold Transmit FIFO threshold
\return none
*/
void spi_set_tx_threshold(SPI_Type *spi, uint8_t threshold)
{
uint32_t val = spi->SPI_TXFTLR;
val &= ~(SPI_TXFTLR_TFT_MASK);
val |= threshold << SPI_TXFTLR_TFT_SHIFT;
spi->SPI_TXFTLR = val;
}
/**
\fn void spi_set_rx_threshold(SPI_Type *spi, uint8_t threshold)
\brief Set Receive FIFO interrupt threshold for the SPI instance
\param[in] spi Pointer to the SPI register map
\param[in] threshold Receive FIFO threshold
\return none
*/
void spi_set_rx_threshold(SPI_Type *spi, uint8_t threshold)
{
spi->SPI_RXFTLR = threshold;
}
/**
\fn void spi_set_tx_fifo_start_level(SPI_Type *spi, uint16_t level)
\brief Set Transmit FIFO start level
\param[in] spi Pointer to the SPI register map
\param[in] level Transmit FIFO start level
\return none
*/
void spi_set_tx_fifo_start_level(SPI_Type *spi, uint16_t level)
{
uint32_t val = spi->SPI_TXFTLR;
val &= ~(SPI_TXFTLR_TXFTHR_MASK);
val |= level << SPI_TXFTLR_TXFTHR_SHIFT;
spi->SPI_TXFTLR = val;
}
/**
\fn void spi_control_ss(SPI_Type *spi, uint8_t slave, SPI_SS_STATE state)
\brief Control the slave select line
\param[in] spi Pointer to the SPI register map
\param[in] slave The slave to be selected
\param[in] state The state of the slave select line
\return none
*/
void spi_control_ss(SPI_Type *spi, uint8_t slave, SPI_SS_STATE state)
{
spi_disable(spi);
if (state == SPI_SS_STATE_ENABLE)
{
spi->SPI_SER |= 1 << slave;
}
else
{
spi->SPI_SER &= ~(1 << slave);
}
spi_enable(spi);
}
/**
\fn void spi_set_sste(SPI_Type *spi, bool enable)
\brief Enable/Disable Slave Select Toggle for the SPI instance
\param[in] spi Pointer to the SPI register map
\param[in] enable Enable/Disable control
\return none
*/
void spi_set_sste(SPI_Type *spi, bool enable)
{
uint32_t val = spi->SPI_CTRLR0;
spi_disable(spi);
if (enable)
{
val |= SPI_CTRLR0_SSTE_ENABLE;
}
else
{
val &= ~SPI_CTRLR0_SSTE_ENABLE;
}
spi->SPI_CTRLR0 = val;
spi_enable(spi);
}
/**
\fn void spi_send(SPI_Type *spi)
\brief Prepare the SPI instance for transmission
\param[in] spi Pointer to the SPI register map
\return none
*/
void spi_send(SPI_Type *spi)
{
spi_set_tmod(spi, SPI_TMOD_TX);
spi->SPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void spi_receive(SPI_Type *spi, spi_transfer_t *transfer)
\brief Prepare the SPI instance for reception
\param[in] spi Pointer to the SPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void spi_receive(SPI_Type *spi, spi_transfer_t *transfer)
{
spi_set_tmod(spi, SPI_TMOD_RX);
spi_disable(spi);
spi->SPI_CTRLR1 = transfer->rx_total_cnt - 1;
spi->SPI_IMR = (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK);
spi_enable(spi);
if (transfer->is_master)
{
/* Initiate the receive operation by writing a dummy byte to the FIFO */
spi->SPI_DR[0] = 0x0;
}
}
/**
\fn void spi_transfer(SPI_Type *spi)
\brief Prepare the SPI instance for transfer
\param[in] spi Pointer to the SPI register map
\return none
*/
void spi_transfer(SPI_Type *spi)
{
spi_set_tmod(spi, SPI_TMOD_TX_AND_RX);
spi->SPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void spi_send_blocking(SPI_Type *spi, spi_transfer_t *transfer)
\brief Execute a blocking SPI send described by the transfer structure.
\param[in] spi Pointer to the SPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void spi_send_blocking(SPI_Type *spi, spi_transfer_t *transfer)
{
uint32_t curr_fifo_level, tx_count, tx_data;
uint32_t index;
spi_set_tmod(spi, SPI_TMOD_TX);
while (transfer->tx_current_cnt < transfer->tx_total_cnt)
{
/* wait for a free FIFO location */
while ((spi->SPI_SR & SPI_SR_TFNF) == 0)
{
}
curr_fifo_level = spi->SPI_TXFLR;
if (transfer->tx_total_cnt >= (transfer->tx_current_cnt + SPI_TX_FIFO_DEPTH - curr_fifo_level))
{
tx_count = SPI_TX_FIFO_DEPTH - curr_fifo_level;
}
else
{
tx_count = (transfer->tx_total_cnt - transfer->tx_current_cnt);
}
for (index = 0; index < tx_count; index++)
{
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
if (transfer->frame_size > 16)
{
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) |
(transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
else if (transfer->frame_size > 8)
{
tx_data = (uint32_t)(transfer->tx_buff[0] | (transfer->tx_buff[1] << 8));
transfer->tx_buff = transfer->tx_buff + 2;
}
else
{
tx_data = transfer->tx_buff[0];
transfer->tx_buff = transfer->tx_buff + 1;
}
}
spi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
}
}
while (spi_busy(spi))
{
}
}
/**
\fn void spi_receive_blocking(SPI_Type *spi, spi_transfer_t *transfer)
\brief Execute a blocking SPI receive described by the transfer structure.
\param[in] spi Pointer to the SPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void spi_receive_blocking(SPI_Type *spi, spi_transfer_t *transfer)
{
uint32_t rx_count;
uint32_t index;
spi_set_tmod(spi, SPI_TMOD_RX);
if (transfer->is_master)
{
spi_disable(spi);
spi->SPI_CTRLR1 = transfer->rx_total_cnt - 1;
spi_enable(spi);
/* Initiate the receive operation by writing a dummy byte to the FIFO */
spi->SPI_DR[0] = 0x0;
}
while (transfer->rx_current_cnt < transfer->rx_total_cnt)
{
/* Wait for data in the Rx FIFO */
while ((spi->SPI_SR & SPI_SR_RFNE) == 0)
{
}
rx_count = spi->SPI_RXFLR;
for (index = 0; index < rx_count; index++)
{
if (transfer->frame_size > 16)
{
*((uint32_t *) transfer->rx_buff) = spi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
}
else if (transfer->frame_size > 8)
{
*((uint16_t *) transfer->rx_buff) = (uint16_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint16_t *)transfer->rx_buff) + 1U;
}
else
{
*((uint8_t *) transfer->rx_buff) = (uint8_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint8_t *)transfer->rx_buff) + 1U;
}
transfer->rx_current_cnt++;
}
}
}
/**
\fn void spi_transfer_blocking(SPI_Type *spi, spi_transfer_t *transfer)
\brief Execute a blocking SPI transfer described by the transfer structure
\param[in] spi Pointer to the SPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void spi_transfer_blocking(SPI_Type *spi, spi_transfer_t *transfer)
{
uint32_t tx_data;
spi_set_tmod(spi, SPI_TMOD_TX_AND_RX);
while (transfer->tx_current_cnt < transfer->tx_total_cnt)
{
/* Wait for space in the FIFO */
while ((spi->SPI_SR & SPI_SR_TFNF) == 0)
{
}
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
if (transfer->frame_size > 16)
{
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) |
(transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
else if (transfer->frame_size > 8)
{
tx_data = (uint32_t)(transfer->tx_buff[0] | (transfer->tx_buff[1] << 8));
transfer->tx_buff = transfer->tx_buff + 2;
}
else
{
tx_data = transfer->tx_buff[0];
transfer->tx_buff = transfer->tx_buff + 1;
}
}
spi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
/* wait for data in the Rx FIFO */
while ((spi->SPI_SR & SPI_SR_RFNE) == 0)
{
}
if (transfer->frame_size > 16)
{
*((uint32_t *) transfer->rx_buff) = spi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
}
else if (transfer->frame_size > 8)
{
*((uint16_t *) transfer->rx_buff) = (uint16_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint16_t *)transfer->rx_buff) + 1U;
}
else
{
*((uint8_t *) transfer->rx_buff) = (uint8_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint8_t *)transfer->rx_buff) + 1U;
}
}
}
/**
\fn void lpspi_send_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
\brief Execute a blocking SPI send described by the transfer structure.
\param[in] lpspi Pointer to the LPSPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void lpspi_send_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
{
uint32_t curr_fifo_level, tx_count, tx_data;
uint32_t index;
lpspi_set_tmod(lpspi, SPI_TMOD_TX);
while (transfer->tx_current_cnt < transfer->tx_total_cnt)
{
/* wait for a free FIFO location */
while ((lpspi->SPI_SR & SPI_SR_TFNF) == 0)
{
}
curr_fifo_level = lpspi->SPI_TXFLR;
if (transfer->tx_total_cnt >= (transfer->tx_current_cnt + SPI_TX_FIFO_DEPTH - curr_fifo_level))
{
tx_count = SPI_TX_FIFO_DEPTH - curr_fifo_level;
}
else
{
tx_count = (transfer->tx_total_cnt - transfer->tx_current_cnt);
}
for (index = 0; index < tx_count; index++)
{
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
if (transfer->frame_size > 16)
{
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) |
(transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
else if (transfer->frame_size > 8)
{
tx_data = (uint32_t)(transfer->tx_buff[0] | (transfer->tx_buff[1] << 8));
transfer->tx_buff = transfer->tx_buff + 2;
}
else
{
tx_data = transfer->tx_buff[0];
transfer->tx_buff = transfer->tx_buff + 1;
}
}
lpspi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
}
}
while (spi_busy(lpspi))
{
}
}
/**
\fn void lpspi_receive_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
\brief Execute a blocking SPI receive described by the transfer structure.
\param[in] lpspi Pointer to the LPSPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void lpspi_receive_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
{
uint32_t rx_count;
uint32_t index;
lpspi_set_tmod(lpspi, SPI_TMOD_RX);
if (transfer->is_master)
{
spi_disable(lpspi);
lpspi->SPI_CTRLR1 = transfer->rx_total_cnt - 1;
spi_enable(lpspi);
/* Initiate the receive operation by writing a dummy byte to the FIFO */
lpspi->SPI_DR[0] = 0x0;
}
while (transfer->rx_current_cnt < transfer->rx_total_cnt)
{
/* Wait for data in the Rx FIFO */
while ((lpspi->SPI_SR & SPI_SR_RFNE) == 0)
{
}
rx_count = lpspi->SPI_RXFLR;
for (index = 0; index < rx_count; index++)
{
if (transfer->frame_size > 16)
{
*((uint32_t *) transfer->rx_buff) = lpspi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
}
else if (transfer->frame_size > 8)
{
*((uint16_t *) transfer->rx_buff) = (uint16_t) (lpspi->SPI_DR[0]);
transfer->rx_buff = ((uint16_t *)transfer->rx_buff) + 1U;
}
else
{
*((uint8_t *) transfer->rx_buff) = (uint8_t) (lpspi->SPI_DR[0]);
transfer->rx_buff = ((uint8_t *)transfer->rx_buff) + 1U;
}
transfer->rx_current_cnt++;
}
}
}
/**
\fn void lpspi_transfer_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
\brief Execute a blocking SPI transfer described by the transfer structure
\param[in] lpspi Pointer to the LPSPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void lpspi_transfer_blocking(SPI_Type *lpspi, spi_transfer_t *transfer)
{
uint32_t tx_data;
spi_set_tmod(lpspi, SPI_TMOD_TX_AND_RX);
while (transfer->tx_current_cnt < transfer->tx_total_cnt)
{
/* Wait for space in the FIFO */
while ((lpspi->SPI_SR & SPI_SR_TFNF) == 0)
{
}
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
if (transfer->frame_size > 16)
{
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) |
(transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
else if (transfer->frame_size > 8)
{
tx_data = (uint32_t)(transfer->tx_buff[0] | (transfer->tx_buff[1] << 8));
transfer->tx_buff = transfer->tx_buff + 2;
}
else
{
tx_data = transfer->tx_buff[0];
transfer->tx_buff = transfer->tx_buff + 1;
}
}
lpspi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
/* wait for data in the Rx FIFO */
while ((lpspi->SPI_SR & SPI_SR_RFNE) == 0)
{
}
if (transfer->frame_size > 16)
{
*((uint32_t *) transfer->rx_buff) = lpspi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
}
else if (transfer->frame_size > 8)
{
*((uint16_t *) transfer->rx_buff) = (uint16_t) (lpspi->SPI_DR[0]);
transfer->rx_buff = ((uint16_t *)transfer->rx_buff) + 1U;
}
else
{
*((uint8_t *) transfer->rx_buff) = (uint8_t) (lpspi->SPI_DR[0]);
transfer->rx_buff = ((uint8_t *)transfer->rx_buff) + 1U;
}
}
}
/**
\fn void spi_mw_transmit(SPI_Type *spi, bool is_slave)
\brief config microwire in transmit mode
\param[in] spi Pointer to the SPI register map
\param[in] is_slave whether config as master/slave
\return none
*/
void spi_mw_transmit(SPI_Type *spi, bool is_slave)
{
spi_disable(spi);
spi->SPI_MWCR |= SPI_MWCR_MDD_TRANSMIT;
spi_enable(spi);
spi->SPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
if (is_slave)
{
spi->SPI_IMR |= (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK);
}
}
/**
\fn void spi_mw_receive(SPI_Type *spi, spi_transfer_t *transfer)
\brief config microwire in receive mode
\param[in] spi Pointer to the SPI register map
\param[in] transfer pointer to transfer structure
\return none
*/
void spi_mw_receive(SPI_Type *spi, spi_transfer_t *transfer)
{
spi_disable(spi);
spi->SPI_MWCR |= SPI_MWCR_MDD_RECEIVE;
spi_enable(spi);
spi->SPI_IMR = (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK);
if (transfer->is_master)
{
spi_disable(spi);
spi->SPI_CTRLR1 = transfer->rx_total_cnt - 1;
spi_enable(spi);
spi->SPI_IMR |= (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
}
/**
\fn void lpspi_set_mode(SPI_Type *spi, SPI_MODE mode)
\brief Set the mode for the LPSPI instance.
\param[in] spi Pointer to the LPSPI register map
\param[in] mode The mode to be set.
\return none
*/
void lpspi_set_mode(SPI_Type *lpspi, SPI_MODE mode)
{
uint32_t val;
spi_disable(lpspi);
val = lpspi->SPI_CTRLR0;
val &= ~(LPSPI_CTRLR0_SCPOL_HIGH | LPSPI_CTRLR0_SCPH_HIGH);
switch (mode)
{
/* Clock Polarity 0, Clock Phase 0 */
case SPI_MODE_0:
break;
/* Clock Polarity 0, Clock Phase 1 */
case SPI_MODE_1:
val |= (LPSPI_CTRLR0_SCPOL_LOW | LPSPI_CTRLR0_SCPH_HIGH);
break;
/* Clock Polarity 1, Clock Phase 0 */
case SPI_MODE_2:
val |= (LPSPI_CTRLR0_SCPOL_HIGH | LPSPI_CTRLR0_SCPH_LOW);
break;
/* Clock Polarity 1, Clock Phase 1 */
case SPI_MODE_3:
val |= (LPSPI_CTRLR0_SCPOL_HIGH | LPSPI_CTRLR0_SCPH_HIGH);
break;
}
lpspi->SPI_CTRLR0 = val;
spi_enable(lpspi);
}
/**
\fn void lpspi_set_protocol(SPI_Type *lpspi, SPI_PROTO format)
\brief Set the protocol format for the LPSPI instance.
\param[in] spi Pointer to the LPSPI register map
\param[in] format The protocol to be set
\return none
*/
void lpspi_set_protocol(SPI_Type *lpspi, SPI_PROTO format)
{
uint32_t val;
spi_disable(lpspi);
val = lpspi->SPI_CTRLR0;
val &= ~(LPSPI_CTRLR0_FRF_MASK);
switch(format)
{
case SPI_PROTO_SPI:
break;
case SPI_PROTO_SSP:
val |= LPSPI_CTRLR0_FRF_TI;
break;
case SPI_PROTO_MICROWIRE:
val |= LPSPI_CTRLR0_FRF_MICROWIRE;
break;
}
lpspi->SPI_CTRLR0 = val;
spi_enable(lpspi);
}
/**
\fn void lpspi_set_dfs(SPI_Type *lpspi, uint8_t dfs)
\brief Set the data frame size for the LPSPI instance.
\param[in] spi Pointer to the LPSPI register map
\param[in] dfs The data frame size
\return none
*/
void lpspi_set_dfs(SPI_Type *lpspi, uint8_t dfs)
{
uint32_t val = 0;
spi_disable(lpspi);
val = lpspi->SPI_CTRLR0;
val &= ~LPSPI_CTRLR0_DFS32_MASK;
val |= (dfs - 1) << LPSPI_CTRLR0_DFS_32;
lpspi->SPI_CTRLR0 = val;
spi_enable(lpspi);
}
/**
\fn void lpspi_set_tmod(SPI_Type *lpspi, SPI_TMOD tmod)
\brief Set the transfer mode for the LPSPI instance.
\param[in] lpspi Pointer to the LPSPI register map
\param[in] tmod Transfer mode
\return none
*/
void lpspi_set_tmod(SPI_Type *lpspi, SPI_TMOD tmod)
{
uint32_t val = 0;
spi_disable(lpspi);
val = lpspi->SPI_CTRLR0;
val &= ~(LPSPI_CTRLR0_TMOD_MASK);
switch(tmod)
{
case SPI_TMOD_TX_AND_RX:
val |= LPSPI_CTRLR0_TMOD_TRANSFER;
break;
case SPI_TMOD_TX:
val |= LPSPI_CTRLR0_TMOD_SEND_ONLY;
break;
case SPI_TMOD_RX:
val |= LPSPI_CTRLR0_TMOD_RECEIVE_ONLY;
break;
case SPI_TMOD_EEPROM_READ:
val |= LPSPI_CTRLR0_TMOD_EEPROM_READ_ONLY;
break;
default:
break;
}
lpspi->SPI_CTRLR0 = val;
spi_enable(lpspi);
}
/**
\fn SPI_TMOD lpspi_get_tmod(SPI_Type *lpspi)
\brief Get the transfer mode of the LPSPI instance.
\param[in] lpspi Pointer to the LPSPI register map
\return The current transfer mode
*/
SPI_TMOD lpspi_get_tmod(SPI_Type *lpspi)
{
uint32_t val = lpspi->SPI_CTRLR0;
if ((val & LPSPI_CTRLR0_TMOD_MASK) == LPSPI_CTRLR0_TMOD_SEND_ONLY)
{
return SPI_TMOD_TX;
}
else if ((val & LPSPI_CTRLR0_TMOD_MASK) == LPSPI_CTRLR0_TMOD_RECEIVE_ONLY)
{
return SPI_TMOD_RX;
}
else if ((val & LPSPI_CTRLR0_TMOD_MASK) == LPSPI_CTRLR0_TMOD_TRANSFER)
{
return SPI_TMOD_TX_AND_RX;
}
else
{
return SPI_TMOD_EEPROM_READ;
}
}
/**
\fn void lpspi_send(SPI_Type *lpspi)
\brief Prepare the SPI instance for transmission
\param[in] lpspi Pointer to the LPSPI register map
\return none
*/
void lpspi_send(SPI_Type *lpspi)
{
lpspi_set_tmod(lpspi, SPI_TMOD_TX);
lpspi->SPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void lpspi_receive(SPI_Type *lpspi, uint32_t total_cnt)
\brief Prepare the LPSPI instance for reception
\param[in] lpspi Pointer to the LPSPI register map
\param[in] total_cnt total number of data count
\return none
*/
void lpspi_receive(SPI_Type *lpspi, uint32_t total_cnt)
{
lpspi_set_tmod(lpspi, SPI_TMOD_RX);
spi_disable(lpspi);
lpspi->SPI_CTRLR1 = total_cnt - 1;
spi_enable(lpspi);
lpspi->SPI_IMR = (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK);
/* Initiate the receive operation by writing a dummy byte to the FIFO */
lpspi->SPI_DR[0] = 0x0;
}
/**
\fn void lpspi_transfer(SPI_Type *lpspi)
\brief Prepare the LPSPI instance for transfer
\param[in] lpspi Pointer to the LPSPI register map
\return none
*/
void lpspi_transfer(SPI_Type *lpspi)
{
lpspi_set_tmod(lpspi, SPI_TMOD_TX_AND_RX);
lpspi->SPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void lpspi_set_sste(SPI_Type *lpspi, bool enable)
\brief Enable/Disable Slave Select Toggle for the LPSPI instance
\param[in] lpspi Pointer to the SPI register map
\param[in] enable Enable/Disable control
\return none
*/
void lpspi_set_sste(SPI_Type *lpspi, bool enable)
{
uint32_t val = lpspi->SPI_CTRLR0;
spi_disable(lpspi);
if (enable)
{
val |= LPSPI_CTRLR0_SSTE_ENABLE;
}
else
{
val &= ~LPSPI_CTRLR0_SSTE_ENABLE;
}
lpspi->SPI_CTRLR0 = val;
spi_enable(lpspi);
}
/**
\fn uint32_t spi_dma_calc_rx_level(uint32_t total_cnt, uint8_t fifo_threshold)
\brief Calculate SPI DMA receive data level
\param[in] fifo_threshold receive fifo threshold value
\param[in] total_cnt total number of data count
\return final value after calculation
*/
uint32_t spi_dma_calc_rx_level(uint32_t total_cnt, uint8_t fifo_threshold)
{
uint32_t temp;
while (fifo_threshold > 0)
{
temp = total_cnt % fifo_threshold;
total_cnt = fifo_threshold;
fifo_threshold = temp;
}
return (total_cnt - 1) ;
}
/**
\fn void spi_dma_send(SPI_Type *spi)
\brief Prepare the SPI instance for DMA send
\param[in] spi Pointer to the SPI register map
\return none
*/
void spi_dma_send(SPI_Type *spi)
{
spi_set_tmod(spi, SPI_TMOD_TX);
/* Enable the TX DMA interface of SPI */
spi_enable_tx_dma(spi);
spi->SPI_IMR = (SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void spi_dma_receive(SPI_Type *spi, spi_transfer_t *transfer)
\brief Prepare the SPI instance for DMA reception
\param[in] spi Pointer to the SPI register map
\param[in] transfer Pointer to transfer structure
\return none
*/
void spi_dma_receive(SPI_Type *spi, spi_transfer_t *transfer)
{
spi_set_tmod(spi, SPI_TMOD_RX);
spi_disable(spi);
spi->SPI_CTRLR1 = transfer->rx_total_cnt - 1;
spi_enable(spi);
/* Enable the RX DMA interface of SPI */
spi_enable_rx_dma(spi);
spi->SPI_IMR |= (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK);
if (transfer->is_master)
{
/* Initiate the receive operation by writing a dummy byte to the FIFO */
spi->SPI_DR[0] = 0x0;
}
}
/**
\fn void spi_dma_transfer(SPI_Type *spi)
\brief Prepare the SPI instance for DMA transfer
\param[in] spi Pointer to the SPI register map
\return none
*/
void spi_dma_transfer(SPI_Type *spi)
{
spi_set_tmod(spi, SPI_TMOD_TX_AND_RX);
/* Enable the TX & RX DMA interface of SPI */
spi_enable_tx_dma(spi);
spi_enable_rx_dma(spi);
spi->SPI_IMR = (SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void lpspi_dma_send(SPI_Type *spi)
\brief Prepare the SPI instance for DMA transmission
\param[in] lpspi Pointer to the LPSPI register map
\return none
*/
void lpspi_dma_send(SPI_Type *lpspi)
{
lpspi_set_tmod(lpspi, SPI_TMOD_TX);
/* Enable the TX DMA interface of LPSPI */
spi_enable_tx_dma(lpspi);
lpspi->SPI_IMR = (SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void lpspi_dma_receive(SPI_Type *lpspi, uint32_t total_cnt)
\brief Prepare the LPSPI instance for DMA reception
\param[in] lpspi Pointer to the LPSPI register map
\param[in] total_cnt total number of data count
\return none
*/
void lpspi_dma_receive(SPI_Type *lpspi, uint32_t total_cnt)
{
lpspi_set_tmod(lpspi, SPI_TMOD_RX);
spi_disable(lpspi);
lpspi->SPI_CTRLR1 = total_cnt - 1;
spi_enable(lpspi);
/* Enable the RX DMA interface of LPSPI */
spi_enable_rx_dma(lpspi);
lpspi->SPI_IMR |= (SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK);
/* Initiate the receive operation by writing a dummy byte to the FIFO */
lpspi->SPI_DR[0] = 0x0;
}
/**
\fn void lpspi_dma_transfer(SPI_Type *lpspi)
\brief Prepare the LPSPI instance for DMA transfer
\param[in] lpspi Pointer to the LPSPI register map
\return none
*/
void lpspi_dma_transfer(SPI_Type *lpspi)
{
lpspi_set_tmod(lpspi, SPI_TMOD_TX_AND_RX);
/* Enable the TX & RX DMA interface of LPSPI */
spi_enable_tx_dma(lpspi);
spi_enable_rx_dma(lpspi);
lpspi->SPI_IMR = (SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
/**
\fn void spi_irq_handler(SPI_Type *spi, spi_master_transfer_t *transfer)
\brief Handle interrupts for the SPI instance.
\param[in] spi Pointer to the SPI register map
\param[in] transfer The transfer structure for the SPI instance
\return none
*/
void spi_irq_handler(SPI_Type *spi, spi_transfer_t *transfer)
{
uint32_t event, tx_data, index, curr_fifo_level;
uint32_t tx_count, rx_count;
event = spi->SPI_ISR;
if (event & SPI_TX_FIFO_EMPTY_EVENT)
{
curr_fifo_level = spi->SPI_TXFLR;
if (transfer->tx_total_cnt >= (transfer->tx_current_cnt + SPI_TX_FIFO_DEPTH - curr_fifo_level))
{
tx_count = SPI_TX_FIFO_DEPTH - curr_fifo_level;
}
else
{
tx_count = (transfer->tx_total_cnt - transfer->tx_current_cnt);
}
for (index = 0; index < tx_count; index++)
{
tx_data = 0;
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
if (transfer->frame_size > 16)
{
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) | (transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
else if (transfer->frame_size > 8)
{
tx_data = (uint32_t)(transfer->tx_buff[0] | (transfer->tx_buff[1] << 8));
transfer->tx_buff = transfer->tx_buff + 2;
}
else
{
tx_data = transfer->tx_buff[0];
transfer->tx_buff = transfer->tx_buff + 1;
}
}
spi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
}
}
if (event & SPI_RX_FIFO_FULL_EVENT)
{
rx_count = spi->SPI_RXFLR;
if (transfer->frame_size > 16)
{
for (index = 0; index < rx_count; index++)
{
*((uint32_t *) transfer->rx_buff) = spi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
transfer->rx_current_cnt++;
}
}
else if (transfer->frame_size > 8)
{
for (index = 0; index < rx_count; index++)
{
*((uint16_t *) transfer->rx_buff) = (uint16_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint16_t *)transfer->rx_buff) + 1U;
transfer->rx_current_cnt++;
}
}
else
{
for (index = 0; index < rx_count; index++)
{
*((uint8_t *) transfer->rx_buff) = (uint8_t) (spi->SPI_DR[0]);
transfer->rx_buff = ((uint8_t *)transfer->rx_buff) + 1U;
transfer->rx_current_cnt++;
}
}
/* Rx threshold is configured as greater than zero */
if (spi->SPI_RXFTLR)
{
if ((transfer->rx_total_cnt - transfer->rx_current_cnt) <= spi->SPI_RXFTLR)
{
spi->SPI_RXFTLR = ((transfer->rx_total_cnt - transfer->rx_current_cnt) - 1U);
}
}
}
if (event & (SPI_RX_FIFO_OVER_FLOW_EVENT | SPI_TX_FIFO_OVER_FLOW_EVENT))
{
/* clear interrupt events */
(void) spi->SPI_TXOICR;
(void) spi->SPI_RXOICR;
spi_disable(spi);
spi_enable(spi);
transfer->status = SPI_TRANSFER_STATUS_OVERFLOW;
}
if (event & SPI_MULTI_MASTER_CONTENTION_EVENT)
{
/* clear interrupt event */
(void) spi->SPI_MSTICR;
transfer->status = SPI_TRANSFER_STATUS_MASTER_CONTENTION;
}
if (event & SPI_RX_FIFO_UNDER_FLOW_EVENT)
{
/* clear interrupt event */
(void) spi->SPI_RXUICR;
transfer->status = SPI_TRANSFER_STATUS_RX_UNDERFLOW;
}
/* SEND ONLY mode : check if the transfer is finished */
if ((transfer->mode == SPI_TMOD_TX) &&
(transfer->tx_total_cnt == transfer->tx_current_cnt))
{
/* Wait for the transfer to complete */
if(!spi_busy(spi))
{
/* Mask the TX interrupts */
spi->SPI_IMR &= ~(SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
transfer->tx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
}
/* RECEIVE ONLY mode : check if the transfer is finished */
if ((transfer->mode == SPI_TMOD_RX) &&
(transfer->rx_total_cnt == transfer->rx_current_cnt))
{
/* Mask the RX interrupts */
spi->SPI_IMR &= ~(SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_RX_FIFO_FULL_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
transfer->rx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
if((transfer->mode == SPI_TMOD_TX_AND_RX) &&
(transfer->rx_total_cnt == (transfer->rx_current_cnt)))
{
/* Mask all the interrupts */
spi->SPI_IMR = 0;
spi_disable(spi);
transfer->rx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
if((transfer->mode == SPI_TMOD_TX_AND_RX) && (transfer->tx_total_cnt == transfer->tx_current_cnt))
{
if((spi->SPI_SR & SPI_SR_TX_FIFO_EMPTY) == SPI_SR_TX_FIFO_EMPTY)
{
/* Reset the Tx FIFO start level */
spi->SPI_TXFTLR &= ~(0xFFU << SPI_TXFTLR_TXFTHR_SHIFT);
/* Mask the TX interrupts */
spi->SPI_IMR &= ~(SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK |
SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK |
SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
}
}
}
/**
\fn void spi_irq_handler(SPI_Type *spi, spi_master_transfer_t *transfer)
\brief Handle interrupts for the MW frame format.
\param[in] spi Pointer to the SPI register map
\param[in] transfer The transfer structure for the SPI instance
\return none
*/
void spi_mw_irq_handler(SPI_Type *spi, spi_transfer_t *transfer)
{
uint32_t event, tx_data, index, curr_fifo_level;
uint32_t tx_count, rx_count;
event = spi->SPI_ISR;
if (event & SPI_TX_FIFO_EMPTY_EVENT)
{
curr_fifo_level = spi->SPI_TXFLR;
if (transfer->tx_total_cnt >= (transfer->tx_current_cnt + SPI_TX_FIFO_DEPTH - curr_fifo_level))
{
tx_count = SPI_TX_FIFO_DEPTH - curr_fifo_level;
}
else
{
tx_count = (transfer->tx_total_cnt - transfer->tx_current_cnt);
}
for (index = 0; index < tx_count; index++)
{
tx_data = 0;
if (transfer->tx_buff == NULL)
{
if (transfer->tx_default_enable)
{
tx_data = transfer->tx_default_val;
}
}
else
{
/* local buffer size will be width of 4 bytes and hardware will take care of transferring
* proper data and control codes based on their size configured */
tx_data = (uint32_t) (transfer->tx_buff[0] | (transfer->tx_buff[1] << 8) | (transfer->tx_buff[2] << 16) | (transfer->tx_buff[3] << 24));
transfer->tx_buff = transfer->tx_buff + 4U;
}
spi->SPI_DR[0] = tx_data;
transfer->tx_current_cnt++;
}
}
if (event & SPI_RX_FIFO_FULL_EVENT)
{
rx_count = spi->SPI_RXFLR;
for (index = 0; index < rx_count; index++)
{
/* local buffer size will be width of 4 bytes and hardware will take care of receiving
* proper data and control codes based on their size configured */
*((uint32_t *) transfer->rx_buff) = spi->SPI_DR[0];
transfer->rx_buff = ((uint32_t *)transfer->rx_buff) + 1U;
transfer->rx_current_cnt++;
}
/* Rx threshold is configured as greater than zero */
if (spi->SPI_RXFTLR)
{
if ((transfer->rx_total_cnt - transfer->rx_current_cnt) <= spi->SPI_RXFTLR)
{
spi->SPI_RXFTLR = ((transfer->rx_total_cnt - transfer->rx_current_cnt) - 1U);
}
}
}
if (event & (SPI_RX_FIFO_OVER_FLOW_EVENT | SPI_TX_FIFO_OVER_FLOW_EVENT))
{
/* clear interrupt events */
(void) spi->SPI_TXOICR;
(void) spi->SPI_RXOICR;
spi_disable(spi);
spi_enable(spi);
transfer->status = SPI_TRANSFER_STATUS_OVERFLOW;
}
if (event & SPI_MULTI_MASTER_CONTENTION_EVENT)
{
/* clear interrupt event */
(void) spi->SPI_MSTICR;
transfer->status = SPI_TRANSFER_STATUS_MASTER_CONTENTION;
}
if (event & SPI_RX_FIFO_UNDER_FLOW_EVENT)
{
/* clear interrupt event */
(void) spi->SPI_RXUICR;
transfer->status = SPI_TRANSFER_STATUS_RX_UNDERFLOW;
}
if (spi->SPI_MWCR & SPI_MWCR_MDD_TRANSMIT)
{
if (transfer->tx_total_cnt == transfer->tx_current_cnt)
{
if (transfer->is_master)
{
if(!spi_busy(spi))
{
spi->SPI_IMR &= ~(SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK | SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK);
transfer->tx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
}
else
{
if (transfer->rx_total_cnt == transfer->rx_current_cnt)
{
spi->SPI_IMR = 0;
transfer->rx_current_cnt = 0;
transfer->tx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
}
}
}
else
{
if (transfer->rx_total_cnt == transfer->rx_current_cnt)
{
spi->SPI_IMR = 0;
transfer->rx_current_cnt = 0;
transfer->status = SPI_TRANSFER_STATUS_COMPLETE;
}
}
}