Author Topic: Cheap / Easy I2C Dev Kit?  (Read 16621 times)

0 Members and 1 Guest are viewing this topic.

Offline katzohkiTopic starter

  • Frequent Contributor
  • **
  • Posts: 378
  • Country: us
    • My Blog
Cheap / Easy I2C Dev Kit?
« on: February 23, 2015, 10:01:43 pm »
Hi all, I'm looking for something that will help me do some simple I2C demonstration / testing. I don't really need to see a protocol / signal analysis, but ideally something "big picture." In my mind, something that would act as a master on the I2C side and a virtual COM port on the PC side would be good so that I can just open a terminal application (Hyper Terminal?) and send / receive data. I was looking at this, UMFT200XD-01, but I don't know if it appears as a master on I2C or exactly how to use it.
 

Offline uChip

  • Contributor
  • Posts: 35
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #1 on: February 23, 2015, 10:33:35 pm »
This might not be what you want to hear, but a super cheap (<$10) easy I2C is to put a bare bones AVR or PIC on a breadboard and write a little code.  Plenty of examples out there to get you started and expandable in any direction you would like.

  - Chip
 

Offline katzohkiTopic starter

  • Frequent Contributor
  • **
  • Posts: 378
  • Country: us
    • My Blog
Re: Cheap / Easy I2C Dev Kit?
« Reply #2 on: February 23, 2015, 10:47:21 pm »
This might not be what you want to hear, but a super cheap (<$10) easy I2C is to put a bare bones AVR or PIC on a breadboard and write a little code.  Plenty of examples out there to get you started and expandable in any direction you would like.

  - Chip

I didn't think of that since the thing I want to test I2C on is a PIC in the first place, but I guess I could set up a second PIC with serial data in to I2C out.
 

Offline DmitryL

  • Regular Contributor
  • *
  • Posts: 242
  • Country: gb
Re: Cheap / Easy I2C Dev Kit?
« Reply #3 on: February 23, 2015, 11:07:29 pm »
Hi all, I'm looking for something that will help me do some simple I2C demonstration / testing. I don't really need to see a protocol / signal analysis, but ideally something "big picture." In my mind, something that would act as a master on the I2C side and a virtual COM port on the PC side would be good so that I can just open a terminal application (Hyper Terminal?) and send / receive data. I was looking at this, UMFT200XD-01, but I don't know if it appears as a master on I2C or exactly how to use it.

google "bus pirate"
 

Offline BlueBill

  • Regular Contributor
  • *
  • Posts: 169
  • Country: ca
Re: Cheap / Easy I2C Dev Kit?
« Reply #4 on: February 24, 2015, 12:50:38 am »
Hi all, I'm looking for something that will help me do some simple I2C demonstration / testing. I don't really need to see a protocol / signal analysis, but ideally something "big picture." In my mind, something that would act as a master on the I2C side and a virtual COM port on the PC side would be good so that I can just open a terminal application (Hyper Terminal?) and send / receive data. I was looking at this, UMFT200XD-01, but I don't know if it appears as a master on I2C or exactly how to use it.

google "bus pirate"

+1

Handy tool the bus pirate. It's also PIC based  :)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #5 on: February 24, 2015, 03:51:10 am »
Note that I2C devices usually have "addresses" and "commands" rather than something that translates easily to a character-oriented "virtual com port."
 

Offline 22swg

  • Frequent Contributor
  • **
  • Posts: 274
  • Country: gb
Re: Cheap / Easy I2C Dev Kit?
« Reply #6 on: February 24, 2015, 10:23:57 am »
I found I2C very frustrating to start with,(Bit banging with PIC16F84 –24LC265 EEPROM ) without having any sniffer to assist, Your “Big Picture” does not really exist, I2C is a standard rather than a protocol, other than the basic physical structure and bit sequences eg.. Start , address, R/W , ack ,nak, Stop  etc . Control and data bytes are  master / slave dependent you can transport anything , at any speed <1Mb this is what makes it so flexible. If you have a specific purpose for I2C then just check out some data sheets, most will have details of their communication requirements. Like below , an SSD1306 I2C OLED display. If you are building a microcontroller  master / slave(s) system then you can design your own protocol...
Check your tongue, your belly and your lust. Better to enjoy someone else’s madness.
 

