You are here

CY8CKIT-049, USB-Serial CY7C65211 use as an I2C master. | Cypress Semiconductor

CY8CKIT-049, USB-Serial CY7C65211 use as an I2C master.

Summary: 8 Replies, Latest post by mappuji on 11 May 2015 05:10 PM PDT
Verified Answers: 0
Last post
Log in to post new comments.
miguelvp's picture
User
28 posts

Not sure if this goes here or in the USB forum but since it's part of the PSoC 4xxx prototype boards I decided to post it in here:

Someone in a forum asked for a cheap and easy USB to I2C Dev Kit, so I suggested using the break off USB Serial part of the CY8CKIT-049.

As my example I used an RTC clock based on the PCF8563 chip from NXP

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



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).



 

I added two 2.2K Ohm pull-up resistors as required for 400Kbps

Altered the I2cmaster example that came with the USB-Serial Software Development Kit

http://www.cypress.com/?rID=83110

I'll include the code at the end of the post.

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

 And it worked great:

So that little chip that we use for communicating with the boot loader has other uses, it can also do UART of course, and SPI.

Here is the code (Windoes based):

 
 
#include "stdafx.h"
 
#include <stdio.h>
#include <windows.h>
#include <dbt.h>
#include <conio.h>
#include "..\..\..\library\inc\CyUSBSerial.h"
 
// 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;
 
//Data configuration and buffer structures
CY_I2C_DATA_CONFIG cyI2CRWDataConfig;
CY_DATA_BUFFER cyDataRWBuffer;
 
//Variables used by application
UINT8 cyNumDevices;
unsigned char deviceID[16];
 
#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;
}
 
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"
};
 
char *month[] =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
 
/** ********************************
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);
// 21 hours, 37 minutes, 30 seconds, day 6, weekday Friday(5), month 3, year 2015
PCF8563_setTime(localtime.wHour, localtime.wMinute, localtime.wSecond, localtime.wDay, localtime.wDayOfWeek, localtime.wMonth, localtime.wYear);
}
else if (command == 'r')
{
// 21 hours, 37 minutes, 30 seconds, day 6, weekday Friday(5), month 3, 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("%s, %s %d, %04d %02d:%02d:%02d %s\n", weekday[time[4]], month[((time[5] > 80) ? time[5] - 80 : time[5])-1], time[3], year, hour, time[1], time[0], (time[2]>11) ? "PM" : "AM");
}
tmp = time[0];
}
CyClose(cyHandle);
}
else
{
printf("\nI2CMaster returned failure code.\n");
}
} //cyNumDevices > 0 && cyReturnStatus == CY_SUCCESS
return 0;
}
 
user_1377889's picture
User
10573 posts

Thank you *VERY* much for posting your experiences here and sharing them with us. What realy satisfied me was your last picture that showed me that not only my "PSoC bench" looks a bit like the Laokoon Group  but others as well (although the wires are thinner)

 

Bob

miguelvp's picture
User
28 posts

 Thanks,

I thought I shared because you can configure the PSoC4200 to have an I2C slave, so you can use the snap off board to communicate with the PSoC4200 via I2C or if you need higher speeds then use SPI

You can make custom programs with the USB-Serial Software Development Kit that supports not only Windows, but also Android, Linux and OSX.

So if you have a cool design based on the CY8CKIT-049 that needs to interact with the PC other than the COM port, or even via the COM port but with a dedicated program with graphics and everything, that little break off board is there for you :)

BTW the RTC module is running great, only lost one second in one day versus the PC that lost 5 seconds.

I did synchronized them both at the same time, well the PC first then the RTC based on the PC time.

 

user_1377889's picture
User
10573 posts

A small tip: you can save some of the precious sram when you write

char * const weekday[] =
                {
                    "Sunday",
                    "Monday",
                    "Tuesday",
                    "Wednesday",
                    "Thursday",
                    "Friday",
                    "Saturday"
                };
 
This will allocate the strings in flash.

 

Happy coding

Bob

miguelvp's picture
User
28 posts

 Thanks, but the code runs on the PC.

That's the beauty of that USB-Serial bridge, you can program the PSoC4 to deal with the hardware and communicate it back to the PC/Laptop/Tablet/etc via I2C/SPI/UART for the GUI via that break-off module hooked into your system that has plenty of resources.

 

user_14586677's picture
User
7645 posts

If I am reading your Rigol screenshot correctly you have ~ 2V of

undershoot, would be a good idea to address that issue with

either diode clamps or layout.

 

Regards, Dana.

miguelvp's picture
User
28 posts

Well spoted,

 

When I reset my scope, which doesn't happen often, it changes the multipliers for both channels to x1 and I have x10 probes.

Since I mainly use only CH1 I forgot to set CH2 (blue) to x10, so the 500mV is really 5V.

 

I should have taken better care for an image I was going to post. Also I should have use the ground springs to get rid off all that ringing that shows on the capture.

 

user_14586677's picture
User
7645 posts

I assumed that the channel was 5V and the undershoot caught my attention,

fairly significant.

 

Regards, Dana.

mappuji's picture
User
5 posts

Great miguelvp, i want to try this project :D

Log in to post new comments.