summaryrefslogtreecommitdiff
path: root/tests/i2c-master
diff options
context:
space:
mode:
Diffstat (limited to 'tests/i2c-master')
-rw-r--r--tests/i2c-master/Makefile.stm32f4-disco40
-rw-r--r--tests/i2c-master/README.md17
-rw-r--r--tests/i2c-master/main-stm32f4-disco.c189
3 files changed, 246 insertions, 0 deletions
diff --git a/tests/i2c-master/Makefile.stm32f4-disco b/tests/i2c-master/Makefile.stm32f4-disco
new file mode 100644
index 0000000..8621f2f
--- /dev/null
+++ b/tests/i2c-master/Makefile.stm32f4-disco
@@ -0,0 +1,40 @@
+##
+## This file is part of the libopencm3 project.
+##
+## This library is free software: you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This library 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 Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this library. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BOARD = stm32f4-disco
+PROJECT = i2c-master-$(BOARD)
+BUILD_DIR = bin-$(BOARD)
+
+SHARED_DIR = ../../shared
+
+CFILES = main-$(BOARD).c
+#CFILES += adc-power.c
+CFILES += trace.c trace_stdio.c
+
+VPATH += $(SHARED_DIR)
+
+INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
+
+OPENCM3_DIR=../../libopencm3/
+
+### This section can go to an arch shared rules eventually...
+DEVICE=stm32f405xg
+#OOCD_INTERFACE = stlink-v2
+#OOCD_TARGET = stm32f4x
+OOCD_FILE = ../../openocd/openocd.stm32f4-disco.cfg
+
+include ../../rules.mk
diff --git a/tests/i2c-master/README.md b/tests/i2c-master/README.md
new file mode 100644
index 0000000..74acefb
--- /dev/null
+++ b/tests/i2c-master/README.md
@@ -0,0 +1,17 @@
+i2c master mode tests.
+
+While many of the disco boards have some form of i2c device onboard,
+which would, on the face of it, make testing easy, it's a different
+device on each board, and there are boards without it.
+
+Instead, use a known I2C peripheral on all boards, and require/expect
+a known fixed i2c slave device. (Eventually, this will be a soft
+controllable i2c slave in the auto test setup ;)
+
+Debug is via SWO wherever possible, PA2 (tx only) on less capable cores
+
+Pinouts:
+
+board SCLK SDA
+f4-disco PB8 PB9 i2c1
+
diff --git a/tests/i2c-master/main-stm32f4-disco.c b/tests/i2c-master/main-stm32f4-disco.c
new file mode 100644
index 0000000..c74b5eb
--- /dev/null
+++ b/tests/i2c-master/main-stm32f4-disco.c
@@ -0,0 +1,189 @@
+/*
+ * Feb 2017 Karl Palsson <karlp@tweak.net.au>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/rcc.h>
+
+#include "trace.h"
+
+#define LED_DISCO_GREEN_PORT GPIOD
+#define LED_DISCO_GREEN_PIN GPIO12
+
+#define CODEC_ADDRESS 0x4a
+
+
+static void codec_gpio_init(void)
+{
+ /* reset pin */
+ rcc_periph_clock_enable(RCC_GPIOD);
+ gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4);
+
+ /* i2c control lines */
+ rcc_periph_clock_enable(RCC_GPIOB);
+ gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO9);
+ gpio_set_output_options(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO6 | GPIO9);
+ gpio_set_af(GPIOB, GPIO_AF4, GPIO6 | GPIO9);
+}
+
+static void codec_i2c_init(void)
+{
+ rcc_periph_clock_enable(RCC_I2C1);
+ i2c_peripheral_disable(I2C1);
+ i2c_reset(I2C1);
+ i2c_set_standard_mode(I2C1);
+ i2c_enable_ack(I2C1);
+ i2c_set_dutycycle(I2C1, I2C_CCR_DUTY_DIV2); /* default, no need to do this really */
+ i2c_set_clock_frequency(I2C1, I2C_CR2_FREQ_42MHZ);
+ /* 42MHz / (100kHz * 2) */
+ i2c_set_ccr(I2C1, 210);
+ /* standard mode, freqMhz+1*/
+ i2c_set_trise(I2C1, 43);
+ i2c_peripheral_enable(I2C1);
+}
+
+static void codec_init(void)
+{
+ int i;
+ /* Configure the Codec related IOs */
+ codec_gpio_init();
+
+ /* reset the codec */
+ gpio_clear(GPIOD, GPIO4);
+ for (i = 0; i < 1000000; i++) { /* Wait a bit. */
+ __asm__("NOP");
+ }
+ gpio_set(GPIOD, GPIO4);
+
+ codec_i2c_init();
+}
+
+static int codec_write_reg(uint8_t reg, uint8_t val)
+{
+ uint32_t i2c = I2C1;
+
+ while ((I2C_SR2(i2c) & I2C_SR2_BUSY)) {
+ }
+
+ i2c_send_start(i2c);
+
+ /* Wait for master mode selected */
+ while (!((I2C_SR1(i2c) & I2C_SR1_SB)
+ & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY))));
+
+ i2c_send_7bit_address(i2c, CODEC_ADDRESS, I2C_WRITE);
+
+ /* Waiting for address is transferred. */
+ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR));
+
+ /* Cleaning ADDR condition sequence. */
+ uint32_t reg32 = I2C_SR2(i2c);
+ (void) reg32; /* unused */
+
+ /* Common above here */
+
+ /* Sending the data. */
+ i2c_send_data(i2c, reg);
+ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF)));
+ i2c_send_data(i2c, val);
+ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF | I2C_SR1_TxE)));
+
+ /* Send STOP condition. */
+ i2c_send_stop(i2c);
+ return 0;
+}
+
+static uint32_t codec_read_reg(uint8_t reg)
+{
+ uint32_t i2c = I2C1;
+
+ while ((I2C_SR2(i2c) & I2C_SR2_BUSY)) {
+ }
+
+ i2c_send_start(i2c);
+
+ /* Wait for master mode selected */
+ while (!((I2C_SR1(i2c) & I2C_SR1_SB)
+ & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY))));
+
+ i2c_send_7bit_address(i2c, CODEC_ADDRESS, I2C_WRITE);
+
+ /* Waiting for address is transferred. */
+ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR));
+
+ /* Cleaning ADDR condition sequence. */
+ uint32_t reg32 = I2C_SR2(i2c);
+ (void) reg32; /* unused */
+
+ /* Common stuff ABOVE HERE */
+
+ i2c_send_data(i2c, reg);
+ while (!(I2C_SR1(i2c) & (I2C_SR1_BTF)));
+
+ i2c_send_start(i2c);
+
+ /* Wait for master mode selected */
+ while (!((I2C_SR1(i2c) & I2C_SR1_SB)
+ & (I2C_SR2(i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY))));
+
+ i2c_send_7bit_address(i2c, CODEC_ADDRESS, I2C_READ);
+
+ /* Waiting for address is transferred. */
+ while (!(I2C_SR1(i2c) & I2C_SR1_ADDR));
+
+ i2c_disable_ack(i2c);
+
+ /* Cleaning ADDR condition sequence. */
+ reg32 = I2C_SR2(i2c);
+ (void) reg32; /* unused */
+
+ i2c_send_stop(i2c);
+
+ while (!(I2C_SR1(i2c) & I2C_SR1_RxNE));
+ uint32_t result = i2c_get_data(i2c);
+
+ i2c_enable_ack(i2c);
+ I2C_SR1(i2c) &= ~I2C_SR1_AF;
+ return result;
+}
+
+static void codec_readid(void)
+{
+ uint8_t res = codec_read_reg(0x01);
+ printf("raw res = %#x Codec is %#x (should be 0x1c), revision %d\n", res, res >> 3, res & 0x7);
+}
+
+int main(void)
+{
+ int i, j;
+ rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
+ /* green led for ticking */
+ rcc_periph_clock_enable(RCC_GPIOD);
+ gpio_mode_setup(LED_DISCO_GREEN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
+ LED_DISCO_GREEN_PIN);
+ printf("hi guys!\n");
+ codec_init();
+ codec_readid();
+
+ codec_write_reg(0x14, 0xff);
+ for (i = 0; i < 8; i++) {
+ uint8_t pass_vol_a = codec_read_reg(0x14);
+ printf("Passthrough vol A was: %#x\n", pass_vol_a);
+ codec_write_reg(0x14, pass_vol_a >> 1);
+ gpio_toggle(LED_DISCO_GREEN_PORT, LED_DISCO_GREEN_PIN);
+ for (j = 0; j < 100000; j++) { /* Wait a bit. */
+ __asm__("NOP");
+ }
+ }
+
+ /* Nothing else to do */;
+ while (1) {
+ ;
+ }
+ return 0;
+}