Offline katzohkiTopic starter

  • Frequent Contributor
  • **
  • Posts: 378
  • Country: us
    • My Blog
Re: Cheap / Easy I2C Dev Kit?
« Reply #7 on: February 24, 2015, 04:54:19 pm »
I really say "big picture" because I want something that I can demo to management like "and if we send a command, the device responds accordingly..." But I do have some tools that I can use to look at the protocol if I need to as it is operating.
 

Offline DmitryL

  • Regular Contributor
  • *
  • Posts: 242
  • Country: gb
Re: Cheap / Easy I2C Dev Kit?
« Reply #8 on: February 24, 2015, 05:13:08 pm »
I really say "big picture" because I want something that I can demo to management like "and if we send a command, the device responds accordingly..." But I do have some tools that I can use to look at the protocol if I need to as it is operating.

google "saleae logic analyser".
Also, bus pirate can do simple I2c sniffing.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #9 on: February 24, 2015, 06:36:08 pm »
The PSoC 4200 prototyping board ($4.00)
http://www.cypress.com/?rID=92146

Comes with a CY7C65211 configured in UART mode but can be detached and configured as I2C.
You will need the USB Serial Software development kit (free but you might need to register to get it) and of course the drivers that they supply.

More info on the Cypress USB-Serial device family can be found here:
http://www.cypress.com/USBSerial/

Edit: the chip itself (USB one not the 4200) is under $2 purchased from Cypress directly and here is where you can find the datasheet:
http://www.cypress.com/?rID=82869
« Last Edit: February 24, 2015, 06:48:36 pm by miguelvp »
 

Offline spudboy488

  • Regular Contributor
  • *
  • Posts: 136
Re: Cheap / Easy I2C Dev Kit?
« Reply #10 on: February 25, 2015, 12:33:56 pm »
If you are going to demo something to management, I have the following suggestion. Get a PIC and put it on one end of a breadboard. Get an I2C I/O expander (such as a MCP23008 or MCP23017) and put a bunch of LEDs and switches on the expander and put it at the other end.  Just have the 2 I2C wires going from the PIC to the expander (of course, common VCC and ground). Write some code to read some switches and blink some LEDs (management loves blinky lights). Emphasize that the expander is being controlled by only the 2 wires. That should help get your point across.
 

Offline andy1

  • Contributor
  • Posts: 25
  • Country: fi
Re: Cheap / Easy I2C Dev Kit?
« Reply #11 on: February 25, 2015, 09:59:16 pm »
Like said before Bus Pirate is almost exactly what you want, easily controllable trough the serial port with realterm etc. supports SPI and I2C and others, I have used it in many projects as a test device as it is really easy to just send some SPI or I2C and check stuff.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #12 on: February 26, 2015, 04:26:18 am »
I wouldn't use the Cypress USB Serial Test program for the final implementation but you could write a program using WinUSB for the last two steps.

Here is the setup of the breakoff part of the PSoC4100 prototype board with a CY7C65211-24LTXI single channel interface (CY7C65215 has dual channels, but not in this prototype board) Also I didn't want to break-off the one in the PSoC4200, but the USB-Serial part is the same for both $4 prototype boards.

I have an RTC board that uses an NXP PCF8563 that uses I2C at 400KHz



I already have all the software and drivers installed so I'm not going to go through that.
So first I open the Cypress USB-Serial Configuration Utility after plugin in the board to my PC USB port, and selected my USB-Serial (Single Channel) target and clicked on Connect:



I left the USB configuration alone, but you can change the VID/PID manufacturer and product strings etc, also left the IO levels to CMOS (you can select TTL) and clicked on the SCB tab:



Next I selected the mode to be I2C and clicked Configure


Edit: Note that you can set the notification LEDs to use GPIO pins to drive transmit and receive individual LEDs or a single one for both tx/rx

Selected 400KHz and set it to be in Master mode and ok.



Back to the previous screen click on program.



And it will come back with success (if everything is setup right).



