2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "drivers/bus_spi.h"
26 #include "drivers/exti.h"
27 #include "drivers/io.h"
28 #include "drivers/io_impl.h"
29 #include "drivers/rcc.h"
32 #define SPI1_NSS_PIN PA4
33 #define SPI1_SCK_PIN PA5
34 #define SPI1_MISO_PIN PA6
35 #define SPI1_MOSI_PIN PA7
39 #define SPI2_NSS_PIN PB12
40 #define SPI2_SCK_PIN PB13
41 #define SPI2_MISO_PIN PB14
42 #define SPI2_MOSI_PIN PB15
46 #define SPI3_NSS_PIN PA15
47 #define SPI3_SCK_PIN PC10
48 #define SPI3_MISO_PIN PC11
49 #define SPI3_MOSI_PIN PC12
53 #define SPI1_NSS_PIN NONE
56 #define SPI2_NSS_PIN NONE
59 #define SPI3_NSS_PIN NONE
63 #if defined(USE_SPI_DEVICE_1)
64 static const uint32_t spiDivisorMapFast
[] = {
65 SPI_MCLK_DIV_256
, // SPI_CLOCK_INITIALIZATON 328.125 KBits/s
66 SPI_MCLK_DIV_128
, // SPI_CLOCK_SLOW 656.25 KBits/s
67 SPI_MCLK_DIV_16
, // SPI_CLOCK_STANDARD 10.5 MBits/s
68 SPI_MCLK_DIV_8
, // SPI_CLOCK_FAST 21.0 MBits/s
69 SPI_MCLK_DIV_4
// SPI_CLOCK_ULTRAFAST 42.0 MBits/s
73 #if defined(USE_SPI_DEVICE_2) || defined(USE_SPI_DEVICE_3)
74 static const uint32_t spiDivisorMapSlow
[] = {
75 SPI_MCLK_DIV_256
, // SPI_CLOCK_INITIALIZATON 164.062 KBits/s
76 SPI_MCLK_DIV_128
, // SPI_CLOCK_SLOW 656.25 KBits/s
77 SPI_MCLK_DIV_16
, // SPI_CLOCK_STANDARD 10.5 MBits/s
78 SPI_MCLK_DIV_8
, // SPI_CLOCK_FAST 21.0 MBits/s
79 SPI_MCLK_DIV_8
// SPI_CLOCK_ULTRAFAST 21.0 MBits/s
83 //MAP spi pin config and af
84 static spiDevice_t spiHardwareMap
[] = {
85 #ifdef USE_SPI_DEVICE_1
86 #if defined(SPI1_SCK_AF) || defined(SPI1_MISO_AF) || defined(SPI1_MOSI_AF)
87 #if !defined(SPI1_SCK_AF) || !defined(SPI1_MISO_AF) || !defined(SPI1_MOSI_AF)
88 #error SPI1: SCK, MISO and MOSI AFs should be defined together in target.h!
90 { .dev
= SPI1
, .nss
= IO_TAG(SPI1_NSS_PIN
), .sck
= IO_TAG(SPI1_SCK_PIN
), .miso
= IO_TAG(SPI1_MISO_PIN
), .mosi
= IO_TAG(SPI1_MOSI_PIN
), .rcc
= RCC_APB2(SPI1
), .sckAF
= SPI1_SCK_AF
, .misoAF
= SPI1_MISO_AF
, .mosiAF
= SPI1_MOSI_AF
, .divisorMap
= spiDivisorMapFast
},
92 { .dev
= SPI1
, .nss
= IO_TAG(SPI1_NSS_PIN
), .sck
= IO_TAG(SPI1_SCK_PIN
), .miso
= IO_TAG(SPI1_MISO_PIN
), .mosi
= IO_TAG(SPI1_MOSI_PIN
), .rcc
= RCC_APB2(SPI1
), .sckAF
= GPIO_MUX_5
, .misoAF
= GPIO_MUX_5
, .mosiAF
= GPIO_MUX_5
, .divisorMap
= spiDivisorMapFast
},
95 { .dev
= NULL
}, // No SPI1
98 #ifdef USE_SPI_DEVICE_2
99 #if defined(SPI2_SCK_AF) || defined(SPI2_MISO_AF) || defined(SPI2_MOSI_AF)
100 #if !defined(SPI2_SCK_AF) || !defined(SPI2_MISO_AF) || !defined(SPI2_MOSI_AF)
101 #error SPI2: SCK, MISO and MOSI AFs should be defined together in target.h!
103 { .dev
= SPI2
, .nss
= IO_TAG(SPI2_NSS_PIN
), .sck
= IO_TAG(SPI2_SCK_PIN
), .miso
= IO_TAG(SPI2_MISO_PIN
), .mosi
= IO_TAG(SPI2_MOSI_PIN
), .rcc
= RCC_APB1(SPI2
), .sckAF
= SPI2_SCK_AF
, .misoAF
= SPI2_MISO_AF
, .mosiAF
= SPI2_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
105 { .dev
= SPI2
, .nss
= IO_TAG(SPI2_NSS_PIN
), .sck
= IO_TAG(SPI2_SCK_PIN
), .miso
= IO_TAG(SPI2_MISO_PIN
), .mosi
= IO_TAG(SPI2_MOSI_PIN
), .rcc
= RCC_APB1(SPI2
), .sckAF
= GPIO_MUX_5
, .misoAF
= GPIO_MUX_5
, .mosiAF
= GPIO_MUX_5
, .divisorMap
= spiDivisorMapSlow
},
108 { .dev
= NULL
}, // No SPI2
111 #ifdef USE_SPI_DEVICE_3
112 #if defined(SPI3_SCK_AF) || defined(SPI3_MISO_AF) || defined(SPI3_MOSI_AF)
113 #if !defined(SPI3_SCK_AF) || !defined(SPI3_MISO_AF) || !defined(SPI3_MOSI_AF)
114 #error SPI3: SCK, MISO and MOSI AFs should be defined together in target.h!
116 { .dev
= SPI3
, .nss
= IO_TAG(SPI3_NSS_PIN
), .sck
= IO_TAG(SPI3_SCK_PIN
), .miso
= IO_TAG(SPI3_MISO_PIN
), .mosi
= IO_TAG(SPI3_MOSI_PIN
), .rcc
= RCC_APB1(SPI3
), .sckAF
= SPI3_SCK_AF
, .misoAF
= SPI3_MISO_AF
, .mosiAF
= SPI3_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
},
118 { .dev
= SPI3
, .nss
= IO_TAG(SPI3_NSS_PIN
), .sck
= IO_TAG(SPI3_SCK_PIN
), .miso
= IO_TAG(SPI3_MISO_PIN
), .mosi
= IO_TAG(SPI3_MOSI_PIN
), .rcc
= RCC_APB1(SPI3
), .sckAF
= GPIO_MUX_6
, .misoAF
= GPIO_MUX_6
, .mosiAF
= GPIO_MUX_6
, .divisorMap
= spiDivisorMapSlow
},
121 { .dev
= NULL
}, // No SPI3
124 #ifdef USE_SPI_DEVICE_4
125 #if defined(SPI4_SCK_AF) || defined(SPI4_MISO_AF) || defined(SPI4_MOSI_AF)
126 #if !defined(SPI4_SCK_AF) || !defined(SPI4_MISO_AF) || !defined(SPI4_MOSI_AF)
127 #error SPI4: SCK, MISO and MOSI AFs should be defined together in target.h!
129 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= SPI4_SCK_AF
, .misoAF
= SPI4_MISO_AF
, .mosiAF
= SPI4_MOSI_AF
, .divisorMap
= spiDivisorMapSlow
}
131 { .dev
= SPI4
, .nss
= IO_TAG(SPI4_NSS_PIN
), .sck
= IO_TAG(SPI4_SCK_PIN
), .miso
= IO_TAG(SPI4_MISO_PIN
), .mosi
= IO_TAG(SPI4_MOSI_PIN
), .rcc
= RCC_APB2(SPI4
), .sckAF
= GPIO_MUX_6
, .misoAF
= GPIO_MUX_6
, .mosiAF
= GPIO_MUX_6
, .divisorMap
= spiDivisorMapSlow
}
134 { .dev
= NULL
} // No SPI4
141 SPIDevice
spiDeviceByInstance(spi_type
*instance
)
143 if (instance
== SPI1
)
146 if (instance
== SPI2
)
149 if (instance
== SPI3
)
155 bool spiInitDevice(SPIDevice device
, bool leadingEdge
)
157 spiDevice_t
*spi
= &(spiHardwareMap
[device
]);
167 RCC_ClockCmd(spi
->rcc
, ENABLE
);
168 RCC_ResetCmd(spi
->rcc
, ENABLE
);
170 IOInit(IOGetByTag(spi
->sck
), OWNER_SPI
, RESOURCE_SPI_SCK
, device
+ 1);
171 IOInit(IOGetByTag(spi
->miso
), OWNER_SPI
, RESOURCE_SPI_MISO
, device
+ 1);
172 IOInit(IOGetByTag(spi
->mosi
), OWNER_SPI
, RESOURCE_SPI_MOSI
, device
+ 1);
174 IOConfigGPIOAF(IOGetByTag(spi
->sck
), SPI_IO_AF_SCK_CFG
, spi
->sckAF
);
175 IOConfigGPIOAF(IOGetByTag(spi
->miso
), SPI_IO_AF_MISO_CFG
, spi
->misoAF
);
176 IOConfigGPIOAF(IOGetByTag(spi
->mosi
), SPI_IO_AF_CFG
, spi
->mosiAF
);
179 IOInit(IOGetByTag(spi
->nss
), OWNER_SPI
, RESOURCE_SPI_CS
, device
+ 1);
180 IOConfigGPIO(IOGetByTag(spi
->nss
), SPI_IO_CS_CFG
);
183 spi_i2s_reset(spi
->dev
);
184 spi_init_type spi_init_struct
;
185 spi_default_para_init (&spi_init_struct
);
186 spi_init_struct
.master_slave_mode
= SPI_MODE_MASTER
;
187 spi_init_struct
.transmission_mode
= SPI_TRANSMIT_FULL_DUPLEX
;
188 spi_init_struct
.first_bit_transmission
= SPI_FIRST_BIT_MSB
;
189 spi_init_struct
.mclk_freq_division
= SPI_MCLK_DIV_8
;
190 spi_init_struct
.frame_bit_num
= SPI_FRAME_8BIT
;
191 spi_init_struct
.cs_mode_selection
= SPI_CS_SOFTWARE_MODE
;
193 spi_init_struct
.clock_polarity
= SPI_CLOCK_POLARITY_HIGH
;
194 spi_init_struct
.clock_phase
= SPI_CLOCK_PHASE_2EDGE
;
198 spi_init_struct
.clock_polarity
= SPI_CLOCK_POLARITY_LOW
;
199 spi_init_struct
.clock_phase
= SPI_CLOCK_PHASE_1EDGE
;
202 spi_init_struct
.clock_polarity
= SPI_CLOCK_POLARITY_HIGH
;
203 spi_init_struct
.clock_phase
= SPI_CLOCK_PHASE_2EDGE
;
206 spi_init(spi
->dev
, &spi_init_struct
);
207 spi_crc_polynomial_set (spi
->dev
, 0x07);
208 spi_crc_enable (spi
->dev
, TRUE
); // enable crc
209 spi_enable (spi
->dev
, TRUE
);
212 // Drive NSS high to disable connected SPI device.
213 IOHi(IOGetByTag(spi
->nss
));
215 spi
->initDone
= true;
219 uint32_t spiTimeoutUserCallback(spi_type
*instance
)
221 SPIDevice device
= spiDeviceByInstance(instance
);
222 if (device
== SPIINVALID
) {
225 spiHardwareMap
[device
].errorCount
++;
226 return spiHardwareMap
[device
].errorCount
;
229 // return uint8_t value or -1 when failure
230 uint8_t spiTransferByte(spi_type
*instance
, uint8_t data
)
232 uint16_t spiTimeout
= 1000;
234 //while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET)
235 while (spi_i2s_flag_get(instance
, SPI_I2S_TDBE_FLAG
) == RESET
)
236 if ((spiTimeout
--) == 0)
237 return spiTimeoutUserCallback(instance
);
239 //SPI_I2S_SendData(instance, data);
240 spi_i2s_data_transmit(instance
, data
);
243 //while (SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_RXNE) == RESET)
244 while (spi_i2s_flag_get(instance
, SPI_I2S_RDBF_FLAG
) == RESET
)
245 if ((spiTimeout
--) == 0)
246 return spiTimeoutUserCallback(instance
);
248 return ((uint8_t) spi_i2s_data_receive(instance
));
252 * Return true if the bus is currently in the middle of a transmission.
254 bool spiIsBusBusy(spi_type
*instance
)
256 //return SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_TXE) == RESET || SPI_I2S_GetFlagStatus(instance, SPI_I2S_FLAG_BSY) == SET;
257 return spi_i2s_flag_get(instance
, SPI_I2S_TDBE_FLAG
) == RESET
|| spi_i2s_flag_get(instance
, SPI_I2S_BF_FLAG
) == SET
;
260 bool spiTransfer(spi_type
*instance
, uint8_t *out
, const uint8_t *in
, int len
)
262 uint16_t spiTimeout
= 1000;
266 uint8_t b
= in
? *(in
++) : 0xFF;
267 while (spi_i2s_flag_get(instance
, SPI_I2S_TDBE_FLAG
) == RESET
) {
268 if ((spiTimeout
--) == 0)
269 return spiTimeoutUserCallback(instance
);
271 spi_i2s_data_transmit(instance
, b
);
273 while (spi_i2s_flag_get(instance
, SPI_I2S_RDBF_FLAG
) == RESET
) {
274 if ((spiTimeout
--) == 0)
275 return spiTimeoutUserCallback(instance
);
277 b
= spi_i2s_data_receive(instance
);
285 void spiSetSpeed(spi_type
*instance
, SPIClockSpeed_e speed
)
287 #define BR_CLEAR_MASK 0xFFC7
288 SPIDevice device
= spiDeviceByInstance(instance
);
289 if (device
== SPIINVALID
) {
293 spi_enable (instance
, FALSE
);
295 // #define BR_BITS ((BIT(5) | BIT(4) | BIT(3)))
296 // const uint16_t tempRegister = (instance->ctrl1 & ~BR_BITS);
297 // instance->ctrl1 = tempRegister | (spiHardwareMap[device].divisorMap[speed] << 3);
300 uint16_t tempRegister
= instance
->ctrl1
;
301 tempRegister
&= BR_CLEAR_MASK
;
302 tempRegister
|= (spiHardwareMap
[device
].divisorMap
[speed
] << 3);
303 instance
->ctrl1
= tempRegister
;
305 spi_enable (instance
, TRUE
);
308 uint16_t spiGetErrorCounter(spi_type
*instance
)
310 SPIDevice device
= spiDeviceByInstance(instance
);
311 if (device
== SPIINVALID
) {
314 return spiHardwareMap
[device
].errorCount
;
317 void spiResetErrorCounter(spi_type
*instance
)
319 SPIDevice device
= spiDeviceByInstance(instance
);
320 if (device
!= SPIINVALID
) {
321 spiHardwareMap
[device
].errorCount
= 0;
325 spi_type
* spiInstanceByDevice( SPIDevice device
)
327 return spiHardwareMap
[device
].dev
;