STM32 OCTOSPI Communication: High-Speed Serial Interface

#define FLASH_SIZE          0x4000000 // 64MB

/* Initialize Hyperflash */
void Hyperflash_Init(void)
{
  OCTOSPI_Init();
  
  /* Reset Hyperflash */
  uint8_t cmd[4] = {0xF0, 0x00, 0x00, 0x00}; 
  OCTOSPI_Write(0, cmd, 4);
  HAL_Delay(1);
  
  /* Configure read/write mode */
  cmd[0] = 0xC0; 
  cmd[1] = 0x00;
  cmd[2] = 0x00; 
  cmd[3] = 0x00;
  OCTOSPI_Write(0, cmd, 4);
}

/* Program download to Hyperflash */
void Program_Hyperflash(uint32_t address, uint8_t *data, uint32_t size)
{
  uint32_t end_addr = address + size;
  uint32_t prog_addr = address;
  
  while(prog_addr < end_addr)
  {
    /* Erase sector */
    Hyperflash_EraseSector(prog_addr);
    
    /* Write data */
    uint32_t len = MIN(256, end_addr - prog_addr);
    OCTOSPI_Write(prog_addr, data, len);
    
    prog_addr += len;
    data += len;
  }
}

/* Boot from Hyperflash */
void Boot_From_Hyperflash(void)
{
  /* Configure OCTOSPI to memory-mapped mode */
  OSPI_MemoryMappedTypeDef sMemMappedCfg;
  sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
  HAL_OSPI_MemoryMapped(&hospi1, &sMemMappedCfg);
  
  /* Redirect vector table */
  SCB->VTOR = OCTOSPI1_BASE;
  
  /* Jump to application in Hyperflash */
  void (*app_reset_handler)(void) = (void(*)(void))(*(volatile uint32_t*)(OCTOSPI1_BASE + 4));
  app_reset_handler();
}

6. Common Issues and Solutions

  1. 1. Communication rate does not meet standards

Solution:

  • • Check clock configuration to ensure OCTOSPI clock is correct
    • • Optimize line layout to reduce interference
    • • Adjust sampling clock phase
    • • Consider using DQS signal for data sampling
  1. 2. Data transmission errors

Solution:

  • • Check wiring for correctness
    • • Ensure communication parameters between master and slave devices are consistent
    • • Increase communication delay
    • • Use an oscilloscope to observe signal quality
  1. 3. Memory-mapped mode does not work properly

Solution:

  • • Check if Flash configuration is correct
    • • Ensure address mapping settings are accurate
    • • Try testing communication using indirect mode first
    • • Disable Cache and read data directly from OCTOSPI

Note: When debugging OCTOSPI issues, it is essential to use a logic analyzer or oscilloscope to observe the actual signal waveform, which is very helpful for locating problems.

Practical Suggestions

  1. 1. Start from simple single-line SPI mode and gradually transition to multi-line mode
  2. 2. Familiarize yourself with the instruction set and timing requirements of the target memory
  3. 3. Set clock frequency reasonably to balance speed and stability
  4. 4. Use DMA to improve data transfer efficiency
  5. 5. Add timeout handling for critical operations
  6. 6. Regularly perform erase balancing to extend Flash life
  7. 7. Consider using ECC technology to improve data reliability
  8. 8. For important data, it is recommended to add checksum and backup mechanisms

Mastering the OCTOSPI interface can greatly enhance the data interaction capability between STM32 and external high-speed memory. It is advisable to start practicing with the official evaluation board and gradually apply it to your own projects. If you have any questions, you can refer to ST official materials or seek help in relevant technical communities.

STM32 DAC Waveform Generator: Transform Your Microcontroller into a Signal Source

Today, let’s talk about the DAC function of the STM32 microcontroller. This little component is a treasure that can turn your microcontroller into a small signal generator. Whether generating sine waves, triangle waves, or square waves, it can easily handle it. For electronics enthusiasts, this is simply a portable laboratory tool!

What is a DAC?

A DAC, or Digital-to-Analog Converter, is a bridge that converts digital signals into analog signals. Imagine how the music files (digital signals) in your phone are turned into pleasant sounds (analog signals). That’s right, it’s all thanks to this little helper called DAC.

In STM32, the DAC acts like a magic box: you input a number between 0-4095, and it outputs a voltage between 0-3.3V. Isn’t this the programmable voltage source we’ve always dreamed of?

Basic Features of STM32 DAC

  • • 12-bit resolution (4096 levels)
    • • Two independent output channels
    • • Optional 8-bit or 12-bit data alignment
    • • Supports DMA transmission
    • • Built-in triangle wave and noise generator
    • • Can be triggered by timers or external signals

STM32 OCTOSPI Communication: 8-Line High-Speed Serial Interface

OCTOSPI is a new high-speed serial peripheral interface introduced by STM32, which can use up to 8 data lines compared to traditional SPI, greatly increasing data transfer rates. This article will introduce the basic concepts, working principles, and usage methods of OCTOSPI on STM32.

1. Basic Concepts of OCTOSPI

OCTOSPI stands for Octal Serial Peripheral Interface, which is an 8-line serial peripheral interface. It is an extension of the SPI interface, supporting up to 8 data lines for parallel transmission.

Main features:

  • • Supports up to 8 data lines
    • • Single-line, dual-line, quad-line, and octal-line modes available
    • • Supports simplex, half-duplex, and full-duplex communication
    • • Maximum clock frequency can reach 200MHz
    • • Compatible with standard SPI interfaces

OCTOSPI interface definition:

  • • CLK: Clock signal
    • • CS: Chip select signal
    • • DQ[0:7]: 8 bidirectional data lines
    • • DQS: Data sampling clock (optional)

The biggest advantage of OCTOSPI over SPI is the significant increase in data transfer rates. For example, at a 200MHz clock, the theoretical bandwidth in 8-line mode can reach 200MB/s, which is 8 times that of standard SPI.

2. Working Principle of OCTOSPI

The working principle of OCTOSPI is similar to that of SPI, both adopting a master-slave structure, with the master controlling the clock and chip select signals.

Basic timing:

  1. 1. The master pulls the CS signal low to select the slave
  2. 2. The master generates clock signals on the CLK
  3. 3. Data is transmitted on DQ[0:7], transferring 1-8 bits per clock cycle
  4. 4. After the transmission ends, the master pulls the CS high

OCTOSPI supports multiple working modes:

  • • Single-line SPI mode: Compatible with standard SPI
    • • Dual-line mode: Uses 2 data lines
    • • Quad-line mode: Uses 4 data lines
    • • Octal-line mode: Uses all 8 data lines

Data line allocation in different modes:

  • • Single-line mode: DQ0=MOSI, DQ1=MISO
    • • Dual-line mode: DQ0-DQ1 for bidirectional data
    • • Quad-line mode: DQ0-DQ3 for bidirectional data
    • • Octal-line mode: DQ0-DQ7 all used for bidirectional data

3. Introduction to STM32 OCTOSPI Peripheral

Main features of the STM32 OCTOSPI controller:

  • • Supports 1/2/4/8 line modes
    • • Maximum clock frequency of 200MHz
    • • 32-byte transmit/receive FIFO
    • • Supports DMA transmission
    • • Indirect and memory-mapped modes
    • • Supports Hyperbus protocol

Block diagram of the OCTOSPI controller:

         +-------------+
         |    AHB Bus   |
         +-------------+
                |
         +-------------+
         |  OCTOSPI Controller |
         +-------------+
           |    |    |
         CLK   CS   DQ[0:7]

Note: Not all STM32 models support OCTOSPI; please refer to the datasheet for confirmation before use.

4. OCTOSPI Programming Example

Below, we will take STM32H7 as an example to demonstrate how to read and write external Flash using OCTOSPI.

4.1 Initialization Configuration

void OCTOSPI_Init(void)
{
  OSPIM_CfgTypeDef sOspiManagerCfg = {0};
  OSPI_HyperbusCfgTypeDef sHyperBusCfg = {0};
  
  /* OCTOSPI1 GPIO configuration */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  
  /* Configure OCTOSPI manager */
  sOspiManagerCfg.ClkPort = 1;
  sOspiManagerCfg.DQSPort = 1;
  sOspiManagerCfg.NCSPort = 1;
  sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW;
  sOspiManagerCfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH;
  HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
  
  /* OCTOSPI parameter configuration */
  hospi1.Instance = OCTOSPI1;
  hospi1.Init.FifoThreshold = 4;
  hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
  hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_HYPERBUS;
  hospi1.Init.DeviceSize = 23; /* 64 MBits */
  hospi1.Init.ChipSelectHighTime = 2;
  hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
  hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
  hospi1.Init.ClockPrescaler = 2; /* OctoSPI clock = 200MHz / ClockPrescaler = 100MHz */
  hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_NONE;
  hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
  hospi1.Init.ChipSelectBoundary = 0;
  hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
  HAL_OSPI_Init(&hospi1);
  
  /* Hyperbus configuration */
  sHyperBusCfg.RWRecoveryTime = 3;
  sHyperBusCfg.AccessTime = HAL_OSPI_HYPERBUS_AT_6_CYCLES;
  sHyperBusCfg.WriteZeroLatency = HAL_OSPI_HYPERBUS_WRITE_ZERO_LATENCY_DISABLE;
  sHyperBusCfg.LatencyMode = HAL_OSPI_HYPERBUS_FIXED_LATENCY;
  HAL_OSPI_HyperbusCfg(&hospi1, &sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
}

4.2 Data Read and Write

/* Write data */
HAL_StatusTypeDef OCTOSPI_Write(uint32_t address, uint8_t *buffer, uint32_t size)
{
  OSPI_RegularCmdTypeDef sCommand = {0};
  
  sCommand.OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.Instruction = 0x02; /* Write command */
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.Address = address;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_8_LINES;
  sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
  sCommand.DataMode = HAL_OSPI_DATA_8_LINES;
  sCommand.NbData = size;
  sCommand.DummyCycles = 0;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
  
  if(HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return HAL_ERROR;
  }
  
  if(HAL_OSPI_Transmit(&hospi1, buffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return HAL_ERROR;
  }
  
  return HAL_OK;
}

/* Read data */  
HAL_StatusTypeDef OCTOSPI_Read(uint32_t address, uint8_t *buffer, uint32_t size)
{
  OSPI_RegularCmdTypeDef sCommand = {0};
  
  sCommand.OperationType = HAL_OSPI_OPTYPE_READ_CFG; 
  sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
  sCommand.Instruction = 0x03; /* Read command */
  sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;
  sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
  sCommand.Address = address;
  sCommand.AddressMode = HAL_OSPI_ADDRESS_8_LINES;
  sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
  sCommand.DataMode = HAL_OSPI_DATA_8_LINES;
  sCommand.NbData = size;
  sCommand.DummyCycles = 0;
  sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
  sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
  
  if(HAL_OSPI_Command(&hospi1, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

Leave a Comment