/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes */ #include "LPC17xx.h" /* LPC17xx definitions */ #include "spi.h" /* bit definitions for register SSPCR0. */ #define SSPCR0_DSS 0 #define SSPCR0_CPOL 6 #define SSPCR0_CPHA 7 #define SSPCR0_SCR 8 /* bit definitions for register SSPCR1. */ #define SSPCR1_SSE 1 /* bit definitions for register SSPSR. */ #define SSPSR_TFE 0 #define SSPSR_TNF 1 #define SSPSR_RNE 2 #define SSPSR_RFF 3 #define SSPSR_BSY 4 /* Local functions */ static uint8_t LPC17xx_SPI_SendRecvByte (uint8_t byte_s); /* Initialize the SSP0, SSP0_PCLK=CCLK=72MHz */ void LPC17xx_SPI_Init (void) { uint32_t dummy; dummy = dummy; // avoid warning #if 0 /* Initialize and enable the SSP0 Interface module. */ LPC_SC->PCONP |= (1 << 21); /* Enable power to SSPI0 block */ /* SSEL is GPIO, output set to high. */ LPC_GPIO0->FIODIR |= (1<<16); /* P0.16 is output */ LPC_PINCON->PINSEL1 &= ~(3<<0); /* P0.16 SSEL (used as GPIO) */ LPC17xx_SPI_DeSelect (); /* set P0.16 high (SSEL inactiv) */ /* SCK, MISO, MOSI are SSP pins. */ LPC_PINCON->PINSEL0 &= ~(3UL<<30); /* P0.15 cleared */ LPC_PINCON->PINSEL0 |= (2UL<<30); /* P0.15 SCK0 */ LPC_PINCON->PINSEL1 &= ~((3<<2) | (3<<4)); /* P0.17, P0.18 cleared */ LPC_PINCON->PINSEL1 |= ((2<<2) | (2<<4)); /* P0.17 MISO0, P0.18 MOSI0 */ #else LPC_SC->PCONP |= (1 << 21); /* Enable power to SSPI0 block */ /* SSEL is GPIO, output set to high. */ LPC_GPIO1->FIODIR |= (1<<21); /* P1.21 is output */ LPC_GPIO1->FIOPIN |= (1<<21); /* set P1.21 high (SSEL inact.)*/ LPC_PINCON->PINSEL3 &= ~(0<<10); /* P1.21 SSEL (used as GPIO) */ /* P3.26 is SD Card Power Supply Enable Pin */ LPC_GPIO3->FIODIR |= (1<<26); /* P3.26 is output */ LPC_GPIO3->FIOPIN &= ~(1<<26); /* set P3.26 low(enable power) */ /* SCK, MISO, MOSI are SSP pins. */ LPC_PINCON->PINSEL3 &= ~(3UL<<8); /* P1.20 cleared */ LPC_PINCON->PINSEL3 |= (3UL<<8); /* P1.20 SCK0 */ LPC_PINCON->PINSEL3 &= ~((3<<14) | (3<<16)); /* P1.23, P1.24 cleared */ LPC_PINCON->PINSEL3 |= ((3<<14) | (3<<16)); /* P1.23 MISO0, P1.24 MOSI0 */ #endif /* PCLK_SSP0=CCLK */ LPC_SC->PCLKSEL1 &= ~(3<<10); /* PCLKSP0 = CCLK/4 (18MHz) */ LPC_SC->PCLKSEL1 |= (1<<10); /* PCLKSP0 = CCLK (72MHz) */ LPC_SSP0->CR0 = 0x0007; /* 8Bit, CPOL=0, CPHA=0 */ LPC_SSP0->CR1 = 0x0002; /* SSP0 enable, master */ LPC17xx_SPI_SetSpeed (SPI_SPEED_400kHz); /* wait for busy gone */ while( LPC_SSP0->SR & ( 1 << SSPSR_BSY ) ); /* drain SPI RX FIFO */ while( LPC_SSP0->SR & ( 1 << SSPSR_RNE ) ) { dummy = LPC_SSP0->DR; } } /* Close SSP0 */ void LPC17xx_SPI_DeInit( void ) { // disable SPI LPC_SSP0->CR1 = 0; #if 0 // Pins to GPIO LPC_PINCON->PINSEL0 &= ~(3UL<<30); LPC_PINCON->PINSEL1 &= ~((3<<2) | (3<<4)); #else LPC_PINCON->PINSEL3 &= ~(3UL<<8); /* P1.20 cleared */ LPC_PINCON->PINSEL3 &= ~((3<<14) | (3<<16)); /* P1.23, P1.24 cleared */ #endif // disable SSP power LPC_SC->PCONP &= ~(1 << 21); } /* Set a SSP0 clock speed to desired value. */ void LPC17xx_SPI_SetSpeed (uint8_t speed) { speed &= 0xFE; if ( speed < 2 ) { speed = 2 ; } LPC_SSP0->CPSR = speed; } /* SSEL: low */ void LPC17xx_SPI_Select () { #if 0 LPC_GPIO0->FIOPIN &= ~(1<<16); #else LPC_GPIO1->FIOPIN &= ~(1<<21); /* SSEL is GPIO, set to high. */ #endif } /* SSEL: high */ void LPC17xx_SPI_DeSelect () { #if 0 LPC_GPIO0->FIOPIN |= (1<<16); #else LPC_GPIO1->FIOPIN |= (1<<21); /* SSEL is GPIO, set to high. */ #endif } /* Send one byte then recv one byte of response. */ static uint8_t LPC17xx_SPI_SendRecvByte (uint8_t byte_s) { uint8_t byte_r; LPC_SSP0->DR = byte_s; while (LPC_SSP0->SR & (1 << SSPSR_BSY) /*BSY*/); /* Wait for transfer to finish */ byte_r = LPC_SSP0->DR; return byte_r; /* Return received value */ } /* Send one byte */ void LPC17xx_SPI_SendByte (uint8_t data) { LPC17xx_SPI_SendRecvByte (data); } /* Recv one byte */ uint8_t LPC17xx_SPI_RecvByte () { return LPC17xx_SPI_SendRecvByte (0xFF); } /* Release SSP0 */ void LPC17xx_SPI_Release (void) { LPC17xx_SPI_DeSelect (); LPC17xx_SPI_RecvByte (); } #if USE_FIFO /* on LPC17xx the FIFOs have 8 elements which each can hold up to 16 bits */ #define FIFO_ELEM 8 /* Receive btr (must be multiple of 4) bytes of data and store in buff. */ void LPC17xx_SPI_RecvBlock_FIFO (uint8_t *buff, uint32_t btr) { uint32_t hwtr, startcnt, i, rec; hwtr = btr/2; /* byte number in unit of short */ if ( btr < FIFO_ELEM ) { startcnt = hwtr; } else { startcnt = FIFO_ELEM; } LPC_SSP0 -> CR0 |= 0x0f; /* DSS to 16 bit */ for ( i = startcnt; i; i-- ) { LPC_SSP0 -> DR = 0xffff; /* fill TX FIFO, prepare clk for receive */ } do { while ( !(LPC_SSP0->SR & ( 1 << SSPSR_RNE ) ) ) { // wait for data in RX FIFO (RNE set) } rec = LPC_SSP0->DR; if ( i < ( hwtr - startcnt ) ) { LPC_SSP0->DR = 0xffff; /* fill TX FIFO, prepare clk for receive */ } *buff++ = (uint8_t)(rec>>8); *buff++ = (uint8_t)(rec); i++; } while ( i < hwtr ); LPC_SSP0->CR0 &= ~0x08; /* DSS to 8 bit */ } /* Send 512 bytes of data block (stored in buff). */ void LPC17xx_SPI_SendBlock_FIFO (const uint8_t *buff) { uint32_t cnt; uint16_t data; LPC_SSP0->CR0 |= 0x0f; /* DSS to 16 bit */ /* fill the FIFO unless it is full */ for ( cnt = 0; cnt < ( 512 / 2 ); cnt++ ) { /* wait for TX FIFO not full (TNF) */ while ( !( LPC_SSP0->SR & ( 1 << SSPSR_TNF ) ) ); data = (*buff++) << 8; data |= *buff++; LPC_SSP0->DR = data; } /* wait for BSY gone */ while ( LPC_SSP0->SR & ( 1 << SSPSR_BSY ) ); /* drain receive FIFO */ while ( LPC_SSP0->SR & ( 1 << SSPSR_RNE ) ) { data = LPC_SSP0->DR; } LPC_SSP0->CR0 &= ~0x08; /* DSS to 8 bit */ } #endif /* USE_FIFO */