]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4XX/spi_api.c
Merge commit 'fdc38ef3f92af7adeeb4de49550d8838c8a39b5c'
[max/tmk_keyboard.git] / tmk_core / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_STM / TARGET_STM32F4XX / spi_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
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 "mbed_assert.h"
17 #include "spi_api.h"
18
19 #if DEVICE_SPI
20 #include <math.h>
21
22 #include "cmsis.h"
23 #include "pinmap.h"
24
25 static const PinMap PinMap_SPI_SCLK[] = {
26     {PA_5,  SPI_1, STM_PIN_DATA(2, 5)},
27     {PB_3,  SPI_1, STM_PIN_DATA(2, 5)},
28     {PB_3,  SPI_3, STM_PIN_DATA(2, 6)},
29     {PB_10, SPI_2, STM_PIN_DATA(2, 5)},
30     {PB_13, SPI_2, STM_PIN_DATA(2, 5)},
31     {PC_10, SPI_3, STM_PIN_DATA(2, 6)},
32     {NC,    NC,    0}
33 };
34
35 static const PinMap PinMap_SPI_MOSI[] = {
36     {PA_7,  SPI_1, STM_PIN_DATA(2, 5)},
37     {PB_5,  SPI_1, STM_PIN_DATA(2, 5)},
38     {PB_5,  SPI_3, STM_PIN_DATA(2, 6)},
39     {PB_15, SPI_2, STM_PIN_DATA(2, 5)},
40     {PC_3,  SPI_2, STM_PIN_DATA(2, 5)},
41     {PC_12, SPI_3, STM_PIN_DATA(2, 6)},
42     {NC,    NC,    0}
43 };
44
45 static const PinMap PinMap_SPI_MISO[] = {
46     {PA_6,  SPI_1, STM_PIN_DATA(2, 5)},
47     {PB_4,  SPI_1, STM_PIN_DATA(2, 5)},
48     {PB_4,  SPI_3, STM_PIN_DATA(2, 6)},
49     {PB_14, SPI_2, STM_PIN_DATA(2, 5)},
50     {PC_2,  SPI_2, STM_PIN_DATA(2, 5)},
51     {PC_11, SPI_3, STM_PIN_DATA(2, 6)},
52     {NC,    NC,    0}
53 };
54
55 static const PinMap PinMap_SPI_SSEL[] = {
56     {PA_4,  SPI_1, STM_PIN_DATA(2, 5)},
57     {PA_4,  SPI_3, STM_PIN_DATA(2, 6)},
58     {PA_15, SPI_1, STM_PIN_DATA(2, 5)},
59     {PA_15, SPI_3, STM_PIN_DATA(2, 6)},
60     {PB_9,  SPI_2, STM_PIN_DATA(2, 5)},
61     {PB_12, SPI_2, STM_PIN_DATA(2, 5)},
62     {NC,    NC,    0}
63 };
64
65
66 static inline int ssp_disable(spi_t *obj);
67 static inline int ssp_enable(spi_t *obj);
68
69 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
70     // determine the SPI to use
71     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
72     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
73     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
74     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
75     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
76     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
77     obj->spi = (SPI_TypeDef*)pinmap_merge(spi_data, spi_cntl);
78     MBED_ASSERT((int)obj->spi != NC);
79
80     // enable power and clocking
81     switch ((int)obj->spi) {
82         case SPI_1:
83             RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN;
84             RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
85             break;
86         case SPI_2:
87             RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
88             RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
89             break;
90         case SPI_3:
91             RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
92             RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
93             break;
94     }
95     
96
97     // set default format and frequency
98     if (ssel == NC) {
99         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
100     } else {
101         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
102     }
103     spi_frequency(obj, 1000000);
104     
105     // enable the ssp channel
106     ssp_enable(obj);
107
108     // pin out the spi pins
109     pinmap_pinout(mosi, PinMap_SPI_MOSI);
110     pinmap_pinout(miso, PinMap_SPI_MISO);
111     pinmap_pinout(sclk, PinMap_SPI_SCLK);
112     if (ssel != NC) {
113         pinmap_pinout(ssel, PinMap_SPI_SSEL);
114     }
115     else {
116         // Use software slave management
117         obj->spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
118     }
119 }
120
121 void spi_free(spi_t *obj) {}
122
123 void spi_format(spi_t *obj, int bits, int mode, int slave) {
124     MBED_ASSERT(((bits == 8) || (bits == 16)) && ((mode >= 0) && (mode <= 3)));
125     ssp_disable(obj);
126
127     int polarity = (mode & 0x2) ? 1 : 0;
128     int phase = (mode & 0x1) ? 1 : 0;
129
130     obj->spi->CR1 &= ~0x807;
131     obj->spi->CR1 |= ((phase) ? 1 : 0) << 0 |
132                      ((polarity) ? 1 : 0) << 1 |
133                      ((slave) ? 0: 1) << 2 |
134                      ((bits == 16) ? 1 : 0) << 11;
135
136     if (obj->spi->SR & SPI_SR_MODF) {
137         obj->spi->CR1 = obj->spi->CR1;
138     }
139
140     ssp_enable(obj);
141 }
142
143 void spi_frequency(spi_t *obj, int hz) {
144     ssp_disable(obj);
145
146     // SPI1 runs from PCLK2, which runs at SystemCoreClock / 2.  SPI2 and SPI3
147     // run from PCLK1, which runs at SystemCoreClock / 4.
148     uint32_t PCLK = SystemCoreClock;
149     switch ((int)obj->spi) {
150         case SPI_1: PCLK = PCLK >> 1; break;
151         case SPI_2: PCLK = PCLK >> 2; break;
152         case SPI_3: PCLK = PCLK >> 2; break;
153     }
154
155     // Choose the baud rate divisor (between 2 and 256)
156     uint32_t divisor = PCLK / hz;
157
158     // Find the nearest power-of-2
159     divisor = divisor > 0 ? divisor-1 : 0;
160     divisor |= divisor >> 1;
161     divisor |= divisor >> 2;
162     divisor |= divisor >> 4;
163     divisor |= divisor >> 8;
164     divisor |= divisor >> 16;
165     divisor++;
166
167     uint32_t baud_rate = __builtin_ffs(divisor) - 1;
168     baud_rate = baud_rate > 0x7 ? 0x7 : baud_rate;
169
170     obj->spi->CR1 &= ~(0x7 << 3);
171     obj->spi->CR1 |= baud_rate << 3;
172
173     ssp_enable(obj);
174 }
175
176 static inline int ssp_disable(spi_t *obj) {
177     // TODO: Follow the instructions in 25.3.8 for safely disabling the SPI
178     return obj->spi->CR1 &= ~SPI_CR1_SPE;
179 }
180
181 static inline int ssp_enable(spi_t *obj) {
182     return obj->spi->CR1 |= SPI_CR1_SPE;
183 }
184
185 static inline int ssp_readable(spi_t *obj) {
186     return obj->spi->SR & SPI_SR_RXNE;
187 }
188
189 static inline int ssp_writeable(spi_t *obj) {
190     return obj->spi->SR & SPI_SR_TXE;
191 }
192
193 static inline void ssp_write(spi_t *obj, int value) {
194     while (!ssp_writeable(obj));
195     obj->spi->DR = value;
196 }
197
198 static inline int ssp_read(spi_t *obj) {
199     while (!ssp_readable(obj));
200     return obj->spi->DR;
201 }
202
203 static inline int ssp_busy(spi_t *obj) {
204     return (obj->spi->SR & SPI_SR_BSY) ? (1) : (0);
205 }
206
207 int spi_master_write(spi_t *obj, int value) {
208     ssp_write(obj, value);
209     return ssp_read(obj);
210 }
211
212 int spi_slave_receive(spi_t *obj) {
213     return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
214 };
215
216 int spi_slave_read(spi_t *obj) {
217     return obj->spi->DR;
218 }
219
220 void spi_slave_write(spi_t *obj, int value) {
221     while (ssp_writeable(obj) == 0) ;
222     obj->spi->DR = value;
223 }
224
225 int spi_busy(spi_t *obj) {
226     return ssp_busy(obj);
227 }
228
229 #endif