EFM32 Pearl Gecko 12 Software Documentation  efm32pg12-doc-5.1.2
si7210.c
Go to the documentation of this file.
1 /***************************************************************************/
16 #include <stddef.h>
17 #include "i2cspm.h"
18 #include "gpiointerrupt.h"
19 #include "em_cmu.h"
20 
21 #include "thunderboard/board.h"
22 #include "thunderboard/util.h"
23 #include "thunderboard/si7210.h"
24 
25 /***************************************************************************/
34 /***************************************************************************/
41 static SI7210_IntCallback callback;
42 static bool outputInvert;
43 static float scale;
50 /***************************************************************************/
59 static uint32_t wakeDevice ( void );
60 static uint8_t calculateSWOP ( float threshold );
61 static uint8_t calculateSWHYST ( float hysteresis );
62 static uint8_t calculateSlTime ( uint32_t samplePeriod, uint8_t *slFast );
63 static uint32_t loadCoeffsFromOtp ( uint8_t otpAddr );
64 static void gpioIntCallback ( uint8_t pin );
65 static void usDelay ( uint32_t delay );
66 
67 /***************************************************************************/
78 static void usDelay( uint32_t delay )
79 {
80 
81  volatile uint32_t cnt;
82 
83  cnt = CMU_ClockFreqGet( cmuClock_HF ) * delay / (uint32_t) 1e6;
84  cnt /= 7; /* 7 cycles per loop count */
85 
86  while( cnt-- )
87  ;
88 
89  return;
90 
91 }
92 
95 /***************************************************************************/
102 uint32_t SI7210_init( void )
103 {
104 
105  uint32_t status;
106  uint8_t deviceId;
107 
108  GPIOINT_Init();
109 
110  /* Enable power to the sensor */
111  BOARD_envSensEnable( true );
112 
113  /* Allow some time for the part to power up */
114  UTIL_delay( 2 );
115 
116  /* Enable pull-up on OUT1 line */
117  GPIO_PinModeSet( SI7210_GPIO_PORT_OUT1, SI7210_GPIO_PIN_OUT1, gpioModeInput, 0 );
118 
119  /* Try to contact the sensor and check it's device ID */
120  status = wakeDevice();
121  if( status != SI7210_OK ) {
122  return status;
123  }
124 
125  status = SI7210_regRead( SI7210_REG_ADDR_HREVID, &deviceId );
126  if( status != SI7210_OK ) {
127  /* For some reason, this transfer is NACKed even though the read succeed... */
128  /* return status; */
129  }
130 
131  if( deviceId != SI7210_DEVICE_ID ) {
132  status = SI7210_ERROR_INVALID_DEVICE_ID;
133  }
134 
135  scale = 0.0f;
136  callback = NULL;
137 
138  return status;
139 
140 }
141 
142 /***************************************************************************/
150 void SI7210_deInit( void )
151 {
152 
153  /* Disable pull-up on OUT1 line */
154  GPIOINT_CallbackUnRegister( SI7210_GPIO_PIN_OUT1 );
155  GPIO_IntConfig( SI7210_GPIO_PORT_OUT1, SI7210_GPIO_PIN_OUT1, false, false, false );
156  GPIO_PinModeSet( SI7210_GPIO_PORT_OUT1, SI7210_GPIO_PIN_OUT1, gpioModeDisabled, 0 );
157 
158  /* Disable sensor power */
159  BOARD_envSensEnable( false );
160 
161 }
162 
163 /***************************************************************************/
170 uint32_t SI7210_suspend( void )
171 {
172 
173  uint32_t status;
174  SI7210_ConfigThreshold config;
175 
176  status = SI7210_regSetBits( SI7210_REG_ADDR_POWER_CTRL,
177  SI7210_REG_POWER_CTRL_SLEEP_MASK );
178 
179  config.mode = SI7210_CONFIG_MODE_THRESHOLD;
180  config.callback = NULL;
181  config.threshold = 200;
182  config.hysteresis = 2;
183  config.polarity = SI7210_CONFIG_POLARITY_OMNI;
184  config.outputInvert = true;
185 
186  SI7210_config( &config );
187 
188  return status;
189 
190 }
191 
192 /***************************************************************************/
202 uint32_t SI7210_config( SI7210_Config config )
203 {
204 
205  uint32_t status;
206  uint8_t *mode;
207  uint8_t value;
208  uint8_t sw_op, sw_hyst;
209  uint8_t slFast, slTime;
210 
211  SI7210_ConfigThreshold *cfgThres;
212  SI7210_ConfigMeasure *cfgMeas;
213 
214  mode = (uint8_t *) config;
215 
216  if( ( *mode != SI7210_CONFIG_MODE_THRESHOLD ) && ( *mode != SI7210_CONFIG_MODE_MEASURE ) ) {
217  return SI7210_ERROR_CONFIG_INVALID_MODE;
218  }
219 
220  /* Wake up device and/or stop measurements */
221  status = wakeDevice();
222  if( status != SI7210_OK )
223  return status;
224 
225  status = SI7210_regSetBits( SI7210_REG_ADDR_POWER_CTRL,
226  SI7210_REG_POWER_CTRL_STOP_MASK );
227 
228  if( status != SI7210_OK )
229  return status;
230 
231  if( *mode == SI7210_CONFIG_MODE_THRESHOLD ) {
232 
233  cfgThres = (SI7210_ConfigThreshold *) config;
234 
235  if( ( cfgThres->threshold == 0.0 ) &&
236  ( cfgThres->hysteresis == 0.0 ) &&
237  ( cfgThres->polarity == 0 ) &&
238  ( cfgThres->outputInvert == 0 ) ) {
239 
240  /* Use default values in the device for all parameters */
241  status = SI7210_regClearBits( SI7210_REG_ADDR_POWER_CTRL,
242  SI7210_REG_POWER_CTRL_USESTORE_MASK );
243 
244  if( status != SI7210_OK )
245  return status;
246  }
247  else {
248 
249  /* Program sw_low4field and sw_op bit fields */
250  sw_op = calculateSWOP( cfgThres->threshold );
251 
252  value = ( cfgThres->outputInvert << SI7210_REG_CTRL1_SW_LOW4FIELD_SHIFT )
253  & SI7210_REG_CTRL1_SW_LOW4FIELD_MASK;
254 
255  value |= ( sw_op << SI7210_REG_CTRL1_SW_OP_SHIFT )
256  & SI7210_REG_CTRL1_SW_OP_MASK;
257 
258  status = SI7210_regWrite( SI7210_REG_ADDR_CTRL1, value );
259  if( status != SI7210_OK )
260  return status;
261 
262  /* Program sw_fieldpolsel and sw_hyst bit fields */
263  sw_hyst = calculateSWHYST( cfgThres->hysteresis );
264 
265  value = ( cfgThres->polarity << SI7210_REG_CTRL2_SW_FIELDPOLSEL_SHIFT )
266  & SI7210_REG_CTRL2_SW_FIELDPOLSEL_MASK;
267 
268  value |= ( sw_hyst << SI7210_REG_CTRL2_SW_HYST_SHIFT )
269  & SI7210_REG_CTRL2_SW_HYST_MASK;
270 
271  status = SI7210_regWrite( SI7210_REG_ADDR_CTRL2, value );
272  if( status != SI7210_OK )
273  return status;
274 
275  /* Enable storing of these parameters in sleep mode */
276  status = SI7210_regSetBits( SI7210_REG_ADDR_POWER_CTRL,
277  SI7210_REG_POWER_CTRL_USESTORE_MASK );
278 
279  if( status != SI7210_OK )
280  return status;
281  }
282 
283  /* Enable sleep timer and clear stop bit to start operation */
284  status = SI7210_regSetBits( SI7210_REG_ADDR_CTRL3,
285  SI7210_REG_CTRL3_SLTIMEENA_MASK );
286 
287  if( status != SI7210_OK )
288  return status;
289 
290  status = SI7210_regClearBits( SI7210_REG_ADDR_POWER_CTRL,
291  SI7210_REG_POWER_CTRL_STOP_MASK );
292 
293  if( status != SI7210_OK )
294  return status;
295 
296  /* Register gpio interrupt with driver */
297  outputInvert = cfgThres->outputInvert;
298  callback = cfgThres->callback;
299  GPIO_IntConfig( SI7210_GPIO_PORT_OUT1, SI7210_GPIO_PIN_OUT1, true, true, true );
300  GPIOINT_CallbackRegister( SI7210_GPIO_PIN_OUT1, gpioIntCallback );
301  }
302  else {
303 
304  cfgMeas = (SI7210_ConfigMeasure *) config;
305  if( cfgMeas->scale == SI7210_CONFIG_SCALE_200mT ) {
306 
307  /* Load coefficients from OTP memory for 200 mT range */
308  status = loadCoeffsFromOtp( SI7210_OTP_ADDR_COEFFS_200MT );
309  if( status != SI7210_OK )
310  return status;
311 
312  scale = 204.7f;
313  }
314  else {
315  scale = 20.47f;
316  }
317 
318  /* Calculate Sltime and Slfast registers */
319  slTime = calculateSlTime( cfgMeas->samplePeriod, &slFast );
320 
321  if( slFast ) {
322  status = SI7210_regSetBits( SI7210_REG_ADDR_CTRL3,
323  SI7210_REG_CTRL3_SLFAST_MASK );
324 
325  if( status != SI7210_OK )
326  return status;
327  }
328  else {
329  status = SI7210_regClearBits( SI7210_REG_ADDR_CTRL3,
330  SI7210_REG_CTRL3_SLFAST_MASK );
331 
332  if( status != SI7210_OK )
333  return status;
334  }
335 
336  status = SI7210_regWrite( SI7210_REG_ADDR_SLTIME, slTime );
337  if( status != SI7210_OK )
338  return status;
339 
340  /* Disable sleep timer and clear stop bit to start operation */
341  status = SI7210_regClearBits( SI7210_REG_ADDR_CTRL3,
342  SI7210_REG_CTRL3_SLTIMEENA_MASK );
343 
344  if( status != SI7210_OK )
345  return status;
346 
347  status = SI7210_regClearBits( SI7210_REG_ADDR_POWER_CTRL,
348  SI7210_REG_POWER_CTRL_STOP_MASK );
349 
350  if( status != SI7210_OK )
351  return status;
352 
353  /* Write correct value into dspsigsel */
354  status = SI7210_regWrite( SI7210_REG_ADDR_DSPSIGSEL, 0x04 );
355  if( status != SI7210_OK )
356  return status;
357 
358  }
359 
360  return status;
361 
362 }
363 
364 /***************************************************************************/
374 uint32_t SI7210_measure( float *result )
375 {
376 
377  uint32_t timeout;
378  uint32_t status;
379  uint8_t data;
380  int32_t field;
381  uint8_t flag;
382 
383  flag = 0;
384 
385  timeout = 1000;
386  while( ( flag == 0 ) && timeout-- ) {
387 
388  status = SI7210_regRead( SI7210_REG_ADDR_DSPSIGM, &data );
389  if( status != SI7210_OK )
390  return status;
391 
392  flag = data >> 7;
393  }
394 
395  if( timeout == 0 ) {
396  return SI7210_ERROR_READ_TIMEOUT;
397  }
398 
399  field = ( ( (uint16_t) data ) & 0x7F ) << 8;
400 
401  status = SI7210_regRead( SI7210_REG_ADDR_DSPSIGL, &data );
402  field |= data;
403  field -= 16384;
404  *result = ( (float) field ) * scale / 16384;
405 
406  return status;
407 
408 }
409 
410 /***************************************************************************/
423 uint32_t SI7210_regRead( uint8_t addr, uint8_t *data )
424 {
425 
428 
429  seq.addr = SI7210_I2C_DEVICE_BUS_ADDRESS << 1;
431 
432  seq.buf[0].len = 1;
433  seq.buf[1].len = 1;
434  seq.buf[0].data = &addr;
435  seq.buf[1].data = data;
436 
437  ret = I2CSPM_Transfer( SI7210_I2C_DEVICE, &seq );
438  if( ret != i2cTransferDone ) {
439  return SI7210_ERROR_I2C_TRANSFER_FAILED;
440  }
441 
442  return SI7210_OK;
443 
444 }
445 
446 /***************************************************************************/
459 uint32_t SI7210_regWrite( uint8_t addr, uint8_t data )
460 {
461 
464 
465  seq.addr = SI7210_I2C_DEVICE_BUS_ADDRESS << 1;
467 
468  seq.buf[0].len = 1;
469  seq.buf[1].len = 1;
470  seq.buf[0].data = &addr;
471  seq.buf[1].data = &data;
472 
473  ret = I2CSPM_Transfer( SI7210_I2C_DEVICE, &seq );
474  if( ret != i2cTransferDone ) {
475  return SI7210_ERROR_I2C_TRANSFER_FAILED;
476  }
477 
478  return SI7210_OK;
479 
480 }
481 
482 /***************************************************************************/
497 uint32_t SI7210_regSetBits( uint8_t addr, uint8_t mask )
498 {
499 
500  uint8_t value;
501  uint32_t status;
502 
503  status = SI7210_regRead( addr, &value );
504  if( status != SI7210_OK ) {
505  return status;
506  }
507 
508  value |= mask;
509 
510  status = SI7210_regWrite( addr, value );
511 
512  return status;
513 
514 }
515 
516 /***************************************************************************/
531 uint32_t SI7210_regClearBits( uint8_t addr, uint8_t mask )
532 {
533 
534  uint8_t value;
535  uint32_t status;
536 
537  status = SI7210_regRead( addr, &value );
538  if( status != SI7210_OK ) {
539  return status;
540  }
541 
542  value &= ~mask;
543 
544  status = SI7210_regWrite( addr, value );
545 
546  return status;
547 
548 }
549 
552 /***************************************************************************/
559 static uint32_t wakeDevice( void )
560 {
561 
564 
565  seq.addr = SI7210_I2C_DEVICE_BUS_ADDRESS << 1;
566  seq.flags = I2C_FLAG_WRITE;
567 
568  seq.buf[0].len = 0;
569  seq.buf[0].data = NULL;
570 
571  ret = I2CSPM_Transfer( SI7210_I2C_DEVICE, &seq );
572  if( ret != i2cTransferDone ) {
573  return SI7210_ERROR_I2C_TRANSFER_FAILED;
574  }
575 
576  usDelay( 10 );
577 
578  return SI7210_OK;
579 
580 }
581 
582 /***************************************************************************/
594 static uint8_t calculateSWOP( float threshold )
595 {
596 
597  int th;
598  uint8_t a;
599  uint8_t swop;
600 
601  th = (int) ( threshold / 0.005 );
602 
603  if( th == 0 ) {
604  /* threshold = 0, when swop = 127 */
605  return 127;
606  }
607  else if( th < 16 ) {
608  threshold = 16;
609  }
610  else if( threshold > 3840 ) {
611  threshold = 3840;
612  }
613 
614  a = th / 16;
615  swop = 0;
616  while( a != 0x01 ) {
617  a = a >> 1; /* Find the most significant 1 of th */
618  swop += 0x10; /* increment sw_op[6:4] */
619  }
620 
621  /* Add remainder as sw_op[3:0] */
622  swop |= th / ( 1 << ( swop >> 4 ) ) - 16;
623 
624  return swop;
625 
626 }
627 
628 /***************************************************************************/
640 static uint8_t calculateSWHYST( float hysteresis )
641 {
642 
643  int hyst;
644  uint8_t a;
645  uint8_t swhyst;
646 
647  hyst = (int) ( hysteresis / 0.005 );
648 
649  if( hyst == 0 ) {
650  /* When sw_op = 63 the hysteresis is set to zero */
651  return 63;
652  }
653  else if( hyst < 8 ) {
654  hyst = 8;
655  }
656  else if( hyst > 1792 ) {
657  hyst = 1792;
658  }
659 
660  a = hyst / 8;
661  swhyst = 0;
662 
663  while( a != 0x01 ) {
664  a = a >> 1;
665  swhyst += 0x08;
666  }
667 
668  swhyst |= hyst / ( 1 << ( swhyst >> 3 ) ) - 8;
669 
670  return swhyst;
671 
672 }
673 
674 /***************************************************************************/
689 static uint8_t calculateSlTime( uint32_t samplePeriod, uint8_t *slFast )
690 {
691 
692  int a;
693  uint8_t slTime;
694 
695  if( samplePeriod == 0 ) {
696  *slFast = 1;
697  slTime = 0;
698  return slTime;
699  }
700 
701  /* Impose limits */
702  if( samplePeriod < 11 ) {
703  samplePeriod = 11;
704  }
705  else if( samplePeriod > 172000 ) {
706  samplePeriod = 172000;
707  }
708 
709  /* Decide on wether we need slFast or not */
710  if( samplePeriod < 750 ) {
711  *slFast = 1;
712  a = samplePeriod * 12 / 32 / 4;
713  }
714  else {
715  *slFast = 0;
716  a = samplePeriod * 12 / 32 / 256;
717  }
718 
719  slTime = 0;
720  while( a != 0x01 ) {
721  a = a >> 1;
722  slTime += 0x20;
723  }
724 
725  if( *slFast ) {
726  slTime |= samplePeriod * 12 / ( 4 << ( slTime >> 5 ) ) - 32;
727  }
728  else {
729  slTime |= samplePeriod * 12 / ( 256 << ( slTime >> 5 ) ) - 32;
730  }
731 
732  return slTime;
733 
734 }
735 
736 /***************************************************************************/
749 static uint32_t SI7210_regReadOTP( uint8_t otpAddr, uint8_t *otpData )
750 {
751 
752  uint32_t status;
753  uint8_t reg;
754 
755  status = SI7210_regRead( SI7210_REG_ADDR_OTP_CTRL, &reg );
756  if( status != SI7210_OK )
757  return status;
758 
759  if( reg & SI7210_REG_OTP_CTRL_BUSY_MASK ) {
760  return SI7210_ERROR_OTP_BUSY;
761  }
762 
763  status = SI7210_regWrite( SI7210_REG_ADDR_OTP_DATA, otpAddr );
764  if( status != SI7210_OK )
765  return status;
766 
767  status = SI7210_regWrite( SI7210_REG_ADDR_OTP_CTRL, SI7210_REG_OTP_CTRL_READ_EN_MASK );
768  if( status != SI7210_OK )
769  return status;
770 
771  status = SI7210_regRead( SI7210_REG_ADDR_OTP_DATA, otpData );
772 
773  return status;
774 
775 }
776 
777 /***************************************************************************/
787 static uint32_t loadCoeffsFromOtp( uint8_t otpAddr )
788 {
789 
790  int i;
791  uint32_t status;
792  uint8_t value;
793 
794  const uint8_t writeAddr[] = {
795 
796  SI7210_REG_ADDR_A0,
797  SI7210_REG_ADDR_A1,
798  SI7210_REG_ADDR_A2,
799  SI7210_REG_ADDR_A3,
800  SI7210_REG_ADDR_A4,
801  SI7210_REG_ADDR_A5
802  };
803 
804  for( i = 0; i < sizeof( writeAddr ); i++ ) {
805 
806  status = SI7210_regReadOTP( otpAddr++, &value );
807 
808  if( status != SI7210_OK ) {
809  return status;
810  }
811 
812  status = SI7210_regWrite( writeAddr[i], value );
813 
814  if( status != SI7210_OK ) {
815  return status;
816  }
817  }
818 
819  return status;
820 
821 }
822 
823 /***************************************************************************/
834 static void gpioIntCallback( uint8_t pin )
835 {
836 
837  uint8_t fieldLevel;
838 
839  if( GPIO_PinInGet( SI7210_GPIO_PORT_OUT1, SI7210_GPIO_PIN_OUT1 ) && !outputInvert ) {
840  fieldLevel = 1;
841  }
842  else {
843  fieldLevel = 0;
844  }
845 
846  if( callback != NULL ) {
847  callback( fieldLevel );
848  }
849 
850  return;
851 
852 }
853 
Clock management unit (CMU) API.
I2C_TransferReturn_TypeDef I2CSPM_Transfer(I2C_TypeDef *i2c, I2C_TransferSeq_TypeDef *seq)
Perform I2C transfer.
Definition: i2cspm.c:124
uint32_t SI7210_regRead(uint8_t addr, uint8_t *data)
Reads register from the Si7021 device.
Definition: si7210.c:423
Driver for the Silicon Labs Si7210 Hall Effect Sensor.
void UTIL_delay(uint32_t ms)
Delays number of msTick Systicks (1 ms)
Definition: util.c:97
static __INLINE void GPIOINT_CallbackUnRegister(uint8_t pin)
Unregisters user callback for given pin number.
Definition: gpiointerrupt.h:66
uint32_t SI7210_suspend(void)
Puts the Si7210 chip in sleep mode.
Definition: si7210.c:170
void GPIOINT_CallbackRegister(uint8_t pin, GPIOINT_IrqCallbackPtr_t callbackPtr)
Registers user callback for given pin number.
Definition: gpiointerrupt.c:91
uint32_t SI7210_regSetBits(uint8_t addr, uint8_t mask)
Sets the given bit(s) in a register in the Si7021 device.
Definition: si7210.c:497
#define I2C_FLAG_WRITE
Indicate plain write sequence: S+ADDR(W)+DATA0+P.
Definition: em_i2c.h:124
I2C_TransferReturn_TypeDef
Definition: em_i2c.h:179
uint32_t BOARD_envSensEnable(bool enable)
Enables or disables the environmental sensor group (Pressure, RH/Temp, UV/Ambient light and Hall sens...
Definition: board.c:492
uint32_t SI7210_measure(float *result)
Performs a measurement.
Definition: si7210.c:374
void GPIO_PinModeSet(GPIO_Port_TypeDef port, unsigned int pin, GPIO_Mode_TypeDef mode, unsigned int out)
Set the mode for a GPIO pin.
Definition: em_gpio.c:269
I2C simple poll-based master mode driver for the DK/STK.
void SI7210_deInit(void)
De-initializes the Si7210 chip. Disables the sensor power domain, this also disables other sensors...
Definition: si7210.c:150
Utility Functions for the Thunderboard Sense.
struct I2C_TransferSeq_TypeDef::@0 buf[2]
uint32_t SI7210_regClearBits(uint8_t addr, uint8_t mask)
Clears the given bit(s) in a register in the Si7021 device.
Definition: si7210.c:531
__STATIC_INLINE void GPIO_IntConfig(GPIO_Port_TypeDef port, unsigned int pin, bool risingEdge, bool fallingEdge, bool enable)
Configure GPIO interrupt.
Definition: em_gpio.h:1104
Master mode transfer message structure used to define a complete I2C transfer sequence (from start to...
Definition: em_i2c.h:252
uint32_t SI7210_init(void)
Initializes the Si7210 chip.
Definition: si7210.c:102
void GPIOINT_Init(void)
Initialization of GPIOINT module.
Definition: gpiointerrupt.c:67
uint32_t SI7210_regWrite(uint8_t addr, uint8_t data)
Writes a register in the Si7021 device.
Definition: si7210.c:459
uint32_t SI7210_config(SI7210_Config config)
Configures the Si7210 chip.
Definition: si7210.c:202
GPIOINT API definition.
#define I2C_FLAG_WRITE_WRITE
Indicate write sequence using two buffers: S+ADDR(W)+DATA0+DATA1+P.
Definition: em_i2c.h:159
#define I2C_FLAG_WRITE_READ
Indicate combined write/read sequence: S+ADDR(W)+DATA0+Sr+ADDR(R)+DATA1+P.
Definition: em_i2c.h:148
uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
Get clock frequency for a clock point.
Definition: em_cmu.c:1550
__STATIC_INLINE unsigned int GPIO_PinInGet(GPIO_Port_TypeDef port, unsigned int pin)
Read the pad value for a single pin in a GPIO port.
Definition: em_gpio.h:781
uint16_t addr
Address to use after (repeated) start.
Definition: em_i2c.h:262
BOARD module header file.