2013-10-17

Coocox SPI Macros and Functions - CooCox

Coocox SPI Macros and Functions 

/***********************************************************************//**
 * @file : LPC11xx_ssp.h
 * @brief : Contains all macro definitions and function prototypes
 * support for SSP firmware library on LPC11xx
 * @version : 1.0
 * @date : 21. Jan. 2010
 * @author : Coocox
 **************************************************************************/

/* Peripheral group ----------------------------------------------------------- */
/** @defgroup SSP
 * @ingroup LPC1100CMSIS_FwLib_Drivers
 * @{
 */

#ifndef __LPC11XX_SSP_H_
#define __LPC11XX_SSP_H_

/* Includes ------------------------------------------------------------------- */
#include "LPC11xx.h"
#include "lpc11xx_iocon.h"
#include "lpc_types.h"


#ifdef __cplusplus
extern "C"
{
#endif


/* Private Macros ------------------------------------------------------------- */
/** @defgroup SSP_Private_Macros
 * @{
 */

/*********************************************************************//**
 * Macro defines for CR0 register
 **********************************************************************/

/** @defgroup SSP_REGISTER_BIT_DEFINITION
 * @{
 */

/** SSP data size select, must be 4 bits to 16 bits */
#define SSP_CR0_DSS(n)   ((uint32_t)((n-1)&0xF))
/** SSP control 0 Motorola SPI mode */
#define SSP_CR0_FRF_SPI   ((uint32_t)(0<<4))
/** SSP control 0 TI synchronous serial mode */
#define SSP_CR0_FRF_TI   ((uint32_t)(1<<4))
/** SSP control 0 National Micro-wire mode */
#define SSP_CR0_FRF_MICROWIRE   ((uint32_t)(2<<4))
/** SPI clock polarity bit (used in SPI mode only), (1) = maintains the
   bus clock high between frames, (0) = low */
#define SSP_CR0_CPOL_HI ((uint32_t)(1<<6))
/** SPI clock out phase bit (used in SPI mode only), (1) = captures data
   on the second clock transition of the frame, (0) = first */
#define SSP_CR0_CPHA_SECOND ((uint32_t)(1<<7))
/** SSP serial clock rate value load macro, divider rate is
   PERIPH_CLK / (cpsr * (SCR + 1)) */
#define SSP_CR0_SCR(n)   ((uint32_t)((n&0xFF)<<8))
/** SSP CR0 bit mask */
#define SSP_CR0_BITMASK ((uint32_t)(0xFFFF))


/*********************************************************************//**
 * Macro defines for CR1 register
 **********************************************************************/
/** SSP control 1 loopback mode enable bit */
#define SSP_CR1_LBM_EN ((uint32_t)(1<<0))
/** SSP control 1 enable bit */
#define SSP_CR1_SSP_EN ((uint32_t)(1<<1))
/** SSP control 1 slave enable */
#define SSP_CR1_SLAVE_EN ((uint32_t)(1<<2))
/** SSP control 1 slave out disable bit, disables transmit line in slave
   mode */
#define SSP_CR1_SO_DISABLE ((uint32_t)(1<<3))
/** SSP CR1 bit mask */
#define SSP_CR1_BITMASK ((uint32_t)(0x0F))


/*********************************************************************//**
 * Macro defines for DR register
 **********************************************************************/
/** SSP data bit mask */
#define SSP_DR_BITMASK(n)   ((n)&0xFFFF)

/*********************************************************************//**
 * Macro defines for SR register
 **********************************************************************/
/** SSP status TX FIFO Empty bit */
#define SSP_SR_TFE      ((uint32_t)(1<<0))
/** SSP status TX FIFO not full bit */
#define SSP_SR_TNF      ((uint32_t)(1<<1))
/** SSP status RX FIFO not empty bit */
#define SSP_SR_RNE      ((uint32_t)(1<<2))
/** SSP status RX FIFO full bit */
#define SSP_SR_RFF      ((uint32_t)(1<<3))
/** SSP status SSP Busy bit */
#define SSP_SR_BSY      ((uint32_t)(1<<4))
/** SSP SR bit mask */
#define SSP_SR_BITMASK ((uint32_t)(0x1F))


/*********************************************************************//**
 * Macro defines for CPSR register
 **********************************************************************/
/** SSP clock prescaler */
#define SSP_CPSR_CPDVSR(n) ((uint32_t)(n&0xFF))
/** SSP CPSR bit mask */
#define SSP_CPSR_BITMASK ((uint32_t)(0xFF))


/*********************************************************************//**
 * Macro define for (IMSC) Interrupt Mask Set/Clear registers
 **********************************************************************/
/** Receive Overrun */
#define SSP_IMSC_ROR ((uint32_t)(1<<0))
/** Receive TimeOut */
#define SSP_IMSC_RT ((uint32_t)(1<<1))
/** Rx FIFO is at least half full */
#define SSP_IMSC_RX ((uint32_t)(1<<2))
/** Tx FIFO is at least half empty */
#define SSP_IMSC_TX ((uint32_t)(1<<3))
/** IMSC bit mask */
#define SSP_IMSC_BITMASK ((uint32_t)(0x0F))

/*********************************************************************//**
 * Macro define for (RIS) Raw Interrupt Status registers
 **********************************************************************/
/** Receive Overrun */
#define SSP_RIS_ROR ((uint32_t)(1<<0))
/** Receive TimeOut */
#define SSP_RIS_RT ((uint32_t)(1<<1))
/** Rx FIFO is at least half full */
#define SSP_RIS_RX ((uint32_t)(1<<2))
/** Tx FIFO is at least half empty */
#define SSP_RIS_TX ((uint32_t)(1<<3))
/** RIS bit mask */
#define SSP_RIS_BITMASK ((uint32_t)(0x0F))


/*********************************************************************//**
 * Macro define for (MIS) Masked Interrupt Status registers
 **********************************************************************/
/** Receive Overrun */
#define SSP_MIS_ROR ((uint32_t)(1<<0))
/** Receive TimeOut */
#define SSP_MIS_RT ((uint32_t)(1<<1))
/** Rx FIFO is at least half full */
#define SSP_MIS_RX ((uint32_t)(1<<2))
/** Tx FIFO is at least half empty */
#define SSP_MIS_TX ((uint32_t)(1<<3))
/** MIS bit mask */
#define SSP_MIS_BITMASK ((uint32_t)(0x0F))


/*********************************************************************//**
 * Macro define for (ICR) Interrupt Clear registers
 **********************************************************************/
/** Writing a 1 to this bit clears the "frame was received when
 * RxFIFO was full" interrupt */
#define SSP_ICR_ROR ((uint32_t)(1<<0))
/** Writing a 1 to this bit clears the "Rx FIFO was not empty and
 * has not been read for a timeout period" interrupt */
#define SSP_ICR_RT ((uint32_t)(1<<1))
/** ICR bit mask */
#define SSP_ICR_BITMASK ((uint32_t)(0x03))


/*********************************************************************//**
 * Macro defines for DMACR register
 **********************************************************************/
/** SSP bit for enabling RX DMA */
#define SSP_DMA_RXDMA_EN   ((uint32_t)(1<<0))
/** SSP bit for enabling TX DMA */
#define SSP_DMA_TXDMA_EN   ((uint32_t)(1<<1))
/** DMACR bit mask */
#define SSP_DMA_BITMASK ((uint32_t)(0x03))

/**
 * @}
 */

/**
 * @}
 */


/* Public Types --------------------------------------------------------------- */
/** @defgroup SSP_Public_Types
 * @{
 */

/** @brief SSP configuration structure */
typedef struct {
uint32_t Databit; /** Databit number, should be SSP_DATABIT_x,
where x is in range from 4 - 16 */
uint32_t CPHA; /** Clock phase, should be:
- SSP_CPHA_FIRST: first clock edge
- SSP_CPHA_SECOND: second clock edge */
uint32_t CPOL; /** Clock polarity, should be:
- SSP_CPOL_HI: high level
- SSP_CPOL_LO: low level */
uint32_t Mode; /** SSP mode, should be:
- SSP_MASTER_MODE: Master mode
- SSP_SLAVE_MODE: Slave mode */
uint32_t FrameFormat; /** Frame Format:
- SSP_FRAME_SPI: Motorola SPI frame format
- SSP_FRAME_TI: TI frame format
- SSP_FRAME_MICROWIRE: National Microwire frame format */
uint32_t ClockRate; /** Clock rate,in Hz */
} SSP_CFG_Type;

/**
 * @brief SSP Transfer Type definitions
 */
typedef enum {
SSP_TRANSFER_POLLING = 0, /**< Polling transfer */
SSP_TRANSFER_INTERRUPT /**< Interrupt transfer */
} SSP_TRANSFER_Type;

/**
 * @brief SPI Data configuration structure definitions
 */
typedef struct {
void *tx_data; /**< Pointer to transmit data */
uint32_t tx_cnt; /**< Transmit counter */
void *rx_data; /**< Pointer to transmit data */
uint32_t rx_cnt; /**< Receive counter */
uint32_t length; /**< Length of transfer data */
uint32_t status; /**< Current status of SSP activity */
void (*callback)(void); /**< Pointer to Call back function when transmission complete
used in interrupt transfer mode */
} SSP_DATA_SETUP_Type;


/**
 * @}
 */


/* Public Macros -------------------------------------------------------------- */
/** @defgroup SSP_Public_Macros
 * @{
 */

/** Macro to determine if it is valid SSP port number */
#define PARAM_SSPx(n) ((((uint32_t *)n)==((uint32_t *)LPC_SSP0)) \
|| (((uint32_t *)n)==((uint32_t *)LPC_SSP1)))

