]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/spi_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NORDIC / TARGET_MCU_NRF51822 / spi_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2013 Nordic Semiconductor
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 //#include <math.h>
17 #include "mbed_assert.h"
18 #include "spi_api.h"
19 #include "cmsis.h"
20 #include "pinmap.h"
21 #include "mbed_error.h"
22
23 #define SPIS_MESSAGE_SIZE 1
24 volatile uint8_t m_tx_buf[SPIS_MESSAGE_SIZE] = {0};
25 volatile uint8_t m_rx_buf[SPIS_MESSAGE_SIZE] = {0};
26
27 // nRF51822's I2C_0 and SPI_0 (I2C_1, SPI_1 and SPIS1) share the same address.
28 // They can't be used at the same time. So we use two global variable to track the usage.
29 // See nRF51822 address information at nRF51822_PS v2.0.pdf - Table 15 Peripheral instance reference
30 extern volatile i2c_spi_peripheral_t i2c0_spi0_peripheral; // from i2c_api.c
31 extern volatile i2c_spi_peripheral_t i2c1_spi1_peripheral;
32
33 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
34 {
35     SPIName spi;
36     
37     if (ssel == NC && i2c0_spi0_peripheral.usage == I2C_SPI_PERIPHERAL_FOR_SPI &&
38             i2c0_spi0_peripheral.sda_mosi == (uint8_t)mosi &&
39             i2c0_spi0_peripheral.scl_miso == (uint8_t)miso &&
40             i2c0_spi0_peripheral.sclk     == (uint8_t)sclk) {
41         // The SPI with the same pins is already initialized
42         spi = SPI_0;
43         obj->peripheral = 0x1;
44     } else if (ssel == NC && i2c1_spi1_peripheral.usage == I2C_SPI_PERIPHERAL_FOR_SPI &&
45             i2c1_spi1_peripheral.sda_mosi == (uint8_t)mosi &&
46             i2c1_spi1_peripheral.scl_miso == (uint8_t)miso &&
47             i2c1_spi1_peripheral.sclk     == (uint8_t)sclk) {
48         // The SPI with the same pins is already initialized
49         spi = SPI_1;
50         obj->peripheral = 0x2;
51     } else if (i2c1_spi1_peripheral.usage == 0) {
52         i2c1_spi1_peripheral.usage = I2C_SPI_PERIPHERAL_FOR_SPI;
53         i2c1_spi1_peripheral.sda_mosi = (uint8_t)mosi;
54         i2c1_spi1_peripheral.scl_miso = (uint8_t)miso;
55         i2c1_spi1_peripheral.sclk     = (uint8_t)sclk;
56         
57         spi = SPI_1;
58         obj->peripheral = 0x2;
59     } else if (i2c0_spi0_peripheral.usage == 0) {
60         i2c0_spi0_peripheral.usage = I2C_SPI_PERIPHERAL_FOR_SPI;
61         i2c0_spi0_peripheral.sda_mosi = (uint8_t)mosi;
62         i2c0_spi0_peripheral.scl_miso = (uint8_t)miso;
63         i2c0_spi0_peripheral.sclk     = (uint8_t)sclk;
64         
65         spi = SPI_0;
66         obj->peripheral = 0x1;
67     } else {
68         // No available peripheral
69         error("No available SPI");
70     }
71
72     if (ssel==NC) {
73         obj->spi  = (NRF_SPI_Type *)spi;
74         obj->spis = (NRF_SPIS_Type *)NC;
75     } else {
76         obj->spi  = (NRF_SPI_Type *)NC;
77         obj->spis = (NRF_SPIS_Type *)spi;
78     }
79
80     // pin out the spi pins
81     if (ssel != NC) { //slave
82         obj->spis->POWER = 0;
83         obj->spis->POWER = 1;
84
85         NRF_GPIO->PIN_CNF[mosi] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
86                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
87                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
88                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
89                                     | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
90         NRF_GPIO->PIN_CNF[miso] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
91                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
92                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
93                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
94                                     | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
95         NRF_GPIO->PIN_CNF[sclk] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
96                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
97                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
98                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
99                                     | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
100         NRF_GPIO->PIN_CNF[ssel] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
101                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
102                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
103                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
104                                     | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
105
106         obj->spis->PSELMOSI = mosi;
107         obj->spis->PSELMISO = miso;
108         obj->spis->PSELSCK  = sclk;
109         obj->spis->PSELCSN  = ssel;
110
111         obj->spis->EVENTS_END      = 0;
112         obj->spis->EVENTS_ACQUIRED = 0;
113         obj->spis->MAXRX           = SPIS_MESSAGE_SIZE;
114         obj->spis->MAXTX           = SPIS_MESSAGE_SIZE;
115         obj->spis->TXDPTR          = (uint32_t)&m_tx_buf[0];
116         obj->spis->RXDPTR          = (uint32_t)&m_rx_buf[0];
117         obj->spis->SHORTS          = (SPIS_SHORTS_END_ACQUIRE_Enabled << SPIS_SHORTS_END_ACQUIRE_Pos);
118
119         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
120     } else { //master
121         obj->spi->POWER = 0;
122         obj->spi->POWER = 1;
123
124         //NRF_GPIO->DIR |= (1<<mosi);
125         NRF_GPIO->PIN_CNF[mosi] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
126                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
127                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
128                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
129                                     | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
130         obj->spi->PSELMOSI = mosi;
131
132         NRF_GPIO->PIN_CNF[sclk] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
133                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
134                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
135                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
136                                     | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
137         obj->spi->PSELSCK = sclk;
138
139         //NRF_GPIO->DIR &= ~(1<<miso);
140         NRF_GPIO->PIN_CNF[miso] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
141                                     | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
142                                     | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
143                                     | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
144                                     | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
145
146         obj->spi->PSELMISO = miso;
147
148         obj->spi->EVENTS_READY = 0U;
149
150         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
151         spi_frequency(obj, 1000000);
152     }
153 }
154
155 void spi_free(spi_t *obj)
156 {
157 }
158
159 static inline void spi_disable(spi_t *obj, int slave)
160 {
161     if (slave) {
162         obj->spis->ENABLE = (SPIS_ENABLE_ENABLE_Disabled << SPIS_ENABLE_ENABLE_Pos);
163     } else {
164         obj->spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);
165     }
166 }
167
168 static inline void spi_enable(spi_t *obj, int slave)
169 {
170     if (slave) {
171         obj->spis->ENABLE = (SPIS_ENABLE_ENABLE_Enabled << SPIS_ENABLE_ENABLE_Pos);
172     } else {
173         obj->spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
174     }
175 }
176
177 void spi_format(spi_t *obj, int bits, int mode, int slave)
178 {
179     uint32_t config_mode = 0;
180     spi_disable(obj, slave);
181
182     if (bits != 8) {
183         error("Only 8bits SPI supported");
184     }
185
186     switch (mode) {
187         case 0:
188             config_mode = (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos);
189             break;
190         case 1:
191             config_mode = (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos);
192             break;
193         case 2:
194             config_mode = (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos);
195             break;
196         case 3:
197             config_mode = (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos) | (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos);
198             break;
199         default:
200             error("SPI format error");
201             break;
202     }
203     //default to msb first
204     if (slave) {
205         obj->spis->CONFIG = (config_mode | (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos));
206     } else {
207         obj->spi->CONFIG = (config_mode | (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos));
208     }
209
210     spi_enable(obj, slave);
211 }
212
213 void spi_frequency(spi_t *obj, int hz)
214 {
215     if ((int)obj->spi==NC) {
216         return;
217     }
218     spi_disable(obj, 0);
219
220     if (hz<250000) { //125Kbps
221         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_K125;
222     } else if (hz<500000) { //250Kbps
223         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_K250;
224     } else if (hz<1000000) { //500Kbps
225         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_K500;
226     } else if (hz<2000000) { //1Mbps
227         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_M1;
228     } else if (hz<4000000) { //2Mbps
229         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_M2;
230     } else if (hz<8000000) { //4Mbps
231         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_M4;
232     } else { //8Mbps
233         obj->spi->FREQUENCY = (uint32_t) SPI_FREQUENCY_FREQUENCY_M8;
234     }
235
236     spi_enable(obj, 0);
237 }
238
239 static inline int spi_readable(spi_t *obj)
240 {
241     return (obj->spi->EVENTS_READY == 1);
242 }
243
244 static inline int spi_writeable(spi_t *obj)
245 {
246     return (obj->spi->EVENTS_READY == 0);
247 }
248
249 static inline int spi_read(spi_t *obj)
250 {
251     while (!spi_readable(obj)) {
252     }
253
254     obj->spi->EVENTS_READY = 0;
255     return (int)obj->spi->RXD;
256 }
257
258 int spi_master_write(spi_t *obj, int value)
259 {
260     while (!spi_writeable(obj)) {
261     }
262     obj->spi->TXD = (uint32_t)value;
263     return spi_read(obj);
264 }
265
266 //static inline int spis_writeable(spi_t *obj) {
267 //    return (obj->spis->EVENTS_ACQUIRED==1);
268 //}
269
270 int spi_slave_receive(spi_t *obj)
271 {
272     return obj->spis->EVENTS_END;
273 }
274
275 int spi_slave_read(spi_t *obj)
276 {
277     return m_rx_buf[0];
278 }
279
280 void spi_slave_write(spi_t *obj, int value)
281 {
282     m_tx_buf[0]                = value & 0xFF;
283     obj->spis->TASKS_RELEASE   = 1;
284     obj->spis->EVENTS_ACQUIRED = 0;
285     obj->spis->EVENTS_END      = 0;
286 }