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;
}