aboutsummaryrefslogblamecommitdiff
path: root/stm-fmc.c
blob: eca4b38f9935014ad8049e5f7eb3aef2be8bfac0 (plain) (tree)
































                                                                           





                                                                                
                          





                                                                                
                                                                                                                







































































































































































                                                                                       
                                                                                         










































































































































                                                                                
/*
 * stm-fmc.c
 * ---------
 * Functions to set up and use the FMC bus.
 *
 * Copyright (c) 2015, NORDUnet A/S All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the NORDUnet nor the names of its contributors may
 *   be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "stm-fmc.h"
#include "stm32f4xx_hal.h"


//------------------------------------------------------------------------------
// Defined Values
//------------------------------------------------------------------------------
#define FMC_FPGA_BASE_ADDR              0x60000000
#define FMC_FPGA_ADDR_MASK              0x03FFFFFC  // there are 26 physical lines, but "only" 24 usable for now
#define FMC_FPGA_NWAIT_MAX_POLL_TICKS   10

#define FMC_GPIO_PORT_NWAIT             GPIOD
#define FMC_GPIO_PIN_NWAIT              GPIO_PIN_6

#define FMC_NWAIT_IDLE                  GPIO_PIN_SET


//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------
static SRAM_HandleTypeDef _fmc_fpga_inst;


//------------------------------------------------------------------------------
// Prototypes
//------------------------------------------------------------------------------
static void _fmc_init_gpio(void);
static void _fmc_init_params(void);
static int _fmc_nwait_idle(void);


//------------------------------------------------------------------------------
void fmc_init(void)
//------------------------------------------------------------------------------
{
  // configure fmc pins
  _fmc_init_gpio();

  // configure fmc registers
  _fmc_init_params();
}


//------------------------------------------------------------------------------
int fmc_write_32(uint32_t addr, uint32_t *data)
//------------------------------------------------------------------------------
{
  // calculate target fpga address
  uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);

  // write data to fpga
  HAL_StatusTypeDef ok = HAL_SRAM_Write_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);

  // check for error
  if (ok != HAL_OK) return -1;

  // wait for transaction to complete
  int wait = _fmc_nwait_idle();

  // check for timeout
  if (wait != 0) return -1;

  // everything went ok
  return 0;
}


//------------------------------------------------------------------------------
int fmc_read_32(uint32_t addr, uint32_t *data)
//------------------------------------------------------------------------------
{
  // calculate target fpga address
  uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK);

  // perform dummy read transaction
  HAL_StatusTypeDef ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);

  // check for error
  if (ok != HAL_OK) return -1;

  // wait for dummy transaction to complete
  int wait = _fmc_nwait_idle();

  // check for timeout
  if (wait != 0) return -1;

  // read data from fpga
  ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1);

  // check for error
  if (ok != HAL_OK) return -1;

  // wait for read transaction to complete
  wait = _fmc_nwait_idle();

  // check for timeout
  if (wait != 0) return -1;

  // everything went ok
  return 0;
}


//------------------------------------------------------------------------------
static int _fmc_nwait_idle()
//------------------------------------------------------------------------------
{
  int cnt; // counter

  // poll NWAIT (number of iterations is limited)
  for (cnt=0; cnt<FMC_FPGA_NWAIT_MAX_POLL_TICKS; cnt++)
    {
      // read pin state
      GPIO_PinState nwait = HAL_GPIO_ReadPin(FMC_GPIO_PORT_NWAIT, FMC_GPIO_PIN_NWAIT);

      // stop waiting if fpga is ready
      if (nwait == FMC_NWAIT_IDLE) break;
    }

  // check for timeout
  if (cnt >= FMC_FPGA_NWAIT_MAX_POLL_TICKS) return -1;

  // ok
  return 0;
}

//------------------------------------------------------------------------------
static void _fmc_init_gpio(void)
//------------------------------------------------------------------------------
{
  // enable gpio clocks
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();
  __GPIOD_CLK_ENABLE();
  __GPIOE_CLK_ENABLE();
  __GPIOF_CLK_ENABLE();
  __GPIOG_CLK_ENABLE();
  __GPIOH_CLK_ENABLE();
  __GPIOI_CLK_ENABLE();

  // enable fmc clock
  __FMC_CLK_ENABLE();

  // structure
  GPIO_InitTypeDef GPIO_InitStruct;

  // Port B
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  // Port D
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
    |GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_4
    |GPIO_PIN_5|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  /*
   * When FMC is working with fixed latency, NWAIT pin must not be
   * configured in AF mode, according to STM32F429 errata.
   */

  // Port D (GPIO!)
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  // Port E
  GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
    |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  // Port F
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
    |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13
    |GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  // Port G
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
    |GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  // Port H
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);

  // Port I
  GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_0|GPIO_PIN_1
    |GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
  HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
}


//------------------------------------------------------------------------------
static void _fmc_init_params(void)
//------------------------------------------------------------------------------
{
  /*
   * fill internal fields
   */
  _fmc_fpga_inst.Instance = FMC_NORSRAM_DEVICE;
  _fmc_fpga_inst.Extended = FMC_NORSRAM_EXTENDED_DEVICE;


  /*
   * configure fmc interface settings
   */

  // use the first bank and corresponding chip select
  _fmc_fpga_inst.Init.NSBank = FMC_NORSRAM_BANK1;

  // data and address buses are separate
  _fmc_fpga_inst.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;

  // fpga mimics psram-type memory
  _fmc_fpga_inst.Init.MemoryType = FMC_MEMORY_TYPE_PSRAM;

  // data bus is 32-bit
  _fmc_fpga_inst.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32;

  // read transaction is sync
  _fmc_fpga_inst.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_ENABLE;

  // this _must_ be configured to high, according to errata, otherwise
  // the processor may hang after trying to access fpga via fmc
  _fmc_fpga_inst.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_HIGH;

  // wrap mode is not supported
  _fmc_fpga_inst.Init.WrapMode = FMC_WRAP_MODE_DISABLE;

  // don't care in fixed latency mode
  _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_DURING_WS;

  // allow write access to fpga
  _fmc_fpga_inst.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;

  // use fixed latency mode (ignore wait signal)
  _fmc_fpga_inst.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;

  // write and read have same timing
  _fmc_fpga_inst.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;

  // don't care in sync mode
  _fmc_fpga_inst.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;

  // write transaction is sync
  _fmc_fpga_inst.Init.WriteBurst = FMC_WRITE_BURST_ENABLE;

  // keep clock always active
  _fmc_fpga_inst.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;

  /*
   * configure fmc timing parameters
   */
  FMC_NORSRAM_TimingTypeDef fmc_timing;

  // don't care in sync mode
  fmc_timing.AddressSetupTime = 15;

  // don't care in sync mode
  fmc_timing.AddressHoldTime = 15;

  // don't care in sync mode
  fmc_timing.DataSetupTime = 255;

  // not needed, since nwait will be polled manually
  fmc_timing.BusTurnAroundDuration = 0;

  // use smallest allowed divisor for best performance
  fmc_timing.CLKDivision = 2;

  // stm is too slow to work with min allowed 2-cycle latency
  fmc_timing.DataLatency = 3;

  // don't care in sync mode
  fmc_timing.AccessMode = FMC_ACCESS_MODE_A;

  // initialize fmc
  HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL);
}


//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------