duplicate emptyline removal (#14027)
[betaflight.git] / src / platform / STM32 / bus_octospi_stm32h7xx.c
blob484283f45b4229737157b53ee91e7328b41feca2
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;
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)
135 uint32_t regval;
137 switch (flagStatus) {
138 case SET:
139 while (!((regval = READ_REG(instance->SR)) & mask))
141 break;
142 case RESET:
143 while (((regval = READ_REG(instance->SR)) & mask))
145 break;
149 typedef struct {
150 uint32_t OperationType;
152 uint32_t Instruction;
153 uint32_t InstructionMode;
154 uint32_t InstructionSize;
155 uint32_t InstructionDtrMode;
157 uint32_t Address;
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
169 uint32_t DataMode;
170 uint32_t DataDtrMode;
171 uint32_t NbData;
173 uint32_t DQSMode;
174 uint32_t SIOOMode;
175 } OSPI_Command_t;
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;
190 MODIFY_REG(
191 instance->ABR,
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));
222 else
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;
243 else
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));
254 else
256 // instruction only
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;
273 else
275 if (cmd->AddressMode != OSPI_ADDRESS_NONE)
277 if (cmd->DataMode != OSPI_DATA_NONE)
279 // address and data
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));
286 else
288 // address only
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;
296 else
298 // no instruction, no address
299 status = ERROR;
303 return status;
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);
320 return status;
324 * Transmit
326 * Call optoSpiCommand first to configure the transaction stages.
328 MMFLASH_CODE_NOINLINE ErrorStatus octoSpiTransmit(OCTOSPI_TypeDef *instance, uint8_t *data)
330 if (data == NULL) {
331 return ERROR;
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;
345 pBuffPtr++;
346 XferCount--;
347 } while (XferCount > 0U);
349 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_TCF, SET);
350 __OSPI_CLEAR_FLAG(instance, OCTOSPI_SR_TCF);
352 return SUCCESS;
356 * Receive
358 * Call optoSpiCommand first to configure the transaction stages.
360 MMFLASH_CODE_NOINLINE ErrorStatus octoSpiReceive(OCTOSPI_TypeDef *instance, uint8_t *data)
362 if (data == NULL) {
363 return ERROR;
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);
379 else
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);
391 pBuffPtr++;
392 XferCount--;
393 } while(XferCount > 0U);
395 octoSpiWaitStatusFlags(instance, OCTOSPI_SR_TCF, SET);
396 __OSPI_CLEAR_FLAG(instance, OCTOSPI_SR_TCF);
398 return SUCCESS;
401 typedef struct
403 // CR register contains the all-important FMODE bits.
404 uint32_t CR;
406 // flash chip specific configuration set by the bootloader
407 uint32_t CCR;
408 uint32_t TCR;
409 uint32_t IR;
410 uint32_t ABR;
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) {
422 return;
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) {
442 return;
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) {
496 Error_Handler();
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;
523 __disable_irq();
524 octoSpiDisableMemoryMappedMode(instance);
525 octoSpiEnableMemoryMappedMode(instance);
526 __enable_irq();
529 MMFLASH_DATA static const uint32_t octoSpi_addressSizeMap[] = {
530 OSPI_ADDRESS_8_BITS,
531 OSPI_ADDRESS_16_BITS,
532 OSPI_ADDRESS_24_BITS,
533 OSPI_ADDRESS_32_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;
562 cmd.NbData = length;
564 cmd.DQSMode = OSPI_DQS_DISABLE;
565 cmd.SIOOMode = OSPI_SIOO_INST_EVERY_CMD;
567 if (out) {
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;
600 cmd.NbData = length;
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;
635 cmd.NbData = length;
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;
671 cmd.NbData = length;
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;
707 cmd.NbData = length;
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;
743 cmd.NbData = length;
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;
779 cmd.NbData = length;
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;
815 cmd.NbData = 0;
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);
835 } else {
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.
840 #else
841 #error MCU not supported.
842 #endif
846 #endif