1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9
10 #include "LPC17xx.h" /* LPC17xx definitions */
11 #include "spi.h"
12
13 /* bit definitions for register SSPCR0. */
14 #define SSPCR0_DSS 0
15 #define SSPCR0_CPOL 6
16 #define SSPCR0_CPHA 7
17 #define SSPCR0_SCR 8
18 /* bit definitions for register SSPCR1. */
19 #define SSPCR1_SSE 1
20 /* bit definitions for register SSPSR. */
21 #define SSPSR_TFE 0
22 #define SSPSR_TNF 1
23 #define SSPSR_RNE 2
24 #define SSPSR_RFF 3
25 #define SSPSR_BSY 4
26
27 /* Local functions */
28 static uint8_t LPC17xx_SPI_SendRecvByte (uint8_t byte_s);
29
30 /* Initialize the SSP0, SSP0_PCLK=CCLK=72MHz */
LPC17xx_SPI_Init(void)31 void LPC17xx_SPI_Init (void)
32 {
33 uint32_t dummy;
34
35 dummy = dummy; // avoid warning
36
37 #if 0
38 /* Initialize and enable the SSP0 Interface module. */
39 LPC_SC->PCONP |= (1 << 21); /* Enable power to SSPI0 block */
40
41 /* SSEL is GPIO, output set to high. */
42 LPC_GPIO0->FIODIR |= (1<<16); /* P0.16 is output */
43 LPC_PINCON->PINSEL1 &= ~(3<<0); /* P0.16 SSEL (used as GPIO) */
44 LPC17xx_SPI_DeSelect (); /* set P0.16 high (SSEL inactiv) */
45
46 /* SCK, MISO, MOSI are SSP pins. */
47 LPC_PINCON->PINSEL0 &= ~(3UL<<30); /* P0.15 cleared */
48 LPC_PINCON->PINSEL0 |= (2UL<<30); /* P0.15 SCK0 */
49 LPC_PINCON->PINSEL1 &= ~((3<<2) | (3<<4)); /* P0.17, P0.18 cleared */
50 LPC_PINCON->PINSEL1 |= ((2<<2) | (2<<4)); /* P0.17 MISO0, P0.18 MOSI0 */
51 #else
52 LPC_SC->PCONP |= (1 << 21); /* Enable power to SSPI0 block */
53
54 /* SSEL is GPIO, output set to high. */
55 LPC_GPIO1->FIODIR |= (1<<21); /* P1.21 is output */
56 LPC_GPIO1->FIOPIN |= (1<<21); /* set P1.21 high (SSEL inact.)*/
57 LPC_PINCON->PINSEL3 &= ~(0<<10); /* P1.21 SSEL (used as GPIO) */
58
59 /* P3.26 is SD Card Power Supply Enable Pin */
60 LPC_GPIO3->FIODIR |= (1<<26); /* P3.26 is output */
61 LPC_GPIO3->FIOPIN &= ~(1<<26); /* set P3.26 low(enable power) */
62
63 /* SCK, MISO, MOSI are SSP pins. */
64 LPC_PINCON->PINSEL3 &= ~(3UL<<8); /* P1.20 cleared */
65 LPC_PINCON->PINSEL3 |= (3UL<<8); /* P1.20 SCK0 */
66 LPC_PINCON->PINSEL3 &= ~((3<<14) | (3<<16)); /* P1.23, P1.24 cleared */
67 LPC_PINCON->PINSEL3 |= ((3<<14) | (3<<16)); /* P1.23 MISO0, P1.24 MOSI0 */
68 #endif
69
70 /* PCLK_SSP0=CCLK */
71 LPC_SC->PCLKSEL1 &= ~(3<<10); /* PCLKSP0 = CCLK/4 (18MHz) */
72 LPC_SC->PCLKSEL1 |= (1<<10); /* PCLKSP0 = CCLK (72MHz) */
73
74 LPC_SSP0->CR0 = 0x0007; /* 8Bit, CPOL=0, CPHA=0 */
75 LPC_SSP0->CR1 = 0x0002; /* SSP0 enable, master */
76
77 LPC17xx_SPI_SetSpeed (SPI_SPEED_400kHz);
78
79 /* wait for busy gone */
80 while( LPC_SSP0->SR & ( 1 << SSPSR_BSY ) );
81
82 /* drain SPI RX FIFO */
83 while( LPC_SSP0->SR & ( 1 << SSPSR_RNE ) )
84 {
85 dummy = LPC_SSP0->DR;
86 }
87 }
88
89 /* Close SSP0 */
LPC17xx_SPI_DeInit(void)90 void LPC17xx_SPI_DeInit( void )
91 {
92 // disable SPI
93 LPC_SSP0->CR1 = 0;
94
95 #if 0
96 // Pins to GPIO
97 LPC_PINCON->PINSEL0 &= ~(3UL<<30);
98 LPC_PINCON->PINSEL1 &= ~((3<<2) | (3<<4));
99 #else
100 LPC_PINCON->PINSEL3 &= ~(3UL<<8); /* P1.20 cleared */
101 LPC_PINCON->PINSEL3 &= ~((3<<14) | (3<<16)); /* P1.23, P1.24 cleared */
102 #endif
103
104 // disable SSP power
105 LPC_SC->PCONP &= ~(1 << 21);
106 }
107
108 /* Set a SSP0 clock speed to desired value. */
LPC17xx_SPI_SetSpeed(uint8_t speed)109 void LPC17xx_SPI_SetSpeed (uint8_t speed)
110 {
111 speed &= 0xFE;
112 if ( speed < 2 ) {
113 speed = 2 ;
114 }
115 LPC_SSP0->CPSR = speed;
116 }
117
118 /* SSEL: low */
LPC17xx_SPI_Select()119 void LPC17xx_SPI_Select ()
120 {
121 #if 0
122 LPC_GPIO0->FIOPIN &= ~(1<<16);
123 #else
124 LPC_GPIO1->FIOPIN &= ~(1<<21); /* SSEL is GPIO, set to high. */
125 #endif
126 }
127
128 /* SSEL: high */
LPC17xx_SPI_DeSelect()129 void LPC17xx_SPI_DeSelect ()
130 {
131 #if 0
132 LPC_GPIO0->FIOPIN |= (1<<16);
133 #else
134 LPC_GPIO1->FIOPIN |= (1<<21); /* SSEL is GPIO, set to high. */
135 #endif
136 }
137
138 /* Send one byte then recv one byte of response. */
LPC17xx_SPI_SendRecvByte(uint8_t byte_s)139 static uint8_t LPC17xx_SPI_SendRecvByte (uint8_t byte_s)
140 {
141 uint8_t byte_r;
142
143 LPC_SSP0->DR = byte_s;
144 while (LPC_SSP0->SR & (1 << SSPSR_BSY) /*BSY*/); /* Wait for transfer to finish */
145 byte_r = LPC_SSP0->DR;
146
147 return byte_r; /* Return received value */
148 }
149
150 /* Send one byte */
LPC17xx_SPI_SendByte(uint8_t data)151 void LPC17xx_SPI_SendByte (uint8_t data)
152 {
153 LPC17xx_SPI_SendRecvByte (data);
154 }
155
156 /* Recv one byte */
LPC17xx_SPI_RecvByte()157 uint8_t LPC17xx_SPI_RecvByte ()
158 {
159 return LPC17xx_SPI_SendRecvByte (0xFF);
160 }
161
162 /* Release SSP0 */
LPC17xx_SPI_Release(void)163 void LPC17xx_SPI_Release (void)
164 {
165 LPC17xx_SPI_DeSelect ();
166 LPC17xx_SPI_RecvByte ();
167 }
168
169
170 #if USE_FIFO
171 /* on LPC17xx the FIFOs have 8 elements which each can hold up to 16 bits */
172 #define FIFO_ELEM 8
173
174 /* Receive btr (must be multiple of 4) bytes of data and store in buff. */
LPC17xx_SPI_RecvBlock_FIFO(uint8_t * buff,uint32_t btr)175 void LPC17xx_SPI_RecvBlock_FIFO (uint8_t *buff, uint32_t btr)
176 {
177 uint32_t hwtr, startcnt, i, rec;
178
179 hwtr = btr/2; /* byte number in unit of short */
180 if ( btr < FIFO_ELEM ) {
181 startcnt = hwtr;
182 } else {
183 startcnt = FIFO_ELEM;
184 }
185
186 LPC_SSP0 -> CR0 |= 0x0f; /* DSS to 16 bit */
187
188 for ( i = startcnt; i; i-- ) {
189 LPC_SSP0 -> DR = 0xffff; /* fill TX FIFO, prepare clk for receive */
190 }
191
192 do {
193 while ( !(LPC_SSP0->SR & ( 1 << SSPSR_RNE ) ) ) {
194 // wait for data in RX FIFO (RNE set)
195 }
196 rec = LPC_SSP0->DR;
197 if ( i < ( hwtr - startcnt ) ) {
198 LPC_SSP0->DR = 0xffff; /* fill TX FIFO, prepare clk for receive */
199 }
200 *buff++ = (uint8_t)(rec>>8);
201 *buff++ = (uint8_t)(rec);
202 i++;
203 } while ( i < hwtr );
204
205 LPC_SSP0->CR0 &= ~0x08; /* DSS to 8 bit */
206 }
207
208 /* Send 512 bytes of data block (stored in buff). */
LPC17xx_SPI_SendBlock_FIFO(const uint8_t * buff)209 void LPC17xx_SPI_SendBlock_FIFO (const uint8_t *buff)
210 {
211 uint32_t cnt;
212 uint16_t data;
213
214 LPC_SSP0->CR0 |= 0x0f; /* DSS to 16 bit */
215
216 /* fill the FIFO unless it is full */
217 for ( cnt = 0; cnt < ( 512 / 2 ); cnt++ )
218 {
219 /* wait for TX FIFO not full (TNF) */
220 while ( !( LPC_SSP0->SR & ( 1 << SSPSR_TNF ) ) );
221
222 data = (*buff++) << 8;
223 data |= *buff++;
224 LPC_SSP0->DR = data;
225 }
226
227 /* wait for BSY gone */
228 while ( LPC_SSP0->SR & ( 1 << SSPSR_BSY ) );
229
230 /* drain receive FIFO */
231 while ( LPC_SSP0->SR & ( 1 << SSPSR_RNE ) ) {
232 data = LPC_SSP0->DR;
233 }
234
235 LPC_SSP0->CR0 &= ~0x08; /* DSS to 8 bit */
236 }
237 #endif /* USE_FIFO */
238