cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F767 QUAD SPI with DMA2

AShel.1
Associate III

I'm using STM32F767 and external flash is interfaced on QUADSPI, I've referred STM32746G-Discovery code for QSPI without DMA and its working fine. I want to implement QSPI using DMA, STM32F767 supports QSPI over DMA on channel 3 and stream 7 so did configuration accordingly, referred STM32F769I_EVAL code to modify my code for DMA. but using DMA its not working, I'm getting error in DMA_SetConfig function

hdma->Instance->CR &= (uint32_t)(~DMA_SxCR_DBM);

I'm using V1.8.0 HAL library.

My code is,

QSPI initialization:

uint8_t QUADSPI_Init(void)
{
  QSPIHandle.Instance = QUADSPI;
 
  /* Call the DeInit function to reset the driver */
  if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
  {
    return QSPI_ERROR;
  }
 
 
  /* QSPI initialization */
  QSPIHandle.Init.ClockPrescaler     = 1; /* AS[6/30]: changed pre-scaler to 1, QSPI freq = 192 MHz/(1+1) = 96 Mhz; 2;*/
  QSPIHandle.Init.FifoThreshold      = 4;
  QSPIHandle.Init.SampleShifting     = QSPI_SAMPLE_SHIFTING_NONE;//QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  QSPIHandle.Init.FlashSize          = QSPI_FLASH_SIZE;//POSITION_VAL(MT25QL128_FLASH_SIZE) - 1;
  QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; /* Min 50ns for nonRead */
  QSPIHandle.Init.ClockMode          = QSPI_CLOCK_MODE_0;
  QSPIHandle.Init.FlashID            = QSPI_FLASH_ID_2;
  QSPIHandle.Init.DualFlash          = QSPI_DUALFLASH_DISABLE;
  /* System level initialization */
  HAL_QSPI_MspInit(&QSPIHandle);
 
  if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
  {
    return QSPI_ERROR;
  }
 
  return QSPI_OK;
}
 
void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
 
  DMA_HandleTypeDef dma_handle;
 
  GPIO_InitTypeDef GPIO_InitStruct;//gpio_init_structure;
 
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /**QUADSPI GPIO Configuration
     PB2     ------> QUADSPI_CLK
     PE7     ------> QUADSPI_BK2_IO0
     PE8     ------> QUADSPI_BK2_IO1
     PE9     ------> QUADSPI_BK2_IO2
     PE10     ------> QUADSPI_BK2_IO3
     PC11     ------> QUADSPI_BK2_NCS
     */
  /* Enable the QuadSPI memory interface clock */
  QSPI_CLK_ENABLE();
  /* Reset the QuadSPI memory interface */
  QSPI_FORCE_RESET();
  QSPI_RELEASE_RESET();
  /* AS[7/3/20 */
 
  /* Enable chosen DMAx clock */
    __DMAx_CLK_ENABLE();
 
  /* Enable GPIO clocks */
  QSPI_CS_GPIO_CLK_ENABLE();
  QSPI_CLK_GPIO_CLK_ENABLE();
  QSPI_D0_GPIO_CLK_ENABLE();
  QSPI_D1_GPIO_CLK_ENABLE();
  QSPI_D2_GPIO_CLK_ENABLE();
  QSPI_D3_GPIO_CLK_ENABLE();
 
  /*##-2- Configure peripheral GPIO ##########################################*/
  GPIO_InitStruct.Pin = GPIO_PIN_2;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
      GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
      HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
 
      GPIO_InitStruct.Pin = GPIO_PIN_11;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
      HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
  /*##-3- Configure the NVIC for QSPI #########################################*/
  /* NVIC configuration for QSPI interrupt */
      /* AS[7/3/20 commented IRQ*/
   HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0);
  HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
#ifdef DMA_ENABLED
      /* AS[7/3/20 added DMA/
   Configure common DMA parameters */
    dma_handle.Init.Channel             = QSPI_DMAx_CHANNEL;
    //dma_handle.Init.Direction           = DMA_MEMORY_TO_MEMORY;
    dma_handle.Init.PeriphInc           = DMA_PINC_DISABLE;//ENABLE;
    dma_handle.Init.MemInc              = DMA_MINC_ENABLE;
    dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;//DMA_PDATAALIGN_WORD;
    dma_handle.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;//DMA_MDATAALIGN_WORD;
    dma_handle.Init.Mode                = DMA_NORMAL;
    dma_handle.Init.Priority            = DMA_PRIORITY_LOW;//HIGH;
    dma_handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;//ENABLE;//DMA_FIFOMODE_DISABLE;
    dma_handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    dma_handle.Init.MemBurst            = DMA_MBURST_SINGLE;
    dma_handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;
 
    dma_handle.Instance = QSPI_DMAx_STREAM;
    /* Associate the DMA handle */
        __HAL_LINKDMA(hqspi, hdma, dma_handle);
    HAL_DMA_Init(&dma_handle);
 
    /* NVIC configuration for DMA transfer complete interrupt */
    HAL_NVIC_SetPriority(QSPI_DMAx_IRQn, 0x05, 0);
    HAL_NVIC_EnableIRQ(QSPI_DMAx_IRQn);
 
}

