aboutsummaryrefslogtreecommitdiff
path: root/platforms/chibios/drivers/spi_master.c
diff options
context:
space:
mode:
Diffstat (limited to 'platforms/chibios/drivers/spi_master.c')
-rw-r--r--platforms/chibios/drivers/spi_master.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c
new file mode 100644
index 000000000..28ddcbb2b
--- /dev/null
+++ b/platforms/chibios/drivers/spi_master.c
@@ -0,0 +1,202 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17#include "spi_master.h"
18
19#include "timer.h"
20
21static pin_t currentSlavePin = NO_PIN;
22
23#if defined(K20x) || defined(KL2x)
24static SPIConfig spiConfig = {NULL, 0, 0, 0};
25#else
26static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
27#endif
28
29__attribute__((weak)) void spi_init(void) {
30 static bool is_initialised = false;
31 if (!is_initialised) {
32 is_initialised = true;
33
34 // Try releasing special pins for a short time
35 setPinInput(SPI_SCK_PIN);
36 setPinInput(SPI_MOSI_PIN);
37 setPinInput(SPI_MISO_PIN);
38
39 chThdSleepMilliseconds(10);
40#if defined(USE_GPIOV1)
41 palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_PAL_MODE);
42 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
43 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
44#else
45 palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
46 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
47 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
48#endif
49 }
50}
51
52bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
53 if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
54 return false;
55 }
56
57 uint16_t roundedDivisor = 2;
58 while (roundedDivisor < divisor) {
59 roundedDivisor <<= 1;
60 }
61
62 if (roundedDivisor < 2 || roundedDivisor > 256) {
63 return false;
64 }
65
66#if defined(K20x) || defined(KL2x)
67 spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
68
69 if (lsbFirst) {
70 spiConfig.tar0 |= SPIx_CTARn_LSBFE;
71 }
72
73 switch (mode) {
74 case 0:
75 break;
76 case 1:
77 spiConfig.tar0 |= SPIx_CTARn_CPHA;
78 break;
79 case 2:
80 spiConfig.tar0 |= SPIx_CTARn_CPOL;
81 break;
82 case 3:
83 spiConfig.tar0 |= SPIx_CTARn_CPHA | SPIx_CTARn_CPOL;
84 break;
85 }
86
87 switch (roundedDivisor) {
88 case 2:
89 spiConfig.tar0 |= SPIx_CTARn_BR(0);
90 break;
91 case 4:
92 spiConfig.tar0 |= SPIx_CTARn_BR(1);
93 break;
94 case 8:
95 spiConfig.tar0 |= SPIx_CTARn_BR(3);
96 break;
97 case 16:
98 spiConfig.tar0 |= SPIx_CTARn_BR(4);
99 break;
100 case 32:
101 spiConfig.tar0 |= SPIx_CTARn_BR(5);
102 break;
103 case 64:
104 spiConfig.tar0 |= SPIx_CTARn_BR(6);
105 break;
106 case 128:
107 spiConfig.tar0 |= SPIx_CTARn_BR(7);
108 break;
109 case 256:
110 spiConfig.tar0 |= SPIx_CTARn_BR(8);
111 break;
112 }
113#else
114 spiConfig.cr1 = 0;
115
116 if (lsbFirst) {
117 spiConfig.cr1 |= SPI_CR1_LSBFIRST;
118 }
119
120 switch (mode) {
121 case 0:
122 break;
123 case 1:
124 spiConfig.cr1 |= SPI_CR1_CPHA;
125 break;
126 case 2:
127 spiConfig.cr1 |= SPI_CR1_CPOL;
128 break;
129 case 3:
130 spiConfig.cr1 |= SPI_CR1_CPHA | SPI_CR1_CPOL;
131 break;
132 }
133
134 switch (roundedDivisor) {
135 case 2:
136 break;
137 case 4:
138 spiConfig.cr1 |= SPI_CR1_BR_0;
139 break;
140 case 8:
141 spiConfig.cr1 |= SPI_CR1_BR_1;
142 break;
143 case 16:
144 spiConfig.cr1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
145 break;
146 case 32:
147 spiConfig.cr1 |= SPI_CR1_BR_2;
148 break;
149 case 64:
150 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
151 break;
152 case 128:
153 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
154 break;
155 case 256:
156 spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
157 break;
158 }
159#endif
160
161 currentSlavePin = slavePin;
162 spiConfig.ssport = PAL_PORT(slavePin);
163 spiConfig.sspad = PAL_PAD(slavePin);
164
165 setPinOutput(slavePin);
166 spiStart(&SPI_DRIVER, &spiConfig);
167 spiSelect(&SPI_DRIVER);
168
169 return true;
170}
171
172spi_status_t spi_write(uint8_t data) {
173 uint8_t rxData;
174 spiExchange(&SPI_DRIVER, 1, &data, &rxData);
175
176 return rxData;
177}
178
179spi_status_t spi_read(void) {
180 uint8_t data = 0;
181 spiReceive(&SPI_DRIVER, 1, &data);
182
183 return data;
184}
185
186spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
187 spiSend(&SPI_DRIVER, length, data);
188 return SPI_STATUS_SUCCESS;
189}
190
191spi_status_t spi_receive(uint8_t *data, uint16_t length) {
192 spiReceive(&SPI_DRIVER, length, data);
193 return SPI_STATUS_SUCCESS;
194}
195
196void spi_stop(void) {
197 if (currentSlavePin != NO_PIN) {
198 spiUnselect(&SPI_DRIVER);
199 spiStop(&SPI_DRIVER);
200 currentSlavePin = NO_PIN;
201 }
202}