From 3afd683d683f482f003405c721800e3ba2ccb637 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Mon, 3 Oct 2016 12:51:52 -0700 Subject: cts: Add I2C tests for read8/16/32 and write8/16/32 This patch adds tests for i2c_read8/16/32 and i2c_write8/16/32. BUG=chromium:653183 BRANCH=none TEST=make buildall. Run cts.py -m i2c for 100kHz with 10k ohms pull-up registers on SCL and SDA. TH=stm32l476g-eval DUT=nucleo-f072rb. Change-Id: I8121b1c5dc7542da45141543e35036ef41364c38 Signed-off-by: Daisuke Nojiri Reviewed-on: https://chromium-review.googlesource.com/393331 Reviewed-by: Randall Spangler --- board/nucleo-f072rb/board.c | 10 +++ board/nucleo-f072rb/board.h | 5 ++ board/nucleo-f072rb/gpio.inc | 6 ++ board/stm32l476g-eval/board.c | 8 ++ board/stm32l476g-eval/board.h | 7 ++ board/stm32l476g-eval/gpio.inc | 7 +- chip/stm32/i2c-stm32l4.c | 8 +- cts/build.mk | 8 ++ cts/i2c/cts.testlist | 14 ++++ cts/i2c/cts_i2c.h | 20 +++++ cts/i2c/dut.c | 104 +++++++++++++++++++++++++ cts/i2c/th.c | 167 +++++++++++++++++++++++++++++++++++++++++ 12 files changed, 359 insertions(+), 5 deletions(-) create mode 100644 cts/i2c/cts.testlist create mode 100644 cts/i2c/cts_i2c.h create mode 100644 cts/i2c/dut.c create mode 100644 cts/i2c/th.c diff --git a/board/nucleo-f072rb/board.c b/board/nucleo-f072rb/board.c index 7bbfdfab39..c3489a9617 100644 --- a/board/nucleo-f072rb/board.c +++ b/board/nucleo-f072rb/board.c @@ -8,6 +8,8 @@ #include "hooks.h" #include "registers.h" #include "task.h" +#include "i2c.h" +#include "timer.h" void button_event(enum gpio_signal signal) { @@ -26,6 +28,14 @@ void tick_event(void) } DECLARE_HOOK(HOOK_TICK, tick_event, HOOK_PRIO_DEFAULT); +#ifdef CTS_MODULE_I2C +const struct i2c_port_t i2c_ports[] = { + {"test", STM32_I2C1_PORT, 100, GPIO_I2C1_SCL, GPIO_I2C1_SDA}, +}; + +const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); +#endif + /****************************************************************************** * Initialize board. */ diff --git a/board/nucleo-f072rb/board.h b/board/nucleo-f072rb/board.h index 6c934f8450..c008deb395 100644 --- a/board/nucleo-f072rb/board.h +++ b/board/nucleo-f072rb/board.h @@ -18,6 +18,11 @@ /* Optional features */ #define CONFIG_STM_HWTIMER32 +#ifdef CTS_MODULE_I2C +#define CONFIG_I2C +#define CONFIG_I2C_MASTER +#endif + #undef CONFIG_WATCHDOG_HELP #undef CONFIG_LID_SWITCH diff --git a/board/nucleo-f072rb/gpio.inc b/board/nucleo-f072rb/gpio.inc index 7b38555ef8..3515d5ca84 100644 --- a/board/nucleo-f072rb/gpio.inc +++ b/board/nucleo-f072rb/gpio.inc @@ -19,6 +19,12 @@ UNIMPLEMENTED(WP_L) ALTERNATE(PIN_MASK(A, 0x000C), 1, MODULE_UART, 0) /* USART2: PA2/PA3 */ +GPIO(I2C1_SCL, PIN(B, 6), GPIO_ODR_HIGH) /* I2C port 1 SCL */ +GPIO(I2C1_SDA, PIN(B, 7), GPIO_ODR_HIGH) /* I2C port 1 SDA */ + +/* I2C1: PB6/7*/ +ALTERNATE(PIN_MASK(B, 0x00C0), GPIO_ALT_F1, MODULE_I2C, GPIO_PULL_UP) + #ifdef CTS_MODULE /* CTS Signals */ GPIO(HANDSHAKE_INPUT, PIN(A, 4), GPIO_INPUT | GPIO_PULL_UP) diff --git a/board/stm32l476g-eval/board.c b/board/stm32l476g-eval/board.c index 6a5089a874..2ef46e8bc1 100644 --- a/board/stm32l476g-eval/board.c +++ b/board/stm32l476g-eval/board.c @@ -7,6 +7,7 @@ #include "gpio.h" #include "hooks.h" #include "registers.h" +#include "i2c.h" #ifdef CTS_MODULE /* @@ -29,3 +30,10 @@ void tick_event(void) count++; } DECLARE_HOOK(HOOK_TICK, tick_event, HOOK_PRIO_DEFAULT); + +#ifdef CTS_MODULE_I2C +const struct i2c_port_t i2c_ports[] = { + {"test", STM32_I2C2_PORT, 100, GPIO_I2C2_SCL, GPIO_I2C2_SDA}, +}; +const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); +#endif diff --git a/board/stm32l476g-eval/board.h b/board/stm32l476g-eval/board.h index 5cfc5b0870..12a83fc8fb 100644 --- a/board/stm32l476g-eval/board.h +++ b/board/stm32l476g-eval/board.h @@ -29,6 +29,13 @@ /* Optional features */ #define CONFIG_STM_HWTIMER32 +#ifdef CTS_MODULE_I2C +#define CONFIG_I2C +#define CONFIG_I2C_SLAVE +#define CONFIG_HOSTCMD_I2C_SLAVE_ADDR 0x3c +#define I2C_PORT_EC STM32_I2C2_PORT +#endif + /* * Allow dangerous commands all the time, since we don't have a write protect * switch. diff --git a/board/stm32l476g-eval/gpio.inc b/board/stm32l476g-eval/gpio.inc index 85447432c0..ff896d8da5 100644 --- a/board/stm32l476g-eval/gpio.inc +++ b/board/stm32l476g-eval/gpio.inc @@ -34,4 +34,9 @@ GPIO(OUTPUT_TEST, PIN(C, 11), GPIO_ODR_LOW) #ifdef CTS_MODULE_GPIO GPIO(INPUT_TEST, PIN(C, 10), GPIO_INPUT | GPIO_PULL_UP) #endif -#endif + +GPIO(I2C2_SCL, PIN(B, 10), GPIO_ODR_HIGH) /* I2C port 2 SCL */ +GPIO(I2C2_SDA, PIN(B, 11), GPIO_ODR_HIGH) /* I2C port 2 SDA */ + +ALTERNATE(PIN_MASK(B, 0x0C00), GPIO_ALT_F4, MODULE_I2C, GPIO_ODR_HIGH) /* I2C2: PB10/11 */ +#endif \ No newline at end of file diff --git a/chip/stm32/i2c-stm32l4.c b/chip/stm32/i2c-stm32l4.c index 0e943767b0..bffa6cea39 100644 --- a/chip/stm32/i2c-stm32l4.c +++ b/chip/stm32/i2c-stm32l4.c @@ -26,7 +26,7 @@ /* Transmit timeout in microseconds */ #define I2C_TX_TIMEOUT_MASTER (10 * MSEC) -#ifdef CONFIG_I2C_SLAVE_ADDR +#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR #define I2C_SLAVE_ERROR_CODE 0xec #if (I2C_PORT_EC == STM32_I2C1_PORT) #define IRQ_SLAVE STM32_IRQ_I2C1 @@ -177,7 +177,7 @@ static void i2c_init_port(const struct i2c_port_t *p) /*****************************************************************************/ -#ifdef CONFIG_I2C_SLAVE_ADDR +#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR static void i2c_event_handler(int port) { @@ -451,11 +451,11 @@ static void i2c_init(void) for (i = 0; i < i2c_ports_used; i++, p++) i2c_init_port(p); -#ifdef CONFIG_I2C_SLAVE_ADDR +#ifdef CONFIG_HOSTCMD_I2C_SLAVE_ADDR STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_RXIE | STM32_I2C_CR1_ERRIE | STM32_I2C_CR1_ADDRIE | STM32_I2C_CR1_STOPIE | STM32_I2C_CR1_NACKIE; - STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000 | CONFIG_I2C_SLAVE_ADDR; + STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000 | CONFIG_HOSTCMD_I2C_SLAVE_ADDR; task_enable_irq(IRQ_SLAVE); #endif } diff --git a/cts/build.mk b/cts/build.mk index 8d132e8da2..63b51c6fbf 100644 --- a/cts/build.mk +++ b/cts/build.mk @@ -9,6 +9,14 @@ ifeq "$(CTS_MODULE)" "gpio" CFLAGS_CTS+=-DCTS_MODULE_GPIO endif +ifeq "$(CTS_MODULE)" "i2c" +CFLAGS_CTS+=-DCTS_MODULE_I2C +CONFIG_I2C=y +ifneq ($(BOARD),stm32l476g-eval) +CONFIG_I2C_MASTER=y +endif +endif + ifeq ($(BOARD),stm32l476g-eval) cts-y+=$(CTS_MODULE)/th.o cts-y+=common/th_common.o diff --git a/cts/i2c/cts.testlist b/cts/i2c/cts.testlist new file mode 100644 index 0000000000..79732dc65b --- /dev/null +++ b/cts/i2c/cts.testlist @@ -0,0 +1,14 @@ +/* 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. + */ + +/* Currently tests will execute in the order they are listed here */ + +/* Test whether sync completes successfully */ +CTS_TEST(write8_test) +CTS_TEST(write16_test) +CTS_TEST(write32_test) +CTS_TEST(read8_test) +CTS_TEST(read16_test) +CTS_TEST(read32_test) \ No newline at end of file diff --git a/cts/i2c/cts_i2c.h b/cts/i2c/cts_i2c.h new file mode 100644 index 0000000000..9d287580bf --- /dev/null +++ b/cts/i2c/cts_i2c.h @@ -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. + */ + +enum cts_i2c_packets { + WRITE_8_OFFSET = 0, + WRITE_16_OFFSET = 1, + WRITE_32_OFFSET = 2, + READ_8_OFFSET = 3, + READ_16_OFFSET = 4, + READ_32_OFFSET = 5, +}; + +#define WRITE_8_DATA 0x42 +#define WRITE_16_DATA 0x1234 +#define WRITE_32_DATA 0xDEADBEEF +#define READ_8_DATA 0x23 +#define READ_16_DATA 0xACED +#define READ_32_DATA 0x01ABCDEF diff --git a/cts/i2c/dut.c b/cts/i2c/dut.c new file mode 100644 index 0000000000..b629475ffa --- /dev/null +++ b/cts/i2c/dut.c @@ -0,0 +1,104 @@ +/* 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. + */ + +#include "common.h" +#include "cts_common.h" +#include "cts_i2c.h" +#include "dut_common.h" +#include "i2c.h" +#include "registers.h" +#include "timer.h" +#include "uart.h" +#include "watchdog.h" + +#define TH_ADDR 0x3c + +enum cts_rc write8_test(void) +{ + int port = i2c_ports[0].port; + + i2c_write8(port, TH_ADDR, WRITE_8_OFFSET, WRITE_8_DATA); + + return CTS_RC_SUCCESS; +} + +enum cts_rc write16_test(void) +{ + int port = i2c_ports[0].port; + + i2c_write16(port, TH_ADDR, WRITE_16_OFFSET, WRITE_16_DATA); + + return CTS_RC_SUCCESS; +} + +enum cts_rc write32_test(void) +{ + int port = i2c_ports[0].port; + + i2c_write32(port, TH_ADDR, WRITE_32_OFFSET, WRITE_32_DATA); + + return CTS_RC_SUCCESS; +} + +enum cts_rc read8_test(void) +{ + int result; + int port = i2c_ports[0].port; + + i2c_read8(port, TH_ADDR, READ_8_OFFSET, &result); + + if (result != READ_8_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc read16_test(void) +{ + int result; + int port = i2c_ports[0].port; + + i2c_read16(port, TH_ADDR, READ_16_OFFSET, &result); + + if (result != READ_16_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc read32_test(void) +{ + int result; + int port = i2c_ports[0].port; + + i2c_read32(port, TH_ADDR, READ_32_OFFSET, &result); + + if (result != READ_32_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + + +#include "cts_testlist.h" + +void cts_task(void) +{ + int i; + + cflush(); + for (i = 0; i < CTS_TEST_ID_COUNT; i++) { + sync(); + CPRINTF("\n%s %d\n", tests[i].name, tests[i].run()); + uart_flush_output(); + } + + CPRINTS("I2C test suite finished"); + uart_flush_output(); + while (1) { + watchdog_reload(); + sleep(1); + } +} diff --git a/cts/i2c/th.c b/cts/i2c/th.c new file mode 100644 index 0000000000..86c3a2c8de --- /dev/null +++ b/cts/i2c/th.c @@ -0,0 +1,167 @@ +/* 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. + */ + +#include +#include "common.h" +#include "cts_common.h" +#include "cts_i2c.h" +#include "dut_common.h" +#include "i2c.h" +#include "registers.h" +#include "timer.h" +#include "uart.h" +#include "watchdog.h" + +static uint8_t inbox[I2C_MAX_HOST_PACKET_SIZE + 2]; +static char data_received; + +void i2c_data_received(int port, uint8_t *buf, int len) +{ + memcpy(inbox, buf, len); + data_received = 1; +} + +/* CTS I2C protocol implementation */ +int i2c_set_response(int port, uint8_t *buf, int len) +{ + switch (buf[0]) { + case READ_8_OFFSET: + buf[0] = READ_8_DATA; + return 1; + case READ_16_OFFSET: + buf[0] = READ_16_DATA & 0xFF; + buf[1] = (READ_16_DATA >> 8) & 0xFF; + return 2; + case READ_32_OFFSET: + buf[0] = READ_32_DATA & 0xFF; + buf[1] = (READ_32_DATA >> 8) & 0xFF; + buf[2] = (READ_32_DATA >> 16) & 0xFF; + buf[3] = (READ_32_DATA >> 24) & 0xFF; + return 4; + default: + return 0; + } +} + +static int wait_for_in_flag(uint32_t timeout_ms) +{ + uint64_t start_time, end_time; + + start_time = get_time().val; + end_time = start_time + timeout_ms * 1000; + + while (get_time().val < end_time) { + if (data_received) + return 0; + msleep(5); + watchdog_reload(); + } + return 1; +} + +static void clear_inbox(void) +{ + memset(inbox, 0, sizeof(inbox)); + data_received = 0; +} + +enum cts_rc write8_test(void) +{ + int in; + + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != WRITE_8_OFFSET) + return CTS_RC_FAILURE; + in = inbox[1]; + if (in != WRITE_8_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc write16_test(void) +{ + int in; + + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != WRITE_16_OFFSET) + return CTS_RC_FAILURE; + in = inbox[2] << 8 | inbox[1] << 0; + if (in != WRITE_16_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc write32_test(void) +{ + int in; + + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != WRITE_32_OFFSET) + return CTS_RC_FAILURE; + in = inbox[4] << 24 | inbox[3] << 16 | inbox[2] << 8 | inbox[1]; + if (in != WRITE_32_DATA) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc read8_test(void) +{ + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != READ_8_OFFSET) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc read16_test(void) +{ + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != READ_16_OFFSET) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +enum cts_rc read32_test(void) +{ + if (wait_for_in_flag(100)) + return CTS_RC_TIMEOUT; + if (inbox[0] != READ_32_OFFSET) + return CTS_RC_FAILURE; + + return CTS_RC_SUCCESS; +} + +#include "cts_testlist.h" + +void cts_task(void) +{ + enum cts_rc result; + int i; + + cflush(); + for (i = 0; i < CTS_TEST_ID_COUNT; i++) { + clear_inbox(); + sync(); + result = tests[i].run(); + CPRINTF("\n%s %d\n", tests[i].name, result); + uart_flush_output(); + } + + CPRINTS("I2C test suite finished"); + uart_flush_output(); + while (1) { + watchdog_reload(); + sleep(1); + } +} -- cgit v1.2.1