mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
609 lines
19 KiB
C
609 lines
19 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 ospi.c
|
|
* @author Silesh C V
|
|
* @email silesh@alifsemi.com
|
|
* @version V1.0.0
|
|
* @date 19-Jun-2023
|
|
* @brief Low level OSPI driver.
|
|
******************************************************************************/
|
|
|
|
#include "ospi.h"
|
|
|
|
/**
|
|
\fn void ospi_set_mode(OSPI_Type *ospi, SPI_MODE mode)
|
|
\brief Set the OSPI mode for the OSPI instance.
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] mode The mode to be set.
|
|
\return none
|
|
*/
|
|
void ospi_set_mode(OSPI_Type *ospi, SPI_MODE mode)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_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;
|
|
}
|
|
|
|
ospi->OSPI_CTRLR0 = val;
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_set_dfs(OSPI_Type *ospi, uint8_t dfs)
|
|
\brief Set the data frame size for the OSPI instance.
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] dfs The data frame size
|
|
\return none
|
|
*/
|
|
void ospi_set_dfs(OSPI_Type *ospi, uint8_t dfs)
|
|
{
|
|
uint32_t val = 0;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~SPI_CTRLR0_DFS_MASK;
|
|
val |= (dfs - 1);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_set_tmod(OSPI_Type *spi, SPI_TMOD tmod)
|
|
\brief Set the transfer mode for the OSPI instance.
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] tmod Transfer mode
|
|
\return none
|
|
*/
|
|
void ospi_set_tmod(OSPI_Type *ospi, SPI_TMOD tmod)
|
|
{
|
|
uint32_t val = 0;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_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;
|
|
}
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_set_tx_threshold(OSPI_Type *ospi, uint8_t threshold)
|
|
\brief Set Transmit FIFO interrupt threshold for the OSPI instance
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] threshold Transmit FIFO threshold
|
|
\return none
|
|
*/
|
|
void ospi_set_tx_threshold(OSPI_Type *ospi, uint8_t threshold)
|
|
{
|
|
uint32_t val = ospi->OSPI_TXFTLR;
|
|
val &= ~(SPI_TXFTLR_TFT_MASK);
|
|
val |= threshold << SPI_TXFTLR_TFT_SHIFT;
|
|
ospi->OSPI_TXFTLR = val;
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_set_rx_sample_delay(OSPI_Type *ospi, uint8_t rx_sample_delay)
|
|
\brief Set Receive sample delay for the OSPI instance
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] threshold Receive FIFO threshold
|
|
\return none
|
|
*/
|
|
void ospi_set_rx_sample_delay(OSPI_Type *ospi, uint8_t rx_sample_delay)
|
|
{
|
|
ospi_disable(ospi);
|
|
ospi->OSPI_RX_SAMPLE_DELAY = rx_sample_delay;
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_set_ddr_drive_edge(OSPI_Type *ospi, uint8_t ddr_drive_edge)
|
|
\brief Set DDR drive edge for the OSPI instance
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] threshold Receive FIFO threshold
|
|
\return none
|
|
*/
|
|
void ospi_set_ddr_drive_edge(OSPI_Type *ospi, uint8_t ddr_drive_edge)
|
|
{
|
|
ospi_disable(ospi);
|
|
ospi->OSPI_DDR_DRIVE_EDGE = ddr_drive_edge;
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_control_ss(OSPI_Type *ospi, uint8_t slave, SPI_SS_STATE state)
|
|
\brief Control the slave select line
|
|
\param[in] spi Pointer to the OSPI register map
|
|
\param[in] slave The slave to be selected
|
|
\param[in] state The state of the slave select line
|
|
\return none
|
|
*/
|
|
void ospi_control_ss(OSPI_Type *ospi, uint8_t slave, SPI_SS_STATE state)
|
|
{
|
|
ospi_disable(ospi);
|
|
|
|
if (state == SPI_SS_STATE_ENABLE)
|
|
{
|
|
ospi->OSPI_SER |= 1 << slave;
|
|
}
|
|
else
|
|
{
|
|
ospi->OSPI_SER &= ~(1 << slave);
|
|
}
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_control_xip_ss(OSPI_Type *ospi, uint8_t slave, SPI_SS_STATE state)
|
|
\brief Control the XIP slave select line
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] slave The slave to be selected
|
|
\param[in] state The state of the slave select line
|
|
\return none
|
|
*/
|
|
void ospi_control_xip_ss(OSPI_Type *ospi, uint8_t slave, SPI_SS_STATE state)
|
|
{
|
|
ospi_disable(ospi);
|
|
|
|
if (state == SPI_SS_STATE_ENABLE)
|
|
{
|
|
ospi->OSPI_XIP_SER |= 1 << slave;
|
|
}
|
|
else
|
|
{
|
|
ospi->OSPI_XIP_SER &= ~(1 << slave);
|
|
}
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
|
|
/**
|
|
\fn void ospi_send(OSPI_Type *spi, ospi_transfer_t *transfer)
|
|
\brief Prepare the OSPI instance for transmission
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] transfer Transfer parameters
|
|
\return none
|
|
*/
|
|
void ospi_send(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~(SPI_CTRLR0_SPI_FRF_MASK | (SPI_CTRLR0_TMOD_MASK | SPI_CTRLR0_SSTE_MASK));
|
|
val |= ((transfer->spi_frf << SPI_CTRLR0_SPI_FRF) | SPI_CTRLR0_TMOD_SEND_ONLY);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_CTRLR1 = 0;
|
|
|
|
val = SPI_TRANS_TYPE_FRF_DEFINED
|
|
| SPI_CTRLR0_SPI_RXDS_ENABLE << SPI_CTRLR0_SPI_RXDS_EN_OFFSET
|
|
| (transfer->ddr << SPI_CTRLR0_SPI_DDR_EN_OFFSET)
|
|
| (SPI_CTRLR0_INST_L_8bit << SPI_CTRLR0_INST_L_OFFSET)
|
|
| (transfer->addr_len << SPI_CTRLR0_ADDR_L_OFFSET)
|
|
| (transfer->dummy_cycle << SPI_CTRLR0_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_IMR = (SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK
|
|
| SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK
|
|
| SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_receive(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
\brief Prepare the OSPI instance for reception
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] transfer Transfer parameters
|
|
\return none
|
|
*/
|
|
void ospi_receive(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~(SPI_CTRLR0_SPI_FRF_MASK | (SPI_CTRLR0_TMOD_MASK | SPI_CTRLR0_SSTE_MASK));
|
|
val |= ((transfer->spi_frf << SPI_CTRLR0_SPI_FRF) | SPI_CTRLR0_TMOD_RECEIVE_ONLY);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_CTRLR1 = transfer->rx_total_cnt - 1;
|
|
|
|
val = SPI_TRANS_TYPE_FRF_DEFINED
|
|
| (SPI_CTRLR0_SPI_RXDS_ENABLE << SPI_CTRLR0_SPI_RXDS_EN_OFFSET)
|
|
| (transfer->ddr << SPI_CTRLR0_SPI_DDR_EN_OFFSET)
|
|
| (SPI_CTRLR0_INST_L_0bit << SPI_CTRLR0_INST_L_OFFSET)
|
|
| (transfer->addr_len << SPI_CTRLR0_ADDR_L_OFFSET)
|
|
| (transfer->dummy_cycle << SPI_CTRLR0_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_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);
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_transfer(OSPI_Type *spi, ospi_transfer_t *transfer)
|
|
\brief Prepare the OSPI instance for transfer
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] transfer Transfer parameters
|
|
\return none
|
|
*/
|
|
void ospi_transfer(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~(SPI_CTRLR0_SPI_FRF_MASK | (SPI_CTRLR0_TMOD_MASK | SPI_CTRLR0_SSTE_MASK ));
|
|
val |= ((transfer->spi_frf << SPI_CTRLR0_SPI_FRF) | SPI_CTRLR0_TMOD_RECEIVE_ONLY);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_CTRLR1 = transfer->rx_total_cnt - 1;
|
|
|
|
val = SPI_TRANS_TYPE_FRF_DEFINED
|
|
| (SPI_CTRLR0_SPI_RXDS_ENABLE << SPI_CTRLR0_SPI_RXDS_EN_OFFSET)
|
|
| (transfer->ddr << SPI_CTRLR0_SPI_DDR_EN_OFFSET)
|
|
| (SPI_CTRLR0_INST_L_8bit << SPI_CTRLR0_INST_L_OFFSET)
|
|
| (transfer->addr_len << SPI_CTRLR0_ADDR_L_OFFSET)
|
|
| (transfer->dummy_cycle << SPI_CTRLR0_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_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);
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_dma_send(OSPI_Type *spi, ospi_transfer_t *transfer)
|
|
\brief Prepare the OSPI instance for transmission with DMA support
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] transfer Transfer parameters
|
|
\return none
|
|
*/
|
|
void ospi_dma_send(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~(SPI_CTRLR0_SPI_FRF_MASK | (SPI_CTRLR0_TMOD_MASK | SPI_CTRLR0_SSTE_MASK));
|
|
val |= ((transfer->spi_frf << SPI_CTRLR0_SPI_FRF) | SPI_CTRLR0_TMOD_SEND_ONLY);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
val = SPI_TRANS_TYPE_FRF_DEFINED
|
|
| SPI_CTRLR0_SPI_RXDS_ENABLE << SPI_CTRLR0_SPI_RXDS_EN_OFFSET
|
|
| (transfer->ddr << SPI_CTRLR0_SPI_DDR_EN_OFFSET)
|
|
| (SPI_CTRLR0_INST_L_8bit << SPI_CTRLR0_INST_L_OFFSET)
|
|
| (transfer->addr_len << SPI_CTRLR0_ADDR_L_OFFSET)
|
|
| (transfer->dummy_cycle << SPI_CTRLR0_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_IMR = SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK;
|
|
|
|
ospi->OSPI_TXFTLR &= ~(0xFFU << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
ospi->OSPI_TXFTLR |= ((transfer->tx_total_cnt - 1U) << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
ospi_enable_tx_dma(ospi);
|
|
|
|
ospi_enable(ospi);
|
|
|
|
}
|
|
|
|
void ospi_dma_transfer(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t val;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
val = ospi->OSPI_CTRLR0;
|
|
val &= ~(SPI_CTRLR0_SPI_FRF_MASK | (SPI_CTRLR0_TMOD_MASK | SPI_CTRLR0_SSTE_MASK ));
|
|
val |= ((transfer->spi_frf << SPI_CTRLR0_SPI_FRF) | SPI_CTRLR0_TMOD_RECEIVE_ONLY);
|
|
ospi->OSPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_CTRLR1 = transfer->rx_total_cnt - 1;
|
|
|
|
val = SPI_TRANS_TYPE_FRF_DEFINED
|
|
| (SPI_CTRLR0_SPI_RXDS_ENABLE << SPI_CTRLR0_SPI_RXDS_EN_OFFSET)
|
|
| (transfer->ddr << SPI_CTRLR0_SPI_DDR_EN_OFFSET)
|
|
| (SPI_CTRLR0_INST_L_8bit << SPI_CTRLR0_INST_L_OFFSET)
|
|
| (transfer->addr_len << SPI_CTRLR0_ADDR_L_OFFSET)
|
|
| (transfer->dummy_cycle << SPI_CTRLR0_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = val;
|
|
|
|
ospi->OSPI_TXFTLR &= ~(0xFFU << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
ospi->OSPI_TXFTLR |= ((transfer->tx_total_cnt - 1U) << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
ospi->OSPI_IMR = SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK
|
|
| SPI_IMR_RX_FIFO_OVER_FLOW_INTERRUPT_MASK
|
|
| SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK;
|
|
|
|
ospi_enable_tx_dma(ospi);
|
|
|
|
ospi_enable_rx_dma(ospi);
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_hyperbus_xip_init(OSPI_Type *ospi, uint8_t wait_cycles)
|
|
\brief Initialize hyperbus XIP configuration for the OSPI instance
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] wait_cycles Wait cycles needed by the hyperbus device
|
|
\return none
|
|
*/
|
|
void ospi_hyperbus_xip_init(OSPI_Type *ospi, uint8_t wait_cycles)
|
|
{
|
|
ospi_disable(ospi);
|
|
|
|
ospi->OSPI_SPI_CTRLR0 = 1 << SPI_CTRLR0_SPI_DM_EN_OFFSET;
|
|
|
|
ospi->OSPI_XIP_CTRL = (1 << XIP_CTRL_XIP_HYPERBUS_EN_OFFSET)
|
|
| (1 << XIP_CTRL_RXDS_SIG_EN_OFFSET)
|
|
| (wait_cycles << XIP_CTRL_WAIT_CYCLES_OFFSET);
|
|
|
|
ospi->OSPI_XIP_WRITE_CTRL = (1 << XIP_WRITE_CTRL_XIPWR_HYPERBUS_EN_OFFSET)
|
|
| (1 << XIP_WRITE_CTRL_XIPWR_RXDS_SIG_EN_OFFSET)
|
|
| (wait_cycles << XIP_WRITE_CTRL_XIPWR_WAIT_CYCLES);
|
|
|
|
ospi_enable(ospi);
|
|
}
|
|
|
|
/**
|
|
\fn void ospi_irq_handler(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
\brief Handle interrupts for the OSPI instance.
|
|
\param[in] ospi Pointer to the OSPI register map
|
|
\param[in] transfer The transfer structure for the SPI instance
|
|
\return none
|
|
*/
|
|
void ospi_irq_handler(OSPI_Type *ospi, ospi_transfer_t *transfer)
|
|
{
|
|
uint32_t event, tx_data, index, rx_count, tx_count;
|
|
uint16_t frame_size;
|
|
|
|
event = ospi->OSPI_ISR;
|
|
|
|
if (event & SPI_TX_FIFO_EMPTY_EVENT)
|
|
{
|
|
frame_size = (SPI_CTRLR0_DFS_MASK & ospi->OSPI_CTRLR0);
|
|
|
|
/* Calculate data count to transfer */
|
|
if (transfer->tx_total_cnt >= (transfer->tx_current_cnt + OSPI_TX_FIFO_DEPTH))
|
|
{
|
|
tx_count = (uint16_t) OSPI_TX_FIFO_DEPTH;
|
|
}
|
|
else
|
|
{
|
|
tx_count = (transfer->tx_total_cnt - transfer->tx_current_cnt);
|
|
}
|
|
|
|
ospi->OSPI_TXFTLR &= ~(0xFFU << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
ospi->OSPI_TXFTLR |= ((tx_count - 1U) << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
for (index = 0; index < tx_count; index++)
|
|
{
|
|
tx_data = 0;
|
|
|
|
if (transfer->tx_buff == NULL)
|
|
{
|
|
/* Check if the default buffer transmit is enabled */
|
|
if (transfer->tx_default_enable == true)
|
|
{
|
|
tx_data = transfer->tx_default_val;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tx_data = transfer->tx_buff[0];
|
|
transfer->tx_buff = (transfer->tx_buff + 1);
|
|
}
|
|
ospi->OSPI_DR0 = tx_data;
|
|
transfer->tx_current_cnt++;
|
|
}
|
|
}
|
|
|
|
if (event & SPI_RX_FIFO_FULL_EVENT)
|
|
{
|
|
frame_size = (SPI_CTRLR0_DFS_MASK & ospi->OSPI_CTRLR0);
|
|
|
|
rx_count = ospi->OSPI_RXFLR;
|
|
|
|
if (frame_size > SPI_CTRLR0_DFS_16bit)
|
|
{
|
|
for (index = 0; index < rx_count; index++)
|
|
{
|
|
*((uint32_t *) transfer->rx_buff) = ospi->OSPI_DR0;
|
|
|
|
transfer->rx_buff = (uint8_t *) transfer->rx_buff + sizeof(uint32_t);
|
|
transfer->rx_current_cnt++;
|
|
}
|
|
}
|
|
else if (frame_size > SPI_CTRLR0_DFS_8bit)
|
|
{
|
|
for (index = 0; index < rx_count; index++)
|
|
{
|
|
*((uint16_t *) transfer->rx_buff) = (uint16_t) (ospi->OSPI_DR0);
|
|
|
|
transfer->rx_buff = (uint8_t *) transfer->rx_buff + sizeof(uint16_t);
|
|
transfer->rx_current_cnt++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (index = 0; index < rx_count; index++)
|
|
{
|
|
/*
|
|
* It is observed that with DFS set to 8, the controller reads in 16bit
|
|
* frames. Workaround this by making two valid 8bit frames out of the
|
|
* DR content.
|
|
*/
|
|
uint32_t val = ospi->OSPI_DR0;
|
|
|
|
*((uint8_t *) transfer->rx_buff) = (uint8_t) ((val >> 8) & 0xff);
|
|
transfer->rx_buff = (uint8_t *) transfer->rx_buff + sizeof(uint8_t);
|
|
transfer->rx_current_cnt++;
|
|
|
|
if (transfer->rx_current_cnt == transfer->rx_total_cnt)
|
|
break;
|
|
|
|
*((uint8_t *) transfer->rx_buff) = (uint8_t) (val & 0xff);
|
|
transfer->rx_buff = (uint8_t *) transfer->rx_buff + sizeof(uint8_t);
|
|
transfer->rx_current_cnt++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (event & (SPI_RX_FIFO_OVER_FLOW_EVENT | SPI_TX_FIFO_OVER_FLOW_EVENT))
|
|
{
|
|
/* Disabling and Enabling the OSPI will Reset the FIFO */
|
|
ospi_disable(ospi);
|
|
ospi_enable(ospi);
|
|
|
|
transfer->status = SPI_TRANSFER_STATUS_OVERFLOW;
|
|
}
|
|
|
|
/* Rx FIFO was accessed when it was empty */
|
|
if (event & SPI_RX_FIFO_UNDER_FLOW_EVENT)
|
|
{
|
|
transfer->status = SPI_TRANSFER_STATUS_RX_UNDERFLOW;
|
|
ospi->OSPI_IMR &= ~(SPI_IMR_RX_FIFO_UNDER_FLOW_INTERRUPT_MASK);
|
|
}
|
|
|
|
/* 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((ospi->OSPI_SR & (SPI_SR_BUSY | SPI_SR_TX_FIFO_EMPTY)) == SPI_SR_TX_FIFO_EMPTY)
|
|
{
|
|
/* Mask the TX interrupts */
|
|
ospi->OSPI_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 */
|
|
ospi->OSPI_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 */
|
|
ospi->OSPI_IMR = 0;
|
|
|
|
ospi_disable(ospi);
|
|
|
|
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((ospi->OSPI_SR & SPI_SR_TX_FIFO_EMPTY) == SPI_SR_TX_FIFO_EMPTY)
|
|
{
|
|
/* Reset the Tx FIFO start level */
|
|
ospi->OSPI_TXFTLR &= ~(0xFFU << SPI_TXFTLR_TXFTHR_SHIFT);
|
|
|
|
/* Mask the TX interrupts */
|
|
ospi->OSPI_IMR &= ~(SPI_IMR_TX_FIFO_EMPTY_INTERRUPT_MASK
|
|
| SPI_IMR_TX_FIFO_OVER_FLOW_INTERRUPT_MASK
|
|
| SPI_IMR_MULTI_MASTER_CONTENTION_INTERRUPT_MASK);
|
|
}
|
|
}
|
|
|
|
/* Read interrupt clear registers */
|
|
(void) ospi->OSPI_TXEICR;
|
|
(void) ospi->OSPI_RXOICR;
|
|
(void) ospi->OSPI_RXUICR;
|
|
(void) ospi->OSPI_ICR;
|
|
}
|