I2C on 8bit port

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
SGapp
Member++
Posts: 21
Joined: Mon May 04, 2020 4:32 pm
Location: Berlin, Germany

I2C on 8bit port

Post by SGapp »

Hey everyone,
I am trying to use I2C on my XUF216 on Port 8D (on P8D6 and P8D7) on tile 1 with the module_i2c_single_port. This is part of a larger PDM to USB converter based on app_usb_aud_mic_array.
Unfortunately, the I2C output is not working. On my logic analyzer it shows me that SDA and SCL are set to 0 but no clocking and no data transmission is happening. See the attached screenshot here. Seems like there are the three parts for device address, register address and data but not clocking.

This my MWE main function, that I tried to run on the XUF216:

Code: Select all

#include <xs1.h>
#include <platform.h>
#include <i2c.h>

on tile [1] : struct r_i2c i2c = {XS1_PORT_8D};

unsigned char tx_data[1] = {0x05};
int len = sizeof(tx_data)/sizeof(tx_data[0]);
unsigned char rx_data[1] = {0xAA};

int main(){
    par
    {
        on tile[1]:{
        i2c_master_init(i2c);
        i2c_master_write_reg(0x4e,0x03, tx_data, len, i2c);
        i2c_master_read_reg(0x4e, 0x03, rx_data,len, i2c);
        }
    }
    return 0;
}
and this is the i2c.h from module_i2c_single_port. I tried to adapt SDA_HIGH and SCL_HIGH as described in this post and changed the S_REST from 0xC to 0x3F, since I want to use the two MSB of this 8bit port.

Code: Select all

// Copyright (c) 2011, XMOS Ltd, All rights reserved
// This software is freely distributable under a derivative of the
// University of Illinois/NCSA Open Source License posted in
// LICENSE.txt and at <http://github.xcore.com/>


#ifndef _i2c_h_
#define _i2c_h_

#ifdef __i2c_conf_h_exists__
#include "i2c_conf.h"
#endif

#include <xs1.h>
#include <xccompat.h>

#ifndef I2C_BIT_TIME

/** This constant defines the time in clock ticks between successive bits.
 * By default set to 1000 for 100 Kbit devices, but it can be overriden to
 * 250 for 400 Kbit devices.
 */
#define I2C_BIT_TIME 10000

#endif

#ifndef SDA_HIGH

/** This constant defines the bit value of a high data bit on the I2C port. The
 * default value is 1, meaning that this is on bit 0 of the port. Set to 2,
 * 4, 8, ... for other bits of the port.
 */

#define SDA_HIGH    (128)

#endif


#ifndef SCL_HIGH

/** This constant defines the bit value of a high clock on the I2C port. The
 * default value is 2, meaning that this is on bit 1 of the port. Set to 1,
 * 4, 8, ... for other bits of the port.
 */
#define SCL_HIGH    (64)

#endif


#ifndef S_REST

/** This constant defines the bit value of the other bits of the I2C port.
 * The default value is 0xC, meaning that bits 2 and 3 are kept high. Note
 * that on occassions the other bits are left to float, so external
 * resistors shall be used to reinforce the default value
 */
#define S_REST  (0x3F)

#endif

#ifndef I2C_REPEATED_START_ON_NACK

/** This constant defines the I2C masters behaviour on receipt of a NACK from a busy
 * slave device. By default the issuing of a repeated start is disabled, and the
 * module will ignore NACKs when reading from the device.
 */
#define I2C_REPEATED_START_ON_NACK 0
#endif

#ifndef  I2C_REPEATED_START_MAX_RETRIES

/** This constant defines the maximum number of times the I2C master should issue a
 * repeated start on receipt of a NACK.
 */
#define I2C_REPEATED_START_MAX_RETRIES 10

#endif

#ifndef  I2C_REPEATED_START_DELAY

/** This constant defines the delay in microseconds (us) that the I2C master must wait following
 * the receipt of a NACK before issuing a repeated start.
 */
#define I2C_REPEATED_START_DELAY 500

#endif

/** Struct that holds the data for instantiating the I2C module - it just
 * comprises one port (the clock line and the data line are on the same port),
 * the only other settable parameter is the speed of the bus which is a compile time
 * define.
 */
struct r_i2c {
    port p_i2c;
};

