[4.4.2] Remove 15 m/s limit on estimated vario (#12788)
[betaflight.git] / src / main / drivers / bus_octospi_stm32h7xx.c
blobf45aaddb4419e6a83bc3c7bd8af6275540281013
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
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <string.h>
30 #include "platform.h"
32 #ifdef USE_OCTOSPI
34 #include "drivers/system.h"
36 #include "drivers/bus_octospi.h"
37 #include "drivers/bus_octospi_impl.h"
39 #if !(defined(STM32H730xx) || defined(STM32H723xx))
40 #error MCU not supported.
41 #endif
43 #define OCTOSPI_INTERFACE_COUNT 1
45 #define OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE ((uint32_t)0x00000000)
46 #define OSPI_FUNCTIONAL_MODE_INDIRECT_READ ((uint32_t)OCTOSPI_CR_FMODE_0)
47 #define OSPI_FUNCTIONAL_MODE_AUTO_POLLING ((uint32_t)OCTOSPI_CR_FMODE_1)
48 #define OSPI_FUNCTIONAL_MODE_MEMORY_MAPPED ((uint32_t)OCTOSPI_CR_FMODE)
50 #define OSPI_DHQC_DISABLE ((uint32_t)0x00000000U)
51 #define OSPI_DHQC_ENABLE ((uint32_t)OCTOSPI_TCR_DHQC)
53 #define OSPI_OPTYPE_COMMON_CFG ((uint32_t)0x00000000U)
55 #define OSPI_OPTYPE_READ_CFG ((uint32_t)0x00000001U)
56 #define OSPI_OPTYPE_WRITE_CFG ((uint32_t)0x00000002U)
57 #define OSPI_OPTYPE_WRAP_CFG ((uint32_t)0x00000003U)
59 #define OSPI_INSTRUCTION_NONE ((uint32_t)0x00000000U)
60 #define OSPI_INSTRUCTION_1_LINE ((uint32_t)OCTOSPI_CCR_IMODE_0)
61 #define OSPI_INSTRUCTION_2_LINES ((uint32_t)OCTOSPI_CCR_IMODE_1)
62 #define OSPI_INSTRUCTION_4_LINES ((uint32_t)(OCTOSPI_CCR_IMODE_0 | OCTOSPI_CCR_IMODE_1))
63 #define OSPI_INSTRUCTION_8_LINES ((uint32_t)OCTOSPI_CCR_IMODE_2)
65 #define OSPI_INSTRUCTION_8_BITS ((uint32_t)0x00000000U)
66 #define OSPI_INSTRUCTION_16_BITS ((uint32_t)OCTOSPI_CCR_ISIZE_0)
67 #define OSPI_INSTRUCTION_24_BITS ((uint32_t)OCTOSPI_CCR_ISIZE_1)
68 #define OSPI_INSTRUCTION_32_BITS ((uint32_t)OCTOSPI_CCR_ISIZE)
70 #define OSPI_INSTRUCTION_DTR_DISABLE ((uint32_t)0x00000000U)
71 #define OSPI_INSTRUCTION_DTR_ENABLE ((uint32_t)OCTOSPI_CCR_IDTR)
73 #define OSPI_ADDRESS_NONE ((uint32_t)0x00000000U) /*!< No address */
74 #define OSPI_ADDRESS_1_LINE ((uint32_t)OCTOSPI_CCR_ADMODE_0) /*!< Address on a single line */
75 #define OSPI_ADDRESS_2_LINES ((uint32_t)OCTOSPI_CCR_ADMODE_1) /*!< Address on two lines */
76 #define OSPI_ADDRESS_4_LINES ((uint32_t)(OCTOSPI_CCR_ADMODE_0 | OCTOSPI_CCR_ADMODE_1)) /*!< Address on four lines */
77 #define OSPI_ADDRESS_8_LINES ((uint32_t)OCTOSPI_CCR_ADMODE_2) /*!< Address on eight lines */
79 #define OSPI_ADDRESS_8_BITS ((uint32_t)0x00000000U) /*!< 8-bit address */
80 #define OSPI_ADDRESS_16_BITS ((uint32_t)OCTOSPI_CCR_ADSIZE_0) /*!< 16-bit address */
81 #define OSPI_ADDRESS_24_BITS ((uint32_t)OCTOSPI_CCR_ADSIZE_1) /*!< 24-bit address */
82 #define OSPI_ADDRESS_32_BITS ((uint32_t)OCTOSPI_CCR_ADSIZE) /*!< 32-bit address */
84 #define OSPI_ADDRESS_DTR_DISABLE ((uint32_t)0x00000000U) /*!< DTR mode disabled for address phase */
85 #define OSPI_ADDRESS_DTR_ENABLE ((uint32_t)OCTOSPI_CCR_ADDTR)
87 #define OSPI_DATA_NONE ((uint32_t)0x00000000U)
88 #define OSPI_DATA_1_LINE ((uint32_t)OCTOSPI_CCR_DMODE_0)
89 #define OSPI_DATA_2_LINES ((uint32_t)OCTOSPI_CCR_DMODE_1)
90 #define OSPI_DATA_4_LINES ((uint32_t)(OCTOSPI_CCR_DMODE_0 | OCTOSPI_CCR_DMODE_1))
91 #define OSPI_DATA_8_LINES ((uint32_t)OCTOSPI_CCR_DMODE_2)
93 #define OSPI_DATA_DTR_DISABLE ((uint32_t)0x00000000U)
94 #define OSPI_DATA_DTR_ENABLE ((uint32_t)OCTOSPI_CCR_DDTR)
96 #define OSPI_ALTERNATE_BYTES_NONE ((uint32_t)0x00000000U)
97 #define OSPI_ALTERNATE_BYTES_1_LINE ((uint32_t)OCTOSPI_CCR_ABMODE_0)
98 #define OSPI_ALTERNATE_BYTES_2_LINES ((uint32_t)OCTOSPI_CCR_ABMODE_1)
99 #define OSPI_ALTERNATE_BYTES_4_LINES ((uint32_t)(OCTOSPI_CCR_ABMODE_0 | OCTOSPI_CCR_ABMODE_1))
100 #define OSPI_ALTERNATE_BYTES_8_LINES ((uint32_t)OCTOSPI_CCR_ABMODE_2)
102 #define OSPI_ALTERNATE_BYTES_8_BITS ((uint32_t)0x00000000U)
103 #define OSPI_ALTERNATE_BYTES_16_BITS ((uint32_t)OCTOSPI_CCR_ABSIZE_0)
104 #define OSPI_ALTERNATE_BYTES_24_BITS ((uint32_t)OCTOSPI_CCR_ABSIZE_1)
105 #define OSPI_ALTERNATE_BYTES_32_BITS ((uint32_t)OCTOSPI_CCR_ABSIZE)
107 #define OSPI_ALTERNATE_BYTES_DTR_DISABLE ((uint32_t)0x00000000U)
108 #define OSPI_ALTERNATE_BYTES_DTR_ENABLE ((uint32_t)OCTOSPI_CCR_ABDTR)
110 #define OSPI_DQS_DISABLE ((uint32_t)0x00000000U)
111 #define OSPI_DQS_ENABLE ((uint32_t)OCTOSPI_CCR_DQSE)
113 #define OSPI_SIOO_INST_EVERY_CMD ((uint32_t)0x00000000U)
114 #define OSPI_SIOO_INST_ONLY_FIRST_CMD ((uint32_t)OCTOSPI_CCR_SIOO)
116 MMFLASH_CODE_NOINLINE static void Error_Handler(void) {
117 while (1) {
118 NOOP;
123 #define __OSPI_GET_FLAG(__INSTANCE__, __FLAG__) ((READ_BIT((__INSTANCE__)->SR, (__FLAG__)) != 0U) ? SET : RESET)
124 #define __OSPI_CLEAR_FLAG(__INSTANCE__, __FLAG__) WRITE_REG((__INSTANCE__)->FCR, (__FLAG__))
125 #define __OSPI_ENABLE(__INSTANCE__) SET_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN)
126 #define __OSPI_DISABLE(__INSTANCE__) CLEAR_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN)
127 #define __OSPI_IS_ENABLED(__INSTANCE__) (READ_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN) != 0U)
129 MMFLASH_CODE_NOINLINE static void octoSpiAbort(OCTOSPI_TypeDef *instance)
131 SET_BIT(instance->CR, OCTOSPI_CR_ABORT);
134 MMFLASH_CODE_NOINLINE static void octoSpiWaitStatusFlags(OCTOSPI_TypeDef *instance, uint32_t mask, FlagStatus flagStatus)
136 uint32_t regval;
138 switch (flagStatus) {
139 case SET:
140 while (!((regval = READ_REG(instance->SR)) & mask))
142 break;
143 case RESET:
144 while (((regval = READ_REG(instance->SR)) & mask))
146 break;
151 typedef struct {
152 uint32_t OperationType;
154 uint32_t Instruction;
155 uint32_t InstructionMode;
156 uint32_t InstructionSize;
157 uint32_t InstructionDtrMode;
159 uint32_t Address;
160 uint32_t AddressMode;
161 uint32_t AddressSize;
162 uint32_t AddressDtrMode;
164 uint32_t AlternateBytes;
165 uint32_t AlternateBytesMode;
166 uint32_t AlternateBytesSize;
167 uint32_t AlternateBytesDtrMode;
169 uint32_t DummyCycles; // 0-31
171 uint32_t DataMode;
172 uint32_t DataDtrMode;
173 uint32_t NbData;
175 uint32_t DQSMode;
176 uint32_t SIOOMode;
177 } OSPI_Command_t;
179 // TODO rename cmd to command
180 MMFLASH_CODE_NOINLINE static ErrorStatus octoSpiConfigureCommand(OCTOSPI_TypeDef *instance, OSPI_Command_t *cmd)
182 ErrorStatus status = SUCCESS;
184 MODIFY_REG(instance->CR, OCTOSPI_CR_FMODE, 0U);
186 instance->CCR = (cmd->DQSMode | cmd->SIOOMode);
188 if (cmd->AlternateBytesMode != OSPI_ALTERNATE_BYTES_NONE)
190 instance->ABR = cmd->AlternateBytes;
192 MODIFY_REG(
193 instance->ABR,
194 (OCTOSPI_CCR_ABMODE | OCTOSPI_CCR_ABDTR | OCTOSPI_CCR_ABSIZE),
195 (cmd->AlternateBytesMode | cmd->AlternateBytesDtrMode | cmd->AlternateBytesSize)
199 MODIFY_REG(instance->TCR, OCTOSPI_TCR_DCYC, cmd->DummyCycles);
201 if (cmd->DataMode != OSPI_DATA_NONE)
203 if (cmd->OperationType == OSPI_OPTYPE_COMMON_CFG)
205 instance->DLR = (cmd->NbData - 1U);
210 if (cmd->InstructionMode != OSPI_INSTRUCTION_NONE)
212 if (cmd->AddressMode != OSPI_ADDRESS_NONE)
214 if (cmd->DataMode != OSPI_DATA_NONE)
216 // instruction, address and data
218 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE |
219 OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE |
220 OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR),
221 (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize |
222 cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize |
223 cmd->DataMode | cmd->DataDtrMode));
225 else
227 // instruction and address
229 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE |
230 OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE),
231 (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize |
232 cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize));
234 // DHQC bit is linked with DDTR
235 if (((instance->TCR & OCTOSPI_TCR_DHQC_Msk) == OSPI_DHQC_ENABLE) &&
236 (cmd->InstructionDtrMode == OSPI_INSTRUCTION_DTR_ENABLE))
238 MODIFY_REG(instance->CCR, OCTOSPI_CCR_DDTR, OSPI_DATA_DTR_ENABLE);
242 instance->IR = cmd->Instruction;
244 instance->AR = cmd->Address;
246 else
248 if (cmd->DataMode != OSPI_DATA_NONE)
250 // instruction and data
252 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE |
253 OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR),
254 (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize |
255 cmd->DataMode | cmd->DataDtrMode));
257 else
259 // instruction only
261 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_IMODE | OCTOSPI_CCR_IDTR | OCTOSPI_CCR_ISIZE),
262 (cmd->InstructionMode | cmd->InstructionDtrMode | cmd->InstructionSize));
264 // DHQC bit is linked with DDTR
265 if (((instance->TCR & OCTOSPI_TCR_DHQC_Msk) == OSPI_DHQC_ENABLE) &&
266 (cmd->InstructionDtrMode == OSPI_INSTRUCTION_DTR_ENABLE))
268 MODIFY_REG(instance->CCR, OCTOSPI_CCR_DDTR, OSPI_DATA_DTR_ENABLE);
272 instance->IR = cmd->Instruction;
276 else
278 if (cmd->AddressMode != OSPI_ADDRESS_NONE)
280 if (cmd->DataMode != OSPI_DATA_NONE)
282 // address and data
284 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE |
285 OCTOSPI_CCR_DMODE | OCTOSPI_CCR_DDTR),
286 (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize |
287 cmd->DataMode | cmd->DataDtrMode));
289 else
291 // address only
293 MODIFY_REG(instance->CCR, (OCTOSPI_CCR_ADMODE | OCTOSPI_CCR_ADDTR | OCTOSPI_CCR_ADSIZE),
294 (cmd->AddressMode | cmd->AddressDtrMode | cmd->AddressSize));
297 instance->AR = cmd->Address;
299 else
301 // no instruction, no address
302 status = ERROR;
306 return status;
309 MMFLASH_CODE_NOINLINE ErrorStatus octoSpiCommand(OCTOSPI_TypeDef *instance, OSPI_Command_t *cmd)
311 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_BUSY, RESET);
313 ErrorStatus status = octoSpiConfigureCommand(instance, cmd);
314 if (status == SUCCESS) {
315 if (cmd->DataMode == OSPI_DATA_NONE)
317 // transfer is already started, wait now.
318 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_TCF, SET);
319 __OSPI_CLEAR_FLAG(instance, OCTOSPI_SR_TCF);
323 return status;
327 * Transmit
329 * Call optoSpiCommand first to configure the transaction stages.
331 MMFLASH_CODE_NOINLINE ErrorStatus octoSpiTransmit(OCTOSPI_TypeDef *instance, uint8_t *data)
333 if (data == NULL) {
334 return ERROR;
338 __IO uint32_t XferCount = READ_REG(instance->DLR) + 1U;
339 uint8_t *pBuffPtr = data;
341 MODIFY_REG(instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE);
343 __IO uint32_t *data_reg = &instance->DR;
346 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_FTF, SET);
348 *((__IO uint8_t *)data_reg) = *pBuffPtr;
349 pBuffPtr++;
350 XferCount--;
351 } while (XferCount > 0U);
353 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_TCF, SET);
354 __OSPI_CLEAR_FLAG(instance, OCTOSPI_SR_TCF);
356 return SUCCESS;
360 * Receive
362 * Call optoSpiCommand first to configure the transaction stages.
364 MMFLASH_CODE_NOINLINE ErrorStatus octoSpiReceive(OCTOSPI_TypeDef *instance, uint8_t *data)
366 if (data == NULL) {
367 return ERROR;
370 __IO uint32_t XferCount = READ_REG(instance->DLR) + 1U;
371 uint8_t *pBuffPtr = data;
373 MODIFY_REG(instance->CR, OCTOSPI_CR_FMODE, OSPI_FUNCTIONAL_MODE_INDIRECT_READ);
375 uint32_t addr_reg = instance->AR;
376 uint32_t ir_reg = instance->IR;
378 // Trigger the transfer by re-writing the address or instruction register
379 if (READ_BIT(instance->CCR, OCTOSPI_CCR_ADMODE) != OSPI_ADDRESS_NONE)
381 WRITE_REG(instance->AR, addr_reg);
383 else
385 WRITE_REG(instance->IR, ir_reg);
388 __IO uint32_t *data_reg = &instance->DR;
392 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_FTF | OCTOSPI_SR_TCF, SET);
394 *pBuffPtr = *((__IO uint8_t *)data_reg);
395 pBuffPtr++;
396 XferCount--;
397 } while(XferCount > 0U);
399 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_TCF, SET);
400 __OSPI_CLEAR_FLAG(instance, OCTOSPI_SR_TCF);
402 return SUCCESS;
405 typedef struct
407 // CR register contains the all-important FMODE bits.
408 uint32_t CR;
410 // flash chip specific configuration set by the bootloader
411 uint32_t CCR;
412 uint32_t TCR;
413 uint32_t IR;
414 uint32_t ABR;
415 // address register - no meaning.
416 // data length register no meaning.
418 } octoSpiMemoryMappedModeConfigurationRegisterBackup_t;
420 octoSpiMemoryMappedModeConfigurationRegisterBackup_t ospiMMMCRBackups[OCTOSPI_INTERFACE_COUNT];
422 void octoSpiBackupMemoryMappedModeConfiguration(OCTOSPI_TypeDef *instance)
424 OCTOSPIDevice device = octoSpiDeviceByInstance(instance);
425 if (device == OCTOSPIINVALID) {
426 return;
429 octoSpiMemoryMappedModeConfigurationRegisterBackup_t *ospiMMMCRBackup = &ospiMMMCRBackups[device];
431 // backup all the registers used by memory mapped mode that:
432 // a) the bootloader configured.
433 // b) that other code in this implementation may have modified when memory mapped mode is disabled.
435 ospiMMMCRBackup->CR = instance->CR;
436 ospiMMMCRBackup->IR = instance->IR;
437 ospiMMMCRBackup->CCR = instance->CCR;
438 ospiMMMCRBackup->TCR = instance->TCR;
439 ospiMMMCRBackup->ABR = instance->ABR;
442 MMFLASH_CODE_NOINLINE void octoSpiRestoreMemoryMappedModeConfiguration(OCTOSPI_TypeDef *instance)
444 OCTOSPIDevice device = octoSpiDeviceByInstance(instance);
445 if (device == OCTOSPIINVALID) {
446 return;
449 octoSpiMemoryMappedModeConfigurationRegisterBackup_t *ospiMMMCRBackup = &ospiMMMCRBackups[device];
451 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_BUSY, RESET);
453 instance->ABR = ospiMMMCRBackup->ABR;
454 instance->TCR = ospiMMMCRBackup->TCR;
456 instance->DLR = 0; // "no meaning" in MM mode.
458 instance->CCR = ospiMMMCRBackup->CCR;
460 instance->IR = ospiMMMCRBackup->IR;
461 instance->AR = 0; // "no meaning" in MM mode.
463 octoSpiAbort(instance);
464 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_BUSY, RESET);
466 instance->CR = ospiMMMCRBackup->CR;
470 * Disable memory mapped mode.
472 * @See octoSpiEnableMemoryMappedMode
473 * @See MMFLASH_CODE_NOINLINE
475 * Once this is called any code or data in the memory mapped region cannot be accessed.
476 * Thus, this function itself must be in RAM, and the caller's code and data should all be in RAM
477 * and this requirement continues until octoSpiEnableMemoryMappedMode is called.
478 * This applies to ISR code that runs from the memory mapped region, so likely the caller should
479 * also disable IRQs before calling this.
481 MMFLASH_CODE_NOINLINE void octoSpiDisableMemoryMappedMode(OCTOSPI_TypeDef *instance)
483 if (READ_BIT(OCTOSPI1->CR, OCTOSPI_CR_FMODE) != OCTOSPI_CR_FMODE) {
484 failureMode(FAILURE_DEVELOPER); // likely not booted with memory mapped mode enabled, or mismatched calls to enable/disable memory map mode.
487 octoSpiAbort(instance);
488 if (__OSPI_GET_FLAG(instance, OCTOSPI_SR_BUSY) == SET) {
490 __OSPI_DISABLE(instance);
491 octoSpiAbort(instance);
493 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_BUSY, RESET);
495 uint32_t fmode = 0x0; // b00 = indirect write, see OCTOSPI->CR->FMODE
496 MODIFY_REG(instance->CR, OCTOSPI_CR_FMODE, fmode);
498 uint32_t regval = READ_REG(instance->CR);
499 if ((regval & OCTOSPI_CR_FMODE) != fmode) {
500 Error_Handler();
503 if (!__OSPI_IS_ENABLED(instance)) {
504 __OSPI_ENABLE(instance);
509 * Enable memory mapped mode.
511 * @See octoSpiDisableMemoryMappedMode
512 * @See MMFLASH_CODE_NOINLINE
515 MMFLASH_CODE_NOINLINE void octoSpiEnableMemoryMappedMode(OCTOSPI_TypeDef *instance)
517 octoSpiAbort(instance);
518 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_BUSY, RESET);
520 octoSpiRestoreMemoryMappedModeConfiguration(instance);
523 MMFLASH_CODE_NOINLINE void octoSpiTestEnableDisableMemoryMappedMode(octoSpiDevice_t *octoSpi)
525 OCTOSPI_TypeDef *instance = octoSpi->dev;
527 __disable_irq();
528 octoSpiDisableMemoryMappedMode(instance);
529 octoSpiEnableMemoryMappedMode(instance);
530 __enable_irq();
533 MMFLASH_DATA static const uint32_t octoSpi_addressSizeMap[] = {
534 OSPI_ADDRESS_8_BITS,
535 OSPI_ADDRESS_16_BITS,
536 OSPI_ADDRESS_24_BITS,
537 OSPI_ADDRESS_32_BITS
540 MMFLASH_CODE static uint32_t octoSpi_addressSizeFromValue(uint8_t addressSize)
542 return octoSpi_addressSizeMap[((addressSize + 1) / 8) - 1]; // rounds to nearest OSPI_ADDRESS_* value that will hold the address.
546 MMFLASH_CODE_NOINLINE bool octoSpiTransmit1LINE(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, const uint8_t *out, int length)
548 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
550 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
552 cmd.Instruction = instruction;
553 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
554 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
555 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
557 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
558 cmd.AddressMode = OSPI_ADDRESS_NONE;
559 cmd.AddressSize = OSPI_ADDRESS_32_BITS;
561 cmd.DummyCycles = dummyCycles;
563 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
565 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
566 cmd.DataMode = OSPI_DATA_NONE;
567 cmd.NbData = length;
569 cmd.DQSMode = OSPI_DQS_DISABLE;
570 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
572 if (out) {
573 cmd.DataMode = OSPI_DATA_1_LINE;
576 ErrorStatus status = octoSpiCommand(instance, &cmd);
578 if (status == SUCCESS && out && length > 0) {
579 status = octoSpiTransmit(instance, (uint8_t *)out);
581 return status == SUCCESS;
584 MMFLASH_CODE_NOINLINE bool octoSpiReceive1LINE(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint8_t *in, int length)
586 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
588 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
590 cmd.Instruction = instruction;
591 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
592 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
593 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
595 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
596 cmd.AddressMode = OSPI_ADDRESS_NONE;
597 cmd.AddressSize = OSPI_ADDRESS_32_BITS;
599 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
601 cmd.DummyCycles = dummyCycles;
603 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
604 cmd.DataMode = OSPI_DATA_1_LINE;
605 cmd.NbData = length;
607 cmd.DQSMode = OSPI_DQS_DISABLE;
608 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
610 ErrorStatus status = octoSpiCommand(instance, &cmd);
612 if (status == SUCCESS) {
613 status = octoSpiReceive(instance, in);
616 return status == SUCCESS;
619 MMFLASH_CODE_NOINLINE bool octoSpiReceive4LINES(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint8_t *in, int length)
621 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
623 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
625 cmd.Instruction = instruction;
626 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
627 cmd.InstructionMode = OSPI_INSTRUCTION_4_LINES;
628 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
630 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
631 cmd.AddressMode = OSPI_ADDRESS_NONE;
632 cmd.AddressSize = OSPI_ADDRESS_32_BITS;
634 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
636 cmd.DummyCycles = dummyCycles;
638 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
639 cmd.DataMode = OSPI_DATA_4_LINES;
640 cmd.NbData = length;
642 cmd.DQSMode = OSPI_DQS_DISABLE;
643 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
645 ErrorStatus status = octoSpiCommand(instance, &cmd);
647 if (status == SUCCESS) {
648 status = octoSpiReceive(instance, in);
651 return status == SUCCESS;
654 MMFLASH_CODE_NOINLINE bool octoSpiReceiveWithAddress1LINE(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint32_t address, uint8_t addressSize, uint8_t *in, int length)
656 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
658 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
660 cmd.Instruction = instruction;
661 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
662 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
663 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
665 cmd.Address = address;
666 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
667 cmd.AddressMode = OSPI_ADDRESS_1_LINE;
668 cmd.AddressSize = octoSpi_addressSizeFromValue(addressSize);
670 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
672 cmd.DummyCycles = dummyCycles;
674 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
675 cmd.DataMode = OSPI_DATA_1_LINE;
676 cmd.NbData = length;
678 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
679 cmd.DQSMode = OSPI_DQS_DISABLE;
681 ErrorStatus status = octoSpiCommand(instance, &cmd);
683 if (status == SUCCESS) {
684 status = octoSpiReceive(instance, in);
687 return status == SUCCESS;
690 MMFLASH_CODE_NOINLINE bool octoSpiReceiveWithAddress4LINES(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint32_t address, uint8_t addressSize, uint8_t *in, int length)
692 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
694 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
696 cmd.Instruction = instruction;
697 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
698 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
699 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
701 cmd.Address = address;
702 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
703 cmd.AddressMode = OSPI_ADDRESS_1_LINE;
704 cmd.AddressSize = octoSpi_addressSizeFromValue(addressSize);
706 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
708 cmd.DummyCycles = dummyCycles;
710 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
711 cmd.DataMode = OSPI_DATA_4_LINES;
712 cmd.NbData = length;
714 cmd.DQSMode = OSPI_DQS_DISABLE;
715 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
717 ErrorStatus status = octoSpiCommand(instance, &cmd);
719 if (status == SUCCESS) {
720 status = octoSpiReceive(instance, in);
723 return status == SUCCESS;
726 MMFLASH_CODE_NOINLINE bool octoSpiTransmitWithAddress1LINE(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint32_t address, uint8_t addressSize, const uint8_t *out, int length)
728 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
730 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
732 cmd.Instruction = instruction;
733 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
734 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
735 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
737 cmd.Address = address;
738 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
739 cmd.AddressMode = OSPI_ADDRESS_1_LINE;
740 cmd.AddressSize = octoSpi_addressSizeFromValue(addressSize);
742 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
744 cmd.DummyCycles = dummyCycles;
746 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
747 cmd.DataMode = OSPI_DATA_1_LINE;
748 cmd.NbData = length;
750 cmd.DQSMode = OSPI_DQS_DISABLE;
751 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
753 ErrorStatus status = octoSpiCommand(instance, &cmd);
755 if (status == SUCCESS) {
756 status = octoSpiTransmit(instance, (uint8_t *)out);
759 return status == SUCCESS;
762 MMFLASH_CODE_NOINLINE bool octoSpiTransmitWithAddress4LINES(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint32_t address, uint8_t addressSize, const uint8_t *out, int length)
764 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
766 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
768 cmd.Instruction = instruction;
769 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
770 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
771 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
773 cmd.Address = address;
774 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
775 cmd.AddressMode = OSPI_ADDRESS_1_LINE;
776 cmd.AddressSize = octoSpi_addressSizeFromValue(addressSize);
778 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
780 cmd.DummyCycles = dummyCycles;
782 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
783 cmd.DataMode = OSPI_DATA_4_LINES;
784 cmd.NbData = length;
786 cmd.DQSMode = OSPI_DQS_DISABLE;
787 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
789 ErrorStatus status = octoSpiCommand(instance, &cmd);
791 if (status == SUCCESS) {
792 status = octoSpiTransmit(instance, (uint8_t *)out);
796 return status == SUCCESS;
799 MMFLASH_CODE_NOINLINE bool octoSpiInstructionWithAddress1LINE(OCTOSPI_TypeDef *instance, uint8_t instruction, uint8_t dummyCycles, uint32_t address, uint8_t addressSize)
801 OSPI_Command_t cmd; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
803 cmd.OperationType = OSPI_OPTYPE_COMMON_CFG;
805 cmd.Instruction = instruction;
806 cmd.InstructionDtrMode = OSPI_INSTRUCTION_DTR_DISABLE;
807 cmd.InstructionMode = OSPI_INSTRUCTION_1_LINE;
808 cmd.InstructionSize = OSPI_INSTRUCTION_8_BITS;
810 cmd.Address = address;
811 cmd.AddressDtrMode = OSPI_ADDRESS_DTR_DISABLE;
812 cmd.AddressMode = OSPI_ADDRESS_1_LINE;
813 cmd.AddressSize = octoSpi_addressSizeFromValue(addressSize);
815 cmd.AlternateBytesMode = OSPI_ALTERNATE_BYTES_NONE;
817 cmd.DummyCycles = dummyCycles;
819 cmd.DataDtrMode = OSPI_DATA_DTR_DISABLE;
820 cmd.DataMode = OSPI_DATA_NONE;
821 cmd.NbData = 0;
823 cmd.DQSMode = OSPI_DQS_DISABLE;
824 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
826 ErrorStatus status = octoSpiCommand(instance, &cmd);
828 return status == SUCCESS;
832 void octoSpiInitDevice(OCTOSPIDevice device)
834 octoSpiDevice_t *octoSpi = &(octoSpiDevice[device]);
836 #if defined(STM32H730xx) || defined(STM32H723xx)
837 if (isMemoryMappedModeEnabledOnBoot()) {
838 // Bootloader has already configured the IO, clocks and peripherals.
839 octoSpiBackupMemoryMappedModeConfiguration(octoSpi->dev);
841 octoSpiTestEnableDisableMemoryMappedMode(octoSpi);
842 } else {
843 failureMode(FAILURE_DEVELOPER); // trying to use this implementation when memory mapped mode is not already enabled by a bootloader
845 // Here is where we would configure the OCTOSPI1/2 and OCTOSPIM peripherals for the non-memory-mapped use case.
847 #else
848 #error MCU not supported.
849 #endif
853 #endif