I2C Development Tool - Page 1
Forum section: electronics / general

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: December 03, 2015, 04:48:14 pm
content: I often write I2C drivers for various MCUs as a lot of the sensors I interface to have I2C interfaces.I have a general -purpose logic analyzer that can decode I2C and I have a dedicated I2C/SPI analyzer. These are very helpful when writing and debugging I2C drivers, but what I really need is an I2C emulator that can induce errors (such as missing ACKs and holding the data line low indefinitely) so that I can test the error handling code in the driver. This is hard to do with real I2C devices as it's hard (or impossible) to make them behave poorly and generate errors and protocol violations.Anyone know of such a device?

author: rx8pilot
author_rank: Super Contributor
timestamp: December 03, 2015, 05:15:47 pm
content: Aardvark from Total Phase does that I think.Sent from my SAMSUNG-SM-G890A using Tapatalk

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: December 03, 2015, 05:35:21 pm
content: Quote from: rx8pilot on December 03, 2015, 05:15:47 pmTotal Phase was at this year's Embedded Systems Conference and I asked one of their reps about this. He said that the Aardvark doesn't have the capability to purposely generate I2C errors. This was back in July, so perhaps they've added this capability since then. A quick download and read of the Aardvark user's manual doesn't turn up anything either, however.

author: rx8pilot
author_rank: Super Contributor
timestamp: December 03, 2015, 06:18:44 pm
content: I am hopeful that this thread turns up a solution. It would be a nice tool to have for sure. My designs that use i2c are subject to all sorts of power problems, RF, out of range inputs, etc. During development, these things cause all sorts of communication issues that take a while pin down. Being able to simulate bad i2c would be handy.

author: suicidaleggroll
author_rank: Super Contributor
timestamp: December 03, 2015, 06:23:16 pm
content: Why not write (or use, there are plenty of them available) an I2C bit-bang driver on an MCU? You can inject any errors you want.

author: rx8pilot
author_rank: Super Contributor
timestamp: December 03, 2015, 06:39:27 pm
content: Quote from: suicidaleggroll on December 03, 2015, 06:23:16 pmSpeaking only for myself, I would almost always prefer to buy a pre-made and properly engineered tool before building my own. Definitely possible to roll your own, but if it is a business tool, it costs me $1000/day to make my own tools. If I spent a few days on it, I would have a $3000+parts and fab and likely still have a half-assed tool that only I understand. It's worth a search. The Aardvark is close, but would need some new software/firmware to make it happen.

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: December 03, 2015, 09:18:51 pm
content: Quote from: suicidaleggroll on December 03, 2015, 06:23:16 pmThat's what I'll probably end up doing if I can't find an existing tool. It wouldn't be difficult to do, but would take time that I wouldn't be able to devote to my main project. For me, as a hobbyist, I think the break point would be around $200-250. Anything more expensive than that would be hard to justify, so I'd do my own. If I needed one commercially, then the break point would be much higher.

author: rx8pilot
author_rank: Super Contributor
timestamp: December 03, 2015, 09:41:33 pm
content: If you make something that is helpful, I will buy one from you to offset the cost.

author: djacobow
author_rank: Super Contributor
timestamp: December 03, 2015, 09:46:56 pm
content: If you want to go cheap, you might look at the Bus Pirate. I don't think the stock fw does intentional i2c errors, but maybe you could modify the fw to do that. Or, if you're super lucky, someone has done it already. Worse case, you have to bit-bang it yourself, which I guess is no time saver.Bus Pirate does have a forum and is actively maintained. I like mine and use it from time to time.http://dangerousprototypes.com/forum/viewforum.php?f=4

author: Howardlong
author_rank: Super Contributor
timestamp: December 03, 2015, 10:11:04 pm
content: I believe that the PicKit Serial Analyzer may do what you want. You can script all sorts of nonsense, particularly as an I2C master, but it will operate as a slave too although I am not too sure if it's as configurable as the master mode. I am not sure of its support in newer versions of Windows, but I have had it working in 8.1 after a bit of jiggery pokery. To be honest, I too would normally roll my own to test for specific scenarios, but sometimes a tool like this has its place. I lost patience trying to battle with Bus Pirate, I only use it for 1-wire decodes as it's the only tool I have that does that protocol.

author: rx8pilot
author_rank: Super Contributor
timestamp: December 03, 2015, 10:15:42 pm
content: I also have a Bus Pirate collecting dust. The software effort was too time consuming to get usefulness out of it.Sent from my SAMSUNG-SM-G890A using Tapatalk

