CaliPile TPiS1S138 Presence and Motion Detector - Library Port Help

Hey guys,

I just stumbled across this site through google. I can give you some limited support since I’m the guy from this video: https://youtu.be/PjIX5PPt5Ng ;).

If you are having a hard time, why do you not use the website to ask us. Let’s see what I can do for you here. Unfortunately I’m not allowed to upload pdf’s, so I cannot share too much here. In general we have a demokit (also available through distributors) which comes with all the technical notes. But certainly you should be able to reach more than 2 meters also without the kit.

So 2 important notes: A bare sensor is indoors safe to use with thresholds above 30 counts at a LP2 setting of 8s and LP1 setting of less or equal 1 (see the video for details). If you put it behind a thin plastic cover such as PP or HD-PE you loose signal but are also less prone to ambient influences.
You can improve the sensors response with a small piece of code, which I simply paste in here.

 // Exemplary c-code for the CaliPile
// Presence detection with host optimization
// The code does 
// - improve the adoption speed of the CaliPile
// - determine the presence of a person

// After start-up of the host system
// The person must leave and enter the field-of-view once
// for a proper operation
// Once a (thermal) instability was recognized
// by heat-up or cool-down of the sensor
// during presence sensing, 
// the host system will switch to safe mode, where
// presence sensing is not possible any more
// this will be indicated by a blinking of the LED

// the code was optimized for the Excelitas Demonstration Set
// in case of a fixed mounting of the bare sensor
// please adapt all settings like filters and thresholds
// to your application conditions 

// this code must be adapted for each host system
// Excelitas is not liable for the code
// All rights belong to Excelitas but the code
// can be used and modified for any CaliPile application
// free of charge

// SMBus/I2C Rx Tx Buffer for register + eeprom content
unsigned char           SMB_buf[64];		 
// SMBUS Slave address = default 10            
unsigned char           slave_address;	                

// timer flag is on to trigger once the host optimization procedure. 
// This will lead to a faster resetting of the sensor at the power-on.
// on power-on you MUST write this configuration to initialize the 
// sensor properly for the host optimization procedure
// thresholds, filter settings etc. must be optimized in the application
// every application is unique and required detailed understanding and/or testing 
//unsigned char   register_write[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
//	0x8D,0x0D,15,30,30,0x09,0x04,20,0xFF,0x00,0,0}; // high sensitivity
unsigned char   register_write[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0x8B,0x0B,30,30,30,0x09,0x04,20,0xFF,0x00,0,0}; // low sensitivity

// 32 bit variables
unsigned long int TPobject;  
unsigned long int TPambient; 

// presence detection requires a stable environment
// once a person is in the field of view there is no way
// to distinguish between background and signal with
// a 1 channel sensor. 
// Thus a stability requirement is needed for safe
// absence detection.
unsigned long int TPambient_was = 0; 

unsigned long int TPObjLP1;  
unsigned long int TPObjLP2; 
unsigned long int TPambLP3;  

// those are states of the CaliPile
// used for presence detection or recognition
typedef enum Tintstatus { 
	STATnointerrupt=0, STATinterrupt, STATabsence, 
	STATpresence, STATresetting, STATsetting} intstatus;
#define MAXSTATUS         5

intstatus  current_status = STATnointerrupt;

// return value: (0) = Transmission OK
//               (1) = SA+W not acked  
//               (2) = start address not acked
//               (3) = SA+R not acked    
// parameters  : start adress = 0...31
//               length = no of bytes to read 1...32
char read_register(char start_adr, char length)
{
    char status;
	// here comes controller specific code for I2C communication
    return(status);
}   
              
// return value: (0) = Transmission OK
//               (1) = SA not acked  
//               (2) = start address not acked
//               (3) = SMB_wbyte(value) not acked
// parameters  : start address = 0...31
//               value  = 0 ... 255
char write_register(char adr, char value)
{
    char status;
    // here comes controller specific code for I2C communication  
    return(status);
 }          

