Blackbox device type 'file' (SITL) considered working when file handler is available
[inav.git] / src / main / drivers / bus_quadspi.c
blob867e664f01b22d1b3021a5a78f3c527bed298465
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 * Author: Dominic Clifton
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <string.h>
27 #include "platform.h"
29 #ifdef USE_QUADSPI
31 #include "drivers/bus_quadspi.h"
32 #include "drivers/bus_quadspi_impl.h"
33 #include "drivers/exti.h"
34 #include "drivers/io.h"
35 #include "drivers/rcc.h"
37 static const quadSpiConfig_t quadSpiConfig[] = {
38 #ifdef USE_QUADSPI_DEVICE_1
39 { .device = QUADSPIDEV_1, .clk = IO_TAG(QUADSPI1_SCK_PIN),
40 .bk1CS = IO_TAG(QUADSPI1_BK1_CS_PIN),
41 .bk1IO0 = IO_TAG(QUADSPI1_BK1_IO0_PIN), .bk1IO1 = IO_TAG(QUADSPI1_BK1_IO1_PIN), .bk1IO2 = IO_TAG(QUADSPI1_BK1_IO2_PIN), .bk1IO3 = IO_TAG(QUADSPI1_BK1_IO3_PIN),
42 .bk2CS = IO_TAG(QUADSPI1_BK2_CS_PIN),
43 .bk2IO0 = IO_TAG(QUADSPI1_BK2_IO0_PIN), .bk2IO1 = IO_TAG(QUADSPI1_BK2_IO1_PIN), .bk2IO2 = IO_TAG(QUADSPI1_BK2_IO2_PIN), .bk2IO3 = IO_TAG(QUADSPI1_BK2_IO3_PIN),
44 .mode = QUADSPI1_MODE, .csFlags = QUADSPI1_CS_FLAGS
46 #endif
49 quadSpiDevice_t quadSpiDevice[QUADSPIDEV_COUNT] = { 0 };
51 QUADSPIDevice quadSpiDeviceByInstance(QUADSPI_TypeDef *instance)
53 #ifdef USE_QUADSPI_DEVICE_1
54 if (instance == QUADSPI) {
55 return QUADSPIDEV_1;
57 #endif
59 return QUADSPIINVALID;
62 QUADSPI_TypeDef *quadSpiInstanceByDevice(QUADSPIDevice device)
64 if (device == QUADSPIINVALID || device >= QUADSPIDEV_COUNT) {
65 return NULL;
68 return quadSpiDevice[device].dev;
71 bool quadSpiInit(QUADSPIDevice device)
73 switch (device) {
74 case QUADSPIINVALID:
75 return false;
76 case QUADSPIDEV_1:
77 #ifdef USE_QUADSPI_DEVICE_1
78 quadSpiInitDevice(device);
79 return true;
80 #else
81 break;
82 #endif
84 return false;
87 uint32_t quadSpiTimeoutUserCallback(QUADSPI_TypeDef *instance)
89 QUADSPIDevice device = quadSpiDeviceByInstance(instance);
90 if (device == QUADSPIINVALID) {
91 return -1;
93 quadSpiDevice[device].errorCount++;
94 return quadSpiDevice[device].errorCount;
97 uint16_t quadSpiGetErrorCounter(QUADSPI_TypeDef *instance)
99 QUADSPIDevice device = quadSpiDeviceByInstance(instance);
100 if (device == QUADSPIINVALID) {
101 return 0;
103 return quadSpiDevice[device].errorCount;
106 void quadSpiResetErrorCounter(QUADSPI_TypeDef *instance)
108 QUADSPIDevice device = quadSpiDeviceByInstance(instance);
109 if (device != QUADSPIINVALID) {
110 quadSpiDevice[device].errorCount = 0;
114 const quadSpiHardware_t quadSpiHardware[] = {
115 #ifdef STM32H7
117 .device = QUADSPIDEV_1,
118 .reg = QUADSPI,
119 .clkPins = {
120 { DEFIO_TAG_E(PB2), GPIO_AF9_QUADSPI },
122 .bk1IO0Pins = {
123 { DEFIO_TAG_E(PC9), GPIO_AF9_QUADSPI },
124 { DEFIO_TAG_E(PD11), GPIO_AF9_QUADSPI },
125 { DEFIO_TAG_E(PF8), GPIO_AF10_QUADSPI },
127 .bk1IO1Pins = {
128 { DEFIO_TAG_E(PC10), GPIO_AF9_QUADSPI },
129 { DEFIO_TAG_E(PD12), GPIO_AF9_QUADSPI },
130 { DEFIO_TAG_E(PF9), GPIO_AF10_QUADSPI },
132 .bk1IO2Pins = {
133 { DEFIO_TAG_E(PE2), GPIO_AF9_QUADSPI },
134 { DEFIO_TAG_E(PF7), GPIO_AF9_QUADSPI },
136 .bk1IO3Pins = {
137 { DEFIO_TAG_E(PA1), GPIO_AF9_QUADSPI },
138 { DEFIO_TAG_E(PD13), GPIO_AF9_QUADSPI },
139 { DEFIO_TAG_E(PF6), GPIO_AF9_QUADSPI },
141 .bk1CSPins = {
142 { DEFIO_TAG_E(PB6), GPIO_AF10_QUADSPI },
143 { DEFIO_TAG_E(PB10), GPIO_AF9_QUADSPI },
144 { DEFIO_TAG_E(PG6), GPIO_AF10_QUADSPI },
146 .bk2IO0Pins = {
147 { DEFIO_TAG_E(PE7), GPIO_AF10_QUADSPI },
148 //{ DEFIO_TAG_E(PH7), GPIO_AF9_QUADSPI }, // FIXME regenerate io_def_generated with support for GPIO 'H'
150 .bk2IO1Pins = {
151 { DEFIO_TAG_E(PE8), GPIO_AF10_QUADSPI },
152 //{ DEFIO_TAG_E(PH3), GPIO_AF9_QUADSPI }, // FIXME regenerate io_def_generated with support for GPIO 'H'
154 .bk2IO2Pins = {
155 { DEFIO_TAG_E(PE9), GPIO_AF10_QUADSPI },
156 { DEFIO_TAG_E(PG9), GPIO_AF9_QUADSPI },
158 .bk2IO3Pins = {
159 { DEFIO_TAG_E(PE10), GPIO_AF10_QUADSPI },
160 { DEFIO_TAG_E(PG14), GPIO_AF9_QUADSPI },
162 .bk2CSPins = {
163 { DEFIO_TAG_E(PC11), GPIO_AF9_QUADSPI },
165 .rcc = RCC_AHB3(QSPI),
167 #endif
170 const quadSpiConfig_t * getQuadSpiConfig(QUADSPIDevice device)
172 const quadSpiConfig_t * pConfig = NULL;
174 for (size_t configIndex = 0; configIndex < ARRAYLEN(quadSpiConfig); configIndex++) {
175 if (quadSpiConfig[configIndex].device == device) {
176 pConfig = &quadSpiConfig[configIndex];
177 break;
181 return pConfig;
185 void quadSpiPinConfigure(QUADSPIDevice device)
187 if (device == QUADSPIINVALID) {
188 return;
191 const quadSpiConfig_t * pConfig = getQuadSpiConfig(device);
193 if (pConfig == NULL) {
194 return;
197 for (size_t hwindex = 0; hwindex < ARRAYLEN(quadSpiHardware); hwindex++) {
198 const quadSpiHardware_t *hw = &quadSpiHardware[hwindex];
200 if (hw->device != device) {
201 continue;
204 quadSpiDevice_t *pDev = &quadSpiDevice[device];
206 for (int pindex = 0; pindex < MAX_QUADSPI_PIN_SEL; pindex++) {
207 if (pConfig->clk == hw->clkPins[pindex].pin) {
208 pDev->clk = hw->clkPins[pindex].pin;
211 // BK1
213 if (pConfig->bk1IO0 == hw->bk1IO0Pins[pindex].pin) {
214 pDev->bk1IO0 = hw->bk1IO0Pins[pindex].pin;
215 pDev->bk1IO0AF = hw->bk1IO0Pins[pindex].af;
217 if (pConfig->bk1IO1 == hw->bk1IO1Pins[pindex].pin) {
218 pDev->bk1IO1 = hw->bk1IO1Pins[pindex].pin;
219 pDev->bk1IO1AF = hw->bk1IO1Pins[pindex].af;
221 if (pConfig->bk1IO2 == hw->bk1IO2Pins[pindex].pin) {
222 pDev->bk1IO2 = hw->bk1IO2Pins[pindex].pin;
223 pDev->bk1IO2AF = hw->bk1IO2Pins[pindex].af;
225 if (pConfig->bk1IO3 == hw->bk1IO3Pins[pindex].pin) {
226 pDev->bk1IO3 = hw->bk1IO3Pins[pindex].pin;
227 pDev->bk1IO3AF = hw->bk1IO3Pins[pindex].af;
229 if (pConfig->bk1CS == hw->bk1CSPins[pindex].pin) {
230 pDev->bk1CS = hw->bk1CSPins[pindex].pin;
231 pDev->bk1CSAF = hw->bk1CSPins[pindex].af;
234 // BK2
236 if (pConfig->bk2IO0 == hw->bk2IO0Pins[pindex].pin) {
237 pDev->bk2IO0 = hw->bk2IO0Pins[pindex].pin;
238 pDev->bk2IO0AF = hw->bk2IO0Pins[pindex].af;
240 if (pConfig->bk2IO1 == hw->bk2IO1Pins[pindex].pin) {
241 pDev->bk2IO1 = hw->bk2IO1Pins[pindex].pin;
242 pDev->bk2IO1AF = hw->bk2IO1Pins[pindex].af;
244 if (pConfig->bk2IO1 == hw->bk2IO2Pins[pindex].pin) {
245 pDev->bk2IO2 = hw->bk2IO2Pins[pindex].pin;
246 pDev->bk2IO2AF = hw->bk2IO2Pins[pindex].af;
248 if (pConfig->bk2IO2 == hw->bk2IO3Pins[pindex].pin) {
249 pDev->bk2IO3 = hw->bk2IO3Pins[pindex].pin;
250 pDev->bk2IO3AF = hw->bk2IO3Pins[pindex].af;
252 if (pConfig->bk2IO3 == hw->bk2CSPins[pindex].pin) {
253 pDev->bk2CS = hw->bk2CSPins[pindex].pin;
254 pDev->bk2CSAF = hw->bk2CSPins[pindex].af;
258 if ((pConfig->csFlags & QUADSPI_BK1_CS_MASK) == QUADSPI_BK1_CS_SOFTWARE) {
259 pDev->bk1CS = pConfig->bk1CS;
261 if ((pConfig->csFlags & QUADSPI_BK2_CS_MASK) == QUADSPI_BK2_CS_SOFTWARE) {
262 pDev->bk2CS = pConfig->bk2CS;
265 bool haveResources = true;
267 // clock pins
269 haveResources = haveResources && pDev->clk;
271 // data pins
273 bool needBK1 = (pConfig->mode == QUADSPI_MODE_DUAL_FLASH) || (pConfig->mode == QUADSPI_MODE_BK1_ONLY);
274 if (needBK1) {
275 bool haveBK1Resources = pDev->bk1IO0 && pDev->bk1IO1 && pDev->bk1IO2 && pDev->bk1IO3 && pDev->bk1CS;
276 haveResources = haveResources && haveBK1Resources;
279 bool needBK2 = (pConfig->mode == QUADSPI_MODE_DUAL_FLASH) || (pConfig->mode == QUADSPI_MODE_BK2_ONLY);
280 if (needBK2) {
281 bool haveBK2Resources = pDev->bk2IO0 && pDev->bk2IO1 && pDev->bk2IO2 && pDev->bk2IO3;
282 haveResources = haveResources && haveBK2Resources;
285 // cs pins
287 if (needBK1) {
288 haveResources = haveResources && pDev->bk1CS;
291 bool needBK2CS =
292 (pConfig->mode == QUADSPI_MODE_DUAL_FLASH && (pConfig->csFlags & QUADSPI_CS_MODE_MASK) == QUADSPI_CS_MODE_SEPARATE) ||
293 (pConfig->mode == QUADSPI_MODE_BK2_ONLY);
295 if (needBK2CS) {
296 haveResources = haveResources && pDev->bk2CS;
299 if (haveResources) {
300 pDev->dev = hw->reg;
301 pDev->rcc = hw->rcc;
304 // copy mode and flags
305 pDev->mode = pConfig->mode;
306 pDev->csFlags = pConfig->csFlags;
310 #endif