mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
1502 lines
44 KiB
C
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;
|
|
}
|
|
}
|
|
}
|