Now, since I can't be bothered to write a WinUSB sample program, I just used the provided USB Serial Test Utility from Cypress, but you really wan't to write your own and talk to your VID/PID or search for your custom manufacturer and/or product string when enumerating USB devices.

But this test utility will allow me to just read the RTC, Also I didn't bother to program this RTC so it's as it came from China because I never had time to play with it until now, but just wanted to see if I could read data from it using this USB-Serial chip.

So I started the test utility and changed the Vendor ID and Product ID to what I programmed the chip with.



Then clicked the Read & verify data, and of course the verify part didn't work but it displays what the RTC is sending at 400KHz



The bus pirate might have easier tools, but for the price ($4 plus you get to keep an Cortex M0 ARM processor) it's a good alternative, you can't even buy the chip and make your own board for the fraction of that break off board that comes with that prototyping board.


Edit: You can also program the CapSense for capacitance touch, and unsused GPIOs mode on top of the Battery Charge Detect for battery powered devices.
« Last Edit: February 26, 2015, 04:42:33 am by miguelvp »
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #13 on: February 26, 2015, 05:08:53 am »
Also in case you are curious about SPI and UART settings:


 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #14 on: February 26, 2015, 06:41:50 am »
And I forgot one more thing, the schematic of the CY7C65211-24LTXI part of the prototype board:


And the pins for I2C Master SCL_OUT and SDA go to pin 21 and 22, marked in the silk screen as SCB_2 and SCB_3 (pin 4 & pin 5 on J6 above).

« Last Edit: February 26, 2015, 07:33:44 am by miguelvp »
 

Offline jancumps

  • Supporter
  • ****
  • Posts: 1272
  • Country: be
  • New Low
Re: Cheap / Easy I2C Dev Kit?
« Reply #15 on: February 26, 2015, 10:50:43 am »
Check out this week's embedded.fm podcast. The guest has designed an i2c LED. That would be the simplest gizmo you can use in your showcase.
Links are in the notes of this edition on the embedded site.
 

Offline katzohkiTopic starter

  • Frequent Contributor
  • **
  • Posts: 378
  • Country: us
    • My Blog
Re: Cheap / Easy I2C Dev Kit?
« Reply #16 on: February 26, 2015, 06:26:45 pm »
@ miguelvp:
Wow, thank you! That is a lot of good info. Sounds like a good way to go.

@jancumps:
The target device is PIC which has an application running on it that will control our product. The idea is to demonstrate the "added capability" that I2C will provide our customers, not so much demonstrate I2C itself.
 

Offline jancumps

  • Supporter
  • ****
  • Posts: 1272
  • Country: be
  • New Low
Re: Cheap / Easy I2C Dev Kit?
« Reply #17 on: February 26, 2015, 06:43:37 pm »
...

@jancumps:
The target device is PIC which has an application running on it that will control our product. The idea is to demonstrate the "added capability" that I2C will provide our customers, not so much demonstrate I2C itself.

Yes, I see that now when I re-read your original post. I didn't get it the first time around.
 

Offline DmitryL

  • Regular Contributor
  • *
  • Posts: 242
  • Country: gb
Re: Cheap / Easy I2C Dev Kit?
« Reply #18 on: February 26, 2015, 10:55:39 pm »
@jancumps:
The target device is PIC which has an application running on it that will control our product. The idea is to demonstrate the "added capability" that I2C will provide our customers, not so much demonstrate I2C itself.

Google "managers power point  bullshit" :)
 

Offline katzohkiTopic starter

  • Frequent Contributor
  • **
  • Posts: 378
  • Country: us
    • My Blog
Re: Cheap / Easy I2C Dev Kit?
« Reply #19 on: February 26, 2015, 11:32:55 pm »
@jancumps:
The target device is PIC which has an application running on it that will control our product. The idea is to demonstrate the "added capability" that I2C will provide our customers, not so much demonstrate I2C itself.

Google "managers power point  bullshit" :)

