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) {
122 #define __OSPI_GET_FLAG(__INSTANCE__, __FLAG__) ((READ_BIT((__INSTANCE__)->SR, (__FLAG__)) != 0U) ? SET : RESET)
123 #define __OSPI_CLEAR_FLAG(__INSTANCE__, __FLAG__) WRITE_REG((__INSTANCE__)->FCR, (__FLAG__))
124 #define __OSPI_ENABLE(__INSTANCE__) SET_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN)
125 #define __OSPI_DISABLE(__INSTANCE__) CLEAR_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN)
126 #define __OSPI_IS_ENABLED(__INSTANCE__) (READ_BIT((__INSTANCE__)->CR, OCTOSPI_CR_EN) != 0U)
128 MMFLASH_CODE_NOINLINE
static void octoSpiAbort(OCTOSPI_TypeDef
*instance
)
130 SET_BIT(instance
->CR
, OCTOSPI_CR_ABORT
);
133 MMFLASH_CODE_NOINLINE
static void octoSpiWaitStatusFlags(OCTOSPI_TypeDef
*instance
, uint32_t mask
, FlagStatus flagStatus
)
137 switch (flagStatus
) {
139 while (!((regval
= READ_REG(instance
->SR
)) & mask
))
143 while (((regval
= READ_REG(instance
->SR
)) & mask
))
150 uint32_t OperationType
;
152 uint32_t Instruction
;
153 uint32_t InstructionMode
;
154 uint32_t InstructionSize
;
155 uint32_t InstructionDtrMode
;
158 uint32_t AddressMode
;
159 uint32_t AddressSize
;
160 uint32_t AddressDtrMode
;
162 uint32_t AlternateBytes
;
163 uint32_t AlternateBytesMode
;
164 uint32_t AlternateBytesSize
;
165 uint32_t AlternateBytesDtrMode
;
167 uint32_t DummyCycles
; // 0-31
170 uint32_t DataDtrMode
;
177 // TODO rename cmd to command
178 MMFLASH_CODE_NOINLINE
static ErrorStatus
octoSpiConfigureCommand(OCTOSPI_TypeDef
*instance
, OSPI_Command_t
*cmd
)
180 ErrorStatus status
= SUCCESS
;
182 MODIFY_REG(instance
->CR
, OCTOSPI_CR_FMODE
, 0U);
184 instance
->CCR
= (cmd
->DQSMode
| cmd
->SIOOMode
);
186 if (cmd
->AlternateBytesMode
!= OSPI_ALTERNATE_BYTES_NONE
)
188 instance
->ABR
= cmd
->AlternateBytes
;
192 (OCTOSPI_CCR_ABMODE
| OCTOSPI_CCR_ABDTR
| OCTOSPI_CCR_ABSIZE
),
193 (cmd
->AlternateBytesMode
| cmd
->AlternateBytesDtrMode
| cmd
->AlternateBytesSize
)
197 MODIFY_REG(instance
->TCR
, OCTOSPI_TCR_DCYC
, cmd
->DummyCycles
);
199 if (cmd
->DataMode
!= OSPI_DATA_NONE
)
201 if (cmd
->OperationType
== OSPI_OPTYPE_COMMON_CFG
)
203 instance
->DLR
= (cmd
->NbData
- 1U);
207 if (cmd
->InstructionMode
!= OSPI_INSTRUCTION_NONE
)
209 if (cmd
->AddressMode
!= OSPI_ADDRESS_NONE
)
211 if (cmd
->DataMode
!= OSPI_DATA_NONE
)
213 // instruction, address and data
215 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_IMODE
| OCTOSPI_CCR_IDTR
| OCTOSPI_CCR_ISIZE
|
216 OCTOSPI_CCR_ADMODE
| OCTOSPI_CCR_ADDTR
| OCTOSPI_CCR_ADSIZE
|
217 OCTOSPI_CCR_DMODE
| OCTOSPI_CCR_DDTR
),
218 (cmd
->InstructionMode
| cmd
->InstructionDtrMode
| cmd
->InstructionSize
|
219 cmd
->AddressMode
| cmd
->AddressDtrMode
| cmd
->AddressSize
|
220 cmd
->DataMode
| cmd
->DataDtrMode
));
224 // instruction and address
226 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_IMODE
| OCTOSPI_CCR_IDTR
| OCTOSPI_CCR_ISIZE
|
227 OCTOSPI_CCR_ADMODE
| OCTOSPI_CCR_ADDTR
| OCTOSPI_CCR_ADSIZE
),
228 (cmd
->InstructionMode
| cmd
->InstructionDtrMode
| cmd
->InstructionSize
|
229 cmd
->AddressMode
| cmd
->AddressDtrMode
| cmd
->AddressSize
));
231 // DHQC bit is linked with DDTR
232 if (((instance
->TCR
& OCTOSPI_TCR_DHQC_Msk
) == OSPI_DHQC_ENABLE
) &&
233 (cmd
->InstructionDtrMode
== OSPI_INSTRUCTION_DTR_ENABLE
))
235 MODIFY_REG(instance
->CCR
, OCTOSPI_CCR_DDTR
, OSPI_DATA_DTR_ENABLE
);
239 instance
->IR
= cmd
->Instruction
;
241 instance
->AR
= cmd
->Address
;
245 if (cmd
->DataMode
!= OSPI_DATA_NONE
)
247 // instruction and data
249 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_IMODE
| OCTOSPI_CCR_IDTR
| OCTOSPI_CCR_ISIZE
|
250 OCTOSPI_CCR_DMODE
| OCTOSPI_CCR_DDTR
),
251 (cmd
->InstructionMode
| cmd
->InstructionDtrMode
| cmd
->InstructionSize
|
252 cmd
->DataMode
| cmd
->DataDtrMode
));
258 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_IMODE
| OCTOSPI_CCR_IDTR
| OCTOSPI_CCR_ISIZE
),
259 (cmd
->InstructionMode
| cmd
->InstructionDtrMode
| cmd
->InstructionSize
));
261 // DHQC bit is linked with DDTR
262 if (((instance
->TCR
& OCTOSPI_TCR_DHQC_Msk
) == OSPI_DHQC_ENABLE
) &&
263 (cmd
->InstructionDtrMode
== OSPI_INSTRUCTION_DTR_ENABLE
))
265 MODIFY_REG(instance
->CCR
, OCTOSPI_CCR_DDTR
, OSPI_DATA_DTR_ENABLE
);
269 instance
->IR
= cmd
->Instruction
;
275 if (cmd
->AddressMode
!= OSPI_ADDRESS_NONE
)
277 if (cmd
->DataMode
!= OSPI_DATA_NONE
)
281 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_ADMODE
| OCTOSPI_CCR_ADDTR
| OCTOSPI_CCR_ADSIZE
|
282 OCTOSPI_CCR_DMODE
| OCTOSPI_CCR_DDTR
),
283 (cmd
->AddressMode
| cmd
->AddressDtrMode
| cmd
->AddressSize
|
284 cmd
->DataMode
| cmd
->DataDtrMode
));
290 MODIFY_REG(instance
->CCR
, (OCTOSPI_CCR_ADMODE
| OCTOSPI_CCR_ADDTR
| OCTOSPI_CCR_ADSIZE
),
291 (cmd
->AddressMode
| cmd
->AddressDtrMode
| cmd
->AddressSize
));
294 instance
->AR
= cmd
->Address
;
298 // no instruction, no address
306 MMFLASH_CODE_NOINLINE ErrorStatus
octoSpiCommand(OCTOSPI_TypeDef
*instance
, OSPI_Command_t
*cmd
)
308 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_BUSY
, RESET
);
310 ErrorStatus status
= octoSpiConfigureCommand(instance
, cmd
);
311 if (status
== SUCCESS
) {
312 if (cmd
->DataMode
== OSPI_DATA_NONE
)
314 // transfer is already started, wait now.
315 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_TCF
, SET
);
316 __OSPI_CLEAR_FLAG(instance
, OCTOSPI_SR_TCF
);
326 * Call optoSpiCommand first to configure the transaction stages.
328 MMFLASH_CODE_NOINLINE ErrorStatus
octoSpiTransmit(OCTOSPI_TypeDef
*instance
, uint8_t *data
)
334 __IO
uint32_t XferCount
= READ_REG(instance
->DLR
) + 1U;
335 uint8_t *pBuffPtr
= data
;
337 MODIFY_REG(instance
->CR
, OCTOSPI_CR_FMODE
, OSPI_FUNCTIONAL_MODE_INDIRECT_WRITE
);
339 __IO
uint32_t *data_reg
= &instance
->DR
;
342 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_FTF
, SET
);
344 *((__IO
uint8_t *)data_reg
) = *pBuffPtr
;
347 } while (XferCount
> 0U);
349 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_TCF
, SET
);
350 __OSPI_CLEAR_FLAG(instance
, OCTOSPI_SR_TCF
);
358 * Call optoSpiCommand first to configure the transaction stages.
360 MMFLASH_CODE_NOINLINE ErrorStatus
octoSpiReceive(OCTOSPI_TypeDef
*instance
, uint8_t *data
)
366 __IO
uint32_t XferCount
= READ_REG(instance
->DLR
) + 1U;
367 uint8_t *pBuffPtr
= data
;
369 MODIFY_REG(instance
->CR
, OCTOSPI_CR_FMODE
, OSPI_FUNCTIONAL_MODE_INDIRECT_READ
);
371 uint32_t addr_reg
= instance
->AR
;
372 uint32_t ir_reg
= instance
->IR
;
374 // Trigger the transfer by re-writing the address or instruction register
375 if (READ_BIT(instance
->CCR
, OCTOSPI_CCR_ADMODE
) != OSPI_ADDRESS_NONE
)
377 WRITE_REG(instance
->AR
, addr_reg
);
381 WRITE_REG(instance
->IR
, ir_reg
);
384 __IO
uint32_t *data_reg
= &instance
->DR
;
388 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_FTF
| OCTOSPI_SR_TCF
, SET
);
390 *pBuffPtr
= *((__IO
uint8_t *)data_reg
);
393 } while(XferCount
> 0U);
395 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_TCF
, SET
);
396 __OSPI_CLEAR_FLAG(instance
, OCTOSPI_SR_TCF
);
403 // CR register contains the all-important FMODE bits.
406 // flash chip specific configuration set by the bootloader
411 // address register - no meaning.
412 // data length register no meaning.
414 } octoSpiMemoryMappedModeConfigurationRegisterBackup_t
;
416 octoSpiMemoryMappedModeConfigurationRegisterBackup_t ospiMMMCRBackups
[OCTOSPI_INTERFACE_COUNT
];
418 void octoSpiBackupMemoryMappedModeConfiguration(OCTOSPI_TypeDef
*instance
)
420 OCTOSPIDevice device
= octoSpiDeviceByInstance(instance
);
421 if (device
== OCTOSPIINVALID
) {
425 octoSpiMemoryMappedModeConfigurationRegisterBackup_t
*ospiMMMCRBackup
= &ospiMMMCRBackups
[device
];
427 // backup all the registers used by memory mapped mode that:
428 // a) the bootloader configured.
429 // b) that other code in this implementation may have modified when memory mapped mode is disabled.
431 ospiMMMCRBackup
->CR
= instance
->CR
;
432 ospiMMMCRBackup
->IR
= instance
->IR
;
433 ospiMMMCRBackup
->CCR
= instance
->CCR
;
434 ospiMMMCRBackup
->TCR
= instance
->TCR
;
435 ospiMMMCRBackup
->ABR
= instance
->ABR
;
438 MMFLASH_CODE_NOINLINE
void octoSpiRestoreMemoryMappedModeConfiguration(OCTOSPI_TypeDef
*instance
)
440 OCTOSPIDevice device
= octoSpiDeviceByInstance(instance
);
441 if (device
== OCTOSPIINVALID
) {
445 octoSpiMemoryMappedModeConfigurationRegisterBackup_t
*ospiMMMCRBackup
= &ospiMMMCRBackups
[device
];
447 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_BUSY
, RESET
);
449 instance
->ABR
= ospiMMMCRBackup
->ABR
;
450 instance
->TCR
= ospiMMMCRBackup
->TCR
;
452 instance
->DLR
= 0; // "no meaning" in MM mode.
454 instance
->CCR
= ospiMMMCRBackup
->CCR
;
456 instance
->IR
= ospiMMMCRBackup
->IR
;
457 instance
->AR
= 0; // "no meaning" in MM mode.
459 octoSpiAbort(instance
);
460 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_BUSY
, RESET
);
462 instance
->CR
= ospiMMMCRBackup
->CR
;
466 * Disable memory mapped mode.
468 * @See octoSpiEnableMemoryMappedMode
469 * @See MMFLASH_CODE_NOINLINE
471 * Once this is called any code or data in the memory mapped region cannot be accessed.
472 * Thus, this function itself must be in RAM, and the caller's code and data should all be in RAM
473 * and this requirement continues until octoSpiEnableMemoryMappedMode is called.
474 * This applies to ISR code that runs from the memory mapped region, so likely the caller should
475 * also disable IRQs before calling this.
477 MMFLASH_CODE_NOINLINE
void octoSpiDisableMemoryMappedMode(OCTOSPI_TypeDef
*instance
)
479 if (READ_BIT(OCTOSPI1
->CR
, OCTOSPI_CR_FMODE
) != OCTOSPI_CR_FMODE
) {
480 failureMode(FAILURE_DEVELOPER
); // likely not booted with memory mapped mode enabled, or mismatched calls to enable/disable memory map mode.
483 octoSpiAbort(instance
);
484 if (__OSPI_GET_FLAG(instance
, OCTOSPI_SR_BUSY
) == SET
) {
486 __OSPI_DISABLE(instance
);
487 octoSpiAbort(instance
);
489 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_BUSY
, RESET
);
491 uint32_t fmode
= 0x0; // b00 = indirect write, see OCTOSPI->CR->FMODE
492 MODIFY_REG(instance
->CR
, OCTOSPI_CR_FMODE
, fmode
);
494 uint32_t regval
= READ_REG(instance
->CR
);
495 if ((regval
& OCTOSPI_CR_FMODE
) != fmode
) {
499 if (!__OSPI_IS_ENABLED(instance
)) {
500 __OSPI_ENABLE(instance
);
505 * Enable memory mapped mode.
507 * @See octoSpiDisableMemoryMappedMode
508 * @See MMFLASH_CODE_NOINLINE
511 MMFLASH_CODE_NOINLINE
void octoSpiEnableMemoryMappedMode(OCTOSPI_TypeDef
*instance
)
513 octoSpiAbort(instance
);
514 octoSpiWaitStatusFlags(instance
, OCTOSPI_SR_BUSY
, RESET
);
516 octoSpiRestoreMemoryMappedModeConfiguration(instance
);
519 MMFLASH_CODE_NOINLINE
void octoSpiTestEnableDisableMemoryMappedMode(octoSpiDevice_t
*octoSpi
)
521 OCTOSPI_TypeDef
*instance
= octoSpi
->dev
;
524 octoSpiDisableMemoryMappedMode(instance
);
525 octoSpiEnableMemoryMappedMode(instance
);
529 MMFLASH_DATA
static const uint32_t octoSpi_addressSizeMap
[] = {
531 OSPI_ADDRESS_16_BITS
,
532 OSPI_ADDRESS_24_BITS
,
536 MMFLASH_CODE
static uint32_t octoSpi_addressSizeFromValue(uint8_t addressSize
)
538 return octoSpi_addressSizeMap
[((addressSize
+ 1) / 8) - 1]; // rounds to nearest OSPI_ADDRESS_* value that will hold the address.
541 MMFLASH_CODE_NOINLINE
bool octoSpiTransmit1LINE(OCTOSPI_TypeDef
*instance
, uint8_t instruction
, uint8_t dummyCycles
, const uint8_t *out
, int length
)
543 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
545 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
547 cmd
.Instruction
= instruction
;
548 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
549 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
550 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
552 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
553 cmd
.AddressMode
= OSPI_ADDRESS_NONE
;
554 cmd
.AddressSize
= OSPI_ADDRESS_32_BITS
;
556 cmd
.DummyCycles
= dummyCycles
;
558 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
560 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
561 cmd
.DataMode
= OSPI_DATA_NONE
;
564 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
565 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
568 cmd
.DataMode
= OSPI_DATA_1_LINE
;
571 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
573 if (status
== SUCCESS
&& out
&& length
> 0) {
574 status
= octoSpiTransmit(instance
, (uint8_t *)out
);
576 return status
== SUCCESS
;
579 MMFLASH_CODE_NOINLINE
bool octoSpiReceive1LINE(OCTOSPI_TypeDef
*instance
, uint8_t instruction
, uint8_t dummyCycles
, uint8_t *in
, int length
)
581 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
583 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
585 cmd
.Instruction
= instruction
;
586 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
587 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
588 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
590 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
591 cmd
.AddressMode
= OSPI_ADDRESS_NONE
;
592 cmd
.AddressSize
= OSPI_ADDRESS_32_BITS
;
594 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
596 cmd
.DummyCycles
= dummyCycles
;
598 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
599 cmd
.DataMode
= OSPI_DATA_1_LINE
;
602 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
603 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
605 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
607 if (status
== SUCCESS
) {
608 status
= octoSpiReceive(instance
, in
);
611 return status
== SUCCESS
;
614 MMFLASH_CODE_NOINLINE
bool octoSpiReceive4LINES(OCTOSPI_TypeDef
*instance
, uint8_t instruction
, uint8_t dummyCycles
, uint8_t *in
, int length
)
616 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
618 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
620 cmd
.Instruction
= instruction
;
621 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
622 cmd
.InstructionMode
= OSPI_INSTRUCTION_4_LINES
;
623 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
625 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
626 cmd
.AddressMode
= OSPI_ADDRESS_NONE
;
627 cmd
.AddressSize
= OSPI_ADDRESS_32_BITS
;
629 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
631 cmd
.DummyCycles
= dummyCycles
;
633 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
634 cmd
.DataMode
= OSPI_DATA_4_LINES
;
637 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
638 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
640 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
642 if (status
== SUCCESS
) {
643 status
= octoSpiReceive(instance
, in
);
646 return status
== SUCCESS
;
649 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
)
651 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
653 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
655 cmd
.Instruction
= instruction
;
656 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
657 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
658 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
660 cmd
.Address
= address
;
661 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
662 cmd
.AddressMode
= OSPI_ADDRESS_1_LINE
;
663 cmd
.AddressSize
= octoSpi_addressSizeFromValue(addressSize
);
665 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
667 cmd
.DummyCycles
= dummyCycles
;
669 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
670 cmd
.DataMode
= OSPI_DATA_1_LINE
;
673 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
674 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
676 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
678 if (status
== SUCCESS
) {
679 status
= octoSpiReceive(instance
, in
);
682 return status
== SUCCESS
;
685 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
)
687 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
689 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
691 cmd
.Instruction
= instruction
;
692 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
693 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
694 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
696 cmd
.Address
= address
;
697 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
698 cmd
.AddressMode
= OSPI_ADDRESS_1_LINE
;
699 cmd
.AddressSize
= octoSpi_addressSizeFromValue(addressSize
);
701 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
703 cmd
.DummyCycles
= dummyCycles
;
705 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
706 cmd
.DataMode
= OSPI_DATA_4_LINES
;
709 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
710 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
712 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
714 if (status
== SUCCESS
) {
715 status
= octoSpiReceive(instance
, in
);
718 return status
== SUCCESS
;
721 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
)
723 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
725 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
727 cmd
.Instruction
= instruction
;
728 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
729 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
730 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
732 cmd
.Address
= address
;
733 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
734 cmd
.AddressMode
= OSPI_ADDRESS_1_LINE
;
735 cmd
.AddressSize
= octoSpi_addressSizeFromValue(addressSize
);
737 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
739 cmd
.DummyCycles
= dummyCycles
;
741 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
742 cmd
.DataMode
= OSPI_DATA_1_LINE
;
745 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
746 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
748 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
750 if (status
== SUCCESS
) {
751 status
= octoSpiTransmit(instance
, (uint8_t *)out
);
754 return status
== SUCCESS
;
757 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
)
759 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
761 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
763 cmd
.Instruction
= instruction
;
764 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
765 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
766 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
768 cmd
.Address
= address
;
769 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
770 cmd
.AddressMode
= OSPI_ADDRESS_1_LINE
;
771 cmd
.AddressSize
= octoSpi_addressSizeFromValue(addressSize
);
773 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
775 cmd
.DummyCycles
= dummyCycles
;
777 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
778 cmd
.DataMode
= OSPI_DATA_4_LINES
;
781 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
782 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
784 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
786 if (status
== SUCCESS
) {
787 status
= octoSpiTransmit(instance
, (uint8_t *)out
);
790 return status
== SUCCESS
;
793 MMFLASH_CODE_NOINLINE
bool octoSpiInstructionWithAddress1LINE(OCTOSPI_TypeDef
*instance
, uint8_t instruction
, uint8_t dummyCycles
, uint32_t address
, uint8_t addressSize
)
795 OSPI_Command_t cmd
; // Can't initialise to zero as compiler optimization will use memset() which is not in RAM.
797 cmd
.OperationType
= OSPI_OPTYPE_COMMON_CFG
;
799 cmd
.Instruction
= instruction
;
800 cmd
.InstructionDtrMode
= OSPI_INSTRUCTION_DTR_DISABLE
;
801 cmd
.InstructionMode
= OSPI_INSTRUCTION_1_LINE
;
802 cmd
.InstructionSize
= OSPI_INSTRUCTION_8_BITS
;
804 cmd
.Address
= address
;
805 cmd
.AddressDtrMode
= OSPI_ADDRESS_DTR_DISABLE
;
806 cmd
.AddressMode
= OSPI_ADDRESS_1_LINE
;
807 cmd
.AddressSize
= octoSpi_addressSizeFromValue(addressSize
);
809 cmd
.AlternateBytesMode
= OSPI_ALTERNATE_BYTES_NONE
;
811 cmd
.DummyCycles
= dummyCycles
;
813 cmd
.DataDtrMode
= OSPI_DATA_DTR_DISABLE
;
814 cmd
.DataMode
= OSPI_DATA_NONE
;
817 cmd
.DQSMode
= OSPI_DQS_DISABLE
;
818 cmd
.SIOOMode
= OSPI_SIOO_INST_EVERY_CMD
;
820 ErrorStatus status
= octoSpiCommand(instance
, &cmd
);
822 return status
== SUCCESS
;
825 void octoSpiInitDevice(OCTOSPIDevice device
)
827 octoSpiDevice_t
*octoSpi
= &(octoSpiDevice
[device
]);
829 #if defined(STM32H730xx) || defined(STM32H723xx)
830 if (isMemoryMappedModeEnabledOnBoot()) {
831 // Bootloader has already configured the IO, clocks and peripherals.
832 octoSpiBackupMemoryMappedModeConfiguration(octoSpi
->dev
);
834 octoSpiTestEnableDisableMemoryMappedMode(octoSpi
);
836 failureMode(FAILURE_DEVELOPER
); // trying to use this implementation when memory mapped mode is not already enabled by a bootloader
838 // Here is where we would configure the OCTOSPI1/2 and OCTOSPIM peripherals for the non-memory-mapped use case.
841 #error MCU not supported.