summaryrefslogtreecommitdiff
path: root/bsp/lpc176x/drivers/spi.c
blob: a6561195c547f8a869d09feb981691011672250a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#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 */