aboutsummaryrefslogblamecommitdiff
path: root/projects/board-test/fmc-test.c
blob: bc5a76896958cce683bd1763570debad86f41741 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * stm-uart.h
 * ---------
 * Functions and defines to use the UART.
 *
 * 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.
 */

#ifndef __STM32_UART_H
#define __STM32_UART_H

#include "stm32f4xx_hal.h"

#define USART_MGMT_BAUD_RATE	921600
#define USART_USER_BAUD_RATE	921600

enum stm_uart_port {
  STM_UART_USER,
  STM_UART_MGMT
};

extern UART_HandleTypeDef huart_mgmt;
extern UART_HandleTypeDef huart_user;

extern HAL_StatusTypeDef uart_send_char(uint8_t ch);
extern HAL_StatusTypeDef uart_recv_char(uint8_t *cp);

extern HAL_StatusTypeDef uart_send_string(char *s);
extern HAL_StatusTypeDef uart_send_number(uint32_t num, uint8_t digits, uint8_t radix);

extern HAL_StatusTypeDef uart_send_char2(enum stm_uart_port port, uint8_t ch);
extern 
                  




























































                                                                                









                                                              




















                                                                                



                                                                       

































                                                                      










                                                              















                                                                                
//------------------------------------------------------------------------------
// main.c
//------------------------------------------------------------------------------

/*
 This requires a special bitstream with a special test register.
 See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked
 `ifdef test:
   //----------------------------------------------------------------
   // Dummy Register
   //
   // General-purpose register to test FMC interface using STM32
   // demo program instead of core selector logic.
   //
   // This register is a bit tricky, but it allows testing of both
   // data and address buses. Reading from FPGA will always return
   // value, which is currently stored in the test register, 
   // regardless of read transaction address. Writing to FPGA has
   // two variants: a) writing to address 0 will store output data
   // data value in the test register, b) writing to any non-zero
   // address will store _address_ of write transaction in the test
   // register.
   //
   // To test data bus, write some different patterns to address 0,
   // then readback from any address and compare.
   //
   // To test address bus, write anything to some different non-zero
   // addresses, then readback from any address and compare returned
   // value with previously written address.
   //
   //----------------------------------------------------------------
 */

//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-fmc.h"
#include "stm-uart.h"

//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------
RNG_HandleTypeDef rng_inst;

// FT: "I changed some interesting-to-look-at-in-the-debugger values to be
// volatile, so that my compiler wouldn't optimize/obscure them."

volatile uint32_t data_diff = 0;
volatile uint32_t addr_diff = 0;


//------------------------------------------------------------------------------
// Prototypes
//------------------------------------------------------------------------------
/* XXX move this to stm-rng.[ch] */
static void MX_RNG_Init(void);

int test_fpga_data_bus(void);
int test_fpga_address_bus(void);


//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
#define TEST_NUM_ROUNDS		100000


//------------------------------------------------------------------------------
int main(void)
//------------------------------------------------------------------------------
{
  int i;
  
  stm_init();

  uart_send_string("Keep calm for FPGA bitstream loading...\r\n");

  // Blink blue LED until the FPGA reports it has loaded it's bitstream
  led_on(LED_BLUE);
  while (! fpgacfg_check_done()) {
      for (i = 0; i < 4; i++) {
	  HAL_Delay(500);
	  led_toggle(LED_BLUE);
      }
  }

  // initialize rng
  MX_RNG_Init();

  // prepare fmc interface
  fmc_init();

  // turn on green led, turn off other leds
  led_on(LED_GREEN);
  led_off(LED_YELLOW);
  led_off(LED_RED);
  led_off(LED_BLUE);

  // vars
  volatile int data_test_ok = 0, addr_test_ok = 0, successful_runs = 0, failed_runs = 0, sleep = 0;

  // main loop (test, until an error is detected)
  while (1)
    {
      // test data bus
      data_test_ok = test_fpga_data_bus();
      // test address bus
      addr_test_ok = test_fpga_address_bus();

      uart_send_string("Data: ");
      uart_send_integer(data_test_ok, 6);
      uart_send_string(", addr: ");
      uart_send_integer(addr_test_ok, 6);
      uart_send_string("\r\n");

      if (data_test_ok == TEST_NUM_ROUNDS &&
	  addr_test_ok == TEST_NUM_ROUNDS) {
	// toggle yellow led to indicate, that we are alive
	led_toggle(LED_YELLOW);

	successful_runs++;
	sleep = 0;
      } else {
	led_on(LED_RED);
	failed_runs++;
	sleep = 2000;
      }

      uart_send_string("Success ");
      uart_send_integer(successful_runs, 0);
      uart_send_string(", fail ");
      uart_send_integer(failed_runs, 0);
      uart_send_string("\r\n\r\n");

      HAL_Delay(sleep);
    }

  // should never reach this line
}


