/* * @brief LPC13xx SSP Registers and control functions * * @note * Copyright(C) NXP Semiconductors, 2012 * All rights reserved. * * @par * Software that is described herein is for illustrative purposes only * which provides customers with programming information regarding the * LPC products. This software is supplied "AS IS" without any warranties of * any kind, and NXP Semiconductors and its licensor disclaim any and * all warranties, express or implied, including all implied warranties of * merchantability, fitness for a particular purpose and non-infringement of * intellectual property rights. NXP Semiconductors assumes no responsibility * or liability for the use of the software, conveys no license or rights under any * patent, copyright, mask work right, or any other intellectual property rights in * or to any products. NXP Semiconductors reserves the right to make changes * in the software without notification. NXP Semiconductors also makes no * representation or warranty that such application will be suitable for the * specified use without further testing or modification. * * @par * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, under NXP Semiconductors' and its * licensor's relevant copyrights in the software, without fee, provided that it * is used in conjunction with NXP Semiconductors microcontrollers. This * copyright, permission, and disclaimer notice must appear in all copies of * this code. */ #include "chip.h" /***************************************************************************** * Private types/enumerations/variables ****************************************************************************/ /***************************************************************************** * Public types/enumerations/variables ****************************************************************************/ /***************************************************************************** * Private functions ****************************************************************************/ STATIC void SSP_Write2BFifo(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { if (xf_setup->tx_data) { Chip_SSP_SendFrame(pSSP, (*(uint16_t *) ((uint32_t) xf_setup->tx_data + xf_setup->tx_cnt))); } else { Chip_SSP_SendFrame(pSSP, 0xFFFF); } xf_setup->tx_cnt += 2; } /** SSP macro: write 1 bytes to FIFO buffer */ STATIC void SSP_Write1BFifo(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { if (xf_setup->tx_data) { Chip_SSP_SendFrame(pSSP, (*(uint8_t *) ((uint32_t) xf_setup->tx_data + xf_setup->tx_cnt))); } else { Chip_SSP_SendFrame(pSSP, 0xFF); } xf_setup->tx_cnt++; } /** SSP macro: read 1 bytes from FIFO buffer */ STATIC void SSP_Read2BFifo(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { uint16_t rDat; while ((Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET) && (xf_setup->rx_cnt < xf_setup->length)) { rDat = Chip_SSP_ReceiveFrame(pSSP); if (xf_setup->rx_data) { *(uint16_t *) ((uint32_t) xf_setup->rx_data + xf_setup->rx_cnt) = rDat; } xf_setup->rx_cnt += 2; } } /** SSP macro: read 2 bytes from FIFO buffer */ STATIC void SSP_Read1BFifo(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { uint16_t rDat; while ((Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET) && (xf_setup->rx_cnt < xf_setup->length)) { rDat = Chip_SSP_ReceiveFrame(pSSP); if (xf_setup->rx_data) { *(uint8_t *) ((uint32_t) xf_setup->rx_data + xf_setup->rx_cnt) = rDat; } xf_setup->rx_cnt++; } } /* Returns clock for the peripheral block */ STATIC CHIP_SYSCTL_CLOCK_T Chip_SSP_GetClockIndex(LPC_SSP_T *pSSP) { CHIP_SYSCTL_CLOCK_T clkSSP; if (pSSP == LPC_SSP0) { clkSSP = SYSCTL_CLOCK_SSP0; } else { clkSSP = SYSCTL_CLOCK_SSP1; } return clkSSP; } /* Returns reset ID for the peripheral block */ STATIC CHIP_SYSCTL_PERIPH_RESET_T Chip_SSP_GetResetIndex(LPC_SSP_T *pSSP) { CHIP_SYSCTL_PERIPH_RESET_T resetSSP; if (pSSP == LPC_SSP0) { resetSSP = RESET_SSP0; } else { resetSSP = RESET_SSP1; } return resetSSP; } /* Returns reset ID for the peripheral block */ STATIC void Chip_SSP_SetSSPClkDivider(LPC_SSP_T *pSSP, uint32_t div) { if (pSSP == LPC_SSP0) { Chip_Clock_SetSSP0ClockDiv(div); } else { Chip_Clock_SetSSP1ClockDiv(div); } } /* Returns SSP peripheral clock for the peripheral block */ STATIC uint32_t Chip_SSP_GetPCLKkRate(LPC_SSP_T *pSSP) { uint32_t sspCLK = Chip_Clock_GetMainClockRate(); if (pSSP == LPC_SSP0) { sspCLK /= Chip_Clock_GetSSP0ClockDiv(); } else { sspCLK /= Chip_Clock_GetSSP1ClockDiv(); } return sspCLK; } /***************************************************************************** * Public functions ****************************************************************************/ /*Set up output clocks per bit for SSP bus*/ void Chip_SSP_SetClockRate(LPC_SSP_T *pSSP, uint32_t clk_rate, uint32_t prescale) { uint32_t temp; temp = pSSP->CR0 & (~(SSP_CR0_SCR(0xFF))); pSSP->CR0 = temp | (SSP_CR0_SCR(clk_rate)); pSSP->CPSR = prescale; } /* SSP Polling Read/Write in blocking mode */ uint32_t Chip_SSP_RWFrames_Blocking(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { /* Clear all remaining frames in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE)) { Chip_SSP_ReceiveFrame(pSSP); } /* Clear status */ Chip_SSP_ClearIntPending(pSSP, SSP_INT_CLEAR_BITMASK); if (Chip_SSP_GetDataSize(pSSP) > SSP_BITS_8) { while (xf_setup->rx_cnt < xf_setup->length || xf_setup->tx_cnt < xf_setup->length) { /* write data to buffer */ if (( Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && ( xf_setup->tx_cnt < xf_setup->length) ) { SSP_Write2BFifo(pSSP, xf_setup); } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ SSP_Read2BFifo(pSSP, xf_setup); } } else { while (xf_setup->rx_cnt < xf_setup->length || xf_setup->tx_cnt < xf_setup->length) { /* write data to buffer */ if (( Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && ( xf_setup->tx_cnt < xf_setup->length) ) { SSP_Write1BFifo(pSSP, xf_setup); } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ SSP_Read1BFifo(pSSP, xf_setup); } } if (xf_setup->tx_data) { return xf_setup->tx_cnt; } else if (xf_setup->rx_data) { return xf_setup->rx_cnt; } return 0; } /* SSP Polling Write in blocking mode */ uint32_t Chip_SSP_WriteFrames_Blocking(LPC_SSP_T *pSSP, uint8_t *buffer, uint32_t buffer_len) { uint32_t tx_cnt = 0, rx_cnt = 0; /* Clear all remaining frames in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE)) { Chip_SSP_ReceiveFrame(pSSP); } /* Clear status */ Chip_SSP_ClearIntPending(pSSP, SSP_INT_CLEAR_BITMASK); if (Chip_SSP_GetDataSize(pSSP) > SSP_BITS_8) { uint16_t *wdata16; wdata16 = (uint16_t *) buffer; while (tx_cnt < buffer_len || rx_cnt < buffer_len) { /* write data to buffer */ if ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && (tx_cnt < buffer_len)) { Chip_SSP_SendFrame(pSSP, *wdata16); wdata16++; tx_cnt += 2; } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET) { Chip_SSP_ReceiveFrame(pSSP); /* read dummy data */ rx_cnt += 2; } } } else { uint8_t *wdata8; wdata8 = buffer; while (tx_cnt < buffer_len || rx_cnt < buffer_len) { /* write data to buffer */ if ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && (tx_cnt < buffer_len)) { Chip_SSP_SendFrame(pSSP, *wdata8); wdata8++; tx_cnt++; } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET && rx_cnt < buffer_len) { Chip_SSP_ReceiveFrame(pSSP); /* read dummy data */ rx_cnt++; } } } return tx_cnt; } /* SSP Polling Read in blocking mode */ uint32_t Chip_SSP_ReadFrames_Blocking(LPC_SSP_T *pSSP, uint8_t *buffer, uint32_t buffer_len) { uint32_t rx_cnt = 0, tx_cnt = 0; /* Clear all remaining frames in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE)) { Chip_SSP_ReceiveFrame(pSSP); } /* Clear status */ Chip_SSP_ClearIntPending(pSSP, SSP_INT_CLEAR_BITMASK); if (Chip_SSP_GetDataSize(pSSP) > SSP_BITS_8) { uint16_t *rdata16; rdata16 = (uint16_t *) buffer; while (tx_cnt < buffer_len || rx_cnt < buffer_len) { /* write data to buffer */ if ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && (tx_cnt < buffer_len)) { Chip_SSP_SendFrame(pSSP, 0xFFFF); /* just send dummy data */ tx_cnt += 2; } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET && rx_cnt < buffer_len) { *rdata16 = Chip_SSP_ReceiveFrame(pSSP); rdata16++; rx_cnt += 2; } } } else { uint8_t *rdata8; rdata8 = buffer; while (tx_cnt < buffer_len || rx_cnt < buffer_len) { /* write data to buffer */ if ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF) == SET) && (tx_cnt < buffer_len)) { Chip_SSP_SendFrame(pSSP, 0xFF); /* just send dummy data */ tx_cnt++; } /* Check overrun error */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE) == SET && rx_cnt < buffer_len) { *rdata8 = Chip_SSP_ReceiveFrame(pSSP); rdata8++; rx_cnt++; } } } return rx_cnt; } /* Clean all data in RX FIFO of SSP */ void Chip_SSP_Int_FlushData(LPC_SSP_T *pSSP) { if (Chip_SSP_GetStatus(pSSP, SSP_STAT_BSY)) { while (Chip_SSP_GetStatus(pSSP, SSP_STAT_BSY)) {} } /* Clear all remaining frames in RX FIFO */ while (Chip_SSP_GetStatus(pSSP, SSP_STAT_RNE)) { Chip_SSP_ReceiveFrame(pSSP); } /* Clear status */ Chip_SSP_ClearIntPending(pSSP, SSP_INT_CLEAR_BITMASK); } /* SSP Interrupt Read/Write with 8-bit frame width */ Status Chip_SSP_Int_RWFrames8Bits(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { /* Check overrun error in RIS register */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } if ((xf_setup->tx_cnt != xf_setup->length) || (xf_setup->rx_cnt != xf_setup->length)) { /* check if RX FIFO contains data */ SSP_Read1BFifo(pSSP, xf_setup); while ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF)) && (xf_setup->tx_cnt != xf_setup->length)) { /* Write data to buffer */ SSP_Write1BFifo(pSSP, xf_setup); /* Check overrun error in RIS register */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ SSP_Read1BFifo(pSSP, xf_setup); } return SUCCESS; } return ERROR; } /* SSP Interrupt Read/Write with 16-bit frame width */ Status Chip_SSP_Int_RWFrames16Bits(LPC_SSP_T *pSSP, Chip_SSP_DATA_SETUP_T *xf_setup) { /* Check overrun error in RIS register */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } if ((xf_setup->tx_cnt != xf_setup->length) || (xf_setup->rx_cnt != xf_setup->length)) { /* check if RX FIFO contains data */ SSP_Read2BFifo(pSSP, xf_setup); while ((Chip_SSP_GetStatus(pSSP, SSP_STAT_TNF)) && (xf_setup->tx_cnt != xf_setup->length)) { /* Write data to buffer */ SSP_Write2BFifo(pSSP, xf_setup); /* Check overrun error in RIS register */ if (Chip_SSP_GetRawIntStatus(pSSP, SSP_RORRIS) == SET) { return ERROR; } /* Check for any data available in RX FIFO */ SSP_Read2BFifo(pSSP, xf_setup); } return SUCCESS; } return ERROR; } /* Set the SSP operating modes, master or slave */ void Chip_SSP_SetMaster(LPC_SSP_T *pSSP, bool master) { if (master) { Chip_SSP_Set_Mode(pSSP, SSP_MODE_MASTER); } else { Chip_SSP_Set_Mode(pSSP, SSP_MODE_SLAVE); } } /* Set the clock frequency for SSP interface */ void Chip_SSP_SetBitRate(LPC_SSP_T *pSSP, uint32_t bitRate) { uint32_t ssp_clk, cr0_div, cmp_clk, prescale; ssp_clk = Chip_SSP_GetPCLKkRate(pSSP); cr0_div = 0; cmp_clk = 0xFFFFFFFF; prescale = 2; while (cmp_clk > bitRate) { cmp_clk = ssp_clk / ((cr0_div + 1) * prescale); if (cmp_clk > bitRate) { cr0_div++; if (cr0_div > 0xFF) { cr0_div = 0; prescale += 2; } } } Chip_SSP_SetClockRate(pSSP, cr0_div, prescale); } /* Initialize the SSP */ void Chip_SSP_Init(LPC_SSP_T *pSSP) { Chip_Clock_EnablePeriphClock(Chip_SSP_GetClockIndex(pSSP)); Chip_SSP_SetSSPClkDivider(pSSP, 1); Chip_SYSCTL_PeriphReset(Chip_SSP_GetResetIndex(pSSP)); Chip_SSP_Set_Mode(pSSP, SSP_MODE_MASTER); Chip_SSP_SetFormat(pSSP, SSP_BITS_8, SSP_FRAMEFORMAT_SPI, SSP_CLOCK_CPHA0_CPOL0); Chip_SSP_SetBitRate(pSSP, 100000); } /* De-initializes the SSP peripheral */ void Chip_SSP_DeInit(LPC_SSP_T *pSSP) { Chip_SSP_Disable(pSSP); Chip_Clock_DisablePeriphClock(Chip_SSP_GetClockIndex(pSSP)); Chip_SSP_SetSSPClkDivider(pSSP, 0); }