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