author: miguelvp
author_rank: Super Contributor
timestamp: December 04, 2015, 01:01:41 am
content: Related:https://www.eevblog.com/forum/microcontrollers/cheap-easy-i2c-dev-kit/My post about using the break off part of that prototyping board that can do i2C connected directly to my PC.QuoteMy tests here:https://www.eevblog.com/forum/microcontrollers/cheap-easy-i2c-dev-kit/msg618200/#msg618200Post about the USB-Serial Software Development Kit that supports Windows, Linux/MAC & Androidhttps://www.eevblog.com/forum/microcontrollers/cheap-easy-i2c-dev-kit/msg619446/#msg619446Board talking to an RTC module using I2C:SCL & SDAcode:Code:#include "stdafx.h"#include <stdio.h>#include <windows.h>#include <dbt.h>#include <conio.h>#include "..\..\..\library\inc\CyUSBSerial.h"/** ****************Data Definitions*** **************** */// Define VID & PID// These numbers depends on individual products#define VID 0x04B4#define PID 0x0004//Variable to store cyHandle of the selected deviceCY_HANDLE cyHandle;//Varible to capture return values from USB Serial APICY_RETURN_STATUS cyReturnStatus;//CY_DEVICE_INFO provides additional details of each device such as product Name, serial number etc..CY_DEVICE_INFO cyDeviceInfo, cyDeviceInfoList;//Structure to store VID & PID defined in CyUSBSerial.hCY_VID_PID cyVidPid;CY_I2C_DATA_CONFIG cyI2CRWDataConfig;CY_DATA_BUFFER cyDataRWBuffer;//Variables used by applicationUINT8 cyNumDevices;unsigned char deviceID;/** ****************Functions*** **************** */#define changeIntToHex(dec) ( (((dec)/10) <<4) + ((dec)%10) )#define converseIntToHex(dec) ( (((dec)>>4) *10) + ((dec)%16) )#define changeHexToInt(hex) ( (((hex)>>4) *16 ) + ((hex)%16) )#define converseHexToInt(hex) ( (((hex)/10) <<4 ) + ((hex)%10) )#define CTRL_BUF1 0x00#define CTRL_BUF2 0x01#define SECOND_DATA_BUF 0x02#define MINUTE_DATA_BUF 0x03#define HOUR_DATA_BUF 0x04#define DAY_DATA_BUF 0x05#define WEEK_DATA_BUF 0x06#define MONTH_DATA_BUF 0x07#define YEAR_DATA_BUF 0x08#define MINUTE_AE_BUF 0x09#define HOUR_AE_BUF 0x0A#define DAY_AE_BUF 0x0B#define WEEK_AE_BUF 0x0C#define CLK_FRQ_BUF 0x0D#define TIMER_CTRL_BUF 0x0E#define COUNT_VAL_BUF 0x0Ftypedef unsigned char uchar;typedef unsigned int uint;void WriteAByte(uchar wordAdr, uchar dat){uchar buffer;buffer = wordAdr;buffer = dat;cyDataRWBuffer.buffer = buffer;cyDataRWBuffer.length = 2;CyI2cWrite(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);// SMBus_Write(0xA2, wordAdr, dat, 2);}void ReadNByte(uchar wordAdr, uchar *pRdDat, uchar length){cyDataRWBuffer.buffer = &wordAdr;cyDataRWBuffer.length = 1;CyI2cWrite(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);// SMBus_Write(0xA2, wordAdr, 0, 1);cyDataRWBuffer.buffer = pRdDat;cyDataRWBuffer.length = length;CyI2cRead(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);// SMBus_Read(0xA3, pRdDat, 11);}void PCF8563_getTime(uchar *buf){ReadNByte(SECOND_DATA_BUF, buf, 11);buf = buf & 0x7f; //get second databuf = buf & 0x7f; //get minute databuf = buf & 0x3f; //get hour databuf = buf & 0x3f; //get day databuf = buf & 0x07; //get weekday databuf = buf & 0x9f; //get century_month data (most significant bit Century bit 0=2000 1=1900)// buf = buf; //get year databuf = buf & 0xff; //get minute_alarm databuf = buf & 0xaf; //get hour_alarm databuf = buf & 0xaf; //get day_alarm databuf = buf & 0x87; //get weekday_alarm databuf = converseIntToHex(buf);buf = converseIntToHex(buf);buf = converseIntToHex(buf);buf = converseIntToHex(buf);buf = converseIntToHex(buf);buf = converseIntToHex(buf);buf = converseIntToHex(buf);}void PCF8563_setTime(uchar hour, uchar minute, uchar second, uchar day, uchar weekday, uchar month, uint year){hour = changeIntToHex(hour);minute = changeIntToHex(minute);second = changeIntToHex(second);day = changeIntToHex(day);weekday = changeIntToHex(weekday);month = changeIntToHex(month);if (year < 2000){// if 19xx set Century bitmonth |= 0x80;}year %= 100;year = changeIntToHex(year);WriteAByte(HOUR_DATA_BUF, hour);WriteAByte(MINUTE_DATA_BUF, minute);WriteAByte(SECOND_DATA_BUF, second);WriteAByte(DAY_DATA_BUF, day);WriteAByte(WEEK_DATA_BUF, weekday);WriteAByte(MONTH_DATA_BUF, month);WriteAByte(YEAR_DATA_BUF, year);}void PCF8563_init(void){WriteAByte(CTRL_BUF1, 0x00); //basic settingWriteAByte(CTRL_BUF2, 0x12); //alarm enable}CY_RETURN_STATUS I2CMasterSetup(int deviceNumber){CY_I2C_CONFIG cyI2CConfig;CY_RETURN_STATUS rStatus;int interfaceNum = 0;// Configure the I2C read and write datacyI2CRWDataConfig.isStopBit = true;cyI2CRWDataConfig.isNakBit = false;cyI2CRWDataConfig.slaveAddress = 0xA2 >> 1;// Configure the I2Cprintf("Opening I2C device with device number %d...\n", deviceNumber);//Open the device at deviceNumberrStatus = CyOpen(deviceNumber, interfaceNum, &cyHandle);if (rStatus != CY_SUCCESS){printf("I2C Device open failed...\n");return rStatus;}// Get configurationprintf("I2C Open successfull. Invoking API for retrieving I2C configuration...\n");rStatus = CyGetI2cConfig(cyHandle, &cyI2CConfig);if (rStatus != CY_SUCCESS){printf("CyGetI2cConfig returned failure code.\n");return rStatus;}printf("I2C Frequency : %d , Slave address : %d\n",cyI2CConfig.frequency,cyI2CConfig.slaveAddress);// Set configuration// Configure I2C with different settingsprintf("Setting new I2C configuration...\n");cyI2CConfig.frequency = 400000;cyI2CConfig.slaveAddress = 0x60; // Ain't matter, this is for slave mode.cyI2CConfig.isMaster = 1;printf("New Configuration - I2C Frequency : %d , Slave address : %d, isMaster : %d\n",cyI2CConfig.frequency,cyI2CConfig.slaveAddress,cyI2CConfig.isMaster);rStatus = CySetI2cConfig(cyHandle, &cyI2CConfig);if (rStatus != CY_SUCCESS){printf("CySetI2cConfig returned failure code.\n");return rStatus;}printf("Setting new I2C configuration successful.\n");// Check to see if the new configuration is applied on I2Cprintf("Checking the new I2C configuration ...\n");rStatus = CyGetI2cConfig(cyHandle, &cyI2CConfig);if (rStatus != CY_SUCCESS){printf("CyGetI2cConfig returned failure code.\n");return rStatus;}printf("I2C Configuration retrieved - I2C Frequency : %d , Slave address : %d, isMaster : %d\n",cyI2CConfig.frequency,cyI2CConfig.slaveAddress,cyI2CConfig.isMaster);return rStatus;}/*Function Name: int FindDeviceAtSCB0()Purpose: Demonstates how to enumerate and find device from the list of devices.- Demonstrates how to use deviceBlock member in DEVICE_INFO structureArguments: NoneRetrun Code: returns -1, if no device is present or deviceIndex of the device.*/int FindDeviceAtSCB0(){CY_VID_PID cyVidPid;cyVidPid.vid = VID; //Defined as macrocyVidPid.pid = PID; //Defined as macro//Array size of cyDeviceInfoList is 16cyReturnStatus = CyGetDeviceInfoVidPid (cyVidPid, deviceID, (PCY_DEVICE_INFO)&cyDeviceInfoList, &cyNumDevices, 16);int deviceIndexAtSCB0 = -1;for (int index = 0; index < cyNumDevices; index++){printf ("\nNumber of interfaces: %d\n \Vid: 0x%X \n\Pid: 0x%X \n\Serial name is: %s\n\Manufacturer name: %s\n\Product Name: %s\n\SCB Number: 0x%X \n\Device Type: %d \n\Device Class: %d\n\n\n",cyDeviceInfoList.numInterfaces,cyDeviceInfoList.vidPid.vid,cyDeviceInfoList.vidPid.pid,cyDeviceInfoList.serialNum,cyDeviceInfoList.manufacturerName,cyDeviceInfoList.productName,cyDeviceInfoList.deviceBlock,cyDeviceInfoList.deviceType,cyDeviceInfoList.deviceClass);// Find the device at device index at SCB0if (cyDeviceInfoList.deviceBlock == SerialBlock_SCB0){deviceIndexAtSCB0 = index;}}return deviceIndexAtSCB0;}char *weekday[] ={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};/** ********************************Application main() function*** ******************************** */int _tmain(int argc, _TCHAR* argv[]){//Assmumptions://1. SCB0 is configured as I2Cint deviceIndexAtSCB0 = FindDeviceAtSCB0();//Open the device at deviceIndexAtSCB0if (deviceIndexAtSCB0 >= 0){//Assuming that device at index is I2C device//Device Open, Close, Configuration, Data operations are handled in the function I2CMastercyReturnStatus = I2CMasterSetup(deviceIndexAtSCB0);if (cyReturnStatus == CY_SUCCESS){SYSTEMTIME localtime;uchar time, tmp = 0;char command;printf("\nI2CMaster returned success.\n");PCF8563_init();printf("\nType s to set, r to reset, anything else to resume current time\n");command = getch();if (command == 's'){GetLocalTime(&localtime);PCF8563_setTime(localtime.wHour, localtime.wMinute, localtime.wSecond, localtime.wDay, localtime.wDayOfWeek, localtime.wMonth, localtime.wYear);}else if (command == 'r'){// 23 hours, 59 minutes, 30 seconds, day 28, weekday Saturday(6), month 2, year 2015PCF8563_setTime(23, 59, 30, 28, 6, 2, 2015);}while (1){PCF8563_getTime(time);if (time != tmp){uint year = time > 80 ? 1900 : 2000;year += time;uint hour = ((time % 12) == 0) ? 12 : time % 12;printf("%-9s %02d:%02d:%02d %s %02d/%02d/%04d\n", weekday[time], hour, time, time, (time>11) ? "PM" : "AM", time, (time > 80) ? time - 80 : time, year);}tmp = time;}CyClose(cyHandle);}else{printf("\nI2CMaster returned failure code.\n");}} //cyNumDevices > 0 && cyReturnStatus == CY_SUCCESSreturn 0;}output (from different code revisions than above)What you do with the actual ARM of the PSoC4 prototyping board? well you could probably program it to do I2C as well but I didn't use it that way.Edit: but I guess I didn't read your whole post, maybe the PSoC4 module for I2C could be modified to introduce the glitches.It's a hardware software module solution that you could modify (both hardware/software) to make your faulty module.http://www.cypress.com/documentation/component-datasheets/psoc-4-serial-communication-block-scbThere is a video somewhere to explain how to import an existing component and modifying it, some have verilog some are udb based and the generated library code can be modified as well, so you could add your missing acks etc at the bare metal.https://www.youtube.com/user/CypressSemi/videosEdit2: here is an example on modifying a component although the acting is a bit terrible and so is the video quality, also the component they modify doesn't have verilog and I'm not sure if the I2C module actually has verilog, I'll check and report back:

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: December 04, 2015, 01:27:42 am
content: Quote from: miguelvp on December 04, 2015, 01:01:41 amThat thread seems to be not relevant. Let me clarify what I want to do in case anyone is confused: I'm writing I2C drivers for master-mode I2C on ARM Cortex-M4 processors. I have plenty of I2C slave devices to test my drivers with, but all of these devices are well-behaved and generally follow the I2C protocol. These devices allow me to get the driver working for the normal case, but don't help me test the exception cases. These exception cases are where the slave device does something unusual or even illegal, such as not responding with an ACK when I sent it data from the master, or holding the data line low indefinitely. Having a slave device that does these nasty things will help me make sure my driver's error handling code is implemented correctly.Quote from: HowardlongI'll check out this device. Thanks for the pointer.

