1 /**************************************************************************//**
2 * @file
3 * @brief SPI implementation of Board Control interface
4 * This implementation use the USART2 SPI interface to control board
5 * control registers. It works
6 * @author Energy Micro AS
7 * @version 2.0.1
8 ******************************************************************************
9 * @section License
10 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
11 *******************************************************************************
12 *
13 * Permission is granted to anyone to use this software for any purpose,
14 * including commercial applications, and to alter it and redistribute it
15 * freely, subject to the following restrictions:
16 *
17 * 1. The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
22 * 4. The source and compiled code may only be used on Energy Micro "EFM32"
23 * microcontrollers and "EFR4" radios.
24 *
25 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
26 * obligation to support this Software. Energy Micro AS is providing the
27 * Software "AS IS", with no express or implied warranties of any kind,
28 * including, but not limited to, any implied warranties of merchantability
29 * or fitness for any particular purpose or warranties against infringement
30 * of any proprietary rights of a third party.
31 *
32 * Energy Micro AS will not be liable for any consequential, incidental, or
33 * special damages, or any other relief, or for any claim by any third party,
34 * arising from your use of this Software.
35 *
36 *****************************************************************************/
37
38 /***************************************************************************//**
39 * @addtogroup BSP
40 * @{
41 ******************************************************************************/
42
43 #include <stdio.h>
44 #include "efm32.h"
45 #include "em_usart.h"
46 #include "em_gpio.h"
47 #include "em_cmu.h"
48 #include "dvk.h"
49 #include "dvk_bcregisters.h"
50
51 #ifdef _EFM32_TINY_FAMILY
52
53 /* USART used for SPI access */
54 #define USART_USED USART0
55 #define USART_CLK cmuClock_USART0
56
57 /* GPIO pins used, please refer to DVK user guide. */
58 #define PIN_SPIBUS_CONNECT 13
59 #define PORT_SPIBUS_CONNECT gpioPortC
60 #define PIN_SPI_TX 10
61 #define PORT_SPI_TX gpioPortE
62 #define PIN_SPI_RX 11
63 #define PORT_SPI_RX gpioPortE
64 #define PIN_SPI_CLK 12
65 #define PORT_SPI_CLK gpioPortE
66 #define PIN_SPI_CS 13
67 #define PORT_SPI_CS gpioPortE
68
69 #else
70
71 /* USART used for SPI access */
72 #define USART_USED USART2
73 #define USART_CLK cmuClock_USART2
74
75 /* GPIO pins used, please refer to DVK user guide. */
76 #define PIN_SPIBUS_CONNECT 13
77 #define PORT_SPIBUS_CONNECT gpioPortC
78 #define PIN_EBIBUS_CONNECT 12
79 #define PORT_EBIBUS_CONNECT gpioPortC
80 #define PIN_SPI_TX 2
81 #define PORT_SPI_TX gpioPortC
82 #define PIN_SPI_RX 3
83 #define PORT_SPI_RX gpioPortC
84 #define PIN_SPI_CLK 4
85 #define PORT_SPI_CLK gpioPortC
86 #define PIN_SPI_CS 5
87 #define PORT_SPI_CS gpioPortC
88
89 #endif
90
91 static volatile uint16_t *lastAddr = NULL;
92
93 /**************************************************************************//**
94 * @brief Initializes SPI interface for access to FPGA registers
95 * for board control
96 *****************************************************************************/
spiInit(void)97 static void spiInit(void)
98 {
99 USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
100
101 /* Enable module clocks */
102 CMU_ClockEnable(cmuClock_GPIO, true);
103 CMU_ClockEnable(cmuClock_HFPER, true);
104 CMU_ClockEnable(USART_CLK, true);
105
106 /* Configure SPI bus connect pins, DOUT set to 0, disable EBI */
107 GPIO_PinModeSet(PORT_SPIBUS_CONNECT, PIN_SPIBUS_CONNECT, gpioModePushPull, 0);
108 GPIO_PinModeSet(PORT_EBIBUS_CONNECT, PIN_EBIBUS_CONNECT, gpioModePushPull, 1);
109
110 /* Configure SPI pins */
111 GPIO_PinModeSet(PORT_SPI_TX, PIN_SPI_TX, gpioModePushPull, 0);
112 GPIO_PinModeSet(PORT_SPI_RX, PIN_SPI_RX, gpioModePushPull, 0);
113 GPIO_PinModeSet(PORT_SPI_CLK, PIN_SPI_CLK, gpioModePushPull, 0);
114 /* Keep CS high to not activate slave */
115 GPIO_PinModeSet(PORT_SPI_CS, PIN_SPI_CS, gpioModePushPull, 1);
116
117 /* Configure to use SPI master with manual CS */
118 /* For now, configure SPI for worst case 32MHz clock in order to work for all */
119 /* configurations. */
120 init.refFreq = 32000000;
121 init.baudrate = 7000000;
122 USART_InitSync(USART_USED, &init);
123
124 /* Enable pins at default location */
125 USART_USED->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_CLKPEN;
126 }
127
128 /**************************************************************************//**
129 * @brief Disables GPIO pins and USART from FPGA register access
130 *****************************************************************************/
spiDisable(void)131 static void spiDisable(void)
132 {
133 USART_Reset(USART_USED);
134
135 /* Disable LCD_SELECT */
136 GPIO_PinModeSet(gpioPortD, 13, gpioModeDisabled, 0);
137
138 /* Disable SPI pins */
139 GPIO_PinModeSet(PORT_SPIBUS_CONNECT, 13, gpioModeDisabled, 0);
140 GPIO_PinModeSet(PORT_SPIBUS_CONNECT, 12, gpioModeDisabled, 0);
141 GPIO_PinModeSet(PORT_SPI_TX, PIN_SPI_TX, gpioModeDisabled, 0);
142 GPIO_PinModeSet(PORT_SPI_RX, PIN_SPI_RX, gpioModeDisabled, 0);
143 GPIO_PinModeSet(PORT_SPI_CLK, PIN_SPI_CLK, gpioModeDisabled, 0);
144 GPIO_PinModeSet(PORT_SPI_CS, PIN_SPI_CS, gpioModeDisabled, 0);
145
146 /* Disable USART clock - we can't disable GPIO or HFPER as we don't know who else
147 * might be using it */
148 CMU_ClockEnable(USART_CLK, false);
149 }
150
151 /**************************************************************************//**
152 * @brief Perform SPI Transfer
153 *****************************************************************************/
spiAccess(uint8_t spiaddr,uint8_t rw,uint16_t spidata)154 static uint16_t spiAccess(uint8_t spiaddr, uint8_t rw, uint16_t spidata)
155 {
156 uint16_t tmp;
157
158 GPIO_PinOutClear(PORT_SPI_CS, PIN_SPI_CS);
159
160 /* For every byte sent, one is received */
161
162 /* Write SPI address */
163 USART_Tx(USART_USED, (spiaddr & 0x3) | rw << 3);
164 /* Just ignore data read back */
165 USART_Rx(USART_USED);
166
167 /* SPI data LSB */
168 USART_Tx(USART_USED, spidata & 0xFF);
169 tmp = (uint16_t)USART_Rx(USART_USED);
170
171 /* SPI data MSB */
172 USART_Tx(USART_USED, spidata >> 8);
173 tmp |= (uint16_t)USART_Rx(USART_USED) << 8;
174
175 GPIO_PinOutSet(PORT_SPI_CS, PIN_SPI_CS);
176
177 return tmp;
178 }
179
180 /**************************************************************************//**
181 * @brief Performs SPI write to FPGA register
182 * @param spiadr Address of register
183 * @param spidata Data to write
184 *****************************************************************************/
spiWrite(uint8_t spiadr,uint16_t spidata)185 static void spiWrite(uint8_t spiadr, uint16_t spidata)
186 {
187 spiAccess(spiadr, 0, spidata);
188 }
189
190 /**************************************************************************//**
191 * @brief Performs SPI read from FPGA register
192 * @param spiadr Address of register
193 * @param spidata Dummy data
194 *****************************************************************************/
spiRead(uint8_t spiadr,uint16_t spidata)195 static uint16_t spiRead(uint8_t spiadr, uint16_t spidata)
196 {
197 return spiAccess(spiadr, 1, spidata);
198 }
199
200 /**************************************************************************//**
201 * @brief Initializes DVK register access
202 * @return true on success, false on failure
203 *****************************************************************************/
DVK_SPI_init(void)204 bool DVK_SPI_init(void)
205 {
206 uint16_t spiMagic;
207
208 spiInit();
209 /* Read "board control Magic" register to verify SPI is up and running */
210 /* if not FPGA is configured to be in EBI mode */
211
212 spiMagic = DVK_SPI_readRegister(BC_MAGIC);
213 if(spiMagic != BC_MAGIC_VALUE)
214 {
215 return false;
216 }
217 else
218 {
219 return true;
220 }
221 }
222
223 /**************************************************************************//**
224 * @brief Disable and free up resources used by SPI board control access
225 *****************************************************************************/
DVK_SPI_disable(void)226 void DVK_SPI_disable(void)
227 {
228 spiDisable();
229 }
230
231 /**************************************************************************//**
232 * @brief Perform read from DVK board control register
233 * @param addr Address of register to read from
234 *****************************************************************************/
DVK_SPI_readRegister(volatile uint16_t * addr)235 uint16_t DVK_SPI_readRegister(volatile uint16_t *addr)
236 {
237 uint16_t data;
238
239 if (addr != lastAddr)
240 {
241 spiWrite(0x00, 0xFFFF & ((uint32_t) addr)); /*LSBs of address*/
242 spiWrite(0x01, 0xFF & ((uint32_t) addr >> 16)); /*MSBs of address*/
243 spiWrite(0x02, (0x0C000000 & (uint32_t) addr) >> 26); /*Chip select*/
244 }
245 /* Read twice */
246 data = spiRead(0x03, 0);
247 data = spiRead(0x03, 0);
248 lastAddr = addr;
249 return data;
250 }
251
252 /**************************************************************************//**
253 * @brief Perform write to DVK board control register
254 * @param addr Address of register to write to
255 * @param data 16-bit to write into register
256 *****************************************************************************/
DVK_SPI_writeRegister(volatile uint16_t * addr,uint16_t data)257 void DVK_SPI_writeRegister(volatile uint16_t *addr, uint16_t data)
258 {
259 if (addr != lastAddr)
260 {
261 spiWrite(0x00, 0xFFFF & ((uint32_t) addr)); /*LSBs of address*/
262 spiWrite(0x01, 0xFF & ((uint32_t) addr >> 16)); /*MSBs of address*/
263 spiWrite(0x02, (0x0C000000 & (uint32_t) addr) >> 26); /*Chip select*/
264 }
265 spiWrite(0x03, data); /*Data*/
266 lastAddr = addr;
267 }
268
269 /** @} (end group BSP) */
270