summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2016-07-27 15:46:42 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-10-07 21:51:54 -0700
commit473ecbe2b36bc44da2552cd5814874a495913fc1 (patch)
tree116b0c658c2fa7916941d114d3ddb6ea33e8a71a
parent241d9e3728c6e2d23d71330be6ddfa5015414f1d (diff)
downloadchrome-ec-473ecbe2b36bc44da2552cd5814874a495913fc1.tar.gz
cts: Add real interrupt test
Interrupt test checks whether DUT can be interrupted by an interrupt and an interrupt handler can be invoked as expected. Note the previous interrupt test ported from test/interrupt.c runs in an emulated environment on the host, thus does not test the real interrupt capability of the chip. BUG=chromium:653195 BRANCH=none TEST=Run cts.py -m interrupt Change-Id: I21cecff07594f048633d1c1b699fb3a1876379e0 Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/363943 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--board/nucleo-f072rb/board.c10
-rw-r--r--board/nucleo-f072rb/gpio.inc12
-rw-r--r--cts/common/cts_common.h3
-rw-r--r--cts/interrupt/cts.testlist20
-rw-r--r--cts/interrupt/dut.c151
-rw-r--r--cts/interrupt/th.c101
6 files changed, 187 insertions, 110 deletions
diff --git a/board/nucleo-f072rb/board.c b/board/nucleo-f072rb/board.c
index c3489a9617..1d60231ebe 100644
--- a/board/nucleo-f072rb/board.c
+++ b/board/nucleo-f072rb/board.c
@@ -16,6 +16,16 @@ void button_event(enum gpio_signal signal)
gpio_set_level(GPIO_LED_U, 1);
}
+#ifdef CTS_MODULE
+/*
+ * Dummy interrupt handler. It's supposed to be overwritten by each suite
+ * if needed.
+ */
+__attribute__((weak)) void cts_irq(enum gpio_signal signal)
+{
+}
+#endif
+
#include "gpio_list.h"
void tick_event(void)
diff --git a/board/nucleo-f072rb/gpio.inc b/board/nucleo-f072rb/gpio.inc
index 3515d5ca84..31149bf633 100644
--- a/board/nucleo-f072rb/gpio.inc
+++ b/board/nucleo-f072rb/gpio.inc
@@ -9,6 +9,16 @@
* Note: Those with interrupt handlers must be declared first. */
GPIO_INT(USER_BUTTON, PIN(C, 13), GPIO_INT_FALLING, button_event)
+#ifdef CTS_MODULE
+#ifndef CTS_MODULE_GPIO
+/* Overload C1 for interrupt. Enabled only for non-GPIO suites as
+ * GPIO tests don't require a separate notification line. */
+GPIO_INT(CTS_IRQ, PIN(C, 1), GPIO_INT_FALLING | GPIO_PULL_UP , cts_irq)
+/* Used to disable interrupt. This IRQ# has to match the number used for the
+ * pin set above */
+#define CTS_IRQ_NUMBER STM32_IRQ_EXTI0_1
+#endif
+#endif
/* Outputs */
GPIO(LED_U, PIN(A, 5), GPIO_OUT_LOW)
@@ -29,6 +39,8 @@ ALTERNATE(PIN_MASK(B, 0x00C0), GPIO_ALT_F1, MODULE_I2C, GPIO_PULL_UP)
/* CTS Signals */
GPIO(HANDSHAKE_INPUT, PIN(A, 4), GPIO_INPUT | GPIO_PULL_UP)
GPIO(HANDSHAKE_OUTPUT, PIN(B, 0), GPIO_ODR_LOW)
+#ifdef CTS_MODULE_GPIO
GPIO(INPUT_TEST, PIN(C, 1), GPIO_INPUT | GPIO_PULL_UP)
+#endif
GPIO(OUTPUT_TEST, PIN(C, 0), GPIO_ODR_LOW)
#endif
diff --git a/cts/common/cts_common.h b/cts/common/cts_common.h
index e3a47d3e1b..607adbc623 100644
--- a/cts/common/cts_common.h
+++ b/cts/common/cts_common.h
@@ -27,7 +27,8 @@
#define CTS_DEBUG_PRINTF(format, args...)
#endif
-#define READ_WAIT_TIME_MS 100
+#define READ_WAIT_TIME_MS 100
+#define CTS_INTERRUPT_TRIGGER_DELAY_US (250 * MSEC)
/* In a single test, only one board can return unknown, the other must
* return a useful result (i.e. success, failure, etc)
diff --git a/cts/interrupt/cts.testlist b/cts/interrupt/cts.testlist
new file mode 100644
index 0000000000..6153c2b52d
--- /dev/null
+++ b/cts/interrupt/cts.testlist
@@ -0,0 +1,20 @@
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Test interrupt_enable/disable */
+CTS_TEST(test_interrupt_enable)
+CTS_TEST(test_interrupt_disable)
+
+/* Test task_wait_for_event */
+CTS_TEST(test_task_wait_event)
+
+/* Test task_disable_irq */
+CTS_TEST(test_task_disable_irq)
+
+/*
+ * Other ideas
+ *
+ * Test back-to-back interrupts, NVIC, Priorities
+ */ \ No newline at end of file
diff --git a/cts/interrupt/dut.c b/cts/interrupt/dut.c
index 63a377fb3c..43740147a7 100644
--- a/cts/interrupt/dut.c
+++ b/cts/interrupt/dut.c
@@ -1,84 +1,135 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
- *
- * Test interrupt support of EC emulator.
*/
#include "common.h"
-#include "console.h"
+#include "gpio.h"
+#include "registers.h"
#include "task.h"
-#include "test_util.h"
+#include "dut_common.h"
#include "timer.h"
-#include "util.h"
+#include "watchdog.h"
-static int main_count;
-static int has_error;
-static int interrupt_count;
+static int got_interrupt;
+static int wake_me_up;
-/* period between 50us and 3.2ms */
-#define PERIOD_US(num) (((num % 64) + 1) * 50)
-
-void my_isr(void)
+/*
+ * Raw busy loop. Returns 1 if loop finishes before interrupt is triggered.
+ * Loop length is controlled by busy_loop_timeout. It has to be set to the
+ * value which makes the loop last longer than CTS_INTERRUPT_TRIGGER_DELAY_US.
+ */
+static int busy_loop(void)
{
- int i = main_count;
+ /* TODO: Derive a proper value from clock speed */
+ const uint32_t busy_loop_timeout = 0xfffff;
+ uint32_t counter = 0;
+
+ while (counter++ < busy_loop_timeout) {
+ if (got_interrupt)
+ break;
+ watchdog_reload();
+ }
+ if (counter > busy_loop_timeout)
+ return 1;
- udelay(3 * PERIOD_US(prng_no_seed()));
- if (i != main_count || !in_interrupt_context())
- has_error = 1;
- interrupt_count++;
+ return 0;
}
-void interrupt_generator(void)
+/*
+ * Interrupt handler.
+ */
+void cts_irq(enum gpio_signal signal)
{
- while (1) {
- udelay(3 * PERIOD_US(prng_no_seed()));
- task_trigger_test_interrupt(my_isr);
- }
+ /* test some APIs */
+ got_interrupt = in_interrupt_context();
+
+ /* Wake up the CTS task */
+ if (wake_me_up)
+ task_wake(TASK_ID_CTS);
}
-static int interrupt_test(void)
+enum cts_rc test_task_wait_event(void)
{
- timestamp_t deadline = get_time();
+ uint32_t event;
- deadline.val += SECOND / 2;
- while (!timestamp_expired(deadline, NULL))
- ++main_count;
+ wake_me_up = 1;
- ccprintf("Interrupt count: %d\n", interrupt_count);
- ccprintf("Main thread tick: %d\n", main_count);
-
- TEST_ASSERT(!has_error);
- TEST_ASSERT(!in_interrupt_context());
+ /* Sleep and wait for interrupt. This shouldn't time out. */
+ event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2);
+ if (event != TASK_EVENT_WAKE) {
+ CPRINTS("Woke up by 0x%08x", event);
+ return CTS_RC_FAILURE;
+ }
+ if (!got_interrupt) {
+ CPRINTS("Interrupt context not detected");
+ return CTS_RC_TIMEOUT;
+ }
- return EC_SUCCESS;
+ return CTS_RC_SUCCESS;
}
-static int interrupt_disable_test(void)
+enum cts_rc test_task_disable_irq(void)
{
- timestamp_t deadline = get_time();
- int start_int_cnt, end_int_cnt;
+ uint32_t event;
- deadline.val += SECOND / 2;
+ wake_me_up = 1;
- interrupt_disable();
- start_int_cnt = interrupt_count;
- while (!timestamp_expired(deadline, NULL))
- ;
- end_int_cnt = interrupt_count;
- interrupt_enable();
+ task_disable_irq(CTS_IRQ_NUMBER);
+ /* Sleep and wait for interrupt. This should time out. */
+ event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2);
+ if (event != TASK_EVENT_TIMER) {
+ CPRINTS("Woke up by 0x%08x", event);
+ return CTS_RC_FAILURE;
+ }
+ task_enable_irq(CTS_IRQ_NUMBER);
- TEST_ASSERT(start_int_cnt == end_int_cnt);
+ return CTS_RC_SUCCESS;
+}
- return EC_SUCCESS;
+enum cts_rc test_interrupt_enable(void)
+{
+ if (busy_loop()) {
+ CPRINTS("Timeout before interrupt");
+ return CTS_RC_TIMEOUT;
+ }
+ return CTS_RC_SUCCESS;
+}
+
+enum cts_rc test_interrupt_disable(void)
+{
+ interrupt_disable();
+ if (!busy_loop()) {
+ CPRINTS("Expected timeout but didn't");
+ return CTS_RC_FAILURE;
+ }
+ return CTS_RC_SUCCESS;
}
+#include "cts_testlist.h"
+
void cts_task(void)
{
- test_reset();
+ enum cts_rc rc;
+ int i;
+
+ gpio_enable_interrupt(GPIO_CTS_IRQ);
+ interrupt_enable();
+ for (i = 0; i < CTS_TEST_ID_COUNT; i++) {
+ got_interrupt = 0;
+ wake_me_up = 0;
+ sync();
+ rc = tests[i].run();
+ interrupt_enable();
+ CPRINTF("\n%s %d\n", tests[i].name, rc);
+ cflush();
+ }
- RUN_TEST(interrupt_test);
- RUN_TEST(interrupt_disable_test);
+ CPRINTS("Interrupt test suite finished");
+ cflush();
- test_print_result();
+ while (1) {
+ watchdog_reload();
+ sleep(1);
+ }
}
diff --git a/cts/interrupt/th.c b/cts/interrupt/th.c
index 63a377fb3c..3bcf2168b6 100644
--- a/cts/interrupt/th.c
+++ b/cts/interrupt/th.c
@@ -1,84 +1,67 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+/* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
- *
- * Test interrupt support of EC emulator.
*/
#include "common.h"
-#include "console.h"
-#include "task.h"
-#include "test_util.h"
+#include "th_common.h"
+#include "gpio.h"
#include "timer.h"
-#include "util.h"
+#include "watchdog.h"
-static int main_count;
-static int has_error;
-static int interrupt_count;
-
-/* period between 50us and 3.2ms */
-#define PERIOD_US(num) (((num % 64) + 1) * 50)
-
-void my_isr(void)
+static void trigger_interrupt(void)
{
- int i = main_count;
-
- udelay(3 * PERIOD_US(prng_no_seed()));
- if (i != main_count || !in_interrupt_context())
- has_error = 1;
- interrupt_count++;
+ usleep(CTS_INTERRUPT_TRIGGER_DELAY_US);
+ gpio_set_level(GPIO_OUTPUT_TEST, 0);
+ usleep(CTS_INTERRUPT_TRIGGER_DELAY_US);
}
-void interrupt_generator(void)
+enum cts_rc test_task_wait_event(void)
{
- while (1) {
- udelay(3 * PERIOD_US(prng_no_seed()));
- task_trigger_test_interrupt(my_isr);
- }
+ trigger_interrupt();
+ return CTS_RC_SUCCESS;
}
-static int interrupt_test(void)
+enum cts_rc test_task_disable_irq(void)
{
- timestamp_t deadline = get_time();
-
- deadline.val += SECOND / 2;
- while (!timestamp_expired(deadline, NULL))
- ++main_count;
-
- ccprintf("Interrupt count: %d\n", interrupt_count);
- ccprintf("Main thread tick: %d\n", main_count);
-
- TEST_ASSERT(!has_error);
- TEST_ASSERT(!in_interrupt_context());
-
- return EC_SUCCESS;
+ trigger_interrupt();
+ return CTS_RC_SUCCESS;
}
-static int interrupt_disable_test(void)
+enum cts_rc test_interrupt_enable(void)
{
- timestamp_t deadline = get_time();
- int start_int_cnt, end_int_cnt;
-
- deadline.val += SECOND / 2;
-
- interrupt_disable();
- start_int_cnt = interrupt_count;
- while (!timestamp_expired(deadline, NULL))
- ;
- end_int_cnt = interrupt_count;
- interrupt_enable();
-
- TEST_ASSERT(start_int_cnt == end_int_cnt);
+ trigger_interrupt();
+ return CTS_RC_SUCCESS;
+}
- return EC_SUCCESS;
+enum cts_rc test_interrupt_disable(void)
+{
+ trigger_interrupt();
+ return CTS_RC_SUCCESS;
}
+#include "cts_testlist.h"
+
void cts_task(void)
{
- test_reset();
+ enum cts_rc rc;
+ int i;
- RUN_TEST(interrupt_test);
- RUN_TEST(interrupt_disable_test);
+ gpio_set_flags(GPIO_OUTPUT_TEST, GPIO_ODR_HIGH);
- test_print_result();
+ for (i = 0; i < CTS_TEST_ID_COUNT; i++) {
+ gpio_set_level(GPIO_OUTPUT_TEST, 1);
+ sync();
+ rc = tests[i].run();
+ CPRINTF("\n%s %d\n", tests[i].name, rc);
+ cflush();
+ }
+
+ CPRINTS("Interrupt test suite finished");
+ cflush();
+
+ while (1) {
+ watchdog_reload();
+ sleep(1);
+ }
}