📄 lpc11xx_ssp.c
字号:
/***********************************************************************//**
* @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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -