Vasily Davydov 25545eb2ea root: init project
Adding basic board repos, main
2022-09-14 11:05:10 +03:00

308 lines
9.4 KiB
C

/*
* @brief LPC15xx SPI driver
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* 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 SPI_Send_Data_RxIgnore(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame_RxIgnore(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize, pXfSetup->ssel);
}
else {
Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
}
pXfSetup->TxCnt++;
}
STATIC void SPI_Send_Data(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->TxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt], pXfSetup->DataSize, pXfSetup->ssel);
}
else {
Chip_SPI_SendMidFrame(pSPI, pXfSetup->pTx[pXfSetup->TxCnt]);
}
pXfSetup->TxCnt++;
}
STATIC void SPI_Send_Dummy(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
if (pXfSetup->RxCnt == (pXfSetup->Length - 1)) {
Chip_SPI_SendLastFrame(pSPI, 0x55, pXfSetup->DataSize, pXfSetup->ssel);
}
else {
Chip_SPI_SendMidFrame(pSPI, 0x55);
}
}
STATIC void SPI_Receive_Data(LPC_SPI_T *pSPI,
SPI_DATA_SETUP_T *pXfSetup)
{
pXfSetup->pRx[pXfSetup->RxCnt] = Chip_SPI_ReceiveFrame(pSPI);
pXfSetup->RxCnt++;
}
/*****************************************************************************
* Public functions
****************************************************************************/
/* Calculate the Clock Rate Divider for SPI Peripheral */
uint32_t Chip_SPI_CalClkRateDivider(LPC_SPI_T *pSPI, uint32_t bitRate)
{
uint32_t SPIClk;
uint32_t DivVal;
/* Get SPI clock rate */
SPIClk = Chip_Clock_GetSystemClockRate(); /*The peripheral clock for both SPIs is the system clock*/
DivVal = SPIClk / bitRate;
return DivVal - 1;
}
/* Set SPI Config register */
void Chip_SPI_SetConfig(LPC_SPI_T *pSPI, SPI_CFG_T *pConfig)
{
uint32_t EnStat = pSPI->CFG & SPI_CFG_SPI_EN;
/* Disable before update CFG register */
if (EnStat) {
Chip_SPI_Disable(pSPI);
}
/* SPI Configure */
pSPI->CFG = ((uint32_t) pConfig->ClockMode) | ((uint32_t) pConfig->DataOrder) | ((uint32_t) pConfig->Mode) |
((uint32_t) pConfig->SSELPol);
/* Rate Divider setting */
pSPI->DIV = SPI_DIV_VAL(pConfig->ClkDiv);
/* Clear status flag*/
Chip_SPI_ClearStatus(
pSPI,
SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
SPI_STAT_FORCE_EOT);
/* Return the previous state */
if (EnStat) {
Chip_SPI_Enable(pSPI);
}
}
void Chip_SPI_Init(LPC_SPI_T *pSPI)
{
if (pSPI == LPC_SPI1) {
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI1);
Chip_SYSCTL_PeriphReset(RESET_SPI1);
}
else {
Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SPI0);
Chip_SYSCTL_PeriphReset(RESET_SPI0);
}
}
/* De-initializes the SPI peripheral */
void Chip_SPI_DeInit(LPC_SPI_T *pSPI)
{
Chip_SPI_Disable(pSPI);
Chip_Clock_DisablePeriphClock((pSPI == LPC_SPI1) ? SYSCTL_CLOCK_SPI1 : SYSCTL_CLOCK_SPI0);
}
/* Configure SPI Delay parameters */
void Chip_SPI_DelayConfig(LPC_SPI_T *pSPI, SPI_DELAY_CONFIG_T *pConfig)
{
pSPI->DLY = SPI_DLY_PRE_DELAY(pConfig->PreDelay);
pSPI->DLY |= SPI_DLY_POST_DELAY(pConfig->PostDelay);
pSPI->DLY |= SPI_DLY_FRAME_DELAY(pConfig->FrameDelay);
if (pConfig->TransferDelay) {
pSPI->DLY |= SPI_DLY_TRANSFER_DELAY(pConfig->TransferDelay - 1);
}
}
/* Disable/Enable Interrupt */
void Chip_SPI_Int_Cmd(LPC_SPI_T *pSPI, uint32_t IntMask, FunctionalState NewState)
{
if (NewState == ENABLE) {
pSPI->INTENSET |= (IntMask & SPI_INTENSET_BITMASK);
}
else {
pSPI->INTENCLR = (IntMask & SPI_INTENCLR_BITMASK);
}
}
/*Send and Receive SPI Data */
uint32_t Chip_SPI_RWFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
uint32_t Status;
/* Clear status */
Chip_SPI_ClearStatus(
pSPI,
SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
SPI_STAT_FORCE_EOT);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while ((pXfSetup->TxCnt < pXfSetup->Length) ||
(pXfSetup->RxCnt < pXfSetup->Length)) {
Status = Chip_SPI_GetStatus(pSPI);
/* In case of TxReady */
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data(pSPI, pXfSetup);
}
/*In case of Rx ready */
if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
SPI_Receive_Data(pSPI, pXfSetup);
}
}
/* Check error */
if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
return 0;
}
return pXfSetup->TxCnt;
}
uint32_t Chip_SPI_WriteFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
/* Clear status */
Chip_SPI_ClearStatus(
pSPI,
SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
SPI_STAT_FORCE_EOT);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF | SPI_TXCTL_RXIGNORE);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while (pXfSetup->TxCnt < pXfSetup->Length) {
/* Wait for TxReady */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
}
/* Make sure the last frame sent completely*/
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_SSD)) {}
Chip_SPI_ClearStatus(pSPI, SPI_STAT_CLR_SSD);
/* Check overrun error */
if (Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXUR) {
return 0;
}
return pXfSetup->TxCnt;
}
uint32_t Chip_SPI_ReadFrames_Blocking(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
/* Clear status */
Chip_SPI_ClearStatus(
pSPI,
SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR | SPI_STAT_CLR_SSA | SPI_STAT_CLR_SSD |
SPI_STAT_FORCE_EOT);
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
pXfSetup->TxCnt = pXfSetup->RxCnt = 0;
while (pXfSetup->RxCnt < pXfSetup->Length) {
/* Wait for TxReady */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_TXRDY)) {}
SPI_Send_Dummy(pSPI, pXfSetup);
/* Wait for receive data */
while (!(Chip_SPI_GetStatus(pSPI) & SPI_STAT_RXRDY)) {}
SPI_Receive_Data(pSPI, pXfSetup);
}
/* Check overrun error */
if (Chip_SPI_GetStatus(pSPI) & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
return 0;
}
return pXfSetup->RxCnt;
}
/* SPI Interrupt Read/Write with 8-bit frame width */
Status Chip_SPI_Int_RWFrames(LPC_SPI_T *pSPI, SPI_DATA_SETUP_T *pXfSetup)
{
uint32_t Status;
Status = Chip_SPI_GetStatus(pSPI);
/* Check error in STAT register */
if (Status & (SPI_STAT_RXOV | SPI_STAT_TXUR)) {
/* Clear errors */
Chip_SPI_ClearStatus(pSPI, SPI_STAT_CLR_RXOV | SPI_STAT_CLR_TXUR);
return ERROR;
}
if (pXfSetup->TxCnt == 0) {
if (pXfSetup->pRx == NULL) {
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF | SPI_TXCTL_RXIGNORE);
}
else {
Chip_SPI_SetControlInfo(pSPI, pXfSetup->DataSize, pXfSetup->ssel | SPI_TXCTL_EOF);
}
}
if (pXfSetup->pRx == NULL) {
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data_RxIgnore(pSPI, pXfSetup);
}
}
else {
/* check if Tx ready */
if ((Status & SPI_STAT_TXRDY) && (pXfSetup->TxCnt < pXfSetup->Length)) {
SPI_Send_Data(pSPI, pXfSetup);
}
/* check if RX FIFO contains data */
if ((Status & SPI_STAT_RXRDY) && (pXfSetup->RxCnt < pXfSetup->Length)) {
SPI_Receive_Data(pSPI, pXfSetup);
}
}
return SUCCESS;
}