256 lines
6.0 KiB
C
256 lines
6.0 KiB
C
/*
|
|
* Copyright (C) 2019 Harald Welte <laforge@gnumonks.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <parts.h>
|
|
|
|
#include "atmel_start.h"
|
|
#include "atmel_start_pins.h"
|
|
|
|
#include "i2c_bitbang.h"
|
|
#include "octsim_i2c.h"
|
|
#include "ncn8025.h"
|
|
|
|
#include "command.h"
|
|
|
|
enum testmode_test {
|
|
TEST_USER_LED,
|
|
/* test the per-slot LED by blinking it shortly */
|
|
TEST_LED,
|
|
/* test the voltages of the SIMVCC */
|
|
TEST_VOLTAGE,
|
|
/* test the clock rates of the SIMCLK pin */
|
|
TEST_CLOCK,
|
|
/* test the RST line by asserting it low and then back high */
|
|
TEST_RST,
|
|
/* test the RST line by asserting it low and then back high */
|
|
TEST_IO,
|
|
_NUM_TESTS
|
|
};
|
|
static const char *test_names[_NUM_TESTS] = {
|
|
[TEST_USER_LED] = "USER_LED",
|
|
[TEST_LED] = "LED",
|
|
[TEST_VOLTAGE] = "VOLTAGE",
|
|
[TEST_CLOCK] = "CLOCK",
|
|
[TEST_RST] = "RST",
|
|
[TEST_IO] = "IO",
|
|
};
|
|
|
|
struct testmode_state {
|
|
uint8_t slot;
|
|
enum testmode_test test_nr;
|
|
int test_int;
|
|
struct ncn8025_settings ncn;
|
|
};
|
|
static struct testmode_state g_tms;
|
|
|
|
#define BLINK_MS 500
|
|
|
|
static void set_slot(uint8_t slot)
|
|
{
|
|
printf("changing slot to %u\r\n", slot);
|
|
g_tms.slot = slot;
|
|
g_tms.ncn = (struct ncn8025_settings) {
|
|
.rstin = false,
|
|
.cmdvcc = false,
|
|
.led = false,
|
|
.clkdiv = SIM_CLKDIV_8,
|
|
.vsel = SIM_VOLT_3V0,
|
|
};
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
ncn8025_get(g_tms.slot, &g_tms.ncn);
|
|
}
|
|
|
|
static void next_test(void)
|
|
{
|
|
g_tms.test_nr = (g_tms.test_nr + 1) % _NUM_TESTS;
|
|
g_tms.test_int = 0;
|
|
printf("changing test to %s\r\n", test_names[g_tms.test_nr]);
|
|
}
|
|
|
|
static void test_user_led(void)
|
|
{
|
|
printf("blinking User LED\r\n");
|
|
|
|
gpio_set_pin_function(PIN_PC26, GPIO_PIN_FUNCTION_OFF);
|
|
gpio_set_pin_direction(PIN_PC26, GPIO_DIRECTION_OUT);
|
|
gpio_set_pin_level(PIN_PC26, true);
|
|
delay_ms(BLINK_MS);
|
|
gpio_set_pin_level(PIN_PC26, false);
|
|
}
|
|
|
|
static void test_led(void)
|
|
{
|
|
printf("blinking Slot LED\r\n");
|
|
|
|
g_tms.ncn.led = true;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
delay_ms(BLINK_MS);
|
|
g_tms.ncn.led = false;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
}
|
|
|
|
static enum ncn8025_sim_voltage voltage[3] = { SIM_VOLT_1V8, SIM_VOLT_3V0, SIM_VOLT_5V0 };
|
|
static const char *voltage_name[3] = { "1.8", "3.0", "5.0" };
|
|
|
|
static void ncn_change_voltage(enum ncn8025_sim_voltage vsel)
|
|
{
|
|
/* first disable the output; VSEL changes require output to be disabled */
|
|
g_tms.ncn.cmdvcc = false;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
|
|
/* then re-enable it with the new voltage setting */
|
|
g_tms.ncn.vsel = vsel;
|
|
g_tms.ncn.cmdvcc = true;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
}
|
|
|
|
static void test_voltage(void)
|
|
{
|
|
printf("Testing Voltage %s\r\n", voltage_name[g_tms.test_int]);
|
|
|
|
ncn_change_voltage(voltage[g_tms.test_int]);
|
|
g_tms.test_int = (g_tms.test_int+1) % 3;
|
|
}
|
|
|
|
static enum ncn8025_sim_clkdiv clk_div[4] = { SIM_CLKDIV_8, SIM_CLKDIV_4, SIM_CLKDIV_2, SIM_CLKDIV_1 };
|
|
static const uint8_t clk_div_val[4] = { 8, 4, 2, 1 };
|
|
|
|
static void test_clock(void)
|
|
{
|
|
printf("Testing Clock Divider %u\r\n", clk_div_val[g_tms.test_int]);
|
|
g_tms.ncn.cmdvcc = true;
|
|
g_tms.ncn.clkdiv = clk_div[g_tms.test_int];
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
g_tms.test_int = (g_tms.test_int+1) % 4;
|
|
}
|
|
|
|
static void test_rst(void)
|
|
{
|
|
printf("blinking RST\r\n");
|
|
|
|
/* well-defined voltage for LED brightness */
|
|
ncn_change_voltage(SIM_VOLT_3V0);
|
|
|
|
g_tms.ncn.cmdvcc = true;
|
|
g_tms.ncn.rstin = true;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
|
|
delay_ms(BLINK_MS);
|
|
|
|
g_tms.ncn.rstin = false;
|
|
ncn8025_set(g_tms.slot, &g_tms.ncn);
|
|
}
|
|
|
|
#ifndef SIM7_IO
|
|
#define SIM7_IO PIN_PB21
|
|
#endif
|
|
static const enum gpio_port sim_io_gpio[] = { SIM0_IO, SIM1_IO, SIM2_IO, SIM3_IO,
|
|
SIM4_IO, SIM5_IO, SIM6_IO, SIM7_IO };
|
|
|
|
static void test_io(void)
|
|
{
|
|
enum gpio_port gpio = sim_io_gpio[g_tms.slot];
|
|
printf("blinking I/O\r\n");
|
|
|
|
/* well-defined voltage for LED brightness */
|
|
ncn_change_voltage(SIM_VOLT_3V0);
|
|
|
|
gpio_set_pin_function(gpio, GPIO_PIN_FUNCTION_OFF);
|
|
gpio_set_pin_direction(gpio, GPIO_DIRECTION_OUT);
|
|
gpio_set_pin_level(gpio, false);
|
|
delay_ms(BLINK_MS);
|
|
gpio_set_pin_level(gpio, true);
|
|
|
|
/* FIXME: restore tack to original function! */
|
|
//gpio_set_pin_function(sim_io_gpio[g_tms.slot], GPIO_PIN_FUNCTION_OFF);
|
|
}
|
|
|
|
typedef void (*test_fn)(void);
|
|
static const test_fn test_functions[_NUM_TESTS] = {
|
|
[TEST_USER_LED] = test_user_led,
|
|
[TEST_LED] = test_led,
|
|
[TEST_VOLTAGE] = test_voltage,
|
|
[TEST_CLOCK] = test_clock,
|
|
[TEST_RST] = test_rst,
|
|
[TEST_IO] = test_io,
|
|
};
|
|
|
|
static void execute_test(void)
|
|
{
|
|
printf("(%u) %-10s: ", g_tms.slot, test_names[g_tms.test_nr]);
|
|
test_functions[g_tms.test_nr]();
|
|
}
|
|
|
|
static int wait_for_key_and_process(void)
|
|
{
|
|
int c;
|
|
|
|
do {
|
|
} while (!usart_async_rings_is_rx_not_empty(&UART_debug));
|
|
|
|
c = getchar();
|
|
if (c < 0)
|
|
return -1;
|
|
|
|
switch (c) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
set_slot(c - '0');
|
|
execute_test();
|
|
break;
|
|
case 'n':
|
|
case 'N':
|
|
next_test();
|
|
execute_test();
|
|
break;
|
|
case 'Q':
|
|
case 'q':
|
|
printf("Leaving Test Mode\r\n");
|
|
return -1;
|
|
case ' ':
|
|
execute_test();
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DEFUN(testmode_fn, cmd_testmode,
|
|
"testmode", "Enter board testing mode (Use `Q` to exit)")
|
|
{
|
|
printf("Manual test mode. 'Q': exit, 'N': next test, SPACE: re-run, '0'-'7': slot\r\n");
|
|
|
|
printf("SPACE will start the current test (%s)\r\n", test_names[g_tms.test_nr]);
|
|
while (1) {
|
|
if (wait_for_key_and_process() < 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void testmode_init(void)
|
|
{
|
|
command_register(&cmd_testmode);
|
|
}
|