lol. I once spent a good couple days preparing to defend my design to upper management (on my boss's advice) and instead spent the presentation being grilled on parts cost. It came out a win, since I was able to push through a fairly unique design somewhat under the radar.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #20 on: February 28, 2015, 07:01:50 am »
@ miguelvp:
Wow, thank you! That is a lot of good info. Sounds like a good way to go.

Also FWIW they have a USB-Serial Software Development Kit that supports Windows, Linux/MAC & Android:
http://www.cypress.com/?rID=83110

I opened up the example project in windows, and requires Visual Studio 2008 or higher, since I have the free Visual Studio Community 2013 (full Visual Studio Professional 2013) I opened the solution and it upgraded the solution to VS2013

The sample code has 5 projects:
deviceenumeration
gpio
i2cmaster
spimaster
uart

but they also provide a pdf with the full documentation of the SDK.

Not sure what the example software for Android, Linux/Mac have but they are free to download after a free sign-in to Cypress.

Output of the deviceenumeration sample
Code: [Select]
Displaying information about all devices binded to USB-Serial driver...

Number of interfaces: 1
                     Vid: 0x4B4
                    Pid: 0x4
                    Serial Number is:
                    Manufacturer name: Cypress Semiconductor
                    Product Name: USB-Serial (Single Channel)
                    SCB Number: 0x0
                    Device Type: 3
                    Device Class: 255

Number of interfaces: 1
                     Vid: 0x4B4
                    Pid: 0x4
                    Serial Number is:
                    Manufacturer name: Cypress Semiconductor
                    Product Name: USB-Serial (Single Channel)
                    SCB Number: 0x1
                    Device Type: 5
                    Device Class: 255

Displaying information about all devices binded to USB-Serial driver with VID: 0
x4B4, PID: 0xA...

I would have to alter the i2cmaster example to drive the clock but it looks simple enough.

Also it seems the SDK allows you to configure the chip on the fly, not sure if it will allow you to switch from I2C to UART to SPI but if in that mode it lets you modify the settings:

Code: [Select]
Opening I2C device with device number 0...
I2C Open successfull. Invoking API for retrieving I2C configuration...
I2C Frequency : 1000 , Slave address : 2
Setting new I2C configuration...
New Configuration - I2C Frequency : 400000 , Slave address : 96, isMaster : 1
Setting new I2C configuration successful.
Checking the new I2C configuration ...
I2C Configuration retrieved - I2C Frequency : 400000 , Slave address : 96, isMas
ter : 1
Performing I2C Read operation...
Completed I2C read successfully. Read 2048 bytes of data.
Edit: changed the configuration to 1KHz and a different slave address to show that it will change it to the new setting
« Last Edit: February 28, 2015, 07:10:52 am by miguelvp »
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #21 on: March 06, 2015, 06:52:29 pm »
Last night I started to play with programming the I2C RTC and let me tell you that without a scope it's hard to say why things are not working the way they should.

The RTC has a slave address at 0xA2 for wrtie and 0xA3 for read, the write is failing because the scope shows that is masking off bit 7 and trying to communicate with 0x22 instead. So others that have mentioned that I2C can be a pain, I agree. Without the scope I would still be scratching my head, but I can see the 0x22 clearly in the serial decoder.

So the API that cypress is not allowing devices past 0x80 and the only way to communicate with it is by using the libusb directly. fortunately I have found old source for the cypress api that might help.
« Last Edit: March 06, 2015, 06:54:37 pm by miguelvp »
 

Offline 22swg

  • Frequent Contributor
  • **
  • Posts: 274
  • Country: gb
Re: Cheap / Easy I2C Dev Kit?
« Reply #22 on: March 06, 2015, 09:22:57 pm »
Most I2C 'start' code shifts the address << 1  so your RTC 0xA2  probably needs to be 0x51 .
Check your tongue, your belly and your lust. Better to enjoy someone else’s madness.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #23 on: March 07, 2015, 04:01:21 am »
Most I2C 'start' code shifts the address << 1  so your RTC 0xA2  probably needs to be 0x51 .

Thanks, that did the trick, I shifted the slave address to the right by one bit and it's all working fine.

I modified the circuit to have two 2.2KOhm pull up resistors needed for 400Kbps as per the USB-Serial datasheet.


I did probe the SCL and SDA to make sure I was reading/writing the right data:


And it worked :)