/*********************************************************************//**
 * SSP configuration parameter defines
 **********************************************************************/
/** Clock phase control bit */
#define SSP_CPHA_FIRST ((uint32_t)(0))
#define SSP_CPHA_SECOND SSP_CR0_CPHA_SECOND
#define PARAM_SSP_CPHA(n) ((n==SSP_CPHA_FIRST) || (n==SSP_CPHA_SECOND))

/** Clock polarity control bit */
#define SSP_CPOL_HI ((uint32_t)(0))
#define SSP_CPOL_LO SSP_CR0_CPOL_LOW
#define PARAM_SSP_CPOL(n) ((n==SSP_CPOL_HI) || (n==SSP_CPOL_LO))

/** SSP master mode enable */
#define SSP_SLAVE_MODE SSP_CR1_SLAVE_EN
#define SSP_MASTER_MODE ((uint32_t)(0))
#define PARAM_SSP_MODE(n) ((n==SSP_SLAVE_MODE) || (n==SSP_MASTER_MODE))

/** SSP data bit number defines */
#define SSP_DATABIT_4 SSP_CR0_DSS(4) /*!< Databit number = 4 */
#define SSP_DATABIT_5 SSP_CR0_DSS(5) /*!< Databit number = 5 */
#define SSP_DATABIT_6 SSP_CR0_DSS(6) /*!< Databit number = 6 */
#define SSP_DATABIT_7 SSP_CR0_DSS(7) /*!< Databit number = 7 */
#define SSP_DATABIT_8 SSP_CR0_DSS(8) /*!< Databit number = 8 */
#define SSP_DATABIT_9 SSP_CR0_DSS(9) /*!< Databit number = 9 */
#define SSP_DATABIT_10 SSP_CR0_DSS(10) /*!< Databit number = 10 */
#define SSP_DATABIT_11 SSP_CR0_DSS(11) /*!< Databit number = 11 */
#define SSP_DATABIT_12 SSP_CR0_DSS(12) /*!< Databit number = 12 */
#define SSP_DATABIT_13 SSP_CR0_DSS(13) /*!< Databit number = 13 */
#define SSP_DATABIT_14 SSP_CR0_DSS(14) /*!< Databit number = 14 */
#define SSP_DATABIT_15 SSP_CR0_DSS(15) /*!< Databit number = 15 */
#define SSP_DATABIT_16 SSP_CR0_DSS(16) /*!< Databit number = 16 */
#define PARAM_SSP_DATABIT(n) ((n==SSP_DATABIT_4) || (n==SSP_DATABIT_5) \
|| (n==SSP_DATABIT_6) || (n==SSP_DATABIT_16) \
|| (n==SSP_DATABIT_7) || (n==SSP_DATABIT_8) \
|| (n==SSP_DATABIT_9) || (n==SSP_DATABIT_10) \
|| (n==SSP_DATABIT_11) || (n==SSP_DATABIT_12) \
|| (n==SSP_DATABIT_13) || (n==SSP_DATABIT_14) \
|| (n==SSP_DATABIT_15))