//------------------------------------------------------------------------------
int test_fpga_data_bus(void)
//------------------------------------------------------------------------------
{
  int c, ok;
  uint32_t rnd, buf;
  HAL_StatusTypeDef hal_result;

  // run some rounds of data bus test
  for (c=0; c<TEST_NUM_ROUNDS; c++)
    {
      data_diff = 0;
      // try to generate "random" number
      hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
      if (hal_result != HAL_OK) break;

      // write value to fpga at address 0
      ok = fmc_write_32(0, &rnd);
      if (ok != 0) break;

      // read value from fpga
      ok = fmc_read_32(0, &buf);
      if (ok != 0) break;

      // compare (abort testing in case of error)
      if (buf != rnd)
	{
	  data_diff = buf;
	  data_diff ^= rnd;

	  uart_send_string("Data bus fail: expected ");
	  uart_send_binary(rnd, 32);
	  uart_send_string(", got ");
	  uart_send_binary(buf, 32);
	  uart_send_string(", diff ");
	  uart_send_binary(data_diff, 32);
	  uart_send_string("\r\n");

	  break;
	}
    }

  data_diff = buf;
  data_diff ^= rnd;

  uart_send_string("Sample of data bus test data: expected ");
  uart_send_binary(rnd, 32);
  uart_send_string(", got ");
  uart_send_binary(buf, 32);
  uart_send_string(", diff ");
  uart_send_binary(data_diff, 32);
  uart_send_string("\r\n");
  // return number of successful tests
  return c;
}


//------------------------------------------------------------------------------
int test_fpga_address_bus(void)
//------------------------------------------------------------------------------
{
  int c, ok;
  uint32_t rnd, buf;
  HAL_StatusTypeDef hal_result;

  // run some rounds of address bus test
  for (c=0; c<TEST_NUM_ROUNDS; c++)
    {
      addr_diff = 0;
      // try to generate "random" number
      hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
      if (hal_result != HAL_OK) break;

      // there are 26 physicaly connected address lines on the alpha,
      // but "only" 24 usable for now (the top two ones are used by FMC
      // to choose bank, and we only have one bank set up currently)
      rnd &= 0x3fffffc;

      // don't test zero addresses (fpga will store data, not address)
      if (rnd == 0) continue;

      // write dummy value to fpga at some non-zero address
      ok = fmc_write_32(rnd, &buf);
      if (ok != 0) break;

      // read value from fpga
      ok = fmc_read_32(0, &buf);
      if (ok != 0) break;

      // fpga receives address of 32-bit word, while we need
      // byte address here to compare
      buf <<= 2;

      // compare (abort testing in case of error)
      if (buf != rnd)
	{
	  addr_diff = buf;
	  addr_diff ^= rnd;

	  uart_send_string("Addr bus fail: expected ");
	  uart_send_binary(rnd, 32);
	  uart_send_string(", got ");
	  uart_send_binary(buf, 32);
	  uart_send_string(", diff ");
	  uart_send_binary(addr_diff, 32);
	  uart_send_string("\r\n");

	  break;
	}
    }

  addr_diff = buf;
  addr_diff ^= rnd;

  uart_send_string("Sample of addr bus test data: expected ");
  uart_send_binary(rnd, 32);
  uart_send_string(", got ");
  uart_send_binary(buf, 32);
  uart_send_string(", diff ");
  uart_send_binary(addr_diff, 32);
  uart_send_string("\r\n");

  return c;
}


//------------------------------------------------------------------------------
static void MX_RNG_Init(void)
//------------------------------------------------------------------------------
{
  rng_inst.Instance = RNG;
  HAL_RNG_Init(&rng_inst);
}


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