Here is the altered code from their I2C eeprom sample with the sample 8051 code that came with the RTC board that only used the hour minutes and seconds and modified it to add day, month, year, century bit and weekday.

The read is hardcoded to read 11 bytes but that can be changed easily to read an arbitrary number of bytes.
Code: [Select]
#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 device
CY_HANDLE cyHandle;
//Varible to capture return values from USB Serial API
CY_RETURN_STATUS cyReturnStatus;

//CY_DEVICE_INFO provides additional details of each device such as product Name, serial number etc..
CY_DEVICE_INFO cyDeviceInfo, cyDeviceInfoList[16];

//Structure to store VID & PID defined in CyUSBSerial.h
CY_VID_PID cyVidPid;

CY_I2C_DATA_CONFIG cyI2CRWDataConfig;
CY_DATA_BUFFER cyDataRWBuffer;

//Variables used by application
UINT8 cyNumDevices;
unsigned char deviceID[16];

/** ****************
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 0x0F

typedef unsigned char uchar;
typedef unsigned int uint;

void WriteAByte(uchar wordAdr, uchar dat)
{
uchar buffer[2];
buffer[0] = wordAdr;
buffer[1] = dat;
cyDataRWBuffer.buffer = buffer;
cyDataRWBuffer.length = 2;
CyI2cWrite(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);
// SMBus_Write(0xA2, wordAdr, dat, 2);
}

void ReadNByte(uchar wordAdr, uchar *pRdDat)
{
cyDataRWBuffer.buffer = &wordAdr;
cyDataRWBuffer.length = 1;
CyI2cWrite(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);
// SMBus_Write(0xA2, wordAdr, 0, 1);

cyDataRWBuffer.buffer = pRdDat;
cyDataRWBuffer.length = 11;
CyI2cRead(cyHandle, &cyI2CRWDataConfig, &cyDataRWBuffer, 5000);
// SMBus_Read(0xA3, pRdDat, 11);
}

void PCF8563_getTime(uchar *buf)
{
ReadNByte(SECOND_DATA_BUF, buf);
buf[0] = buf[0] & 0x7f; //get seconds data
buf[1] = buf[1] & 0x7f; //get minutes data
buf[2] = buf[2] & 0x3f; //get hours data
buf[3] = buf[3] & 0x3f; //get days data
buf[4] = buf[4] & 0x07; //get weekdays data
buf[5] = buf[5] & 0x9f; //get century_months data (most significant bit Century bit 0=2000 1=1900)
// buf[6] = buf[6]; //get years data
buf[7] = buf[7] & 0xff; //get minutes_alarm data
buf[8] = buf[8] & 0xaf; //get hours_alarm data
buf[9] = buf[9] & 0xaf; //get days_alarm data
buf[10] = buf[10] & 0x87; //get weekdays_alarm data

buf[0] = converseIntToHex(buf[0]);
buf[1] = converseIntToHex(buf[1]);
buf[2] = converseIntToHex(buf[2]);
buf[3] = converseIntToHex(buf[3]);
buf[4] = converseIntToHex(buf[4]);
buf[5] = converseIntToHex(buf[5]);
buf[6] = converseIntToHex(buf[6]);
}

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 bit
month |= 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 setting
WriteAByte(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 data
cyI2CRWDataConfig.isStopBit = true;
cyI2CRWDataConfig.isNakBit = false;
cyI2CRWDataConfig.slaveAddress = 0xA2 >> 1;

// Configure the I2C
printf("Opening I2C device with device number %d...\n", deviceNumber);

//Open the device at deviceNumber
rStatus = CyOpen(deviceNumber, interfaceNum, &cyHandle);
if (rStatus != CY_SUCCESS)
{
printf("I2C Device open failed...\n");
return rStatus;
}

// Get configuration
printf("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 settings
printf("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 I2C
printf("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 structure             
Arguments: None

Retrun Code: returns -1, if no device is present or deviceIndex of the device.
*/
int FindDeviceAtSCB0()
{
CY_VID_PID cyVidPid;

cyVidPid.vid = VID; //Defined as macro
cyVidPid.pid = PID; //Defined as macro

//Array size of cyDeviceInfoList is 16
cyReturnStatus = 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[index].numInterfaces,                 
cyDeviceInfoList[index].vidPid.vid,
cyDeviceInfoList[index].vidPid.pid,
cyDeviceInfoList[index].serialNum,
cyDeviceInfoList[index].manufacturerName,
cyDeviceInfoList[index].productName,
cyDeviceInfoList[index].deviceBlock,
cyDeviceInfoList[index].deviceType[0],
cyDeviceInfoList[index].deviceClass[0]);