/** SSP Frame Format definition */
/** Motorola SPI mode */
#define SSP_FRAME_SPI SSP_CR0_FRF_SPI
/** TI synchronous serial mode */
#define SSP_FRAME_TI SSP_CR0_FRF_TI
/** National Micro-wire mode */
#define SSP_FRAME_MICROWIRE SSP_CR0_FRF_MICROWIRE

#define PARAM_SSP_FRAME(n) ((n==SSP_FRAME_SPI) || (n==SSP_FRAME_TI) || (n==SSP_FRAME_MICROWIRE))


/*********************************************************************//**
 * SSP Status defines
 **********************************************************************/
/** SSP status TX FIFO Empty bit */
#define SSP_STAT_TXFIFO_EMPTY SSP_SR_TFE
/** SSP status TX FIFO not full bit */
#define SSP_STAT_TXFIFO_NOTFULL SSP_SR_TNF
/** SSP status RX FIFO not empty bit */
#define SSP_STAT_RXFIFO_NOTEMPTY SSP_SR_RNE
/** SSP status RX FIFO full bit */
#define SSP_STAT_RXFIFO_FULL SSP_SR_RFF
/** SSP status SSP Busy bit */
#define SSP_STAT_BUSY SSP_SR_BSY

#define PARAM_SSP_STAT(n) ((n==SSP_STAT_TXFIFO_EMPTY) || (n==SSP_STAT_TXFIFO_NOTFULL) \
|| (n==SSP_STAT_RXFIFO_NOTEMPTY) || (n==SSP_STAT_RXFIFO_FULL) \
|| (n==SSP_STAT_BUSY))


/*********************************************************************//**
 * SSP Interrupt Configuration defines
 **********************************************************************/
/** Receive Overrun */
#define SSP_INTCFG_ROR SSP_IMSC_ROR
/** Receive TimeOut */
#define SSP_INTCFG_RT SSP_IMSC_RT
/** Rx FIFO is at least half full */
#define SSP_INTCFG_RX SSP_IMSC_RX
/** Tx FIFO is at least half empty */
#define SSP_INTCFG_TX SSP_IMSC_TX

#define PARAM_SSP_INTCFG(n) ((n==SSP_INTCFG_ROR) || (n==SSP_INTCFG_RT) \
|| (n==SSP_INTCFG_RX) || (n==SSP_INTCFG_TX))


/*********************************************************************//**
 * SSP Configured Interrupt Status defines
 **********************************************************************/
/** Receive Overrun */
#define SSP_INTSTAT_ROR SSP_MIS_ROR
/** Receive TimeOut */
#define SSP_INTSTAT_RT SSP_MIS_RT
/** Rx FIFO is at least half full */
#define SSP_INTSTAT_RX SSP_MIS_RX
/** Tx FIFO is at least half empty */
#define SSP_INTSTAT_TX SSP_MIS_TX

#define PARAM_SSP_INTSTAT(n) ((n==SSP_INTSTAT_ROR) || (n==SSP_INTSTAT_RT) \
|| (n==SSP_INTSTAT_RX) || (n==SSP_INTSTAT_TX))


/*********************************************************************//**
 * SSP Raw Interrupt Status defines
 **********************************************************************/
/** Receive Overrun */
#define SSP_INTSTAT_RAW_ROR SSP_RIS_ROR
/** Receive TimeOut */
#define SSP_INTSTAT_RAW_RT SSP_RIS_RT
/** Rx FIFO is at least half full */
#define SSP_INTSTAT_RAW_RX SSP_RIS_RX
/** Tx FIFO is at least half empty */
#define SSP_INTSTAT_RAW_TX SSP_RIS_TX

#define PARAM_SSP_INTSTAT_RAW(n) ((n==SSP_INTSTAT_RAW_ROR) || (n==SSP_INTSTAT_RAW_RT) \
|| (n==SSP_INTSTAT_RAW_RX) || (n==SSP_INTSTAT_RAW_TX))


/*********************************************************************//**
 * SSP Interrupt Clear defines
 **********************************************************************/
/** Writing a 1 to this bit clears the "frame was received when
 * RxFIFO was full" interrupt */
#define SSP_INTCLR_ROR SSP_ICR_ROR
/** Writing a 1 to this bit clears the "Rx FIFO was not empty and
 * has not been read for a timeout period" interrupt */
#define SSP_INTCLR_RT SSP_ICR_RT

#define PARAM_SSP_INTCLR(n) ((n==SSP_INTCLR_ROR) || (n==SSP_INTCLR_RT))


/*********************************************************************//**
 * SSP DMA defines
 **********************************************************************/
/** SSP bit for enabling RX DMA */
#define SSP_DMA_TX SSP_DMA_RXDMA_EN
/** SSP bit for enabling TX DMA */
#define SSP_DMA_RX SSP_DMA_TXDMA_EN

#define PARAM_SSP_DMA(n) ((n==SSP_DMA_TX) || (n==SSP_DMA_RX))

/* SSP Status Implementation definitions */
#define SSP_STAT_DONE (1UL<<8) /**< Done */
#define SSP_STAT_ERROR (1UL<<9) /**< Error */

/**
 * @}
 */


/* Public Functions ----------------------------------------------------------- */
/** @defgroup SSP_Public_Functions
 * @{
 */

