[G4] SPI support
[betaflight.git] / src / main / drivers / bus_spi_hal.c
blob34640777ba33be65f1359210cf268380a355cbeb
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
20 * HAL version resurrected from v3.1.7 (by jflyper)
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <strings.h>
27 #include "platform.h"
29 #ifdef USE_SPI
31 #include "bus_spi.h"
32 #include "bus_spi_impl.h"
33 #include "dma.h"
34 #include "io.h"
35 #include "io_impl.h"
36 #include "nvic.h"
37 #include "rcc.h"
39 void spiInitDevice(SPIDevice device, bool leadingEdge)
41 spiDevice_t *spi = &(spiDevice[device]);
43 if (!spi->dev) {
44 return;
47 spi->leadingEdge = leadingEdge;
49 // Enable SPI clock
50 RCC_ClockCmd(spi->rcc, ENABLE);
51 RCC_ResetCmd(spi->rcc, ENABLE);
53 IOInit(IOGetByTag(spi->sck), OWNER_SPI_SCK, RESOURCE_INDEX(device));
54 IOInit(IOGetByTag(spi->miso), OWNER_SPI_MISO, RESOURCE_INDEX(device));
55 IOInit(IOGetByTag(spi->mosi), OWNER_SPI_MOSI, RESOURCE_INDEX(device));
57 #if defined(STM32F3)
58 IOConfigGPIOAF(IOGetByTag(spi->sck), SPI_IO_AF_CFG, spi->af);
59 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_CFG, spi->af);
60 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->af);
61 #endif
63 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
64 IOConfigGPIOAF(IOGetByTag(spi->sck), spi->leadingEdge ? SPI_IO_AF_SCK_CFG_LOW : SPI_IO_AF_SCK_CFG_HIGH, spi->sckAF);
65 IOConfigGPIOAF(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG, spi->misoAF);
66 IOConfigGPIOAF(IOGetByTag(spi->mosi), SPI_IO_AF_CFG, spi->mosiAF);
67 #endif
69 #if defined(STM32F10X)
70 IOConfigGPIO(IOGetByTag(spi->sck), SPI_IO_AF_SCK_CFG);
71 IOConfigGPIO(IOGetByTag(spi->miso), SPI_IO_AF_MISO_CFG);
72 IOConfigGPIO(IOGetByTag(spi->mosi), SPI_IO_AF_MOSI_CFG);
73 #endif
75 spi->hspi.Instance = spi->dev;
76 // DeInit SPI hardware
77 HAL_SPI_DeInit(&spi->hspi);
79 spi->hspi.Init.Mode = SPI_MODE_MASTER;
80 spi->hspi.Init.Direction = SPI_DIRECTION_2LINES;
81 spi->hspi.Init.DataSize = SPI_DATASIZE_8BIT;
82 spi->hspi.Init.NSS = SPI_NSS_SOFT;
83 spi->hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
84 spi->hspi.Init.CRCPolynomial = 7;
85 spi->hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
86 spi->hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
87 spi->hspi.Init.TIMode = SPI_TIMODE_DISABLED;
88 #if !defined(STM32G4)
89 spi->hspi.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
90 spi->hspi.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; /* Recommanded setting to avoid glitches */
91 #endif
93 if (spi->leadingEdge) {
94 spi->hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
95 spi->hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
97 else {
98 spi->hspi.Init.CLKPolarity = SPI_POLARITY_HIGH;
99 spi->hspi.Init.CLKPhase = SPI_PHASE_2EDGE;
102 // Init SPI hardware
103 HAL_SPI_Init(&spi->hspi);
106 // return uint8_t value or -1 when failure
107 uint8_t spiTransferByte(SPI_TypeDef *instance, uint8_t out)
109 uint8_t in;
111 spiTransfer(instance, &out, &in, 1);
112 return in;
116 * Return true if the bus is currently in the middle of a transmission.
118 bool spiIsBusBusy(SPI_TypeDef *instance)
120 SPIDevice device = spiDeviceByInstance(instance);
121 if(spiDevice[device].hspi.State == HAL_SPI_STATE_BUSY)
122 return true;
123 else
124 return false;
127 bool spiTransfer(SPI_TypeDef *instance, const uint8_t *out, uint8_t *in, int len)
129 SPIDevice device = spiDeviceByInstance(instance);
130 HAL_StatusTypeDef status;
132 #define SPI_DEFAULT_TIMEOUT 10
134 if (!in) {
135 // Tx only
136 status = HAL_SPI_Transmit(&spiDevice[device].hspi, out, len, SPI_DEFAULT_TIMEOUT);
137 } else if(!out) {
138 // Rx only
139 status = HAL_SPI_Receive(&spiDevice[device].hspi, in, len, SPI_DEFAULT_TIMEOUT);
140 } else {
141 // Tx and Rx
142 status = HAL_SPI_TransmitReceive(&spiDevice[device].hspi, out, in, len, SPI_DEFAULT_TIMEOUT);
145 if(status != HAL_OK) {
146 spiTimeoutUserCallback(instance);
149 return true;
152 // Position of Prescaler bits are different from MCU to MCU
154 static uint32_t baudRatePrescaler[8] = {
155 SPI_BAUDRATEPRESCALER_2,
156 SPI_BAUDRATEPRESCALER_4,
157 SPI_BAUDRATEPRESCALER_8,
158 SPI_BAUDRATEPRESCALER_16,
159 SPI_BAUDRATEPRESCALER_32,
160 SPI_BAUDRATEPRESCALER_64,
161 SPI_BAUDRATEPRESCALER_128,
162 SPI_BAUDRATEPRESCALER_256,
165 void spiSetDivisor(SPI_TypeDef *instance, uint16_t divisor)
167 SPIDevice device = spiDeviceByInstance(instance);
169 HAL_SPI_DeInit(&spiDevice[device].hspi);
171 spiDevice_t *spi = &(spiDevice[device]);
173 int prescalerIndex = ffs(divisor) - 2; // prescaler begins at "/2"
175 if (prescalerIndex < 0 || prescalerIndex >= (int)ARRAYLEN(baudRatePrescaler)) {
176 return;
179 spi->hspi.Init.BaudRatePrescaler = baudRatePrescaler[prescalerIndex];
181 HAL_SPI_Init(&spi->hspi);
184 #ifdef USE_DMA
185 DMA_HandleTypeDef* dmaHandleByInstance(SPI_TypeDef *instance)
187 return &spiDevice[spiDeviceByInstance(instance)].hdma;
190 void SPI1_IRQHandler(void)
192 HAL_SPI_IRQHandler(&spiDevice[SPIDEV_1].hspi);
195 void SPI2_IRQHandler(void)
197 HAL_SPI_IRQHandler(&spiDevice[SPIDEV_2].hspi);
200 void SPI3_IRQHandler(void)
202 HAL_SPI_IRQHandler(&spiDevice[SPIDEV_3].hspi);
205 void SPI4_IRQHandler(void)
207 HAL_SPI_IRQHandler(&spiDevice[SPIDEV_4].hspi);
210 void dmaSPIIRQHandler(dmaChannelDescriptor_t* descriptor)
212 SPIDevice device = descriptor->userParam;
213 if (device != SPIINVALID)
214 HAL_DMA_IRQHandler(&spiDevice[device].hdma);
216 #endif // USE_DMA
217 #endif