// Find the device at device index at SCB0
if (cyDeviceInfoList[index].deviceBlock == SerialBlock_SCB0)
{
deviceIndexAtSCB0 = index;
}
}
return deviceIndexAtSCB0;
}

/** ********************************
Application main() function
*** ******************************** */     
int _tmain(int argc, _TCHAR* argv[])
{
//Assmumptions:
//1. SCB0 is configured as I2C

int deviceIndexAtSCB0 = FindDeviceAtSCB0();

//Open the device at deviceIndexAtSCB0
if (deviceIndexAtSCB0 >= 0)
{
//Assuming that device at index is I2C device
//Device Open, Close, Configuration, Data operations are handled in the function I2CMaster

cyReturnStatus = I2CMasterSetup(deviceIndexAtSCB0);
if (cyReturnStatus == CY_SUCCESS)
{
uchar time[16], tmp = 0;
printf("\nI2CMaster returned success.\n");
PCF8563_init();
// 9 hours, 37 minutes, 30 seconds, day 6, weekday Friday(5), month 3, year 2015
PCF8563_setTime(9, 37, 30, 6, 5, 3, 2015);
while (1)
{
PCF8563_getTime(time);
if (time[0] != tmp)
{
uint year = time[5] > 80 ? 1900 : 2000;
year += time[6];
printf("%02d:%02d:%02d %02d/%02d/%04d\n", time[2], time[1], time[0], time[3], (time[5] > 80) ? time[5] - 80: time[5] , year);
}
tmp = time[0];
}
CyClose(cyHandle);
}
else
{
printf("\nI2CMaster returned failure code.\n");
}

} //cyNumDevices > 0 && cyReturnStatus == CY_SUCCESS
return 0;
}

It actually wasn't that painful after all, the only thing I was missing is that the slave address is shifted and the read/write bit is appended by the CyI2cWrite and CyI2cRead calls.
« Last Edit: March 07, 2015, 04:19:38 am by miguelvp »
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Cheap / Easy I2C Dev Kit?
« Reply #24 on: March 07, 2015, 06:13:44 am »
Made some changes to get the time set from the systems time by pressing 's' at startup.
'r' at startup resets to 30 seconds before midnight on February 28th 2015 to see if it can handle leap years (and it does as seen in this screen capture)


Any other key will use the time set in the RTC, I did move the jumper in the board so it uses the battery to backup the time.

I didn't implement any of the alarm set and looking at the control status 2 for AF to check the alarm that stays on until cleared.
Also I didn't implement the timer countdown and control nor the CLKOUT control, but pretty much all the bases to program and read the RTC via I2C is in here.

Edit: also if AF is set and the alarm is enabled, the INT_n will trigger at a specified clock setting based on the control status flags.

Code: [Select]
#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 device
CY_HANDLE cyHandle;
//Varible to capture return values from USB Serial API
CY_RETURN_STATUS cyReturnStatus;

//CY_DEVICE_INFO provides additional details of each device such as product Name, serial number etc..
CY_DEVICE_INFO cyDeviceInfo, cyDeviceInfoList[16];

//Structure to store VID & PID defined in CyUSBSerial.h
CY_VID_PID cyVidPid;

CY_I2C_DATA_CONFIG cyI2CRWDataConfig;
CY_DATA_BUFFER cyDataRWBuffer;

//Variables used by application
UINT8 cyNumDevices;
unsigned char deviceID[16];