void SSP_SetClock (SSP_TypeDef *SSPx, uint32_t target_clock);
void SSP_DeInit(SSP_TypeDef* SSPx);
void SSP_SSP0PinsInit(SCK0_Position_Typedef sck0, FunctionalState useSSEL);
void SSP_SSP1PinsInit(FunctionalState useSSEL);
void SSP_Init(SSP_TypeDef *SSPx, SSP_CFG_Type *SSP_ConfigStruct);
void SSP_ConfigStructInit(SSP_CFG_Type *SSP_InitStruct);
void SSP_Cmd(SSP_TypeDef* SSPx, FunctionalState NewState);
void SSP_LoopBackCmd(SSP_TypeDef* SSPx, FunctionalState NewState);
void SSP_SlaveOutputCmd(SSP_TypeDef* SSPx, FunctionalState NewState);
void SSP_SendData(SSP_TypeDef* SSPx, uint16_t Data);
uint16_t SSP_ReceiveData(SSP_TypeDef* SSPx);
int32_t SSP_ReadWrite (SSP_TypeDef *SSPx, SSP_DATA_SETUP_Type *dataCfg, \
SSP_TRANSFER_Type xfType);
FlagStatus SSP_GetStatus(SSP_TypeDef* SSPx, uint32_t FlagType);
void SSP_IntConfig(SSP_TypeDef *SSPx, uint32_t IntType, FunctionalState NewState);
IntStatus SSP_GetRawIntStatus(SSP_TypeDef *SSPx, uint32_t RawIntType);
IntStatus SSP_GetIntStatus (SSP_TypeDef *SSPx, uint32_t IntType);
void SSP_ClearIntPending(SSP_TypeDef *SSPx, uint32_t IntType);
void SSP0_StdIntHandler(void);
void SSP1_StdIntHandler(void);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* __LPC11XX_SSP_H_ */

/**
 * @}
 */

/* --------------------------------- End Of File ------------------------------ */





/***********************************************************************//**
 * @file : lpc11xx_ssp.c
 * @brief : Contains all functions support for SSP firmware library on LPC11xx
 * @version : 1.0
 * @date : 21. Jan. 2010
 * @author : Coocox
 **********************************************************************/

/* Peripheral group ----------------------------------------------------------- */
/** @addtogroup SSP
 * @{
 */

/* Includes ------------------------------------------------------------------- */
#include "lpc11xx_ssp.h"
#include "lpc11xx_syscon.h"
#include "lpc11xx_libcfg.h"


#if _SSP

/* Private Types -------------------------------------------------------------- */
/** @defgroup SSP_Private_Types
 * @{
 */

/** @brief SSP device configuration structure type */
typedef struct
{
int32_t dataword; /* Current data word: 0 - 8 bit; 1 - 16 bit */
uint32_t    txrx_setup; /* Transmission setup */
void (*inthandler)(SSP_TypeDef *SSPx);   /* Transmission interrupt handler */
} SSP_CFG_T;

/**
 * @}
 */

/* Private Variables ---------------------------------------------------------- */
/** @defgroup SSP_Private_Variables
 * @{
 */

/* SSP configuration data */
static SSP_CFG_T sspdat[2];

/**
 * @}
 */


/* Private Functions ---------------------------------------------------------- */
/** @defgroup SSP_Private_Functions
 * @{
 */

/**
 * @brief Convert from SSP peripheral to number
 */
static int32_t SSP_getNum(SSP_TypeDef *SSPx){
if (SSPx == LPC_SSP0) {
return (0);
} else if (SSPx == LPC_SSP1) {
return (1);
}
return (-1);
}


/*********************************************************************//**
 * @brief Standard Private SSP Interrupt handler
 * @param None
 * @return None
 ***********************************************************************/
void SSP_IntHandler(SSP_TypeDef *SSPx)
{
SSP_DATA_SETUP_Type *xf_setup;
    uint16_t tmp;
    int32_t sspnum;

    // Disable interrupt
    SSPx->IMSC = 0;

    sspnum = SSP_getNum(SSPx);
    xf_setup = (SSP_DATA_SETUP_Type *)sspdat[sspnum].txrx_setup;

    // save status
    tmp = SSPx->RIS;
    xf_setup->status = tmp;

    // Check overrun error
    if (tmp & SSP_RIS_ROR){
    // Clear interrupt
    SSPx->ICR = SSP_RIS_ROR;
    // update status
    xf_setup->status |= SSP_STAT_ERROR;
    // Callback
    if (xf_setup->callback != NULL){
    xf_setup->callback();
    }
    return;
    }

    if ((xf_setup->tx_cnt != xf_setup->length) || (xf_setup->rx_cnt != xf_setup->length)){
    /* check if RX FIFO contains data */
while ((SSPx->SR & SSP_SR_RNE) && (xf_setup->rx_cnt != xf_setup->length)){
// Read data from SSP data
tmp = SSP_ReceiveData(SSPx);

// Store data to destination
if (xf_setup->rx_data != NULL)
{
if (sspdat[sspnum].dataword == 0){
*(uint8_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint8_t) tmp;
} else {
*(uint16_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint16_t) tmp;
}
}
// Increase counter
if (sspdat[sspnum].dataword == 0){
xf_setup->rx_cnt++;
} else {
xf_setup->rx_cnt += 2;
}
}

while ((SSPx->SR & SSP_SR_TNF) && (xf_setup->tx_cnt != xf_setup->length)){
// Write data to buffer
if(xf_setup->tx_data == NULL){
if (sspdat[sspnum].dataword == 0){
SSP_SendData(SSPx, 0xFF);
xf_setup->tx_cnt++;
} else {
SSP_SendData(SSPx, 0xFFFF);
xf_setup->tx_cnt += 2;
}
} else {
if (sspdat[sspnum].dataword == 0){
SSP_SendData(SSPx, (*(uint8_t *)((uint32_t)xf_setup->tx_data + xf_setup->tx_cnt)));
xf_setup->tx_cnt++;
} else {
SSP_SendData(SSPx, (*(uint16_t *)((uint32_t)xf_setup->tx_data + xf_setup->tx_cnt)));
xf_setup->tx_cnt += 2;
}
}

   // Check overrun error
   if ((tmp = SSPx->RIS) & SSP_RIS_ROR){
    // update status
    xf_setup->status |= SSP_STAT_ERROR;
    // Callback
    if (xf_setup->callback != NULL){
    xf_setup->callback();
    }
    return;
   }

// Check for any data available in RX FIFO
while ((SSPx->SR & SSP_SR_RNE) && (xf_setup->rx_cnt != xf_setup->length)){
// Read data from SSP data
tmp = SSP_ReceiveData(SSPx);

// Store data to destination
if (xf_setup->rx_data != NULL)
{
if (sspdat[sspnum].dataword == 0){
*(uint8_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint8_t) tmp;
} else {
*(uint8_t *)((uint32_t)xf_setup->rx_data + xf_setup->rx_cnt) = (uint16_t) tmp;
}
}
// Increase counter
if (sspdat[sspnum].dataword == 0){
xf_setup->rx_cnt++;
} else {
xf_setup->rx_cnt += 2;
}
}
}
    }

// If there more data to sent or receive
if ((xf_setup->rx_cnt != xf_setup->length) || (xf_setup->tx_cnt != xf_setup->length)){
// Enable all interrupt
SSPx->IMSC = SSP_IMSC_BITMASK;
} else {
// Save status
xf_setup->status = SSP_STAT_DONE;
// Callback
if (xf_setup->callback != NULL){
xf_setup->callback();
}
}
}

