sdk-ameba-v4.0c_180328/component/common/mbed/targets/hal/rtl8711b/spi_api.c

1311 lines
38 KiB
C
Raw Normal View History

2019-04-02 08:34:25 +00:00
/** mbed Microcontroller Library
******************************************************************************
* @file spi_api.c
* @author
* @version V1.0.0
* @date 2016-08-01
* @brief This file provides mbed API for SPI.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and
* possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#include "objects.h"
#include "spi_api.h"
#include "spi_ex_api.h"
#include "PinNames.h"
#include "pinmap.h"
typedef struct {
GDMA_InitTypeDef SSITxGdmaInitStruct;
GDMA_InitTypeDef SSIRxGdmaInitStruct;
IRQn_Type IrqNum;
SPI_TypeDef *spi_dev;
void (*RxCompCallback)(void *Para);
void *RxCompCbPara;
void (*TxCompCallback)(void *Para);
void *TxCompCbPara;
void (*TxIdleCallback)(void *Para);
void *TxIdleCbPara;
void *RxData;
void *TxData;
u32 RxLength;
u32 TxLength;
u32 Index;
u32 Role;
/* mbed var */
u32 dma_en;
}HAL_SSI_ADAPTOR, *PHAL_SSI_ADAPTOR;
HAL_SSI_ADAPTOR ssi_adapter_g[2];
SSI_InitTypeDef SSI_InitStruct[2];
void spi_flush_rx_fifo (spi_t *obj);
static void spi_tx_done_callback(VOID *spi_obj)
{
spi_t *obj = (spi_t *)spi_obj;
spi_irq_handler handler;
if (obj->state & SPI_STATE_TX_BUSY) {
obj->state &= ~SPI_STATE_TX_BUSY;
if (obj->irq_handler) {
handler = (spi_irq_handler)obj->irq_handler;
handler(obj->irq_id, SpiTxIrq);
}
}
}
static void spi_rx_done_callback(VOID *spi_obj)
{
spi_t *obj = (spi_t *)spi_obj;
spi_irq_handler handler;
obj->state &= ~SPI_STATE_RX_BUSY;
if (obj->irq_handler) {
handler = (spi_irq_handler)obj->irq_handler;
handler(obj->irq_id, SpiRxIrq);
}
}
// Bus Idle: Real TX done, TX FIFO empty and bus shift all data out already
void spi_bus_tx_done_callback(VOID *spi_obj)
{
spi_t *obj = (spi_t *)spi_obj;
spi_irq_handler handler;
if (obj->bus_tx_done_handler) {
handler = (spi_irq_handler)obj->bus_tx_done_handler;
handler(obj->bus_tx_done_irq_id, 0);
}
}
/**
* @brief Set SPI interrupt bus tx done handler if needed.
* @param obj: spi object define in application software.
* @param handler: interrupt bus tx done callback function
* @param id: interrupt callback parameter
* @retval none
*/
void spi_bus_tx_done_irq_hook(spi_t *obj, spi_irq_handler handler, uint32_t id)
{
obj->bus_tx_done_handler = (u32)handler;
obj->bus_tx_done_irq_id = (u32)id;
}
static u32 ssi_interrupt(void *Adaptor)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Adaptor;
u32 InterruptStatus = SSI_GetIsr(ssi_adapter->spi_dev);
u32 DataFrameSize = SSI_GetDataFrameSize(ssi_adapter->spi_dev);
SSI_SetIsrClean(ssi_adapter->spi_dev, InterruptStatus);
if (InterruptStatus & (BIT_ISR_TXOIS | BIT_ISR_RXUIS | BIT_ISR_RXOIS | BIT_ISR_MSTIS)) {
DBG_PRINTF(MODULE_SPI, LEVEL_INFO, "[INT] Tx/Rx Warning %x \n", InterruptStatus);
}
if ((InterruptStatus & BIT_ISR_RXFIS) ) {
u32 TransLen = 0;
TransLen = SSI_ReceiveData(ssi_adapter->spi_dev, ssi_adapter->RxData, ssi_adapter->RxLength);
ssi_adapter->RxLength -= TransLen;
if (DataFrameSize > 8) {
// 16~9 bits mode
ssi_adapter->RxData = (void*)(((u16*)ssi_adapter->RxData) + TransLen);
} else {
// 8~4 bits mode
ssi_adapter->RxData = (void*)(((u8*)ssi_adapter->RxData) + TransLen);
}
if (ssi_adapter->RxLength == 0) {
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM), DISABLE);
if (ssi_adapter->RxCompCallback != NULL) {
ssi_adapter->RxCompCallback(ssi_adapter->RxCompCbPara);
}
}
}
if (InterruptStatus & BIT_ISR_TXEIS) {
u32 TransLen = 0;
volatile u32 bus_busy;
u32 i;
/* all data complete */
if (ssi_adapter->TxLength == 0) {
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_TXOIM | BIT_IMR_TXEIM), DISABLE);
for (i=0;i<1000000;i++) {
bus_busy = SSI_Busy(ssi_adapter->spi_dev);
if (!bus_busy) {
break; // break the for loop
}
}
// If it's not a dummy TX for master read SPI, then call the TX_done callback
if (ssi_adapter->TxData != NULL) {
if (ssi_adapter->TxIdleCallback != NULL) {
ssi_adapter->TxIdleCallback(ssi_adapter->TxIdleCbPara);
}
}
return 0;
}
TransLen = SSI_SendData(ssi_adapter->spi_dev, ssi_adapter->TxData,
ssi_adapter->TxLength, ssi_adapter->Role);
ssi_adapter->TxLength -= TransLen;
if (DataFrameSize > 8) {
// 16~9 bits mode
ssi_adapter->TxData = (void*)(((u16*)ssi_adapter->TxData) + TransLen);
} else {
// 8~4 bits mode
ssi_adapter->TxData = (void*)(((u8*)ssi_adapter->TxData) + TransLen);
}
/* all data write into fifo */
if (ssi_adapter->TxLength == 0) {
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_TXOIM), DISABLE);
// If it's not a dummy TX for master read SPI, then call the TX_done callback
if (ssi_adapter->TxData != NULL) {
if (ssi_adapter->TxCompCallback != NULL) {
ssi_adapter->TxCompCallback(ssi_adapter->TxCompCbPara);
}
}
}
}
return 0;
}
static u32 ssi_int_read(void *Adapter, void *RxData, u32 Length)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 DataFrameSize = SSI_GetDataFrameSize(ssi_adapter->spi_dev);
assert_param(Length != 0);
/* As a Slave mode, if the peer(Master) side is power off, the BUSY flag is always on */
if (SSI_Busy(ssi_adapter->spi_dev)) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "ssi_int_read: SSI is busy\n");
return _FALSE;
}
if (DataFrameSize > 8) {
/* 16~9 bits mode */
ssi_adapter->RxLength = Length >> 1; // 2 bytes(16 bit) every transfer
} else {
/* 8~4 bits mode */
ssi_adapter->RxLength = Length; // 1 byte(8 bit) every transfer
}
ssi_adapter->RxData = RxData;
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM), ENABLE);
return _TRUE;
}
static u32 ssi_int_write(void *Adapter, u8 *pTxData, u32 Length)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 DataFrameSize = SSI_GetDataFrameSize(ssi_adapter->spi_dev);
assert_param(Length != 0);
if (DataFrameSize > 8) {
/* 16~9 bits mode */
ssi_adapter->TxLength = Length >> 1; // 2 bytes(16 bit) every transfer
} else {
/* 8~4 bits mode */
ssi_adapter->TxLength = Length; // 1 byte(8 bit) every transfer
}
ssi_adapter->TxData = (void*)pTxData;
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_TXOIM | BIT_IMR_TXEIM), ENABLE);
return _TRUE;
}
/* GDMA IRQ Handler */
static void ssi_dma_tx_irq(void *Data)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Data;
PGDMA_InitTypeDef GDMA_InitStruct;
GDMA_InitStruct = &ssi_adapter->SSITxGdmaInitStruct;
/* Clear Pending ISR */
GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
/* Call user TX complete callback */
if (NULL != ssi_adapter->TxCompCallback) {
ssi_adapter->TxCompCallback(ssi_adapter->TxCompCbPara);
}
SSI_SetDmaEnable(ssi_adapter->spi_dev, DISABLE, BIT_SHIFT_DMACR_TDMAE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
ssi_adapter->dma_en &= ~SPI_DMA_TX_EN;
}
static void ssi_dma_rx_irq(void *Data)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Data;
PGDMA_InitTypeDef GDMA_InitStruct;
GDMA_InitStruct = &ssi_adapter->SSIRxGdmaInitStruct;
/* Clear Pending ISR */
GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
/* Set SSI DMA Disable */
SSI_SetDmaEnable(ssi_adapter->spi_dev, DISABLE, BIT_SHIFT_DMACR_RDMAE);
/* Call user RX complete callback */
if (NULL != ssi_adapter->RxCompCallback) {
ssi_adapter->RxCompCallback(ssi_adapter->RxCompCbPara);
}
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
ssi_adapter->dma_en &= ~SPI_DMA_RX_EN;
}
static u32 ssi_dma_send(void *Adapter, u8 *pTxData, u32 Length)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 ret = _TRUE;
assert_param(Length != 0);
assert_param(pTxData != NULL);
if (ssi_adapter->dma_en & SPI_DMA_TX_EN) {
return _FALSE;
}
ssi_adapter->dma_en |= SPI_DMA_TX_EN;
ssi_adapter->TxLength = Length;
ssi_adapter->TxData = (void*)pTxData;
SSI_SetDmaEnable(ssi_adapter->spi_dev, ENABLE, BIT_SHIFT_DMACR_TDMAE);
ret = SSI_TXGDMA_Init(ssi_adapter->Index, &ssi_adapter->SSITxGdmaInitStruct,
ssi_adapter, (IRQ_FUN) ssi_dma_tx_irq,
pTxData, Length);
NVIC_SetPriority(GDMA_IrqNum[0][ssi_adapter->SSITxGdmaInitStruct.GDMA_ChNum], 10);
return ret;
}
static u32 ssi_dma_recv(void *Adapter, u8 *pRxData, u32 Length)
{
PHAL_SSI_ADAPTOR ssi_adapter = (PHAL_SSI_ADAPTOR) Adapter;
u32 ret = _TRUE;
assert_param(Length != 0);
assert_param(pRxData != NULL);
if (ssi_adapter->dma_en & SPI_DMA_RX_EN) {
return _FALSE;
}
ssi_adapter->dma_en |= SPI_DMA_RX_EN;
ssi_adapter->RxLength = Length;
ssi_adapter->RxData = (void*)pRxData;
ret = SSI_RXGDMA_Init(ssi_adapter->Index, &ssi_adapter->SSIRxGdmaInitStruct,
ssi_adapter, (IRQ_FUN) ssi_dma_rx_irq,
pRxData, Length);
NVIC_SetPriority(GDMA_IrqNum[0][ssi_adapter->SSIRxGdmaInitStruct.GDMA_ChNum], 11);
/* Set SSI DMA Enable */
SSI_SetDmaEnable(ssi_adapter->spi_dev, ENABLE, BIT_SHIFT_DMACR_RDMAE);
return ret;
}
static u32 spi_stop_recv(spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
PGDMA_InitTypeDef GDMA_InitStruct = &ssi_adapter->SSIRxGdmaInitStruct;
u32 DMAStopAddr = 0;
u32 ReceivedCnt;
u8 DmaMode = 0;
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM), DISABLE);
if (ssi_adapter->dma_en & SPI_DMA_RX_EN) {
DmaMode=1;
/* Set SSI DMA Disable */
SSI_SetDmaEnable(ssi_adapter->spi_dev, DISABLE, BIT_SHIFT_DMACR_RDMAE);
/* Clear Pending ISR */
GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_SRC_DST);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
DMAStopAddr = GDMA_GetDstAddr(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
ReceivedCnt = DMAStopAddr - (u32)(ssi_adapter->RxData);
ssi_adapter->RxLength-= ReceivedCnt;
ssi_adapter->RxData = (u8 *)(ssi_adapter->RxData) + ReceivedCnt;
ssi_adapter->dma_en &= ~SPI_DMA_RX_EN;
}
if (ssi_adapter->RxLength > 0) {
ReceivedCnt = SSI_ReceiveData(ssi_adapter->spi_dev, ssi_adapter->RxData, ssi_adapter->RxLength);
if (DmaMode && (SSI_GetDataFrameSize(ssi_adapter->spi_dev) > 8))
ReceivedCnt=ReceivedCnt*2;
ssi_adapter->RxLength -= ReceivedCnt;
}
if (ssi_adapter->RxLength == 0) {
spi_flush_rx_fifo(obj);
}
obj->state &= ~ SPI_STATE_RX_BUSY;
return HAL_OK;
}
/**
* @brief Initializes the SPI device, include clock/function/interrupt/SPI registers.
* @param obj: spi object define in application software.
* @param mosi: MOSI PinName according to pinmux spec.
* @param miso: MISO PinName according to pinmux spec.
* @param sclk: SCLK PinName according to pinmux spec.
* @param ssel: CS PinName according to pinmux spec.
* @retval none
* @note must set obj->spi_index to MBED_SPI0 or MBED_SPI1 before using spi_init
*/
void spi_init (spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
if ((obj->spi_idx != MBED_SPI0) && (obj->spi_idx != MBED_SPI1)) {
DBG_PRINTF(MODULE_SPI, LEVEL_ERROR, "spi_init: you should set spi_idx MBED_SPI0 or MBED_SPI1");
assert_param(0);
}
ssi_adapter->Index = spi_idx;
obj->sclk = (u8)sclk;
if (spi_idx == 1) {
ssi_adapter->Role = SSI_MASTER;
RCC_PeriphClockCmd(APBPeriph_SPI1, APBPeriph_SPI1_CLOCK, ENABLE);
Pinmux_Config(mosi, PINMUX_FUNCTION_SPIM);
Pinmux_Config(miso, PINMUX_FUNCTION_SPIM);
Pinmux_Config(sclk, PINMUX_FUNCTION_SPIM);
Pinmux_Config(ssel, PINMUX_FUNCTION_SPIM);
} else {
ssi_adapter->Role = SSI_SLAVE;
RCC_PeriphClockCmd(APBPeriph_SPI0, APBPeriph_SPI0_CLOCK, ENABLE);
Pinmux_Config(mosi, PINMUX_FUNCTION_SPIS);
Pinmux_Config(miso, PINMUX_FUNCTION_SPIS);
Pinmux_Config(sclk, PINMUX_FUNCTION_SPIS);
Pinmux_Config(ssel, PINMUX_FUNCTION_SPIS);
}
//TODO: Implement default setting structure.
SSI_StructInit(&SSI_InitStruct[spi_idx]);
if (spi_idx == 1) {
SSI_InitStruct[spi_idx].SPI_Role = SSI_MASTER;
} else {
PAD_PullCtrl(ssel, GPIO_PuPd_UP);
PAD_PullCtrl(sclk, GPIO_PuPd_UP);
}
ssi_adapter->spi_dev = SPI_DEV_TABLE[ssi_adapter->Index].SPIx;
ssi_adapter->IrqNum = SPI_DEV_TABLE[ssi_adapter->Index].IrqNum;
InterruptRegister((IRQ_FUN)ssi_interrupt, ssi_adapter->IrqNum, (u32)ssi_adapter, 10);
InterruptEn(ssi_adapter->IrqNum, 10);
SSI_Init(ssi_adapter->spi_dev, &SSI_InitStruct[spi_idx]);
ssi_adapter->TxCompCallback = spi_tx_done_callback;
ssi_adapter->TxCompCbPara = (void*)obj;
ssi_adapter->RxCompCallback = spi_rx_done_callback;
ssi_adapter->RxCompCbPara = (void*)obj;
ssi_adapter->TxIdleCallback = spi_bus_tx_done_callback;
ssi_adapter->TxIdleCbPara = (void*)obj;
obj->state = SPI_STATE_READY;
#ifdef CONFIG_GDMA_EN
ssi_adapter->dma_en = 0;
#endif
}
/**
* @brief Deinitializes the SPI device, include interrupt/DMA/DISABLE SPI.
* @param obj: spi object define in application software.
* @retval none
*/
void spi_free (spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
InterruptDis(ssi_adapter->IrqNum);
InterruptUnRegister(ssi_adapter->IrqNum);
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM), DISABLE);
if (ssi_adapter->dma_en & SPI_DMA_RX_EN) {
PGDMA_InitTypeDef GDMA_InitStruct = &ssi_adapter->SSIRxGdmaInitStruct;
/* Set SSI DMA Disable */
SSI_SetDmaEnable(ssi_adapter->spi_dev, DISABLE, BIT_SHIFT_DMACR_RDMAE);
/* Clear Pending ISR */
GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_SRC_DST);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
}
if (ssi_adapter->dma_en & SPI_DMA_TX_EN) {
PGDMA_InitTypeDef GDMA_InitStruct = &ssi_adapter->SSITxGdmaInitStruct;
/* Set SSI DMA Disable */
SSI_SetDmaEnable(ssi_adapter->spi_dev, DISABLE, BIT_SHIFT_DMACR_TDMAE);
/* Clear Pending ISR */
GDMA_ClearINT(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
GDMA_ChCleanAutoReload(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, CLEAN_RELOAD_SRC_DST);
GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, DISABLE);
GDMA_ChnlFree(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum);
}
obj->state = 0;
SSI_Cmd(ssi_adapter->spi_dev, DISABLE);
}
/**
* @brief Set SPI format,include DFS/Phase/Polarity.
* @param obj: spi object define in application software.
* @param bits: data frame size, 4-16 supported.
* @param mode: this parameter can be one of the following values:
* @arg 0 : [Polarity,Phase]=[0,0]
* @arg 1 : [Polarity,Phase]=[0,1]
* @arg 2 : [Polarity,Phase]=[1,0]
* @arg 3 : [Polarity,Phase]=[1,1]
* @param slave: this parameter can be one of the following values:
* @arg 0 : indicates role-master
* @arg 1 : indicates role-slave
* @retval none
*/
void spi_format (spi_t *obj, int bits, int mode, int slave)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
u32 SclkPhase;
u32 SclkPolarity;
u32 DataFrameSize = (bits - 1);
/*
* mode | POL PHA
* -----+--------
* 0 | 0 0
* 1 | 0 1
* 2 | 1 0
* 3 | 1 1
*
* SCPOL_INACTIVE_IS_LOW = 0,
* SCPOL_INACTIVE_IS_HIGH = 1
*
* SCPH_TOGGLES_IN_MIDDLE = 0,
* SCPH_TOGGLES_AT_START = 1
*/
switch (mode)
{
case 0:
SclkPolarity = SCPOL_INACTIVE_IS_LOW;
SclkPhase = SCPH_TOGGLES_IN_MIDDLE;
break;
case 1:
SclkPolarity = SCPOL_INACTIVE_IS_LOW;
SclkPhase = SCPH_TOGGLES_AT_START;
break;
case 2:
SclkPolarity = SCPOL_INACTIVE_IS_HIGH;
SclkPhase = SCPH_TOGGLES_IN_MIDDLE;
break;
case 3:
SclkPolarity = SCPOL_INACTIVE_IS_HIGH;
SclkPhase = SCPH_TOGGLES_AT_START;
break;
default: // same as 3
SclkPolarity = SCPOL_INACTIVE_IS_HIGH;
SclkPhase = SCPH_TOGGLES_AT_START;
break;
}
if (slave == 1) {
if (spi_idx == 0) {
ssi_adapter->Role = SSI_SLAVE;
} else {
assert_param(0);
}
} else {
if (spi_idx == 1) {
ssi_adapter->Role = SSI_MASTER;
} else {
assert_param(0);
}
}
SSI_SetSclkPhase(ssi_adapter->spi_dev, SclkPhase);
SSI_SetSclkPolarity(ssi_adapter->spi_dev, SclkPolarity);
SSI_SetDataFrameSize(ssi_adapter->spi_dev, DataFrameSize);
if (slave == 1) {
if (SclkPolarity == SCPOL_INACTIVE_IS_LOW) {
PAD_PullCtrl((u32)obj->sclk, GPIO_PuPd_DOWN);
}
else {
PAD_PullCtrl((u32)obj->sclk, GPIO_PuPd_UP);
}
}
}
/**
* @brief Set SPI baudrate.
* @param obj: spi master object define in application software.
* @param hz: baudrate for SPI bus
* @retval none
* @note "hz" should be less or equal to half of the SPI IpClk
*/
void spi_frequency (spi_t *obj, int hz)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
SSI_SetBaud(ssi_adapter->spi_dev, (u32)hz, CPU_ClkGet(_FALSE)/2);
}
void spi_slave_select(spi_t *obj, ChipSelect slaveindex)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
if((ssi_adapter->Role == SSI_MASTER) && (spi_idx == 1)){
SSI_SetSlaveEnable(ssi_adapter->spi_dev,slaveindex);
} else {
assert_param(0);
}
}
static inline void ssi_write (spi_t *obj, int value)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
while (!SSI_Writeable(ssi_adapter->spi_dev));
SSI_WriteData(ssi_adapter->spi_dev, value);
}
static inline int ssi_read(spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
while (!SSI_Readable(ssi_adapter->spi_dev));
return (int)SSI_ReadData(ssi_adapter->spi_dev);
}
/**
* @brief Master send one frame use SPI.
* @param obj: spi master object define in application software.
* @param value: the data to transmit.
* @retval : data received from slave
*/
int spi_master_write (spi_t *obj, int value)
{
ssi_write(obj, value);
return ssi_read(obj);
}
/**
* @brief Get slave readable && busy state.
* @param obj: spi slave object define in application software.
* @retval : slave Readable && Busy State
*/
int spi_slave_receive (spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int Readable;
int Busy;
Readable = SSI_Readable(ssi_adapter->spi_dev);
Busy = (int)SSI_Busy(ssi_adapter->spi_dev);
return ((Readable && !Busy) ? 1 : 0);
}
/**
* @brief Slave receive one frame use SPI.
* @param obj: spi slave object define in application software.
* @retval : data received from master
*/
int spi_slave_read (spi_t *obj)
{
return ssi_read(obj);
}
/**
* @brief Slave send one frame use SPI.
* @param obj: spi slave object define in application software.
* @param value: the data to transmit.
* @retval none
*/
void spi_slave_write (spi_t *obj, int value)
{
ssi_write(obj, value);
}
/**
* @brief Get SPI busy state.
* @param obj: spi object define in application software.
* @retval : current busy state
*/
int spi_busy (spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
return (int)SSI_Busy(ssi_adapter->spi_dev);
}
/**
* @brief SPI device to flush rx fifo.
* @param obj: spi object define in application software.
* @retval none
*/
void spi_flush_rx_fifo (spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
u32 rx_fifo_level;
u32 i;
while(SSI_Readable(ssi_adapter->spi_dev)){
rx_fifo_level = SSI_GetRxCount(ssi_adapter->spi_dev);
for(i=0;i<rx_fifo_level;i++) {
SSI_ReadData(ssi_adapter->spi_dev);
}
}
}
/**
* @brief slave recv target length data use interrupt mode.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : stream init status
*/
int32_t spi_slave_read_stream(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spis int rx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
//DBG_PRINTF(MODULE_SPI, LEVEL_INFO, "rx_buffer addr: %X, length: %d\n", rx_buffer, length);
obj->state |= SPI_STATE_RX_BUSY;
if ((ret = ssi_int_read(ssi_adapter, rx_buffer, length)) != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief slave send target length data use interrupt mode.
* @param obj: spi slave object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param length: number of data bytes to be send.
* @retval : stream init status
*/
int32_t spi_slave_write_stream(spi_t *obj, char *tx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_TX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spis int tx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_TX_BUSY;
if ((ret=ssi_int_write(ssi_adapter, (u8 *) tx_buffer, length)) != _TRUE) {
obj->state &= ~SPI_STATE_TX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief master recv target length data use interrupt mode.
* @param obj: spi master object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : stream init status
*/
int32_t spi_master_read_stream(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim int rx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
// wait bus idle
while(SSI_Busy(ssi_adapter->spi_dev));
obj->state |= SPI_STATE_RX_BUSY;
if ((ret = ssi_int_read(ssi_adapter, rx_buffer, length)) == _TRUE) {
/* as Master mode, it need to push data to TX FIFO to generate clock out
then the slave can transmit data out */
// send some dummy data out
if ((ret=ssi_int_write(ssi_adapter, NULL, length)) != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
}
else {
obj->state &= ~SPI_STATE_RX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief master send target length data use interrupt mode.
* @param obj: spi master object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param length: number of data bytes to be send.
* @retval : stream init status
*/
int32_t spi_master_write_stream(spi_t *obj, char *tx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_TX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim int tx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_TX_BUSY;
/* as Master mode, sending data will receive data at sametime, so we need to
drop those received dummy data */
if ((ret=ssi_int_write(ssi_adapter, (u8 *) tx_buffer, length)) != _TRUE) {
obj->state &= ~SPI_STATE_TX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief master send & recv target length data use interrupt mode.
* @param obj: spi master object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be send & recv.
* @retval : stream init status
*/
int32_t spi_master_write_read_stream(spi_t *obj, char *tx_buffer,
char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & (SPI_STATE_RX_BUSY|SPI_STATE_TX_BUSY)) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim int trx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
// wait bus idle
while(SSI_Busy(ssi_adapter->spi_dev));
obj->state |= SPI_STATE_RX_BUSY;
/* as Master mode, sending data will receive data at sametime */
if ((ret = ssi_int_read(ssi_adapter, rx_buffer, length)) == _TRUE) {
obj->state |= SPI_STATE_TX_BUSY;
if ((ret=ssi_int_write(ssi_adapter, (u8 *) tx_buffer, length)) != _TRUE) {
obj->state &= ~(SPI_STATE_RX_BUSY|SPI_STATE_TX_BUSY);
// Disable RX IRQ
SSI_INTConfig(ssi_adapter->spi_dev, (BIT_IMR_RXFIM | BIT_IMR_RXOIM | BIT_IMR_RXUIM), DISABLE);
}
}
else {
obj->state &= ~(SPI_STATE_RX_BUSY);
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief Set SPI interrupt handler if needed.
* @param obj: spi object define in application software.
* @param handler: interrupt callback function
* @param id: interrupt callback parameter
* @retval none
*/
void spi_irq_hook(spi_t *obj, spi_irq_handler handler, uint32_t id)
{
obj->irq_handler = (u32)handler;
obj->irq_id = (u32)id;
}
/**
* @brief slave recv target length data use DMA mode.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : stream init status
*/
int32_t spi_slave_read_stream_dma(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim dma rx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
ret = ssi_dma_recv(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief slave send target length data use DMA mode.
* @param obj: spi slave object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param length: number of data bytes to be send.
* @retval : stream init status
*/
int32_t spi_slave_write_stream_dma(spi_t *obj, char *tx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_TX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spis dma tx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_TX_BUSY;
ret = ssi_dma_send(ssi_adapter, (u8 *) tx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_TX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
#define USE_DMA_WRITE_MASTER_READ 1
/**
* @brief master recv target length data use DMA mode.
* @param obj: spi master object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : stream init status
* @note : DMA or Interrupt mode can be used to TX dummy data
*/
int32_t spi_master_read_stream_dma(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim dma rx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
ret = ssi_dma_recv(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
// for master mode, we need to send data to generate clock out
#ifdef USE_DMA_WRITE_MASTER_READ
// TX DMA is on already, so use DMA to TX data
// Make the GDMA to use the rx_buffer too
ret = ssi_dma_send(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
#else
// TX DMA isn't enabled, so we just use Interrupt mode to TX dummy data
if ((ret=ssi_int_write(ssi_adapter, NULL, length)) != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
}
#endif
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief master send target length data use DMA mode.
* @param obj: spi master object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param length: number of data bytes to be send.
* @retval : stream init status
*/
int32_t spi_master_write_stream_dma(spi_t *obj, char *tx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & SPI_STATE_TX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spim dma tx: state(0x%x) is not ready\r\n",
obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_TX_BUSY;
ret = ssi_dma_send(ssi_adapter, (u8 *) tx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_TX_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief master send & recv target length data use DMA mode.
* @param obj: spi master object define in application software.
* @param tx_buffer: buffer to be written to Tx FIFO.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be send & recv.
* @retval : stream init status
*/
int32_t spi_master_write_read_stream_dma(spi_t *obj, char *tx_buffer,
char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int32_t ret;
if (obj->state & (SPI_STATE_RX_BUSY|SPI_STATE_TX_BUSY)) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spi_master_write_and_read_stream: state(0x%x) is not ready\r\n", obj->state);
return HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
ret = ssi_dma_recv(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
return HAL_BUSY;
}
obj->state |= SPI_STATE_TX_BUSY;
ret = ssi_dma_send(ssi_adapter, (u8 *) tx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_TX_BUSY;
return HAL_BUSY;
}
return (ret == _TRUE) ? HAL_OK : HAL_BUSY;
}
/**
* @brief slave recv target length data use DMA mode and timeout mechanism.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @param timeout_ms: timeout waiting time.
* @retval : number of bytes read already
*/
int32_t spi_slave_read_stream_dma_timeout(spi_t *obj, char *rx_buffer, uint32_t length, uint32_t timeout_ms)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
int ret, timeout = 0;
uint32_t StartCount = 0;
assert_param(timeout_ms > 0);
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spi_slave_read_stream_dma: state(0x%x) is not ready\r\n", obj->state);
return -HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
ret = ssi_dma_recv(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
return -HAL_BUSY;
}
StartCount = SYSTIMER_TickGet();
while (1) {
/* complete */
if ((obj->state & SPI_STATE_RX_BUSY) == 0) {
break;
}
/* time out */
if (SYSTIMER_GetPassTime(StartCount) > timeout_ms) {
ret = spi_stop_recv(obj);
obj->state &= ~ SPI_STATE_RX_BUSY;
timeout = 1;
DBG_PRINTF(MODULE_SPI, LEVEL_INFO, "Slave is timeout\n");
break;
}
}
//if (SSI_GetDataFrameSize(SPIx) > 8){
// ssi_adapter->RxLength <<= 1;
//}
if(timeout)
return (length - ssi_adapter->RxLength);
else
return length;
}
/**
* @brief slave recv target length data use DMA mode and stop if the spi bus is idle.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : number of bytes read already
*/
int32_t spi_slave_read_stream_dma_terminate(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
SPI_TypeDef *SPIx = SPI_DEV_TABLE[spi_idx].SPIx;
int ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spi_slave_read_stream_dma: state(0x%x) is not ready\r\n", obj->state);
return -HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
ret = ssi_dma_recv(ssi_adapter, (u8 *) rx_buffer, length);
if (ret != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
return -HAL_BUSY;
}
while(obj->state & SPI_STATE_RX_BUSY){
if(SSI_Busy(SPIx) == 0){
ret = spi_stop_recv(obj);
goto EndOfDMACS;
}
}
EndOfDMACS:
if((obj->state & SPI_STATE_RX_BUSY) != 0){
obj->state &= ~ SPI_STATE_RX_BUSY;
}
//if (SSI_GetDataFrameSize(SPIx) > 8) {
// ssi_adapter->RxLength <<= 1;
//}
return (length - ssi_adapter->RxLength);
}
/**
* @brief Slave device to flush tx fifo.
* @param obj: spi slave object define in application software.
* @note : It will discard all data in both tx fifo and rx fifo
*/
void spi_slave_flush_fifo(spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
SPI_TypeDef *SPIx = SPI_DEV_TABLE[spi_idx].SPIx;
SSI_Cmd(SPIx, DISABLE);
SSI_Cmd(SPIx, ENABLE);
obj->state &= ~SPI_STATE_TX_BUSY;
}
/**
* @brief slave recv target length data use interrupt mode and timeout mechanism.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @param timeout_ms: timeout waiting time.
* @retval : number of bytes read already
*/
int32_t spi_slave_read_stream_timeout(spi_t *obj, char *rx_buffer, uint32_t length, uint32_t timeout_ms)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
SPI_TypeDef *SPIx = SPI_DEV_TABLE[spi_idx].SPIx;
uint32_t ret;
uint32_t timeout = 0;
uint32_t StartCount = 0;
assert_param(timeout_ms > 0);
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spi_slave_read_stream: state(0x%x) is not ready\r\n", obj->state);
return -HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
if ((ret = ssi_int_read(ssi_adapter, rx_buffer, length)) != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
return -HAL_BUSY;
}
StartCount = SYSTIMER_TickGet();
while (1) {
/* complete */
if ((obj->state & SPI_STATE_RX_BUSY) == 0) {
break;
}
/* time out */
if (SYSTIMER_GetPassTime(StartCount) > timeout_ms) {
ret = spi_stop_recv(obj);
obj->state &= ~ SPI_STATE_RX_BUSY;
timeout = 1;
DBG_PRINTF(MODULE_SPI, LEVEL_INFO, "Slave is timeout\n");
break;
}
}
if (SSI_GetDataFrameSize(SPIx) > 8){
ssi_adapter->RxLength <<= 1;
}
if(timeout)
return (length - ssi_adapter->RxLength);
else
return length;
}
/**
* @brief slave recv target length data use interrupt mode and stop if the spi bus is idle.
* @param obj: spi slave object define in application software.
* @param rx_buffer: buffer to save data read from SPI FIFO.
* @param length: number of data bytes to be read.
* @retval : number of bytes read already
*/
int32_t spi_slave_read_stream_terminate(spi_t *obj, char *rx_buffer, uint32_t length)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
PHAL_SSI_ADAPTOR ssi_adapter = &ssi_adapter_g[spi_idx];
SPI_TypeDef *SPIx = SPI_DEV_TABLE[spi_idx].SPIx;
int ret;
if (obj->state & SPI_STATE_RX_BUSY) {
DBG_PRINTF(MODULE_SPI, LEVEL_WARN, "spi_slave_read_stream_dma: state(0x%x) is not ready\r\n", obj->state);
return -HAL_BUSY;
}
obj->state |= SPI_STATE_RX_BUSY;
if ((ret = ssi_int_read(ssi_adapter, rx_buffer, length)) != _TRUE) {
obj->state &= ~SPI_STATE_RX_BUSY;
return -HAL_BUSY;
}
while(obj->state & SPI_STATE_RX_BUSY) {
if(SSI_Busy(SPIx) == 0){
ret = spi_stop_recv(obj);
goto EndOfCS;
}
}
EndOfCS:
if((obj->state & SPI_STATE_RX_BUSY) != 0){
obj->state &= ~ SPI_STATE_RX_BUSY;
}
if (SSI_GetDataFrameSize(SPIx) > 8) {
ssi_adapter->RxLength <<= 1;
}
return (length - ssi_adapter->RxLength);
}
/**
* @brief Open SPI device clock.
* @param obj: spi object define in application software.
* @retval none
*/
void spi_enable(spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
if (spi_idx == 1) {
RCC_PeriphClockCmd(APBPeriph_SPI1, APBPeriph_SPI1_CLOCK, ENABLE);
} else {
RCC_PeriphClockCmd(APBPeriph_SPI0, APBPeriph_SPI0_CLOCK, ENABLE);
}
}
/**
* @brief Close SPI device clock.
* @param obj: spi object define in application software.
* @retval none
*/
void spi_disable(spi_t *obj)
{
uint8_t spi_idx = obj->spi_idx &0x0F;
if (spi_idx == 1) {
RCC_PeriphClockCmd(APBPeriph_SPI1, APBPeriph_SPI1_CLOCK, DISABLE);
} else {
RCC_PeriphClockCmd(APBPeriph_SPI0, APBPeriph_SPI0_CLOCK, DISABLE);
}
}