/Designs/Tools/I2C-PIC-USB/SW/PIC18F4550/main.c
0,0 → 1,174
#include "main.h"
 
#define USB_CON_SENSE_PIN PIN_D4
 
#include <pic18_usb.h>
#include "usbconfig.h"
#include <usb.h>
 
#include <usb.c>
 
 
/* commands from USB, must e.g. match command ids in kernel driver */
#define CMD_ECHO 0
#define CMD_GET_FUNC 1
#define CMD_SET_DELAY 2
#define CMD_GET_STATUS 3
 
#define CMD_I2C_IO 4
#define CMD_I2C_BEGIN 1 // flag fo I2C_IO
#define CMD_I2C_END 2 // flag fo I2C_IO
 
/* linux kernel flags */
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
 
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
 
#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE
#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \
I2C_FUNC_SMBUS_WRITE_BYTE_DATA
#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA
#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
 
#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_PROC_CALL | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
I2C_FUNC_SMBUS_I2C_BLOCK
 
/* ------------------------------------------------------------------------- */
#define DEFAULT_DELAY 10 // default 10us (100khz)
static unsigned clock_delay = DEFAULT_DELAY;
static unsigned clock_delay2 = DEFAULT_DELAY/2;
 
static unsigned short expected;
static unsigned char saved_cmd;
 
unsigned int8 control_data[8];
 
struct i2c_cmd {
unsigned char type;
unsigned char cmd;
unsigned short flags;
unsigned short addr;
unsigned short len;
};
 
#define STATUS_IDLE 0
#define STATUS_ADDRESS_ACK 1
#define STATUS_ADDRESS_NAK 2
 
unsigned int8 status = STATUS_IDLE;
 
void main()
{
 
unsigned int8 replyBuf[4];
 
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_2);
setup_psp(PSP_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_ccp1(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
 
usb_init();
 
 
 
while (TRUE) {
if (usb_enumerated())
{
usb_gets(0,control_data,8,100);
 
switch(control_data[1])
{
case CMD_ECHO: // echo (for transfer reliability testing)
replyBuf[0] = control_data[2];
replyBuf[1] = control_data[3];
usb_puts(0,replyBuf,2,50);
break;
case CMD_GET_FUNC:
usb_puts(0,(I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL),32,50);
break;
case CMD_SET_DELAY:
/* The delay function used delays 4 system ticks per cycle. */
/* This gives 1/3us at 12Mhz per cycle. The delay function is */
/* called twice per clock edge and thus four times per full cycle. */
/* Thus it is called one time per edge with the full delay */
/* value and one time with the half one. Resulting in */
/* 2 * n * 1/3 + 2 * 1/2 n * 1/3 = n us. */
clock_delay = *(unsigned short*)(control_data+2);
if(!clock_delay) clock_delay = 1;
clock_delay2 = clock_delay/2;
if(!clock_delay2) clock_delay2 = 1;
break;
case CMD_I2C_IO:
case CMD_I2C_IO + CMD_I2C_BEGIN:
case CMD_I2C_IO + CMD_I2C_END:
case CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END:
// these are only allowed as class transfers
// return i2c_do((struct i2c_cmd*)data);
break;
case CMD_GET_STATUS:
replyBuf[0] = status;
usb_puts(0,replyBuf,1,50);
break;
default:
// must not happen ...
break;
}
 
delay_ms(10);
}
}
}