author: miguelvp
author_rank: Super Contributor
timestamp: December 04, 2015, 01:51:02 am
content: My bad, as I explained later on the post edits, I guess I didn't read your full needs.In any event as I mentioned on my edits, you can use a PSoC4 module and modify it to your needs giving random failures, because all the components they have can be imported and modified, for example the SCB module that does I2C can be imported and you can change it and break it at will:So you can still use that prototyping board but using the PSoC4 instead of the USB-UART module by itself.

author: westfw
author_rank: Super Contributor
timestamp: December 04, 2015, 03:52:25 am
content: QuoteHypothetically, how would you wish to configure such a device?Throw up a waveform, click on a a bit transition to delete it? (get rid of ack bits, blow away CRC, etc?)Have "standardized" error tests: "run the missing ack test" and have each/several ack bits in a message left out?How would you want to configure the "normal" I2C responses? Have a set of common emulated devices (2404 EEPROM. xxx DAC..)? Have a "learning mode" where the test equipment sat between your driver and the real device and watched normal transactions go by, and then had them available for trashing? Trash transactions to a real device, as a "man in the middle" in real time? (If that's even possible?)Bit banging or hardware seems the way to go; I don't imagine that anyone's I2C slave peripheral is capable of introducing obvious errors. But is big-banging even practical at modern I2C speeds? The slave doesn't get to slow down the master clock, does it? Or would you be willing to put up with lower-speed operations to find "logic" errors rather than speed issues?

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: December 04, 2015, 04:07:59 am
content: Quote from: westfw on December 04, 2015, 03:52:25 amA common I2C speed is 100 kHz. Bit banging at that speed is easy (and at 400 kHz (the other common I2C speed) as well). I'd be fine with a device that could handle that rate, or even slower. Slave devices can slow down the clock via clock stretching, where it holds the clock low. This capability would be handy to check whether the master can deal with clock stretching by a slave.As far as being able to configure such a device, it would be nice to be able to script it to generate any combination of errors.

author: rx8pilot
author_rank: Super Contributor
timestamp: December 04, 2015, 04:12:18 am
content: Bit banging at 400Khz is definitely not a problem.Sent from my SAMSUNG-SM-G890A using Tapatalk

author: mikerj
author_rank: Super Contributor
timestamp: December 04, 2015, 06:04:32 pm
content: Quote from: westfw on December 04, 2015, 03:52:25 amYes, a slave can control the speed of a fully compliant master device by clock stretching (holding SCL low after a byte transfer). Most simple bit bashing master implementations ignore this.Also it seems like the OP actually wants a slave device, and bit bashing a (fully compliant) slave is a far more difficult task. The Aardvark is a great tool and can be used as a slave, but probably doesn't have the level of control that the OP requires in this mode and you can get latency problems that simply wouldn't occur on a real slave peripheral. One possibility would be to use a second master device which is normally idle, but could be used to inject extra clocks etc. which would certainly test the error handling and recovery capabilities of the main master device.

author: Ian.M
author_rank: Super Contributor
timestamp: December 04, 2015, 06:31:23 pm
content: A couple of MOSFETs, one to break the SDA line, connected with a Schottky diode in parallel with its body diode to let the master pull the line low but block the slave from doing so when its off, and the other to hold SDA low, + a logic circuit to detect start bits and an externally triggered and clocked pattern generator would allow you to inject all sorts of nastyness between the master and an actual I2C device with pretty much off-the-shelf hardware. With suitable hardware assistance any reasonably fast MCU could handle the fault injection in realtime even at 400KHz. For added s--ts and giggles, add the same circuit to SCL so you can bork clock-stretching on the fly.

author: Electro Fan
author_rank: Super Contributor
timestamp: December 18, 2015, 02:48:49 am
content: I think there is a (probably small niche but maybe growing) market for something that allows users to create digital signals with various levels of control from the bit level to the Byte level to relatively long strings. Something that allows control over speed/frequency, voltage, pulse width, rise and fall times, plus much more in the way of protocol management. The Total Phase Aardvark is a step in the direction - but with more functionality and for multiple protocols. Kind of like a cross between an arbitrary wave form generator and a protocol emulator. As it evolved it would have a continuum of capabilities ranging from highly custom bit banging to libraries. The use cases would range from teaching to simulation support to debugging. The standard protocols would range from RS-232 to I2C to SPI and CAN and maybe others. It would allow everything from waveform shaping and sequencing to error detection and correction manipulation. It could be both data entry driven and graphically manipulated. It would allow users to have one, two, or more nodes (boards) in combinations of point to point and master/slave/multipoint networks. All of this wouldn't happen on Day 1 but it be designed as a modular and very extensible platform. Maybe something that leverages other platforms from Arduino to TI Launchpad to take your pick - it would have/support software and hardware components. Probably would have some libraries or utilities to leverage oscilloscopes, logic analyzers, and maybe arbitrary waveform generators. Kind of a big wish list but the more insight/visibility and control it lends to observing and manipulating communications the better. The Swiss army knife of digital communications for learning, developing, and testing - but designed to leverage other resources so as to be relatively low cost and/or open source. Something that helps take the nearly invisible and mysterious and make it more visible, understandable, and managable.