/** ****************
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 0x0F

typedef unsigned char uchar;
typedef unsigned int uint;

void WriteAByte(uchar wordAdr, uchar dat)
{
uchar buffer[2];
buffer[0] = wordAdr;
buffer[1] = 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[0] = buf[0] & 0x7f; //get second data
buf[1] = buf[1] & 0x7f; //get minute data
buf[2] = buf[2] & 0x3f; //get hour data
buf[3] = buf[3] & 0x3f; //get day data
buf[4] = buf[4] & 0x07; //get weekday data
buf[5] = buf[5] & 0x9f; //get century_month data (most significant bit Century bit 0=2000 1=1900)
// buf[6] = buf[6]; //get year data
buf[7] = buf[7] & 0xff; //get minute_alarm data
buf[8] = buf[8] & 0xaf; //get hour_alarm data
buf[9] = buf[9] & 0xaf; //get day_alarm data
buf[10] = buf[10] & 0x87; //get weekday_alarm data

buf[0] = converseIntToHex(buf[0]);
buf[1] = converseIntToHex(buf[1]);
buf[2] = converseIntToHex(buf[2]);
buf[3] = converseIntToHex(buf[3]);
buf[4] = converseIntToHex(buf[4]);
buf[5] = converseIntToHex(buf[5]);
buf[6] = converseIntToHex(buf[6]);
}

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 bit
month |= 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 setting
WriteAByte(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 data
cyI2CRWDataConfig.isStopBit = true;
cyI2CRWDataConfig.isNakBit = false;
cyI2CRWDataConfig.slaveAddress = 0xA2 >> 1;

// Configure the I2C
printf("Opening I2C device with device number %d...\n", deviceNumber);

//Open the device at deviceNumber
rStatus = CyOpen(deviceNumber, interfaceNum, &cyHandle);
if (rStatus != CY_SUCCESS)
{
printf("I2C Device open failed...\n");
return rStatus;
}

// Get configuration
printf("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 settings
printf("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 I2C
printf("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 structure             
Arguments: None

Retrun Code: returns -1, if no device is present or deviceIndex of the device.
*/
int FindDeviceAtSCB0()
{
CY_VID_PID cyVidPid;

cyVidPid.vid = VID; //Defined as macro
cyVidPid.pid = PID; //Defined as macro

//Array size of cyDeviceInfoList is 16
cyReturnStatus = 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[index].numInterfaces,                 
cyDeviceInfoList[index].vidPid.vid,
cyDeviceInfoList[index].vidPid.pid,
cyDeviceInfoList[index].serialNum,
cyDeviceInfoList[index].manufacturerName,
cyDeviceInfoList[index].productName,
cyDeviceInfoList[index].deviceBlock,
cyDeviceInfoList[index].deviceType[0],
cyDeviceInfoList[index].deviceClass[0]);

// Find the device at device index at SCB0
if (cyDeviceInfoList[index].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 I2C

int deviceIndexAtSCB0 = FindDeviceAtSCB0();

//Open the device at deviceIndexAtSCB0
if (deviceIndexAtSCB0 >= 0)
{
//Assuming that device at index is I2C device
//Device Open, Close, Configuration, Data operations are handled in the function I2CMaster

cyReturnStatus = I2CMasterSetup(deviceIndexAtSCB0);
if (cyReturnStatus == CY_SUCCESS)
{
SYSTEMTIME localtime;
uchar time[16], 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 2015
PCF8563_setTime(23, 59, 30, 28, 6, 2, 2015);
}
while (1)
{
PCF8563_getTime(time);
if (time[0] != tmp)
{
uint year = time[5] > 80 ? 1900 : 2000;
year += time[6];
uint hour = ((time[2] % 12) == 0) ? 12 : time[2] % 12;
printf("%-9s %02d:%02d:%02d %s %02d/%02d/%04d\n", weekday[time[4]], hour, time[1], time[0], (time[2]>11) ? "PM" : "AM", time[3], (time[5] > 80) ? time[5] - 80 : time[5], year);
}
tmp = time[0];
}
CyClose(cyHandle);
}
else
{
printf("\nI2CMaster returned failure code.\n");
}

} //cyNumDevices > 0 && cyReturnStatus == CY_SUCCESS
return 0;
}
« Last Edit: March 07, 2015, 07:53:28 am by miguelvp »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf