Other Parts Discussed in Thread: , SYSBIOS, CC2540
Tool/software: Code Composer Studio
Is there any way to use the SYS/BIOS Seconds Module to generate an Unix Timestamp in ms?
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: CC2650
Tool/software: Code Composer Studio
Hello!
I'm trying to modify the sensortag_cc2650 sample project so I can acquire sensor data (mainly accelerometer and gyroscope) along with their corresponding timestamps (in ms).
I was suggested to take a look at the RTC time provider and use the Benchmark Example as reference, but I'm a bit lost around this....
Anyone could guide me with this?
Thanks in advance
Hi,
I suggest you look into the TImestamp module in the TI-RTOS kernel:
You could use it like this:
#include <xdc/runtime/Types.h> #include <xdc/runtime/Timestamp.h> Timestamp_getFreq(&freq); t0 = Timestamp_get32(); ... do work t1 = Timestamp_get32(); delta = (t0 - t1) / freq.lo; // Time in S, scale accordingly
Hi,
Thanks again for your repply, then I guess I'll use the Seconds Module.
I'm currently working with the sensortag_cc2650stk, specifically with the sensortag_mov.c
Do you think it would be OK if I use Seconds_get(); in the SensorTagMov_processSensorEvent() when I get the accelerometer data?
#include <time.h> #include <ti/sysbios/hal/Seconds.h> UInt32 t; Seconds_Set(1535526855) //Current Unix Timestamp (02/29/2018 @7:14 am) GTM void SensorTagMov_processSensorEvent(void) { ... { // Read accelerometer data SensorMpu9250_accRead((uint16_t*)&sensorData[6]); t = Seconds_get(); } ... }
Moreover, I understand that I have to expand the Movement Sensor GATT Service in order to have a timestamp attribute, is this correct? In this case I would need to assign t so sensorData before sending it?
I'm following the Bluetooth Low Energy Costume Profile Tutorial to get familiar with this.
Best,
Alejandra
Hi,
There is a similar tutorial for the CC2650 available that you should be able to follow:
It is for the v2.2.1 stack but I would expect it to work for you on the v2.2.2 as well.
Dear M-W,
Thanks for the tutorial, after completing it and reading the documentation for the services within the sensortag_cc2650stk project, I started modifying the movement service, in particular the Data characteristic.
I consider that the simplest way to add the time stamp to the accelerometer data, is to increase by four the Size (bytes) of the Data characteristic.
In this way I could just assign my UInt32 t=Seconds_get() into the last four bytes of the data characteristic.
Do you think that my reasoning is correct? If so, would It be enough to modify:
// In movementservice.h // Length of sensor data in bytes #define MOVEMENT_DATA_LEN 22 //Used to be 18 // In movementservice.c // Characteristic Value: data static uint8_t sensorData[SENSOR_DATA_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
If not, do you have any suggestions on how to approach this?
Thanks,
Alejandra
Sure,
I defined MOVEMENT_DATA_LEN as 22. And this is what I'm doing in sensortag_mov.c
#ifndef EXCLUDE_MOV /********************************************************************* * INCLUDES */ #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Queue.h> #include "gatt.h" #include "gattservapp.h" #include "board.h" #include "movementservice.h" #include "sensortag_mov.h" #include "SensorMpu9250.h" #include "SensorTagTest.h" #include "SensorUtil.h" #include "util.h" #include "string.h" #include <time.h> #include <ti/sysbios/hal/Seconds.h> /********************************************************************* * MACROS */ #define MOVEMENT_INACT_CYCLES (MOVEMENT_INACT_TIMEOUT * \ (10000/sensorPeriod) / 10) /********************************************************************* * CONSTANTS and MACROS */ // How often to perform sensor reads (milliseconds) #define SENSOR_DEFAULT_PERIOD 1000 // Length of the data for this sensor #define SENSOR_DATA_LEN MOVEMENT_DATA_LEN // Event flag for this sensor #define SENSOR_EVT ST_GYROSCOPE_SENSOR_EVT // Movement task states #define APP_STATE_ERROR 0xFF #define APP_STATE_OFF 0 #define APP_STATE_IDLE 1 #define APP_STATE_ACTIVE 2 // Movement task configuration #define MOVEMENT_INACT_TIMEOUT 10 // 10 seconds #define GYR_SHAKE_THR 10.0 #define WOM_THR 10 // Configuration bit-masks (bits 0-6 defined in sensor_mpu9250.h) #define MOV_WOM_ENABLE 0x0080 #define MOV_MASK_WOM_THRESHOLD 0x3C00 // TBD #define MOV_MASK_INACT_TIMEOUT 0xC000 // TBD /********************************************************************* * TYPEDEFS */ /********************************************************************* * GLOBAL VARIABLES */ UInt32 t; //Set time to Current Unix Timestamp (05/09/2018 @2:32 pm UTC) Seconds_set(1536157938); /********************************************************************* * LOCAL VARIABLES */ static Clock_Struct periodicClock; static uint16_t sensorPeriod; static volatile bool sensorReadScheduled; static uint8_t sensorData[SENSOR_DATA_LEN]; // Application state variables // MPU config: // bit 0-2: accelerometer enable(z,y,x) // bit 3-5: gyroscope enable (z,y,x) // bit 6: magnetometer enable // bit 7: WOM enable // bit 8-9: accelerometer range (2,4,8,16) static uint16_t mpuConfig; static uint8_t appState; static volatile bool mpuDataRdy; static uint32_t nActivity; static uint8_t movThreshold; static uint8_t mpuIntStatus; static uint8_t nMotions; /********************************************************************* * LOCAL FUNCTIONS */ static void sensorChangeCB(uint8_t paramID); static void initCharacteristicValue(uint8_t paramID, uint8_t value, uint8_t paramLen); static void SensorTagMov_clockHandler(UArg arg); static void appStateSet(uint8_t newState); static void SensorTagMov_processInterrupt(void); /********************************************************************* * PROFILE CALLBACKS */ static sensorCBs_t sensorCallbacks = { sensorChangeCB, // Characteristic value change callback }; /********************************************************************* * PUBLIC FUNCTIONS */ /********************************************************************* * @fn SensorTagMov_processSensorEvent * * @brief SensorTag Movement sensor event processor. * * @param none * * @return none */ void SensorTagMov_processSensorEvent(void) { if (sensorReadScheduled) { uint8_t axes; axes = mpuConfig & MPU_AX_ALL; if ((axes != ST_CFG_SENSOR_DISABLE) && (axes != ST_CFG_ERROR)) { // Get interrupt status (clears interrupt) mpuIntStatus = SensorMpu9250_irqStatus(); // Process gyro and accelerometer if (mpuDataRdy || appState == APP_STATE_ACTIVE) { if (mpuIntStatus & MPU_MOVEMENT) { // Motion detected (small filter) nMotions++; if (nMotions == 2) { nActivity = MOVEMENT_INACT_CYCLES; } } else if (mpuIntStatus & MPU_DATA_READY) { // Read gyro data SensorMpu9250_gyroRead((uint16_t*)sensorData); // Read accelerometer data SensorMpu9250_accRead((uint16_t*)&sensorData[6]); //Get current Unix Timestamp t = Seconds_get(); //Store t which is UInt32 into sensorData last four bytes. sensorData[18] = t; sensorData[19] = t>>8; sensorData[20] = t>>16; sensorData[21] = t>>24; } mpuDataRdy = false; if (appState == APP_STATE_ACTIVE && !!(mpuConfig & MPU_AX_MAG)) { uint8_t status; status = SensorMpu9250_magRead((int16_t*)&sensorData[12]); // Always measure magnetometer (not interrupt driven) if (status == MAG_BYPASS_FAIL) { // Idle on error nActivity = 0; appState = APP_STATE_ERROR; } else if (status != MAG_STATUS_OK) { SensorMpu9250_magReset(); } } } if (nActivity>0) { if (appState != APP_STATE_ACTIVE) { // Transition to active state appState = APP_STATE_ACTIVE; nMotions = 0; if (SensorMpu9250_reset()) { SensorMpu9250_enable(axes); } } if (mpuConfig & MOV_WOM_ENABLE) { nActivity--; } // Send data Movement_setParameter(SENSOR_DATA, SENSOR_DATA_LEN, sensorData); } else { if (appState != APP_STATE_IDLE) { // Transition from active to idle state nMotions = 0; appState = APP_STATE_IDLE; if (SensorMpu9250_reset()) { SensorMpu9250_enableWom(movThreshold); } } } } sensorReadScheduled = false; } }
I only included SensorTagMov_processSensorEvent which is what I'm modifying.
On the other hand, If I want a sampling frequency of 100Hz I should change the SENSOR_DEFAULT_PERIOD, right?
If instead I use the Seconds_set(); inside a Function Declaration, such as SensorTagMov_init()
void SensorTagMov_init(void) { //Set Time Seconds_set(1536157938); // Add service Movement_addService(); // Register callbacks with profile Movement_registerAppCBs(&sensorCallbacks); // Initialize the module state variables mpuConfig = ST_CFG_SENSOR_DISABLE; sensorPeriod = SENSOR_DEFAULT_PERIOD; sensorReadScheduled = false; appState = APP_STATE_OFF; nMotions = 0; if (SensorMpu9250_init()) { SensorTagMov_reset(); SensorMpu9250_registerCallback(SensorTagMov_processInterrupt); } // Initialize characteristics initCharacteristicValue(SENSOR_PERI, SENSOR_DEFAULT_PERIOD / SENSOR_PERIOD_RESOLUTION, sizeof(uint8_t)); // Create continuous clock for internal periodic events. Util_constructClock(&periodicClock, SensorTagMov_clockHandler, 1000, sensorPeriod, false, 0); }
I get the following:
Hi M-W,
Attached there is a file with the screenshots from what I'm reading out of the data with LigthBlue Explore. And the description of the number of bytes setted on MOVEMENT_DATA_LEN in each of them.
Could you guide me through the breakpoint process? I'm not sure about what to do there...
Thanks,
Alejandra
Dear M-W,
The easy, glorious, beautiful TI sniffer doesn't seem to be working... Its not finding any BLE devices. :(
I tried following this tutorial: http://processors.wiki.ti.com/index.php/BLE_sniffer_guide
Any other suggestions?
Also, why do you say I'm not actually observing the correct values? I placed the timestamp values on the Magnetometer bytes of the Data array and they seem to be correct. I just don't seem to understand what happens when It comes to 22 bytes...
Hi,
Any suggestions in how to look at the sniffer logs considering that I only have the CC2650 SensorTag and DevKit?
Best
Alejandra
Hi M-W,
I missed you :P
I'm still having problems with the 22 bytes (in most cases) and is very strange... So I think for now I'm giving up with that and I'll just sent the timestamp instead of the magnetometer bytes, since I'm not using it anyways.
Moreover, I realized I was being an idiot by using the Seconds module since what I need is a resolution of milliseconds. Is there any way to also get the milliseconds with the Seconds module? Or should I use the Timestamp module (as you suggested forever ago, sorry), as follows?
// On Sensortag_mov.c #include <xdc/runtime/Types.h> #include <xdc/runtime/Timestamp.h> ... void SensorTagMov_processSensorEvent(void) { ... else if (mpuIntStatus & MPU_DATA_READY) { // Read gyro data SensorMpu9250_gyroRead((uint16_t*)sensorData); // Read accelerometer data SensorMpu9250_accRead((uint16_t*)&sensorData[6]); t = Timestamp_get32(); sensorData[12] = t>>24; sensorData[13] = t>>16; sensorData[14] = t>>8; sensorData[15] = t; } ... Movement_setParameter(SENSOR_DATA, SENSOR_DATA_LEN, sensorData); }
In that case, would I be able to get a timestamp that provides the difference (in milliseconds) between each reading of the movement sensor?
Also, I'm not sure I understand how I'm I supposed to use the Timestamp frequency, and the Timestamp_getFreq(&freq); (In the documentation it says I should use it to convert the Timestamp value into units of real time, but is very unclear for me how this works). Could you guide me through this?
Thanks,
Alejandra
Dear M-W,
I got the USB dongle and I'm trying to use it with the "Packet Sniffer" (the one that supports BLE) but I'm not being able to start the packet capturing, I always get an error noise.
I'm trying to update the dongle's firmware using the SmartRF Flash Programmer, (I also installed Smart RF Studio so I could have the CEBAL Driver) but I'm not being able to see my dongle in the Flash Programmer, is there anything else I should consider?
Thanks,
Alejandra
Dear M-W,
I did not get the CC debugger needed for programming the dongle.
I'll try to get one if possible, now I changed the drive of the dongle and I'm being able to use it with the beautiful Packet Sniffer, so for now it is OK.
I made an android app that connects to the sensortag and starts reading/stop reading the data every 5 seconds. (It reads during 5 seconds then it stops reading and it starts reading again, for a total of 25 seconds)
I used the Sniffer during this acquisition (attached file), but I'm not sure about how should I interpret it. Do you have any guide about how to interpret the received packets? I'm specifically interested in checking the data being transfered from the movement service.
I'm currently using this as guide: http://processors.wiki.ti.com/index.php/BLE_sniffer_guide
Acquisition 5-5.psd
Hi M-W,
Currently I don't have any yellow fields, from the debugger of my app I can see that data is being transmitted, but on the sniffer I don't have anything related to the connection packages. I only have the advertising packets.
Even If I go back to the SensorTag App and the unmodified firmware I still get only advertising packets.
I went to the Peripheral.c to set gapRole_AdvChanMap = GAP_ADVCHAN_37; and set the channel in the sniffer to 37 to see if anything changed but the behaviour remained the same. (Did the same with 38 and 39)
Moreover, I tried setting the Initiator Address on the Sniffer to the cell phone's address and to the sensortag address.
I also tried to test this in a less crowded enviroment, but still nothing.
Attached is a screenshot of what I usually see.
Yes, it is. Thanks.
Does it make sense to you that a CC2650 with the firmware programmed to transmit the movement sensor data at 100 Hz (to my app) does it at 30 Hz with one battery and at 100 Hz with another battery?
Best,
Alejandra
I'm almost sure.
Would there be any signs of the device actually restarting?
I did 5 tests for each battery, with the same app at 100Hz, and the same CC2650, withouth modifying nor re-loading the firmware.
I'm using an Energizer CR2032 and a Duracel DL2032 (According to what I understand they are the same battery and should have the same behaviour)
First I used the Duracel battery and I was able to acquire at ~100 Hz. (This frequency determined by both the total samples / test duration, and the mean timestamp difference between samples)
Then, I used the Energizer battery and the frequency droped to ~30 Hz in each of the 5 acquisitions.
I find it very strange, and I cannot seem to understand this behaviour.
Best,
Alejandra
Hi M-W,
Mysterious update: I did five more tests with each battery, 1 min each, and the Duracel keept going at ~ 100 Hz, while the Energizer went as follows:
Test 1: ~ 33.28 Hz
Test 2: ~ 42. 84 Hz
Test 3: ~ 63.18 Hz
Test 4: ~ 86.58 Hz
Test 5: ~ 100 Hz
I find this even more strange, but is consistent with the frequency behaviour I was experiencing before. Any idea of why this happens?