I didn't have much time so I used Arduino for the sensor board which makes design cumbersome to fit inside a helmet. However, I have some time this week so I created code for MSP432. ADXL345 can be accessible through either an SPI (3- or 4-wire) or I2C digital interface. I prefer I2C because I have used TMP102 temperature sensor which has I2C interface. Using I2C, I don't need to use additional pins. ADXL345 is not very easy to use. It requires some setting before gathering the data. You may ask why I have chosen it, the reason is I have a spare one.
I modified the Sparkfun Arduino library for the MSP432 with the minimum setting. First, we need to wake-up accelerometer and tell it to take measurements. This is done sending commands to POWER_CTL register. Second, we need to set the range of the sensor. The range varies from 2g to 16g. The more the range the less the sensitivity. I prefer the sensitivity so set it to 2g which is the default value. I may change this values when I embed the design inside the helmet and take real scenario measurements.
The ADXL345 provides more than x,y,z data. It can provide interrupt for activity, inactivity, freefall and more. To use interrupt we need to set them. ACT_INACT_CTL (value = 01110111) register is control register for activity and inactivity detection.
"Then THRESH_ACT register is eight bits and holds the threshold value for detecting activity. The data format is unsigned, so the magnitude of the activity event is compared with the value in the THRESH_ACT register. The scale factor is 62.5 mg/LSB."
THRESH_INACT register has a similar task which holds the threshold for the inactivity. After setting thresholds, I set the FREE_FALL register which can detect the free-fall.
ADXL345 has two interrupt pin but eight interrupt sources. Therefore, we need to map the interrupts for the pins. I am using activity, inactivity, free-fall interrupts (maybe data available when my design becomes more clear).
Any bits set to 0 in this register send their respective interrupts to the INT1 pin, whereas bits set to 1 send their respective interrupts to the INT2 pin. All selected interrupts for a given pin are OR’ed.
I will use interrupt pin 1 for the inactivity and free-fall and interrupt pin 2 for the activity (activity is used to double check). Therefore, I need to write 0bxxx100xx (0b11110011).
After setting all the values, we need to enable interrupts so we need to send 0b00011100 to INT_ENABLE register.
Here is the initialization code for the ADXL345. I coded this as a library file but I2C_transfer function can be only called from inside the task. Therefore following function is a task.
void ADXL345_init (UArg arg0, UArg arg1) { uint8_t txBuffer[2]; uint8_t rxBuffer[2]; I2C_Handle i2c; I2C_Params i2cParams; I2C_Transaction i2cTransaction; /* Create I2C for usage */ I2C_Params_init(&i2cParams); i2cParams.bitRate = I2C_100kHz; i2c = I2C_open(adxl345_I2C, &i2cParams); if (i2c == NULL) { System_abort("Error Initializing I2C\n"); } else { System_printf("I2C Initialized!\n"); } /**** ADXL345 TURN ON ***/ txBuffer[0] = ADXL345_POWER_CTL; //Wakeup txBuffer[1] = 0; i2cTransaction.slaveAddress = ADXL345_I2C_ADDR; i2cTransaction.writeBuf = txBuffer; i2cTransaction.writeCount = 2; i2cTransaction.readBuf = rxBuffer; i2cTransaction.readCount =1; I2C_transfer(i2c, &i2cTransaction); txBuffer[1] = 16; // Auto_sleep I2C_transfer(i2c, &i2cTransaction); txBuffer[1] = 8; // Measure I2C_transfer(i2c, &i2cTransaction); /***** Give the range settings *****/ // Accepted values are 2g, 4g, 8g or 16g - ADXL345_DATA_FORMAT // Higher Values = Wider Measurement Range // Lower Values = Greater Sensitivity /**** Activity Inactivity setting ***/ txBuffer[0] = ADXL345_ACT_INACT_CTL; txBuffer[1] = 0b01110111; I2C_transfer(i2c, &i2cTransaction); txBuffer[0] = ADXL345_TIME_INACT; // txBuffer[1] = 10; I2C_transfer(i2c, &i2cTransaction); /**** Activity Threshold ***/ txBuffer[0] = ADXL345_THRESH_ACT; txBuffer[1] = 75; // 62.5mg per increment // Activity thresholds (0-255) I2C_transfer(i2c, &i2cTransaction); /**** Inactivity Threshold ***/ txBuffer[0] = ADXL345_THRESH_INACT; txBuffer[1] = 20; // 62.5mg per increment // Inactivity thresholds (0-255) I2C_transfer(i2c, &i2cTransaction); /**** Free-Fall Threshold and Time ***/ txBuffer[0] = ADXL345_THRESH_FF; txBuffer[1] = 7; // (5 - 9) recommended - 62.5mg per increment I2C_transfer(i2c, &i2cTransaction); txBuffer[0] = ADXL345_TIME_FF; txBuffer[1] = 30; // (20 - 70) recommended - 5ms per increment I2C_transfer(i2c, &i2cTransaction); /**** Interrupt setup ***/ //Interrupt mapping txBuffer[0] = ADXL345_INT_MAP; txBuffer[1] = 0; // 0b11110011; //inactivity and free-fall is int1, activity is int2 ( others are int 2 but disabled) I2C_transfer(i2c, &i2cTransaction); //Interrupt enable txBuffer[0] = ADXL345_INT_ENABLE; txBuffer[1] = 0b00011100; //activity, inactivity, and free-fall interrupts are enabled I2C_transfer(i2c, &i2cTransaction); /* Deinitialized I2C */ I2C_close(i2c); System_printf("I2C closed!\n"); System_flush(); /* Construct BIOS objects */ Task_Params taskParams; Task_Params_init(&taskParams); taskParams.stackSize = TASKSTACKSIZE; taskParams.stack = &taskI2CStack; Task_construct(&taskI2CStruct, (Task_FuncPtr)readPos, &taskParams, NULL); }
ADXL345 has the interrupt output so we need to get this on MSP432. It was a little trick to find how interrupts work on TI-RTOS then it becomes very easy. First, MSP_EXP432P401R.c should be configured. I set up the p3.6 pin for the INT1 output of the ADXL345 so I added the following code to gpioConfigs driver. Then give that pin a name inside MSP_EXP432P401R.h.
/* MSP_EXP432P401R_P3.6 */
GPIOMSP432_P3_6 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING,
MSP_EXP432P401R.c Pin Configuration
GPIO_PinConfig gpioPinConfigs[] = { /* Input pins */ /* MSP_EXP432P401R_S1 */ GPIOMSP432_P1_1 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_RISING, /* MSP_EXP432P401R_S2 */ GPIOMSP432_P1_4 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_RISING, /* MSP_EXP432P401R_P3.6 */ GPIOMSP432_P3_6 | GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING, /* Output pins */ /* MSP_EXP432P401R_LED1 */ GPIOMSP432_P1_0 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, /* MSP_EXP432P401R_LED_RED */ GPIOMSP432_P2_0 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, /* * MSP_EXP432P401R_LED_GREEN & MSP_EXP432P401R_LED_BLUE are used for * PWM examples. Uncomment the following lines if you would like to control * the LEDs with the GPIO driver. */ /* MSP_EXP432P401R_LED_GREEN */ //GPIOMSP432_P2_1 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, /* MSP_EXP432P401R_LED_BLUE */ //GPIOMSP432_P2_2 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW };
MSP_EXP432P401R.h Pin tagging
typedef enum MSP_EXP432P401R_GPIOName { MSP_EXP432P401R_S1 = 0, MSP_EXP432P401R_S2, MSP_EXP432P401R_INT1, MSP_EXP432P401R_LED1, MSP_EXP432P401R_LED_RED, /* * MSP_EXP432P401R_LED_GREEN & MSP_EXP432P401R_LED_BLUE are used for * PWM examples. Uncomment the following lines if you would like to control * the LEDs with the GPIO driver. */ //MSP_EXP432P401R_LED_GREEN, //MSP_EXP432P401R_LED_BLUE, MSP_EXP432P401R_GPIOCOUNT } MSP_EXP432P401R_GPIOName;
Finally, activate the interrupt inside the main function.
/* install Button callback */ GPIO_setCallback(MSP_EXP432P401R_INT1 , gpioButtonFxn0); /* Enable interrupts */ GPIO_enableInt(MSP_EXP432P401R_INT1 );
Now the design has the same features with the previous one but Arduino is removed. This make it more compact, cheaper, and more based on MSP432
You can see all the links related to this project in the first blog: Safe & Sound Wearables - Trackable Safety Helmet for Miners #1: Introduction to Project
Top Comments