/**
 * @}
 */


/* Public Functions ----------------------------------------------------------- */
/** @addtogroup SSP_Public_Functions
 * @{
 */

/*********************************************************************//**
 * @brief Setup clock rate for SSP device
 * @param[in] SSPx SSP peripheral definition, should be
 * SSP0 or SSP1.
 * @param[in] target_clock : clock of SSP (Hz)
 * @return None
 ***********************************************************************/
void SSP_SetClock (SSP_TypeDef *SSPx, uint32_t target_clock)
{
    uint32_t prescale, cr0_div, cmp_clk, ssp_clk;

    CHECK_PARAM(PARAM_SSPx(SSPx));

    /* The SSP clock is derived from the (main system oscillator / 2),
       so compute the best divider from that clock */
    if (SSPx == LPC_SSP0){
    ssp_clk = SYSCON_GetSSP0Clock(0);
    } else if (SSPx == LPC_SSP1) {
    ssp_clk = SYSCON_GetSSP0Clock(1);
    } else {
    return;
    }

/* Find closest divider to get at or under the target frequency.
  Use smallest prescale possible and rely on the divider to get
  the closest target frequency */
cr0_div = 0;
cmp_clk = 0xFFFFFFFF;
prescale = 2;
while (cmp_clk > target_clock)
{
cmp_clk = ssp_clk / ((cr0_div + 1) * prescale);
if (cmp_clk > target_clock)
{
cr0_div++;
if (cr0_div > 0xFF)
{
cr0_div = 0;
prescale += 2;
}
}
}

    /* Write computed prescaler and divider back to register */
    SSPx->CR0 &= (~SSP_CR0_SCR(0xFF)) & SSP_CR0_BITMASK;
    SSPx->CR0 |= (SSP_CR0_SCR(cr0_div)) & SSP_CR0_BITMASK;
    SSPx->CPSR = prescale & SSP_CPSR_BITMASK;
}


/*********************************************************************//**
 * @brief De-initializes the SSPx peripheral registers to their
*                  default reset values.
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @return None
 **********************************************************************/
void SSP_DeInit(SSP_TypeDef* SSPx)
{
CHECK_PARAM(PARAM_SSPx(SSPx));

if (SSPx == LPC_SSP0){
        /* Reset SSP0 */        
        SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_SSP0, ENABLE);                
        SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_SSP0, DISABLE);                

/* Set up clock and power for SSP0 module */
SYSCON_AHBPeriphClockCmd(SYSCON_AHBPeriph_SSP0, DISABLE);
} else if (SSPx == LPC_SSP1) {
        /* Reset SSP1 */        
        SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_SSP1, ENABLE);                
        SYSCON_PeriphResetCmd(SYSCON_RSTPeriph_SSP1, DISABLE);                        

/* Set up clock and power for SSP1 module */
SYSCON_AHBPeriphClockCmd(SYSCON_AHBPeriph_SSP1, DISABLE);
}
}

/********************************************************************//**
 * @brief Assigns SSP0 pins:
 *                MISO : PIO0_8
 *                MOSI : PIO0_9
 *                SCK  : PIO0_10/PIO2_11/PIO0_6
 *                SSEL : PIO0_2
 * @param[in] sck0 Locate SCK0 position, it can be
 *                   SCK0_PIO0_10 : pin location SWCLK/PIO0_10/SCK0/CT16B0_MAT2
 *                                  NOTE: SWCLK is JTAG pin
 *                   SCK0_PIO2_11 : pin location PIO2_11/SCK0
 *                   SCK0_PIO0_6  : pin location PIO0_6/SCK0
 *
 *               Note: SCK0_PIO0_10 is multiplexed with JTAG pins
 * @param[in] useSSEL Assign SSEL pin or not
 * @return None
 *********************************************************************/
void SSP_SSP0PinsInit(SCK0_Position_Typedef sck0, FunctionalState useSSEL)
{
    IOCON_SCK0Locate(sck0);

    IOCON_SetPinFunc(IOCON_PIO0_8, PIO0_8_FUN_MISO0);
    IOCON_SetPinFunc(IOCON_PIO0_9, PIO0_9_FUN_MOSI0);

    if(useSSEL == ENABLE) {
        IOCON_SetPinFunc(IOCON_PIO0_2, PIO0_2_FUN_SSEL0);
    }
           
    switch(sck0) {
    case SCK0_PIO0_10:
        IOCON_SetPinFunc(IOCON_PIO0_10, PIO0_10_FUN_SCK0); break;      
    case SCK0_PIO2_11:
        IOCON_SetPinFunc(IOCON_PIO2_11, PIO2_11_FUN_SCK0); break;
    case SCK0_PIO0_6:
        IOCON_SetPinFunc(IOCON_PIO0_6,  PIO0_6_FUN_SCK0);  break;
    default: break;
    }    
}