/**Function that initialises the ports on an I2C device.
 *
 * \param i2c Bidirectional port connected to both SDA and SCL.
 */
void i2c_master_init(REFERENCE_PARAM(struct r_i2c, i2cPorts));


/**Function that writes to a register on an I2C device.
 *
 * Note that this function uses the same interface as module_i2c but that
 * the fields master_num and clock_mul are ignored by this function.
 *
 * \param device     Bus address of device, number between 0x00 and 0x7F.
 *
 * \param reg_addr   Address of register to write to, value between 0x00 and 0x7F.
 *
 * \param data       Array where data is stored.
 *
 * \param nbytes     Number of bytes to read and store in data. This parameter
 *                   must be set to '1' and is ignored in this module.
 *                   This parameter is provided for compatibililty with module_i2c_master.
 *
 * \param i2c  Bidirectional port connected to both SDA and SCL.
 */
int i2c_master_write_reg(int device, int reg_addr,
                         const unsigned char data[],
                         int nbytes,
                         REFERENCE_PARAM(struct r_i2c, i2cPorts));

#ifdef __XS2A__
/**Function that reads a register on an I2C device. Supported on XCORE200 only.
 *
 * \param device     Bus address of device, number between 0x00 and 0x7F.
 *
 * \param reg_addr   Address of register to write to, value between 0x00 and 0x7F.
 *
 * \param data       Array where return data will be stored.
 *
 * \param nbytes     Number of bytes to read and store in data. This parameter
 *                   must be set to '1' and is ignored in this module.
 *                   This parameter is provided for compatibililty with module_i2c_master.
 *
 * \param i2c  Bidirectional port connected to both SDA and SCL.
 */
int i2c_master_read_reg(int device, int addr,
                        unsigned char data[],
                        int nbytes,
                        REFERENCE_PARAM(struct r_i2c, i2cPorts));


int i2c_master_rx(int device, unsigned char data[], int nbytes,
        REFERENCE_PARAM(struct r_i2c, i2cPorts));

#endif
#endif


Any hints why I can't get it working are greatly appreciated.
Best regards,
Simon


User avatar
akp
XCore Expert
Posts: 578
Joined: Thu Nov 26, 2015 11:47 pm

Post by akp »

Seems like you're using a really old library. You should have the 5.0.0 lib_i2c
Then refer to this document https://www.xmos.com/download/lib_i2c-[ ... .0rc3).pdf
You'll see you need to initialize your single port master using the following prototype

Code: Select all

[[distributable]]
void
i2c_master_single_port(server interface i2c_master_if c[n],
static const size_t n,
port p_i2c,
static const unsigned kbits_per_second,
static const unsigned scl_bit_position,
static const unsigned sda_bit_position,
static const unsigned other_bits_mask)
And you'll use the new interface calls (i2c.read, i2c.write, i2c.read_reg, i2c.write_reg, etc)
SGapp
Member++
Posts: 21
Joined: Mon May 04, 2020 4:32 pm
Location: Berlin, Germany

Post by SGapp »

Hi akp,
thanks for your quick response. I tried to use the lib_i2c and run the single port example from the xmos Github here. The build process reports a lot of errors in the i2c_master_single_port.xc file.
When investigating this problem, I found this Thread but I was unable to resolve my errors. I tried deleting all the module_i2c folders and deleted lib_i2c, lib_logging and lib_xassert a couple of times but this did not help.

My Makefile:

Code: Select all

# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling
TARGET = XUF216-256-TQ128-C20

# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME = test

BUILD_FLAGS     = -DFLASH_MAX_UPGRADE_SIZE=64*1024 -fcomment-asm -Xmapper --map -Xmapper MAPFILE -Wall -O3 -report -lquadflash -fsubword-select -save-temps -g -fxscope -DXSCOPE -DSDA_HIGH=2 -DSCL_HIGH=1 -DXUD_SERIES_SUPPORT=4 -march=xs2a -DUSB_TILE=tile[1] -DADAT_TX_USE_SHARED_BUFF=1 -DQUAD_SPI_FLASH=1 -Wno-timing

# The USED_MODULES variable lists other module used by the application.
USED_MODULES = lib_i2c lib_logging lib_xassert

# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.
XCC_FLAGS = $(BUILD_FLAGS) -O2 -g

# The XCORE_ARM_PROJECT variable, if set to 1, configures this
# project to create both xCORE and ARM binaries.
XCORE_ARM_PROJECT = 0

