si114x_functions.c

00001 //-----------------------------------------------------------------------------
00002 // Si114x_functions.c
00003 //-----------------------------------------------------------------------------
00004 // Copyright 2013 Silicon Laboratories, Inc.
00005 // http://www.silabs.com
00006 //
00007 // File Description:
00008 //
00009 // This file contains low-level routines that access the i2c controller
00010 // The code has been ported from the generic Si114x API to the EFM32
00011 // platform.
00012 //
00013 // Target:         Si114x
00014 //
00015 //-----------------------------------------------------------------------------
00016 #include "si114x_functions.h"
00017 
00018 
00019 #ifndef DELETE_PORTING_SECTION
00020 //-----------------------------------------------------------------------------
00021 #include "rtcdriver.h"
00022 #include "em_device.h"
00023 #include "si1147_i2c.h"
00024 
00025 s16 Si114xWriteToRegister(HANDLE si114x_handle, u8 address, u8 data)
00026 {
00027 
00028   return Si1147_Write_Register (((si114x_i2c_t*)si114x_handle)->i2c,((si114x_i2c_t*)si114x_handle)->addr, address, data);
00029 
00030 }
00031 
00032 s16 Si114xReadFromRegister(HANDLE si114x_handle, u8 address)
00033 {
00034     uint8_t data;
00035     Si1147_Read_Register (((si114x_i2c_t*)si114x_handle)->i2c,((si114x_i2c_t*)si114x_handle)->addr, address, &data);
00036     return data;
00037 }
00038 
00039 s16 Si114xBlockWrite(HANDLE si114x_handle,
00040                         u8 address, u8 length, u8 const *values)
00041 {
00042 
00043      return Si1147_Write_Block_Register (((si114x_i2c_t*)si114x_handle)->i2c,((si114x_i2c_t*)si114x_handle)->addr, address, length, values);
00044 
00045 }
00046 
00047 s16 Si114xBlockRead(HANDLE si114x_handle,
00048                         u8 address, u8 length, u8 *values)
00049 {
00050     return Si1147_Read_Block_Register (((si114x_i2c_t*)si114x_handle)->i2c,((si114x_i2c_t*)si114x_handle)->addr, address, length, values);
00051 }
00052 
00053 extern volatile uint32_t msTicks;
00054 void delay_10ms()
00055 {
00056     // This is needed immediately after a reset command to the Si114x
00057     // In the PGM_Toolkit, there is sufficient latency, so none is added
00058     // here. This is a reminder that when porting code, that this must
00059     // be implemented.
00060     RTCDRV_Delay(10);
00061 
00062 }
00063 
00064 //-----------------------------------------------------------------------------
00065 //------ End of Porting section. No need to modify anything else below --------
00066 //-----------------------------------------------------------------------------
00067 #endif // DELETE_PORTING_SECTION
00068 
00069 
00070 //-----------------------------------------------------------------------------
00071 // Following functions reads/writes i2c registers that will not wake up
00072 // the Si114x's internal MCU
00073 //
00074 static s16 _waitUntilSleep(HANDLE si114x_handle)
00075 {
00076     s16 retval;
00077     // This loops until the Si114x is known to be in its sleep state
00078     // or if an i2c error occurs
00079     while (1)
00080     {
00081         retval = Si114xReadFromRegister(si114x_handle, REG_CHIP_STAT);
00082         if (retval == 1) break;
00083         if (retval <  0) return retval;
00084     }
00085     return 0;
00086 }
00087 
00088 //-----------------------------------------------------------------------------
00089 // The following functions writes to the CMD register and can therefore
00090 // wake up the internal MCU
00091 
00092 s16 Si114xReset(HANDLE si114x_handle)
00093 {
00094     s32 retval = 0;
00095 
00096     retval+=Si114xWriteToRegister(si114x_handle, REG_MEAS_RATE,  0x00);
00097     retval+=Si114xWriteToRegister(si114x_handle, REG_ALS_RATE, 0x0);
00098     retval+=Si114xPauseAll(si114x_handle);
00099     // The clearing of the registers could be redundant, but it is okay.
00100     // This is to make sure that these registers are cleared.
00101     retval+=Si114xWriteToRegister(si114x_handle, REG_MEAS_RATE,  0x00);
00102     retval+=Si114xWriteToRegister(si114x_handle, REG_IRQ_ENABLE, 0x00);
00103     retval+=Si114xWriteToRegister(si114x_handle, REG_IRQ_MODE1,  0x00);
00104     retval+=Si114xWriteToRegister(si114x_handle, REG_IRQ_MODE2,  0x00);
00105     retval+=Si114xWriteToRegister(si114x_handle, REG_INT_CFG  ,  0x00);
00106     // retval+=Si114xWriteToRegister(si114x_handle, REG_COMMAND,    0x01);
00107     retval+=Si114xWriteToRegister(si114x_handle, REG_IRQ_STATUS, 0xFF);
00108 
00109     // Perform the Reset Command
00110     retval+=Si114xWriteToRegister(si114x_handle, REG_COMMAND, 1);
00111 
00112     // Delay for 10 ms. This delay is needed to allow the Si114x
00113     // to perform internal reset sequence.
00114     delay_10ms();
00115 
00116     // Write Hardware Key
00117     retval+=Si114xWriteToRegister(si114x_handle, REG_HW_KEY, HW_KEY_VAL0);
00118 
00119     return retval;
00120 }
00121 
00122 
00123 static s16 _sendCmd(HANDLE si114x_handle, u8 command)
00124 {
00125     s16  response;
00126     s16  retval;
00127 
00128     // Get the response register contents
00129     if ((response=Si114xReadFromRegister(si114x_handle, REG_RESPONSE))<0)
00130         return response;
00131 
00132     // Double-check the response register is consistent
00133     while(1)
00134     {
00135         if((retval=_waitUntilSleep(si114x_handle)) != 0) return retval;
00136 
00137         if(command==0) break; // Skip if the command is NOP
00138 
00139         retval=Si114xReadFromRegister(si114x_handle, REG_RESPONSE);
00140         if(retval==response) break;
00141         else if(retval<0) return retval;
00142         else response = retval;
00143     }
00144 
00145     // Send the Command
00146     if ((retval=Si114xWriteToRegister(si114x_handle, REG_COMMAND, command)) !=0)
00147         return retval;
00148 
00149     // Expect a change in the response register
00150     while(1)
00151     {
00152 
00153         if(command==0) break; // Skip if the command is NOP
00154 
00155         retval= Si114xReadFromRegister(si114x_handle, REG_RESPONSE);
00156         if (retval != response) break;
00157         else if(retval<0) return retval;
00158     }
00159     return 0;
00160 }
00161 
00162 s16 Si114xParamRead(HANDLE si114x_handle, u8 address)
00163 {
00164     // returns Parameter[address]
00165     s16 retval;
00166     u8 cmd = 0x80 + (address & 0x1F);
00167     if((retval=_sendCmd(si114x_handle, cmd ))!=0) return retval;
00168     return Si114xReadFromRegister(si114x_handle, REG_PARAM_RD);
00169 }
00170 
00171 s16 Si114xNop       (HANDLE si114x_handle) {return _sendCmd(si114x_handle,0x00);}
00172 s16 Si114xPsForce   (HANDLE si114x_handle) {return _sendCmd(si114x_handle,0x05);}
00173 s16 Si114xAlsForce  (HANDLE si114x_handle) {return _sendCmd(si114x_handle,0x06);}
00174 s16 Si114xPsAlsForce(HANDLE si114x_handle) {return _sendCmd(si114x_handle,0x07);}
00175 s16 Si114xPsAlsAuto (HANDLE si114x_handle) {return _sendCmd(si114x_handle,0x0F);}
00176 
00177 //-----------------------------------------------------------------------------
00178 // Si114xParamSet writes to the PARAM_WR and CMD register
00179 //
00180 s16 Si114xParamSet(HANDLE si114x_handle, u8 address, u8 data)
00181 {
00182     s16     retval;
00183     u8      buffer[2];
00184     //s16     response;
00185 
00186     if((retval = _waitUntilSleep(si114x_handle))!=0) return retval;
00187     buffer[0]= data;
00188     buffer[1]= 0xA0 + (address & 0x1F);
00189     retval=Si114xBlockWrite(si114x_handle, REG_PARAM_WR, 2, (const u8 *)buffer);
00190     if(retval!=0) return retval;
00191     while(1)
00192     {
00193         retval=Si114xReadFromRegister(si114x_handle, REG_PARAM_RD);
00194         if (retval==data) break;
00195     }
00196     return 0;
00197 }
00198 
00199 
00200 //-----------------------------------------------------------------------------
00201 // use this to pause measurements
00202 static s16 _PsAlsPause (HANDLE si114x_handle)
00203 {
00204     return _sendCmd(si114x_handle,0x0B);
00205 }
00206 
00207 s16 Si114xPauseAll(HANDLE si114x_handle)
00208 {
00209     while (1)
00210     {
00211         // Keep sending nops until the response is zero
00212         while (1)
00213         {
00214             if ((Si114xReadFromRegister(si114x_handle, REG_RESPONSE))==0)
00215                 break;
00216             else
00217                 Si114xNop(si114x_handle);
00218         }
00219 
00220         // Pause the device
00221         _PsAlsPause(si114x_handle);
00222 
00223         // Wait for response
00224         while(1)
00225         {
00226             if ((Si114xReadFromRegister(si114x_handle, REG_RESPONSE))!=0)
00227                 break;
00228         }
00229 
00230         // When the PsAlsPause() response is good, we expect it to be a '1'.
00231         if ((Si114xReadFromRegister(si114x_handle, REG_RESPONSE))==1)
00232             break;  // otherwise, start over.
00233     }
00234     return 0;
00235 }
00236 
00237 
00238 s16 si114x_get_calibration( HANDLE si114x_handle, SI114X_CAL_S *si114x_cal, char security)
00239 {
00240    (void) si114x_handle;
00241    (void) si114x_cal;
00242    (void) security;
00243    // although the SI114x_CAL_S structure is not filled up properly, the set_ucoef() function will not use it.
00244    return 0;
00245 }
00246 
00247 s16 si114x_set_ucoef( HANDLE si114x_handle, u8 ref_ucoef[], SI114X_CAL_S *si114x_cal )
00248 {
00249    (void) ref_ucoef;
00250    (void) si114x_cal;
00251    s16 response;
00252    u8 ucoef[4] = { 0x29, 0x89, 0x02, 0x00 } ;
00253 
00254    // This will write 4 bytes starting with I2C address 0x13
00255     response = Si114xBlockWrite( si114x_handle, REG_UCOEF0, 4, &ucoef[0] );
00256     return response;
00257 }
00258