238 lines
6.5 KiB
C
238 lines
6.5 KiB
C
/*
|
|
* 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 */
|