# The VERBOSE variable, if set to 1, enables verbose output from the make system.
VERBOSE = 0

MODULE_LIBRARIES = xud_x200

XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
Errors

Code: Select all

Description								Resource			Path		Location	Type
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 127	C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 127	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 127	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 128	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 128	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 128	C/C++ Problem
parse error before "else"						i2c_master_single_port.xc	/lib_i2c/src	line 134	C/C++ Problem
parse error before "if"						i2c_master_single_port.xc	/lib_i2c/src	line 132	C/C++ Problem
incompatible type for argument 1 of `__builtin_peek'			i2c_master_single_port.xc	/lib_i2c/src	line 131	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 129	C/C++ Problem
parse error before "p_i2c"						i2c_master_single_port.xc	/lib_i2c/src	line 129	C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 138	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 138	C/C++ Problem
redefinition of 'fall_time'						i2c_master_single_port.xc	/lib_i2c/src	line 137	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 108	C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 108	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 109	C/C++ Problem
redefinition of 'sdaValue'						i2c_master_single_port.xc	/lib_i2c/src	line 109	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 109	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 109	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 124	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 122	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 121	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 126	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 126	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 126	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 104	C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 104	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 104	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 105	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 105	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 106	C/C++ Problem
parse error before "p_i2c"						i2c_master_single_port.xc	/lib_i2c/src	line 106	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 105	C/C++ Problem
redefinition of 'sdaValue'						i2c_master_single_port.xc	/lib_i2c/src	line 105	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 108	C/C++ Problem
'fall_time' redeclared as different kind of symbol			i2c_master_single_port.xc	/lib_i2c/src	line 107	C/C++ Problem
use of undeclared identifer `bit_time'				i2c_master_single_port.xc	/lib_i2c/src	line 107	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 75		C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 75		C/C++ Problem
parse error before '}' token						i2c_master_single_port.xc	/lib_i2c/src	line 71		C/C++ Problem
parse error before "while"						i2c_master_single_port.xc	/lib_i2c/src	line 69		C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 98		C/C++ Problem
parse error before '}' token						i2c_master_single_port.xc	/lib_i2c/src	line 85		C/C++ Problem
parse error before "if"						i2c_master_single_port.xc	/lib_i2c/src	line 83		C/C++ Problem
redefinition of 'time'							i2c_master_single_port.xc	/lib_i2c/src	line 75		C/C++ Problem
cannot redefine built in compiler function `__builtin_timer_after'	i2c_master_single_port.xc	/lib_i2c/src	line 75		C/C++ Problem
use of undeclared identifer `sdaValue'				i2c_master_single_port.xc	/lib_i2c/src	line 102	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 101	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 99		C/C++ Problem
redefinition of 'sdaValue'						i2c_master_single_port.xc	/lib_i2c/src	line 103	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 103	C/C++ Problem
'p_i2c' redeclared as different kind of symbol			i2c_master_single_port.xc	/lib_i2c/src	line 103	C/C++ Problem
redefinition of 'i'							i2c_master_single_port.xc	/lib_i2c/src	line 202	C/C++ Problem
parse error before '!=' token						i2c_master_single_port.xc	/lib_i2c/src	line 202	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 66		C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 186	C/C++ Problem
parse error before "when"						i2c_master_single_port.xc	/lib_i2c/src	line 186	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 186	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 187	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 187	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 187	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 189	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 188	C/C++ Problem
parse error before "p_i2c"						i2c_master_single_port.xc	/lib_i2c/src	line 188	C/C++ Problem
parse error before "for"						i2c_master_single_port.xc	/lib_i2c/src	line 202	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 190	C/C++ Problem
parse error before "compute_bus_off_ticks"				i2c_master_single_port.xc	/lib_i2c/src	line 190	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 189	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 189	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 167	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 167	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 166	C/C++ Problem
parse error before ':>' token						i2c_master_single_port.xc	/lib_i2c/src	line 168	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 168	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 167	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 183	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 181	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 180	C/C++ Problem
redefinition of 'fall_time'						i2c_master_single_port.xc	/lib_i2c/src	line 168	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 185	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 185	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 185	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 139	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 138	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 155	C/C++ Problem
parse error before numeric constant					i2c_master_single_port.xc	/lib_i2c/src	line 154	C/C++ Problem
parse error before '}' token						i2c_master_single_port.xc	/lib_i2c/src	line 142	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 139	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 139	C/C++ Problem
redefinition of 'p_i2c'						i2c_master_single_port.xc	/lib_i2c/src	line 161	C/C++ Problem
parse error before "if"						i2c_master_single_port.xc	/lib_i2c/src	line 159	C/C++ Problem
redefinition of 'tmr'							i2c_master_single_port.xc	/lib_i2c/src	line 157	C/C++ Problem
parse error before "bit_time"						i2c_master_single_port.xc	/lib_i2c/src	line 166	C/C++ Problem
cannot declare a function in local scope.				i2c_master_single_port.xc	/lib_i2c/src	line 162	C/C++ Problem
parse error before "p_i2c"						i2c_master_single_port.xc	/lib_i2c/src	line 162	C/C++ Problem
redefinition of 'other_bits_mask'					i2c_master_single_port.xc	/lib_i2c/src	line 161	C/C++ Problem
parse error before '<:' token						i2c_master_single_port.xc	/lib_i2c/src	line 161	C/C++ Problem
In my experience that many errors indicate a forgotten lib or module but I included the dependent libs as described in the lib_i2c documentation. What else could this be?
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Review the following i2c example and see if it helps:

https://github.com/xmos/lib_i2c/blob/ma ... _master.xc

If still raising errors, post your full project for a review.
SGapp
Member++
Posts: 21
Joined: Mon May 04, 2020 4:32 pm
Location: Berlin, Germany

Post by SGapp »

Hi mon2,
thanks for pointing out the example again, the error messages from my previous post refer to exactly this example.
I am using xTimeComposer Community_14.4.1 (build 235-acbb966) on Mac OS X 10.11.6, with lib_i2c (5.0.0), lib_logging (2.1.0) and lib_xassert (3.0.0)
The complete project is attached to this post.


EDIT: After setting up a blank project and step by step going towards what I need it seems that in the Makefile the build flag

Code: Select all

-DSDA_HIGH=2 -DSCL_HIGH=1
causes the error messages.
Attachments
i2c_test.zip
(71.59 KiB) Downloaded 136 times
i2c_test.zip
(71.59 KiB) Downloaded 136 times
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Welcome to the XMOS jungle. You will have a better chance at winning the lottery back-to-back than to figure this out as-is.

Here is a possible work around. Please review and follow carefully.

1) Launch the xTimeComposer IDE. Start with a fresh workspace.

2) Left side of the IDE -> select Examples -> Enter "AN00156" in the search bar -> double click on this code example for the I2C bus use.

3) Upon returning back to the Edit perspective of the IDE -> Project Tab -> Clean -> Build All. Watch the fireworks while the tools gather the required dependencies and will self-correct the errors. This should all compile in the end but will be based on the I2C library 4.0.0 (or similar).

4) Once the above project has compiled -> Go to the Libraries tab at the bottom left of the IDE tool -> enter I2C -> Double click on the i2C library to import the latest 5.0.0 release as noted by akp. Once this is imported -> Project Tab -> Clean -> Build All.

This should again self-correct / meditate and build the project in the end with a resulting .xe file.

Do note that this code example is based on SINGLE BIT port use. That is, single bit port for I2C_SDA and another single bit port for I2C_SCL. Either way, it will compile and work using the latest I2C library. Once this is all confirmed to compile without errors, proceed to change the source code to make use of the actual multibit port master method.

You should also be able to change the target CPU to suit but suggest that you take gentle steps and make only a single modification -> compile to confirm there are no raised errors -> repeat as required.

Do post your results. If it works for you, will go and buy a lottery ticket. Good luck.

PS: If interested, can post the full project here.
SGapp
Member++
Posts: 21
Joined: Mon May 04, 2020 4:32 pm
Location: Berlin, Germany

Post by SGapp »

Thank you very much for this detailed explanation.
I decided to stay with the old library and play a little bit with this -DSDA_HIGH=x and -DSCL_HIGH=y commands in the Makefile.
Turns out that this also needs to be changed to the relevant bit on the 8 bit port.
So in my case I am using P8D6 and P8D7 which results in -DSDA_HIGH=128 and -DSCL_HIGH=64. This works like expected.
Going to buy this lottery ticket now ;)
Post Reply