From 115b771e56aba7e7d066c8a58819d61d51009116 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Tue, 21 Feb 2017 21:37:36 +0000 Subject: i2c: Initial stub import of old f4 code Currently (despite docs) is an import of code reading the onboard i2c peripheral --- tests/i2c-master/Makefile.stm32f4-disco | 40 +++++++ tests/i2c-master/README.md | 17 +++ tests/i2c-master/main-stm32f4-disco.c | 189 ++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 tests/i2c-master/Makefile.stm32f4-disco create mode 100644 tests/i2c-master/README.md create mode 100644 tests/i2c-master/main-stm32f4-disco.c 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 . +## + +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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit