#include #include "i2c.h" #include "mcf5xxx.h" //#include "m52xxevb.h" #include "ow.h" #include "debug.h" static unsigned char OW_CRC_TABLE[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; #define OW_BUSY_MAX_WAIT 2000 #define OW_ROM_SEARCH 0xF0 /** * 1W-master address is in the form of 00110XX (7bit) where XX is determined * by how pins AD0 and AD1 are wired. To simplify how the 1Wmaster is * addressed in our routines the high nibble (0011) is prepended automatically * now any 1W-master can be addressed by 1-4 **/ #define I2C_ADDR_MASK 0x18 /** * 1Wire master configuration * (~1ws|~spu|~ppm|~apu|1ws|spu|ppm|apu) * 1ws - 1wire speed, 0- normal, 1 - overdrive * spu - strong pullup. 0 * ppm - presence pulse masking. used for long 1-wire. 0 * apu - active pullup. for parasitic devices. 0 * ------- * normal conf: 11110000 = 0xF0 * overdrive conf: 01111000 = 0x78 **/ #define OW_MASTER_CONF 0xF0 #define OW_MAX_DEVICES 100 struct ow_llistStruct{ struct ow_llistStruct *next; uint8 *addr; }; struct i2c_llistStruct{ struct i2c_llistStruct *next; struct ow_llistStruct *owd; uint8 addr; }; typedef struct i2c_llistStruct i2c_llist; typedef struct ow_llistStruct ow_llist; i2c_llist *i2cChain=NULL; /** * Finds master device in chain and returns pointer to it. If not found then * it is automatically created * Retures pointer to master device or NULL on failure **/ i2c_llist* OW_getMasterChain(uint8 i2cSlave){ i2c_llist *i2cPtr=NULL; //ow_llist *owLastPtr=NULL; if(i2cChain==NULL){ //Chain is empty i2cChain=malloc(sizeof(i2c_llist)); if(i2cChain==NULL){ DBG_PRINTL("OW_getMasterChain: malloc failed 0.\n"); return NULL; } i2cChain->addr=i2cSlave; i2cChain->owd=NULL; i2cChain->next=NULL; i2cPtr=i2cChain; }else{ //Chain is not empty find/add the device i2cPtr=i2cChain; while(i2cPtr){ //Find master in chain if(i2cPtr->addr==i2cSlave) break; if(i2cPtr->next==NULL) break; i2cPtr=i2cPtr->next; } if(i2cPtr==NULL){ //None found DBG_PRINTL("OW_getMasterChain: overran list.\n"); return NULL; }else if(i2cPtr->next==NULL && i2cPtr->addr!=i2cSlave){ //i2cSlave not in list, add it i2cPtr->next=malloc(sizeof(i2c_llist)); if(i2cPtr->next==NULL){ DBG_PRINTL("OW_getMasterChain: malloc failed 1.\n"); return NULL; } i2cPtr=i2cPtr->next; i2cPtr->owd=NULL; i2cPtr->next=NULL; i2cPtr->addr=i2cSlave; } //If neither if clause triggered then we found device in while loop } return i2cPtr; } /** * Stores a 1wire device to the 1w subchain (of master chain). If reset is * non-zero then chain is purged out before being reassigned. * returns 1 on sucess 0 of failure **/ int OW_store(uint8 i2cSlave, uint8 *owSlave, int reset){ ow_llist* owPtr=NULL; i2c_llist* i2cPtr=OW_getMasterChain(i2cSlave); int i; if (i2cPtr==NULL){ DBG_PRINTL("OW_store: OW_getMasterChain failed.\n"); return 0; } //Remove the subchain if(reset){ owPtr=i2cPtr->owd; if(owPtr!=NULL){ //If its null then nothing needs to be done i2cPtr->owd=i2cPtr->owd->next; while(i2cPtr->owd!=NULL){ //Free and delink everything in OW chain free(owPtr->addr); free(owPtr); owPtr=i2cPtr->owd; i2cPtr->owd=i2cPtr->owd->next; } free(owPtr->addr); free(owPtr); i2cPtr->owd=NULL; } } //make space for OW_device if(i2cPtr->owd==NULL){ i2cPtr->owd=malloc(sizeof(ow_llist)); if(i2cPtr->owd==NULL){ DBG_PRINTL("OW_store: malloc failed 0.\n"); return 0; } owPtr=i2cPtr->owd; }else{ owPtr=i2cPtr->owd; while(owPtr->next!=NULL){ owPtr=owPtr->next; } owPtr->next=malloc(sizeof(ow_llist)); if(owPtr->next==NULL){ DBG_PRINTL("OW_store: malloc failed 1.\n"); return 0; } owPtr=owPtr->next; } //Store device owPtr->next=NULL; owPtr->addr=malloc(sizeof(uint8*)*8); if(owPtr->addr==NULL){ DBG_PRINTL("OW_store: malloc failed 2. Please reset chain.\n"); return 0; } for(i=0; i<8; i++){ *(owPtr->addr+i)=*(owSlave+i); } //DBG_PRINTF("i2cPtr->owd: %0x\n", i2cPtr->owd); return 1; } /** * Finds the nth device in the chain of a particular family type and initiates * communication with it. * Returns 0 on failure (no device found) 1 on sucess. **/ int OW_invoke(uint8 i2cSlave, uint8 owFam, int number){ i2c_llist *i2cPtr=NULL; ow_llist *owPtr=NULL; int i=0; if(i2cChain==NULL){ DBG_PRINTL("OW_invoke: OW chain is empty.\n"); return 0; } i2cPtr=i2cChain; //Find master in chain while(i2cPtr){ if(i2cPtr->addr==i2cSlave) break; if(i2cPtr->next==NULL) break; i2cPtr=i2cPtr->next; } if(i2cPtr==NULL || i2cPtr->addr!=i2cSlave){ //None found DBG_PRINTL("OW_invoke: OW chain not found.\n"); return 0; } owPtr=i2cPtr->owd; //Find nth device in ow chain of particular family while(owPtr){ if(owFam==*owPtr->addr){ if(number==i) break; i++; } owPtr=owPtr->next; } if(number!=i) return 0; //Reset, so as to make sure we are in the right state if(!OW_masterReset(i2cSlave)){ DBG_PRINTL("OW_invoke: masterReset failed.\n"); return 0; } if(!OW_reset(i2cSlave)){ DBG_PRINTL("OW_invoke: reset failed.\n"); return 0; } //Address the device if(!OW_command(i2cSlave, DS2482_OW_WRITE_BYTE, OW_ROM_MATCH)){ DBG_PRINTL("OW_invoke: ROM match command failed.\n"); return 0; } for(i=0; i<8; i++){ if(!OW_command(i2cSlave, DS2482_OW_WRITE_BYTE, *(owPtr->addr+i))){ DBG_PRINTL("OW_invoke: Writing failed.\n"); return 0; } } return 1; } /** * Initializes 1W master. * Returns 0/1 on failure/sucess **/ int OW_masterInit(uint8 i2cSlave){ uint8 buff; //Issue reset, this sets ConfigReg to 0x00 if(!OW_masterReset(i2cSlave)){ DBG_PRINTL("OW_masterInit: reset failed\n"); return 0; } //Write configuration if(!OW_command(i2cSlave, DS2482_I2C_CONFIG, OW_MASTER_CONF)){ DBG_PRINTL("OW_masterInit: Writing config failure\n"); return 0; } //read back and compare the config, to confirm if(I2C_read(i2cSlave|I2C_ADDR_MASK, &buff, 1)<=0){ DBG_PRINTL("OW_masterInit: Read-back failed\n"); return 0; } //When config read only low nibble is sent. if(buff==(OW_MASTER_CONF&0x0F)){ return 1; }else{ DBG_PRINTL("OW_masterInit: Read-back mismatch\n"); return 0; } } int OW_crc8(uint8 data){ return OW_CRC_TABLE[data]; } //DUMMY FUNCTIOn int OW_crc16(uint8 owm, uint8 ndev, char* data, int len){ int csum=0; csum=OW_getByte(owm)<<8; csum|=OW_getByte(owm); //return crc16(csum, data, len); return 1; } /** * Resets the 1W master device to initial state * Returns 0/1 on failure/sucess **/ int OW_masterReset(uint8 i2cSlave){ uint8 buff; //Send reset command if(I2C_writeByte(i2cSlave|I2C_ADDR_MASK, DS2482_I2C_RESET)){ return 1; }else{ DBG_PRINTL("OW_masterReset: reset signal transmittion failure\n"); return 0; } //read back 1 byte to make sure everything is ok if(I2C_read(i2cSlave|I2C_ADDR_MASK, &buff, 1)<=0){ DBG_PRINTL("OW_masterReset: read\n"); return 0; } return 1; } /** * Repeatedly reads register (at regPtr) masks out values and compares to cmp **/ int OW_idleMask(uint8 i2cSlave, uint8 mask, uint8 cmp){ int i; uint8 buff; for(i=0; i<=OW_BUSY_MAX_WAIT; i++){ if(!I2C_read(i2cSlave|I2C_ADDR_MASK, &buff, 1)){ DBG_PRINTL("OW_idleMask: read failed\n"); return -1; } if((buff & mask) == cmp ){ return buff; } } //If we fail might as well reset master.. if(!OW_masterReset(i2cSlave)){ DBG_PRINTL("OW_idleMask: reset failed\n"); } DBG_PRINTL("OW_idleMask: wait exhausted\n"); return -1; } /** * Resets the 1W bus * Returns 0/1 on failure/sucess **/ int OW_reset(uint8 i2cSlave){ uint8 buff; int i=0; //Send reset command if(I2C_writeByte(i2cSlave|I2C_ADDR_MASK, DS2482_OW_RESET)<=0){ DBG_PRINTL("OW_reset: reset signal transmittion failure\n"); return 0; } //Idle untill no longer busy if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ DBG_PRINTL("OW_reset: Exhausted waiting for bus\n"); return 0; } //Check for presence pulse detect if(OW_idleMask(i2cSlave, 0x03, 0x02)>=0){ return 1; } DBG_PRINTL("OW_reset: Exhausted waiting for presence pulse\n"); return 0; } /** * Writes 1 bit to the bus. * This functions is pretty useless since very few single bit operations exits * the only exception is during search and that case is taken care of by the * OW_triplet function * Returns 0/1 on failure/sucess * TODO: test function **/ int OW_writeBit(uint8 i2cSlave, uint8 data){ if(!OW_command(i2cSlave, DS2482_OW_WRITE_BIT, (data<<7)|0x7F)){ DBG_PRINTL("OW_writeBit: I2C write failed\n"); return 0; } if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ DBG_PRINTL("OW_writeBit: Exhausted waiting for bus\n"); return 0; } return 1; } /** * Reads 1 bit from bus. If fails returns -1 * This functions is pretty useless since very few single bit operations exits * the only exception is during search and that case is taken care of by the * OW_triplet function * Returns 0/1 on failure/sucess * TODO: Test this function **/ int OW_readBit(uint8 i2cSlave){ int buff; int i; if(!OW_writeBit(i2cSlave, 1)){ DBG_PRINTL("OW_readBit: Write failed\n"); return 0; } /** * Setting pointer is not necessary, its set to status after OW_writeBit if(!OW_command(i2cSlave, DS2482_I2C_SET_READ_PTR, DS2482_REG_STATUS)){ DBG_PRINTL("OW_readBit: Commad write failed\n"); return -1; } **/ //Idle untill data us ready buff=OW_idleMask(i2cSlave, 0x01, 0x00); if(buff>=0){ return (buff&0x20)==1; } DBG_PRINTL("OW_writeBit: Exhausted waiting for bus\n"); return -1; } /** * Writes one byte * Returns 0/1 on failure/sucess **/ int OW_writeByte(uint8 i2cSlave, uint8 data){ //Set read pointer to the status register to check 1 wire busy if(!OW_command(i2cSlave, DS2482_I2C_SET_READ_PTR, DS2482_REG_STATUS)){ DBG_PRINTL("OW_writeByte: Commad write failed\n"); return 0; } //if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ // DBG_PRINTL("OW_writeByte: Exhausted waiting for bus (1)\n"); // return 0; //} //Write data if(!OW_command(i2cSlave, DS2482_OW_WRITE_BYTE, data)){ DBG_PRINTL("OW_writeByte: Data write failed\n"); return 0; } //if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ // DBG_PRINTL("OW_writeByte: Exhausted waiting for bus (2)\n"); // return 0; //} return 1; } /** * Sends 2 bytes over i2c, first the command, then the param usually used to * send a command to the 1W master and the param to the 1W slave. * Returns 0/1 on failure/sucess **/ int OW_command(uint8 i2cSlave, uint8 command, uint8 param){ if(!OW_commandNoIdle(i2cSlave, command, param)){ DBG_PRINTL("OW_command: Commad write failed\n"); return 0; } if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ DBG_PRINTL("OW_command: Exhausted waiting for bus (1)\n"); return 0; } return 1; } int OW_commandNoIdle(uint8 i2cSlave, uint8 command, uint8 param){ uint8 buff[2]; //Set read pointer to the status register to check 1 wire busy buff[0] = command; buff[1] = param; if(!I2C_write(i2cSlave|I2C_ADDR_MASK, &buff[0], 2)){ DBG_PRINTL("OW_commandNoIdle: Commad write failed\n"); return 0; } return 1; } /** * Sets read pointer to reg and reads it back. * returns -1 on failure and value of reg otherwise **/ int OW_getReg(uint8 i2cSlave, uint8 reg){ uint8 buff; //DBG_PRINTL("OW_getReg: invoked\n"); //Set read pointer to the status register to check 1 wire busy if(!OW_command(i2cSlave, DS2482_I2C_SET_READ_PTR, DS2482_REG_STATUS)){ DBG_PRINTL("OW_getReg: Commad write failed (1)\n"); return -1; } //Send read command if(!I2C_writeByte(i2cSlave|I2C_ADDR_MASK, DS2482_OW_READ_BYTE)){ DBG_PRINTL("OW_getReg: Failed sending Read command\n"); return -1; } if(OW_idleMask(i2cSlave, 0x01, 0x00)<0){ DBG_PRINTL("OW_getReg: Exhausted waiting for bus (2)\n"); return -1; } //Read in the byte if(!OW_commandNoIdle(i2cSlave, DS2482_I2C_SET_READ_PTR, reg)){ DBG_PRINTL("OW_getReg: Read command write failed\n"); return -1; }else if(!I2C_read(i2cSlave|I2C_ADDR_MASK, &buff, 1)){ DBG_PRINTL("OW_getReg: Read command write failed\n"); return -1; } return (int)buff; } /** * Reads in one byte from the OW bus (which got stored to data register) **/ uint8 OW_getByte(uint8 i2cSlave){ int i=OW_getReg(i2cSlave, DS2482_REG_DATA); if(i<0){ DBG_PRINTL("OW_getByte: WARNING read byte failed\n"); return 0; } return (uint8)i; } /** * Returns number of bytes written/read * TODO: test function **/ int OW_block(uint8 i2cSlave, uint8 *data, int len){ int i=0; while(i0){ *dir=0xFF; } //Send command if(!OW_command(i2cSlave, DS2482_OW_TRIPLET, *dir)){ DBG_PRINTL("OW_triplet: Command write failed\n"); return 0; } //Idle untill data is ready buff=OW_idleMask(i2cSlave, 0x01, 0x00); if(buff>=0){ *firstBit=(buff >> 5) & 1; *secondBit=(buff >> 6) & 1; *dir=(buff >> 7) & 1; return 1; }else{ DBG_PRINTL("OW_triplet: Wait ehausted\n"); return 0; } } int OW_searchAll(uint8 i2cSlave){ uint8 deviceAddress[8]; uint8 lastDiscrepancy=0; int ret=0; int i, ii; if(!OW_masterInit(i2cSlave)){ DBG_PRINTF("OW_searchAll: init failed\n"); return 0; } for(i=0; i