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
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.
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) {
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
)
138 switch (flagStatus
) {
140 while (!((regval
= READ_REG(instance
->SR
)) & mask
))
144 while (((regval
= READ_REG(instance
->SR
)) & mask
))
152 uint32_t OperationType
;
154 uint32_t Instruction
;
155 uint32_t InstructionMode
;
156 uint32_t InstructionSize
;
157 uint32_t InstructionDtrMode
;
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
172 uint32_t DataDtrMode
;
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
;
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
));
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
;
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
));
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
;
278 if (cmd
->AddressMode
!= OSPI_ADDRESS_NONE
)
280 if (cmd
->DataMode
!= OSPI_DATA_NONE
)
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
));
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
;
301 // no instruction, no address
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
);
329 * Call optoSpiCommand first to configure the transaction stages.
331 MMFLASH_CODE_NOINLINE ErrorStatus
octoSpiTransmit(OCTOSPI_TypeDef
*instance
, uint8_t *data
)
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
;
351 } while (XferCount
> 0U);
353 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_TCF
, SET
);
354 __OSPI_CLEAR_FLAG(instance
, OCTOSPI_SR_TCF
);
362 * Call optoSpiCommand first to configure the transaction stages.
364 MMFLASH_CODE_NOINLINE ErrorStatus
octoSpiReceive(OCTOSPI_TypeDef
*instance
, uint8_t *data
)
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
);
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
);
397 } while(XferCount
> 0U);
399 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_TCF
, SET
);
400 __OSPI_CLEAR_FLAG(instance
, OCTOSPI_SR_TCF
);
407 // CR register contains the all-important FMODE bits.
410 // flash chip specific configuration set by the bootloader
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
) {
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
) {
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
) {
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
;
528 octoSpiDisableMemoryMappedMode(instance
);
529 octoSpiEnableMemoryMappedMode(instance
);
533 MMFLASH_DATA
static const uint32_t octoSpi_addressSizeMap
[] = {
535 OSPI_ADDRESS_16_BITS
,
536 OSPI_ADDRESS_24_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
;
569 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
570 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
);
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.
848 #error MCU not supported.