/********************************************************************//**
 * @brief Assigns SSP1 pins:
 *                MISO : PIO2_2
 *                MOSI : PIO2_3
 *                SCK  : PIO2_1
 *                SSEL : PIO2_0
 * @param[in] useSSEL Assign SSEL pin or not
 * @return None
 *********************************************************************/
void SSP_SSP1PinsInit(FunctionalState useSSEL)
{
    IOCON_SetPinFunc(IOCON_PIO2_2, PIO2_2_FUN_MISO1);
    IOCON_SetPinFunc(IOCON_PIO2_3, PIO2_3_FUN_PIO_MOSI1);
    IOCON_SetPinFunc(IOCON_PIO2_1, PIO2_1_FUN_SCK1);

    if(useSSEL == ENABLE) {
        IOCON_SetPinFunc(IOCON_PIO2_0, PIO2_0_FUN_SSEL1);
    }   
}

/********************************************************************//**
 * @brief Initializes the SSPx peripheral according to the specified
*               parameters in the SSP_ConfigStruct.
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] SSP_ConfigStruct Pointer to a SSP_CFG_Type structure
*                    that contains the configuration information for the
*                    specified SSP peripheral.
 * @return None
 *********************************************************************/
void SSP_Init(SSP_TypeDef *SSPx, SSP_CFG_Type *SSP_ConfigStruct)
{
uint32_t tmp;

CHECK_PARAM(PARAM_SSPx(SSPx));

if(SSPx == LPC_SSP0) {
/* Set up clock and power for SSP0 module */
SYSCON_AHBPeriphClockCmd(SYSCON_AHBPeriph_SSP0, ENABLE);
} else if(SSPx == LPC_SSP1) {
/* Set up clock and power for SSP1 module */
SYSCON_AHBPeriphClockCmd(SYSCON_AHBPeriph_SSP1, ENABLE);
} else {
return;
}

/* Configure SSP, interrupt is disable, LoopBack mode is disable,
* SSP is disable, Slave output is disable as default
*/
tmp = ((SSP_ConfigStruct->CPHA) | (SSP_ConfigStruct->CPOL) \
| (SSP_ConfigStruct->FrameFormat) | (SSP_ConfigStruct->Databit))
& SSP_CR0_BITMASK;
// write back to SSP control register
SSPx->CR0 = tmp;
tmp = SSP_getNum(SSPx);
if (SSP_ConfigStruct->Databit > SSP_DATABIT_8){
sspdat[tmp].dataword = 1;
} else {
sspdat[tmp].dataword = 0;
}

tmp = SSP_ConfigStruct->Mode & SSP_CR1_BITMASK;
// Write back to CR1
SSPx->CR1 = tmp;

// Set clock rate for SSP peripheral
SSP_SetClock(SSPx, SSP_ConfigStruct->ClockRate);
}



/*****************************************************************************//**
* @brief Fills each SSP_InitStruct member with its default value:
* - CPHA = SSP_CPHA_FIRST
* - CPOL = SSP_CPOL_HI
* - ClockRate = 1000000
* - Databit = SSP_DATABIT_8
* - Mode = SSP_MASTER_MODE
* - FrameFormat = SSP_FRAME_SSP
* @param[in] SSP_InitStruct Pointer to a SSP_CFG_Type structure
*                    which will be initialized.
* @return None
*******************************************************************************/
void SSP_ConfigStructInit(SSP_CFG_Type *SSP_InitStruct)
{
SSP_InitStruct->CPHA = SSP_CPHA_FIRST;
SSP_InitStruct->CPOL = SSP_CPOL_HI;
SSP_InitStruct->ClockRate = 1000000;
SSP_InitStruct->Databit = SSP_DATABIT_8;
SSP_InitStruct->Mode = SSP_MASTER_MODE;
SSP_InitStruct->FrameFormat = SSP_FRAME_SPI;
}


/*********************************************************************//**
 * @brief Enable or disable SSP peripheral's operation
 * @param[in] SSPx SSP peripheral, should be SSP0 or SSP1
 * @param[in] NewState New State of SSPx peripheral's operation
 * @return none
 **********************************************************************/
void SSP_Cmd(SSP_TypeDef* SSPx, FunctionalState NewState)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

if (NewState == ENABLE)
{
SSPx->CR1 |= SSP_CR1_SSP_EN;
}
else
{
SSPx->CR1 &= (~SSP_CR1_SSP_EN) & SSP_CR1_BITMASK;
}
}



/*********************************************************************//**
 * @brief Enable or disable Loop Back mode function in SSP peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] NewState New State of Loop Back mode, should be:
 * - ENABLE: Enable this function
 * - DISABLE: Disable this function
 * @return None
 **********************************************************************/
void SSP_LoopBackCmd(SSP_TypeDef* SSPx, FunctionalState NewState)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

if (NewState == ENABLE)
{
SSPx->CR1 |= SSP_CR1_LBM_EN;
}
else
{
SSPx->CR1 &= (~SSP_CR1_LBM_EN) & SSP_CR1_BITMASK;
}
}



/*********************************************************************//**
 * @brief Enable or disable Slave Output function in SSP peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] NewState New State of Slave Output function, should be:
 * - ENABLE: Slave Output in normal operation
 * - DISABLE: Slave Output is disabled. This blocks
 * SSP controller from driving the transmit data
 * line (MISO)
 * Note: This function is available when SSP peripheral in Slave mode
 * @return None
 **********************************************************************/
void SSP_SlaveOutputCmd(SSP_TypeDef* SSPx, FunctionalState NewState)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));

if (NewState == ENABLE)
{
SSPx->CR1 &= (~SSP_CR1_SO_DISABLE) & SSP_CR1_BITMASK;
}
else
{
SSPx->CR1 |= SSP_CR1_SO_DISABLE;
}
}



/*********************************************************************//**
 * @brief Transmit a single data through SSPx peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP
 * @param[in] Data Data to transmit (must be 16 or 8-bit long,
 * this depend on SSP data bit number configured)
 * @return none
 **********************************************************************/