Main:

 status =  QUADSPI_Init();
  sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
    sCommand.AddressSize       = QSPI_ADDRESS_24_BITS;
    sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;
    sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
    sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
 
    
  while(1)
  {
  switch(step)
      {
        case 0:
          CmdCplt = 0;
 
          /* Initialize Reception buffer --------------------------------------- */
          for (index = 0; index < BUFFERSIZE; index++)
          {
            aRxBuffer[index] = 0;
          }
        /*  if(QUADSPI_Erase_Block(WRITE_READ_ADDR) != QSPI_OK)
          {
        	  CmdCplt = 0;
          }*/
          /* Enable write operations ------------------------------------------- */
          QSPI_WriteEnable(&QSPIHandle);
 
          /* Erasing Sequence -------------------------------------------------- */
          sCommand.Instruction = SECTOR_ERASE_CMD;
          sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
          sCommand.Address     = address;
          sCommand.DataMode    = QSPI_DATA_NONE;
          sCommand.DummyCycles = 0;
 
          if (HAL_QSPI_Command_IT(&QSPIHandle, &sCommand) != HAL_OK)
          {
            Error_Handler();
          }
          /*if(QUADSPI_Erase_Block(WRITE_READ_ADDR) != QSPI_OK)
          {
        	  Error_Handler();
          }
          else
          {
        	  CmdCplt++;
          }*/
 
          step++;
          break;
 
        case 1:
          if(CmdCplt != 0)
          {
            CmdCplt = 0;
            StatusMatch = 0;
 
            /* Configure automatic polling mode to wait for end of erase ------- */
            QSPI_AutoPollingMemReady(&QSPIHandle);
 
            step++;
          }
          break;
 
        case 2:
          if(StatusMatch != 0)
          {
            StatusMatch = 0;
            TxCplt = 0;
 
            /* Enable write operations ----------------------------------------- */
            QSPI_WriteEnable(&QSPIHandle);
 
            /* Writing Sequence ------------------------------------------------ */
            sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
            sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
            sCommand.DataMode    = QSPI_DATA_4_LINES;
            sCommand.NbData      = BUFFERSIZE;
 
            if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
            {
              Error_Handler();
            }
            DMA_Update(&QSPIHandle);
            if (HAL_QSPI_Transmit_DMA(&QSPIHandle, aTxBuffer) != HAL_OK)
            {
              Error_Handler();
            }
 
            step++;
          }
          break;
 
        case 3:
          if(TxCplt != 0)
          {
            TxCplt = 0;
            StatusMatch = 0;
 
            /* Configure automatic polling mode to wait for end of program ----- */
            QSPI_AutoPollingMemReady(&QSPIHandle);
 
            step++;
          }
          break;
 
        case 4:
          if(StatusMatch != 0)
          {
            StatusMatch = 0;
            RxCplt = 0;
 
            /* Configure Volatile Configuration register (with new dummy cycles) */
            QSPI_DummyCyclesCfg(&QSPIHandle);
 
            /* Reading Sequence ------------------------------------------------ */
            sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
            sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
 
            if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
            {
              Error_Handler();
            }
 
            if (HAL_QSPI_Receive_DMA(&QSPIHandle, aRxBuffer) != HAL_OK)
            {
              Error_Handler();
            }
            step++;
          }
          break;
 
        case 5:
          if (RxCplt != 0)
          {
            RxCplt = 0;
 
            /* Result comparison ----------------------------------------------- */
            for (index = 0; index < BUFFERSIZE; index++)
            {
              if (aRxBuffer[index] != aTxBuffer[index])
              {
                //BSP_LED_On(LED2);
              }
            }
            //BSP_LED_Toggle(LED1);
 
            address += QSPI_PAGE_SIZE;
            if(address >= QSPI_END_ADDR)
            {
              address = 0;
            }
            step = 0;
          }
          break;
 
        default :
          Error_Handler();
      }
}

2 REPLIES 2
AShel.1
Associate III

Hello,

I've tried debugging all steps, at the end its raising hard fault. please help

Writing with DMA to QSPI interface, and trying concurrent memory-mapped operation, hard pressed to see that working.

>>..at the end its raising hard fault.

Kind of suggests that you're trying to access memory that's not mapped.

Unpack the Hard Fault to understand the specific code and registers at the faulting location, and what they are trying to do.

Start with an ability to output diagnostic data to a UART, and use a hard fault handler capable of outputting actionable data.

QSPI, expect to spend many man-days of effort on understanding/tuning interactions.

Code without using DMA, and switching mapping mode, determine how fast that is, and what the ceiling for performance is, and how much faster you might be able to get within the limitation of the devices.

QSPI write/erase is generally very slow. Optimal use case is reading from a device you've previously programmed.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..