// optimize the response of the sensor by
// setting filters to fast values once an
// interrupt was detected
// determine presence with the over-temperature feature
// call this procedure in case of all CaliPile interrupts 
char presence_detection()
{
    char chipstatus;
    char interruptstatus; 
    char interruptmask;
    char LPsettings; 
    char mask;
    char i;  
    unsigned int dTPamb;
    intstatus new_status;
    char under_temperature_soft; 
      
    //LED = 1;
    
    // read the chip status and 
    // interrupt status to reset the interrupt of the chip
    // if this method is called via an interrupt, make
    // sure the interrupt was not read previously
    // otherwise use the chip status which may
    // be not up-to-date depending on the readout speed   
                      
    read_register(0, 32);
    interruptstatus = SMB_buf[18]; // interrupt status + chip status     
    chipstatus = SMB_buf[19];
     
    // simulate here the interrupt since interrupt pin is not used on this board                 
    // read the interruptmask
    interruptmask = SMB_buf[25];  
    // compare interrupstatus with the mask like the sensor is doing it
    if ((interruptstatus & interruptmask) == 0)
    {
        return 0;
    }      
    
    // initialize the status
    new_status = current_status;
    
    // ************ ambient temperature stability condition check *****************
    // determine the current ambient offset to previously registered one
    TPambient = SMB_buf[10];// & mask;
    TPambient <<= 8;
    TPambient |= SMB_buf[11];
    // divide it by 2 to get rom 16 bit to 15 bit PTAT resolution with a slope of 172 counts/K 
    TPambient >>= 1;
    // initialize the variable the first time
    if (TPambient_was == 0) TPambient_was = TPambient;
    if (TPambient_was > TPambient)
        dTPamb = TPambient_was - TPambient;
    else
        dTPamb = TPambient - TPambient_was;
    if (dTPamb > 30) // did the condition change by more than ~0.2K? Please optimize this condition for your application
    {
        if (current_status == STATpresence)
        {
            // if the situation is not stable, the overtemperature limit is probably not correct
            new_status = STATresetting;
            // indicate with the LED
            for (i = 0; i < 3; i++)
            {
                LED = 0;   
                DEBUGPIN = 0;
                delay_ms(100); 
                LED = 1;     
                DEBUGPIN = 1;
                delay_ms(100);
            }
        }
        TPambient_was = TPambient;
    }    
    // ************ end of temperature stability condition check ******************  

    // use the chip status to capture the current condition
    // interruptstatus = chipstatus;

    // initialize the chip for first time usage after power on
    if (current_status == STATnointerrupt) new_status = STATresetting;

    // entrance condition to presence condition
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. must come from the absence condition
    // 3. must be identified as presence flag after interrupt
    // 4. must have positive sign on presence flag    
    // use chip status not to miss a current condition which was not triggered
    if (new_status == current_status && current_status == STATabsence 
        && (chipstatus & 0x08) != 0 && (chipstatus & 0x80) == 0)   
        //&& (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) == 0)
    {
        new_status = STATpresence;
    }    
    
    // entrance condition to set fast filter resetting
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. must come from the absence condition
    // 3. must be identified as presence flag after interrupt
    // 4. must have negative sign on presence flag  
    // use chip status not to miss a current condition which was not triggered
    if (new_status == current_status && current_status == STATabsence 
        && (chipstatus & 0x08) != 0 && (chipstatus & 0x80) != 0)
        //&& (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) != 0)
    {
        new_status = STATresetting;
    }    
    
    // entrance condition to enter the absence status
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. Enter only when the current_status is resetting
    // 3. must have presence flag (filters catched up) 
    // 4. Presence sign flag must indicate negative number 
    // use interrupt status to look into the memory of the sensor
    if (new_status == current_status && current_status == STATresetting
        //&& (chipstatus & 0x08) != 0 && (chipstatus & 0x80) == 0 
        && (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) == 0
        )
    {
        new_status = STATabsence;
    } 
       
    // ********* check in software the under temperature condition ***********
    if (current_status == STATpresence)
    {
        // please note: using the internal under-temperature feature to generate a trigger 
        // requires the person to approach the device first 
        // to generate a signal which is above the threshold by 64 counts at least
        // otherwise the lamp will turn off again 
        // this is due to the internal hysteresis              
        // numbers can be compared on the µC from time to time in addition which is here reflected     
        under_temperature_soft = 0;
        if (SMB_buf[1] < SMB_buf[28])
        { 
            under_temperature_soft = 1;
        }
        if (SMB_buf[1] == SMB_buf[28] && SMB_buf[2] < SMB_buf[29])  
        {
            under_temperature_soft = 1;
        }     
    }  
    
    // entrance condition to enter the resetting condition
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. Enter only when the current_status is the presence condition
    // 4. Enter only when undertemperature was sensed or better 
    // 4. Enter only when software undertemperature was sensed
    if (new_status == current_status && current_status == STATpresence
        //&& (chipstatus & 0x10) != 0  // use chip status which is the up to date condition not cleared in the interrupt register
        && under_temperature_soft != 0 // use in addition the software undeartemperature in case of weak signals below 64 counts
        )
    {
        new_status = STATresetting;
    } 

    if (new_status != current_status)
    {
        // configuration according to the new status
        if (new_status == STATresetting)
        { 
            // make the background low pass follow the filtered signal nearly with nearly the same speed 
            write_register(20, 0xCD);
            interruptmask = 0x08;
            write_register(25, interruptmask);
            // set now the presence threshold to a value of only 1 so that a sign change
            // will be triggered immediately
            write_register(22, 1);
        } 
        
        if (new_status == STATabsence)
        {
            // restore default filter settings and the threshold
            write_register(20, register_write[20]);
            write_register(22, register_write[22]);
            // prepare the system to go to sleep and listen only to the positive presence interrupt              
            // trigger on the presence feature only and put your host to sleep
            interruptmask = 0x08;                  
            write_register(25, interruptmask);
        }   
        
        if (new_status == STATpresence)
        {
            interruptmask = 0;
            // setup for presence detection via overtemperature
            // store the last L1val to overtemperature for the overtemperature feature in case of absence detection   
            // optionally LP2 can be used but may be less robust an absence misinterpretation due to a warm seat or similar
            // LP1 may give you a shorter distance but is more robust to sence your absence
            TPObjLP1 = 0;
            TPObjLP2 = 0;

            // copy first 16 bit of TPLP1 or TPLP2 to the TPOT

            TPObjLP1 = SMB_buf[5];
            TPObjLP1 <<= 8;
            TPObjLP1 |= SMB_buf[6];
            TPObjLP1 <<= 8;
            TPObjLP1 |= SMB_buf[7];
            TPObjLP1 >>= 4;

            mask = 0x0F;
            TPObjLP2 = (unsigned int)(SMB_buf[7] & mask);
            TPObjLP2 <<= 8;
            TPObjLP2 |= SMB_buf[8];
            TPObjLP2 <<= 8;
            TPObjLP2 |= SMB_buf[9];
            // use LP1 if you want a safer absence measurement
            // use LP2 if you want a better presence measurement
            TPOTthres = TPObjLP1 / 8; // 20 bits maped on 17 bits 
            TPOTthres >>= 1; // last bit is not used   
            // set now the current thereshold
            write_register(29, (char)TPOTthres);
            TPOTthres >>= 8; // shift the first 8 bits to the last position
            write_register(28, (char)TPOTthres);   

            // store the current ambient temperature as a hint if the condition is stable
            TPambient_was = TPambient; 
            
            // set the system to send an interrupt on an undertemperature event 
            // make sure bit 4 in register 26 is set to 0 to notice an undertemperature event!
            interruptmask = 0x10;  
                                      
            // enable the timer to check periodically the temperature stability condition
            // and make sure the timing of readout and real events did not skip one interrupt condition 
            interruptmask |= 0x01;  

            interruptmask |= 0x08;
            write_register(25, interruptmask);
        }

        // indication of new status
        if (new_status == STATpresence)
        {
            LED = 1;   
            DEBUGPIN = 1;
        }
        else
        {
            LED = 0;   
            DEBUGPIN = 0;
        }

        current_status = new_status;
        return 1;
    }  
    return 0;
}

// optimize the response of the sensor by
// setting filters to fast values once an
// interrupt was detected
// call this procedure in case of all interrupts:
// returns 1 if an interrupt was handled
char    host_optimization()
{
    char chipstatus;
    char interruptstatus; 
    char interruptmask;
    char LPsettings; 
    char mask;
    char i;  
    intstatus new_status; 
     
   
    
    //LED = 1;
    
    // read the chip status and 
    // interrupt status to reset the interrupt of the chip
    // if this method is called via an interrupt, make
    // sure the interrupt was not read previously
    // otherwise use the chip status which may
    // be not up-to-date depending on the readout speed   
                      
    read_register(0, 32);
    interruptstatus = SMB_buf[18]; // interrupt status + chip status     
    chipstatus = SMB_buf[19];
     
    // simulate here the interrupt since interrupt pin is not used on this board                 
    // read the interruptmask
    interruptmask = SMB_buf[25];  
    // compare interrupstatus with the mask like the sensor is doing it
    if ((interruptstatus & interruptmask) == 0)
    {
        return 0;
    }

    // initialize the status
    new_status = current_status;

    // use the chip status to capture the current condition
    // interruptstatus = chipstatus;

    // initialize the chip for first time usage after power on
    //if (current_status == STATnointerrupt) new_status = STATresetting;

    // entrance condition to set fast filter setting
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. must come from the no interrupt condition
    // 3. must be identified as presence flag after interrupt
    // 4. must have positive sign on presence flag    
    // use chip status not to miss a current condition which was not triggered
    if (new_status == current_status && current_status == STATnointerrupt 
        && (chipstatus & 0x08) != 0 && (chipstatus & 0x80) == 0)   
        //&& (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) == 0)
    {
        new_status = STATsetting;
    }    
    
    // entrance condition to set fast filter resetting
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. must come from the no interrupt condition
    // 3. must be identified as presence flag after interrupt
    // 4. must have negative sign on presence flag  
    // use chip status not to miss a current condition which was not triggered
    if (new_status == current_status && current_status == STATnointerrupt 
        && (chipstatus & 0x08) != 0 && (chipstatus & 0x80) != 0)
        //&& (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) != 0)
    {
        new_status = STATresetting;
    }
    
    // entrance condition to enter the no interrupt status
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. Enter only when the current_status is setting
    // 3. must have presence flag (filters catched up) 
    // 4. Presence sign flag must indicate negative number  
    // use interrupt status to look into the memory of the sensor
    if (new_status == current_status && current_status == STATsetting
        //&& (chipstatus & 0x08) != 0 && (chipstatus & 0x80) != 0  
        && (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) != 0
        )
    {
        new_status = STATnointerrupt;
    }     
    
    // entrance condition to enter the no interrupt status
    // 1. Enter only when the new_status was not redefined by another condition
    // 2. Enter only when the current_status is resetting
    // 3. must have presence flag (filters catched up) 
    // 4. Presence sign flag must indicate positive number 
    // use interrupt status to look into the memory of the sensor
    if (new_status == current_status && current_status == STATresetting
        //&& (chipstatus & 0x08) != 0 && (chipstatus & 0x80) == 0 
        && (interruptstatus & 0x08) != 0 && (interruptstatus & 0x80) == 0
        )
    {
        new_status = STATnointerrupt;
    }

    if (new_status != current_status)
    {
        // configuration according to the new status
        if (new_status == STATsetting || new_status == STATresetting)
        { 
            // make the background low pass follow the filtered signal nearly with nearly the same speed 
            write_register(20, 0xCD);
            interruptmask = 0x08;
            write_register(25, interruptmask);
            // set now the presence threshold to a value of only 1 so that a sign change
            // will be triggered immediately
            write_register(22, 1);
        } 
        
        if (new_status == STATnointerrupt)
        {
            // restore default filter settings and the threshold
            write_register(20, register_write[20]);
            write_register(22, register_write[22]);
            // prepare the system to go to sleep and listen only to the positive presence interrupt              
            // trigger on the presence feature only and put your host to sleep
            interruptmask = 0x08;                  
            write_register(25, interruptmask);
        }

        // indication of new status
        if (new_status == STATresetting || new_status == STATsetting)
        {
            LED = 1;   
            DEBUGPIN = 1;
        }
        else
        {
            LED = 0;   
            DEBUGPIN = 0;
        }

        current_status = new_status;
        return 1;
    } 
    return 0;
}
          
void main(void)
{
	// ...
	// reload SA from E2PROM
	general_call(0x04);     
	// wait until the device is ready for communication
    delay_us(300);
    // write registers 20 to 29 	
    write_configuration();
	// check the correct settings
    read_configuration();

    while (1){   
        // use either of both: presence_detection or host_optimization
        //while (presence_detection() != 0)
        {
            // repreat checking the sensor as long as the sensor keeps changing its configuration
        } 
        
        while (host_optimization()!=0)
        {
            // repreat checking the sensor as long as the sensor keeps changing its configuration
        }  
		// ...
    }
} // end main
4 Likes