void SSP_SendData(SSP_TypeDef* SSPx, uint16_t Data)
{
CHECK_PARAM(PARAM_SSPx(SSPx));

SSPx->DR = SSP_DR_BITMASK(Data);
}



/*********************************************************************//**
 * @brief Receive a single data from SSPx peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP
 * @return Data received (16-bit long)
 **********************************************************************/
uint16_t SSP_ReceiveData(SSP_TypeDef* SSPx)
{
CHECK_PARAM(PARAM_SSPx(SSPx));

return ((uint16_t) (SSP_DR_BITMASK(SSPx->DR)));
}

/*********************************************************************//**
 * @brief SSP Read write data function
 * @param[in] SSPx Pointer to SSP peripheral, should be SSP0 or SSP1
 * @param[in] dataCfg Pointer to a SSP_DATA_SETUP_Type structure that
 * contains specified information about transmit
 * data configuration.
 * @param[in] xfType Transfer type, should be:
 * - SSP_TRANSFER_POLLING: Polling mode
 * - SSP_TRANSFER_INTERRUPT: Interrupt mode
 * @return Actual Data length has been transferred in polling mode.
 * In interrupt mode, always return (0)
 * Return (-1) if error.
 * Note: This function can be used in both master and slave mode.
 ***********************************************************************/
int32_t SSP_ReadWrite (SSP_TypeDef *SSPx, SSP_DATA_SETUP_Type *dataCfg, \
SSP_TRANSFER_Type xfType)
{
uint8_t *rdata8;
    uint8_t *wdata8;
uint16_t *rdata16;
    uint16_t *wdata16;
    uint32_t stat;
    uint32_t tmp;
    int32_t sspnum;
    int32_t dataword;

    dataCfg->rx_cnt = 0;
    dataCfg->tx_cnt = 0;
    dataCfg->status = 0;


/* Clear all remaining data in RX FIFO */
while (SSPx->SR & SSP_SR_RNE){
tmp = (uint32_t) SSP_ReceiveData(SSPx);
}

// Clear status
SSPx->ICR = SSP_ICR_BITMASK;

sspnum = SSP_getNum(SSPx);
dataword = sspdat[sspnum].dataword;

// Polling mode ----------------------------------------------------------------------
if (xfType == SSP_TRANSFER_POLLING){
if (dataword == 0){
rdata8 = (uint8_t *)dataCfg->rx_data;
wdata8 = (uint8_t *)dataCfg->tx_data;
} else {
rdata16 = (uint16_t *)dataCfg->rx_data;
wdata16 = (uint16_t *)dataCfg->tx_data;
}
while ((dataCfg->tx_cnt != dataCfg->length) || (dataCfg->rx_cnt != dataCfg->length)){
if ((SSPx->SR & SSP_SR_TNF) && (dataCfg->tx_cnt != dataCfg->length)){
// Write data to buffer
if(dataCfg->tx_data == NULL){
if (dataword == 0){
SSP_SendData(SSPx, 0xFF);
dataCfg->tx_cnt++;
} else {
SSP_SendData(SSPx, 0xFFFF);
dataCfg->tx_cnt += 2;
}
} else {
if (dataword == 0){
SSP_SendData(SSPx, *wdata8);
wdata8++;
dataCfg->tx_cnt++;
} else {
SSP_SendData(SSPx, *wdata16);
wdata16++;
dataCfg->tx_cnt += 2;
}
}
}

// Check overrun error
if ((stat = SSPx->RIS) & SSP_RIS_ROR){
// save status and return
dataCfg->status = stat | SSP_STAT_ERROR;
return (-1);
}

// Check for any data available in RX FIFO
while ((SSPx->SR & SSP_SR_RNE) && (dataCfg->rx_cnt != dataCfg->length)){
// Read data from SSP data
tmp = SSP_ReceiveData(SSPx);

// Store data to destination
if (dataCfg->rx_data != NULL)
{
if (dataword == 0){
*(rdata8) = (uint8_t) tmp;
rdata8++;
} else {
*(rdata16) = (uint16_t) tmp;
rdata16++;
}
}
// Increase counter
if (dataword == 0){
dataCfg->rx_cnt++;
} else {
dataCfg->rx_cnt += 2;
}
}
}

// save status
dataCfg->status = SSP_STAT_DONE;

if (dataCfg->tx_data != NULL){
return dataCfg->tx_cnt;
} else if (dataCfg->rx_data != NULL){
return dataCfg->rx_cnt;
} else {
return (0);
}
}

// Interrupt mode ----------------------------------------------------------------------
else if (xfType == SSP_TRANSFER_INTERRUPT){
sspdat[sspnum].inthandler = SSP_IntHandler;
sspdat[sspnum].txrx_setup = (uint32_t)dataCfg;

while ((SSPx->SR & SSP_SR_TNF) && (dataCfg->tx_cnt != dataCfg->length)){
// Write data to buffer
if(dataCfg->tx_data == NULL){
if (sspdat[sspnum].dataword == 0){
SSP_SendData(SSPx, 0xFF);
dataCfg->tx_cnt++;
} else {
SSP_SendData(SSPx, 0xFFFF);
dataCfg->tx_cnt += 2;
}
} else {
if (sspdat[sspnum].dataword == 0){
SSP_SendData(SSPx, (*(uint8_t *)((uint32_t)dataCfg->tx_data + dataCfg->tx_cnt)));
dataCfg->tx_cnt++;
} else {
SSP_SendData(SSPx, (*(uint16_t *)((uint32_t)dataCfg->tx_data + dataCfg->tx_cnt)));
dataCfg->tx_cnt += 2;
}
}

// Check error
if ((stat = SSPx->RIS) & SSP_RIS_ROR){
// save status and return
dataCfg->status = stat | SSP_STAT_ERROR;
return (-1);
}

// Check for any data available in RX FIFO
while ((SSPx->SR & SSP_SR_RNE) && (dataCfg->rx_cnt != dataCfg->length)){
// Read data from SSP data
tmp = SSP_ReceiveData(SSPx);

// Store data to destination
if (dataCfg->rx_data != NULL)
{
if (sspdat[sspnum].dataword == 0){
*(uint8_t *)((uint32_t)dataCfg->rx_data + dataCfg->rx_cnt) = (uint8_t) tmp;
} else {
*(uint16_t *)((uint32_t)dataCfg->rx_data + dataCfg->rx_cnt) = (uint16_t) tmp;
}
}
// Increase counter
if (sspdat[sspnum].dataword == 0){
dataCfg->rx_cnt++;
} else {
dataCfg->rx_cnt += 2;
}
}
}

// If there more data to sent or receive
if ((dataCfg->rx_cnt != dataCfg->length) || (dataCfg->tx_cnt != dataCfg->length)){
// Enable all interrupt
SSPx->IMSC = SSP_IMSC_BITMASK;
} else {
// Save status
dataCfg->status = SSP_STAT_DONE;
}
return (0);
}

return (-1);
}

/*********************************************************************//**
 * @brief Checks whether the specified SSP status flag is set or not
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] FlagType Type of flag to check status, should be one
 * of following:
 * - SSP_STAT_TXFIFO_EMPTY: TX FIFO is empty
 * - SSP_STAT_TXFIFO_NOTFULL: TX FIFO is not full
 * - SSP_STAT_RXFIFO_NOTEMPTY: RX FIFO is not empty
 * - SSP_STAT_RXFIFO_FULL: RX FIFO is full
 * - SSP_STAT_BUSY: SSP peripheral is busy
 * @return New State of specified SSP status flag
 **********************************************************************/
FlagStatus SSP_GetStatus(SSP_TypeDef* SSPx, uint32_t FlagType)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_SSP_STAT(FlagType));

return ((SSPx->SR & FlagType) ? SET : RESET);
}



/*********************************************************************//**
 * @brief Enable or disable specified interrupt type in SSP peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] IntType Interrupt type in SSP peripheral, should be:
 * - SSP_INTCFG_ROR: Receive Overrun interrupt
 * - SSP_INTCFG_RT: Receive Time out interrupt
 * - SSP_INTCFG_RX: RX FIFO is at least half full interrupt
 * - SSP_INTCFG_TX: TX FIFO is at least half empty interrupt
 * @param[in] NewState New State of specified interrupt type, should be:
 * - ENABLE: Enable this interrupt type
 * - DISABLE: Disable this interrupt type
 * @return None
 **********************************************************************/
void SSP_IntConfig(SSP_TypeDef *SSPx, uint32_t IntType, FunctionalState NewState)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_SSP_INTCFG(IntType));

if (NewState == ENABLE)
{
SSPx->IMSC |= IntType;
}
else
{
SSPx->IMSC &= (~IntType) & SSP_IMSC_BITMASK;
}
}


/*********************************************************************//**
 * @brief Check whether the specified Raw interrupt status flag is
 * set or not
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] RawIntType Raw Interrupt Type, should be:
 * - SSP_INTSTAT_RAW_ROR: Receive Overrun interrupt
 * - SSP_INTSTAT_RAW_RT: Receive Time out interrupt
 * - SSP_INTSTAT_RAW_RX: RX FIFO is at least half full interrupt
 * - SSP_INTSTAT_RAW_TX: TX FIFO is at least half empty interrupt
 * @return New State of specified Raw interrupt status flag in SSP peripheral
 * Note: Enabling/Disabling specified interrupt in SSP peripheral does not
 * effect to Raw Interrupt Status flag.
 **********************************************************************/
IntStatus SSP_GetRawIntStatus(SSP_TypeDef *SSPx, uint32_t RawIntType)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_SSP_INTSTAT_RAW(RawIntType));

return ((SSPx->RIS & RawIntType) ? SET : RESET);
}


/*********************************************************************//**
 * @brief Check whether the specified interrupt status flag is
 * set or not
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] RawIntType Raw Interrupt Type, should be:
 * - SSP_INTSTAT_ROR: Receive Overrun interrupt
 * - SSP_INTSTAT_RT: Receive Time out interrupt
 * - SSP_INTSTAT_RX: RX FIFO is at least half full interrupt
 * - SSP_INTSTAT_TX: TX FIFO is at least half empty interrupt
 * @return New State of specified interrupt status flag in SSP peripheral
 * Note: Enabling/Disabling specified interrupt in SSP peripheral effects
 * to Interrupt Status flag.
 **********************************************************************/
IntStatus SSP_GetIntStatus (SSP_TypeDef *SSPx, uint32_t IntType)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_SSP_INTSTAT(IntType));

return ((SSPx->MIS & IntType) ? SET :RESET);
}



/*********************************************************************//**
 * @brief Clear specified interrupt pending in SSP peripheral
 * @param[in] SSPx SSP peripheral selected, should be SSP0 or SSP1
 * @param[in] IntType Interrupt pending to clear, should be:
 * - SSP_INTCLR_ROR: clears the "frame was received when
 * RxFIFO was full" interrupt.
 * - SSP_INTCLR_RT: clears the "Rx FIFO was not empty and
 * has not been read for a timeout period" interrupt.
 * @return None
 **********************************************************************/
void SSP_ClearIntPending(SSP_TypeDef *SSPx, uint32_t IntType)
{
CHECK_PARAM(PARAM_SSPx(SSPx));
CHECK_PARAM(PARAM_SSP_INTCLR(IntType));

SSPx->ICR = IntType;
}

/**
 * @brief Standard SSP0 Interrupt handler
 * @param[in] None
 * @return None
 */
void SSP0_StdIntHandler(void)
{
// Call relevant handler
sspdat[0].inthandler(LPC_SSP0);
}

/**
 * @brief Standard SSP1 Interrupt handler
 * @param[in] None
 * @return None
 */
void SSP1_StdIntHandler(void)
{
// Call relevant handler
sspdat[1].inthandler(LPC_SSP1);
}

/**
 * @}
 */

#endif /* _SSP */

/**
 * @}
 */

/* --------------------------------- End Of File ------------------------------ */

.END

No comments:

Post a Comment