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)
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
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
49 quadSpiDevice_t quadSpiDevice
[QUADSPIDEV_COUNT
] = { 0 };
51 QUADSPIDevice
quadSpiDeviceByInstance(QUADSPI_TypeDef
*instance
)
53 #ifdef USE_QUADSPI_DEVICE_1
54 if (instance
== QUADSPI
) {
59 return QUADSPIINVALID
;
62 QUADSPI_TypeDef
*quadSpiInstanceByDevice(QUADSPIDevice device
)
64 if (device
== QUADSPIINVALID
|| device
>= QUADSPIDEV_COUNT
) {
68 return quadSpiDevice
[device
].dev
;
71 bool quadSpiInit(QUADSPIDevice device
)
77 #ifdef USE_QUADSPI_DEVICE_1
78 quadSpiInitDevice(device
);
87 uint32_t quadSpiTimeoutUserCallback(QUADSPI_TypeDef
*instance
)
89 QUADSPIDevice device
= quadSpiDeviceByInstance(instance
);
90 if (device
== QUADSPIINVALID
) {
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
) {
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
[] = {
117 .device
= QUADSPIDEV_1
,
120 { DEFIO_TAG_E(PB2
), GPIO_AF9_QUADSPI
},
123 { DEFIO_TAG_E(PC9
), GPIO_AF9_QUADSPI
},
124 { DEFIO_TAG_E(PD11
), GPIO_AF9_QUADSPI
},
125 { DEFIO_TAG_E(PF8
), GPIO_AF10_QUADSPI
},
128 { DEFIO_TAG_E(PC10
), GPIO_AF9_QUADSPI
},
129 { DEFIO_TAG_E(PD12
), GPIO_AF9_QUADSPI
},
130 { DEFIO_TAG_E(PF9
), GPIO_AF10_QUADSPI
},
133 { DEFIO_TAG_E(PE2
), GPIO_AF9_QUADSPI
},
134 { DEFIO_TAG_E(PF7
), GPIO_AF9_QUADSPI
},
137 { DEFIO_TAG_E(PA1
), GPIO_AF9_QUADSPI
},
138 { DEFIO_TAG_E(PD13
), GPIO_AF9_QUADSPI
},
139 { DEFIO_TAG_E(PF6
), GPIO_AF9_QUADSPI
},
142 { DEFIO_TAG_E(PB6
), GPIO_AF10_QUADSPI
},
143 { DEFIO_TAG_E(PB10
), GPIO_AF9_QUADSPI
},
144 { DEFIO_TAG_E(PG6
), GPIO_AF10_QUADSPI
},
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'
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'
155 { DEFIO_TAG_E(PE9
), GPIO_AF10_QUADSPI
},
156 { DEFIO_TAG_E(PG9
), GPIO_AF9_QUADSPI
},
159 { DEFIO_TAG_E(PE10
), GPIO_AF10_QUADSPI
},
160 { DEFIO_TAG_E(PG14
), GPIO_AF9_QUADSPI
},
163 { DEFIO_TAG_E(PC11
), GPIO_AF9_QUADSPI
},
165 .rcc
= RCC_AHB3(QSPI
),
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
];
185 void quadSpiPinConfigure(QUADSPIDevice device
)
187 if (device
== QUADSPIINVALID
) {
191 const quadSpiConfig_t
* pConfig
= getQuadSpiConfig(device
);
193 if (pConfig
== NULL
) {
197 for (size_t hwindex
= 0; hwindex
< ARRAYLEN(quadSpiHardware
); hwindex
++) {
198 const quadSpiHardware_t
*hw
= &quadSpiHardware
[hwindex
];
200 if (hw
->device
!= device
) {
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
;
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
;
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;
269 haveResources
= haveResources
&& pDev
->clk
;
273 bool needBK1
= (pConfig
->mode
== QUADSPI_MODE_DUAL_FLASH
) || (pConfig
->mode
== QUADSPI_MODE_BK1_ONLY
);
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
);
281 bool haveBK2Resources
= pDev
->bk2IO0
&& pDev
->bk2IO1
&& pDev
->bk2IO2
&& pDev
->bk2IO3
;
282 haveResources
= haveResources
&& haveBK2Resources
;
288 haveResources
= haveResources
&& pDev
->bk1CS
;
292 (pConfig
->mode
== QUADSPI_MODE_DUAL_FLASH
&& (pConfig
->csFlags
& QUADSPI_CS_MODE_MASK
) == QUADSPI_CS_MODE_SEPARATE
) ||
293 (pConfig
->mode
== QUADSPI_MODE_BK2_ONLY
);
296 haveResources
= haveResources
&& pDev
->bk2CS
;
304 // copy mode and flags
305 pDev
->mode
= pConfig
->mode
;
306 pDev
->csFlags
= pConfig
->csFlags
;