Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
8 years, 8 months ago.
Logical operator frustrating me
Hello,
I am posting this question out of frustration. I am trying to log data from two separate sensors (gyroscope and accelerometer) into one file. Setting their sampling rates to be the same I thought I would wait fro both their FIFOs to reach 20 samples and then transfer all the data to the SD card, to this I am looking for an interrupt from both sensors. When a interrupt is fired a flag is set to clear that sensors FIFO and move that data to an onboard array after completing this a data ready flag is set, one for each data_array. Once both local arrays are full then all the data gets moved to the SD card for storage. The issue I am having is on the last step, if I wait for both flags to be set nothing happens but if I wait for only one array to be filled things go slightly weird as can be seen in the attached file /media/uploads/Kas_Lewis/data.txt and image
I am attaching my FULL code even though the issue is on line 277. Any suggestions as to how I can read BOTH sensors data and store it on the SD card would be very much appreciated. I have also tried speeding up the SPI clock incase the writing speed to the SD card was holding things up but, the clock will not go above 1MHz.
#include "mbed.h" #include "SDFileSystem.h" //FXOS8700CQ #define FXOS_ADDRESS_W 0x3C #define FXOS_ADDRESS_R 0x3D #define FXOS_STATUS 0x00 #define FXOS_OUT_X_MSB 0x01 #define FXOS_F_SETUP 0x09 #define FXOS_TRIG_CFG 0x0A #define FXOS_SYS_MOD 0x0B #define FXOS_INT_SOURCE 0x0C #define FXOS_WHO_AM_I 0x0D #define FXOS_ID 0xC7 #define FXOS_XYZ_DATA_CFG 0x0E #define FXOS_TRANSIENT_CFG 0x1D #define FXOS_TRANSIENT_SRC 0x1E #define FXOS_ASLP_COUNT 0x29 #define FXOS_CTRL_REG_1 0x2A #define FXOS_CTRL_REG_2 0x2B #define FXOS_CTRL_REG_3 0x2C #define FXOS_CTRL_REG_4 0x2D #define FXOS_CTRL_REG_5 0x2E #define FXOS_OFF_X 0x2F #define FXOS_OFF_Y 0x30 #define FXOS_OFF_Z 0x31 #define FXOS_TEMP 0x51 #define FXOS_M_CTRL_REG_1 0x5B #define FXOS_M_CTRL_REG_2 0x5C #define FXOS_M_CTRL_REG_3 0x5D //FXAS21002C #define FXAS_ADDRESS_W 0x40 #define FXAS_ADDRESS_R 0x41 #define FXAS_STATUS 0x00 #define FXAS_OUT_X_MSB 0x01 #define FXAS_F_SETUP 0x09 #define FXAS_F_EVENT 0x0A #define FXAS_INT_SRC_FLAG 0x0B #define FXAS_WHO_AM_I 0x0C #define FXAS_ID 0xD7 #define FXAS_CTRL_REG_0 0x0D #define FXAS_RT_CFG 0x0E #define FXAS_TEMP 0x12 #define FXAS_CTRL_REG_1 0x13 #define FXAS_CTRL_REG_2 0x14 #define FXAS_CTRL_REG_3 0x15 typedef struct { int16_t x; int16_t y; int16_t z; }SRAW; //Global variables int FXAS_FIFO_FULL_FLAG = 0; int FXOS_FIFO_FULL_FLAG = 0; char fxos_data_1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; char fxas_data_1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Setup UART to PC Serial pc(USBTX, USBRX); //Setup I2C I2C sensors(PTE0, PTE1); //FXOS8700C Control Pins InterruptIn fxos_int1_8700(PTD4); //INT1-8700 InterruptIn fxos_int2_8700(PTA4); //INT2-8700 //FXAS21002C Control Pins InterruptIn fxas_int1_21002(PTA5); //INT1-21002 InterruptIn fxas_int2_21002(PTA13); //INT2-21002 //SD File System SDFileSystem sd(PTD2, PTD3, PTD1, PTD0, "sd"); ////LED Setup DigitalOut led_1(LED1, 1); //red DigitalOut led_2(LED2, 1); //green //DigitalOut led_3(LED3, 1); //blue <- NB!! Wont play nice with SDFileSystem //****************************************************************// //Functions int i2c_write(char address, char device_register, char data){ sensors.start(); sensors.write((char)address); sensors.write((char)device_register); sensors.write((char)data); sensors.stop(); return 0; } int i2c_write(char address, char device_register, int stop){ sensors.start(); sensors.write((char)address); sensors.write((char)device_register); if(stop == 1){ sensors.stop(); } return 0; } char i2c_read(char address, char device_register){ char data; sensors.start(); sensors.write(address); sensors.write(device_register); sensors.start(); sensors.write(address | 0x01); data = (char)sensors.read(0); sensors.stop(); return data; } int i2c_write_verify(char address, char device_register, char data){ char return_data; int return_val; sensors.start(); sensors.write((char)address); sensors.write((char)device_register); sensors.write((char)data); sensors.stop(); sensors.start(); sensors.write(address); sensors.write(device_register); sensors.start(); sensors.write(address | 0x01); return_data = sensors.read(0); sensors.stop(); if (return_data == data){ return_val = 0; } else{ return_val = -1; } return return_val; } int fxas_init() { int return_val = 0; int sensor_id = 0; sensor_id = i2c_read(FXAS_ADDRESS_W, FXAS_WHO_AM_I); // pc.printf("Expected ID from FXAS21002C is 0xD7\n\r"); // pc.printf("Returned value: %X\n\n\r", sensor_id); if (sensor_id == FXAS_ID){ return_val = 0; return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_CTRL_REG_1, 0x00); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_F_SETUP, 0x00); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_F_SETUP, 0x54); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_CTRL_REG_0, 0x03); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_CTRL_REG_2, 0xC2); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_CTRL_REG_3, 0x00); return_val += i2c_write_verify(FXAS_ADDRESS_W, FXAS_CTRL_REG_1, 0x13); } else{ return_val = -1; } return return_val; } int fxos_init() { int return_val = 0; int sensor_id = 0; sensor_id = i2c_read(FXOS_ADDRESS_W, FXOS_WHO_AM_I); // pc.printf("Expected ID from FXOS8700CQ is 0xC7\n\r"); // pc.printf("Returned value: %X\n\n\r", sensor_id); if (sensor_id == FXOS_ID){ return_val = 0; return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_1, 0x00); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_F_SETUP, 0x00); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_F_SETUP, 0x54); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_ASLP_COUNT, 0xFF); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_XYZ_DATA_CFG, 0x02); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_2, 0x00); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_3, 0x02); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_4, 0x41); //Enable FIFO & DRDY Interrupts return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_5, 0x40); //FIFO -> Int_1, DRDY -> Imt_2 return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_M_CTRL_REG_1, 0x00); return_val += i2c_write_verify(FXOS_ADDRESS_W, FXOS_CTRL_REG_1, 0x21); } else{ return_val = -1; } return return_val; } //Interrupt for FXAS21002 INT_1 void read_fxas_data(){ // //Read data from FXAS21002 sensor if(FXAS_FIFO_FULL_FLAG != 2){ FXAS_FIFO_FULL_FLAG = 1; // led_1.write(0); } } //Interrupt for FXOS8700S INT_1 void read_fxos_data(){ //Read data from FXOS8700C sensor if(FXOS_FIFO_FULL_FLAG != 2){ FXOS_FIFO_FULL_FLAG = 1; // led_2.write(0); } } int main() { int initilised = 0; int index = 0; int test_index = 0; int fxos_data_flag_1 = 0; int fxas_data_flag_1 = 0; //Configure interrupts fxas_int1_21002.rise(&read_fxas_data);//FIFO -> Int_1 // fxas_int2_21002.rise(&read_fxas_data);//DRDY -> Int_2 fxos_int1_8700.rise(&read_fxos_data);//FIFO -> Int_1 // fxos_int2_8700.rise(&read_fxos_data);//DRDY -> Int_2 sensors.frequency(400000); pc.baud(115200); printf("\n\rHello World!\n\r"); mkdir("/sd/sensor_data", 0777); FILE *fp = fopen("/sd/sensor_data/data.txt", "w"); if(fp == NULL) { error("Could not open file for write\n"); } fprintf(fp, "\n\r\n\r"); fprintf(fp, "Hello fun SD Card World!\n\r\n\r"); fprintf(fp, "Thank you for trying this thing out\n\r\n\r"); fprintf(fp, "Have a good day \n\r\n\r"); fclose(fp); fprintf(fp, "\n\r\n\r"); fprintf(fp, "Hello fun SD Card World!\n\r\n\r"); fprintf(fp, "Thank you for trying this thing out\n\r\n\r"); fprintf(fp, "Have a good day \n\r\n\r"); fclose(fp); printf("Goodbye World!\n\r\n\r"); //Initlilise the FXOS8700CQ Accelorometer & the FXAS21002C Gyroscope initilised = fxas_init() & fxos_init(); // pc.printf("Returned value: %d\n\n\r", initilised); while(1) { if (FXOS_FIFO_FULL_FLAG == 1){//0.976mg * (fxos_data >> 2) = total g force (250dps scale) FXOS_FIFO_FULL_FLAG = 0; i2c_write(FXOS_ADDRESS_W, FXOS_STATUS, 0); sensors.read(FXOS_ADDRESS_R, fxos_data_1, 139, false);//Reads the status register on every pass 0x06 -> 0x00 fxos_data_flag_1 = 1; } if (FXAS_FIFO_FULL_FLAG == 1){//7.8125mdps * fxas_data = total g force (250dps scale) FXAS_FIFO_FULL_FLAG = 0; i2c_write(FXAS_ADDRESS_W, FXAS_STATUS, 0); sensors.read(FXAS_ADDRESS_R, fxas_data_1, 139, false);//Reads the status register on the first if set to otherwise 0x06 -> 0x01 fxos_data_flag_1 = 1; } if ((fxos_data_flag_1 == 1) || (fxas_data_flag_1 == 1)){ //<<-- Issue appears to be on this line //Store data on SD card fp = fopen("/sd/sensor_data/data.txt", "a"); if(fp == NULL) { error("Could not open file for write\n"); } for (index = 1; index < 139; index += 7){ //move data to SD card if (index % 7 == 0){ index++; } fprintf(fp, "%d\t%d\t%d\t\t", ((int16_t)(((fxos_data_1[((index % 7) + 1)] << 8) | fxos_data_1[((index % 7) + 2)])) >> 2), ((int16_t)(((fxos_data_1[((index % 7) + 3)] << 8) | fxos_data_1[((index % 7) + 4)])) >> 2), ((int16_t)(((fxos_data_1[((index % 7) + 5)] << 8) | fxos_data_1[((index % 7) + 6)])) >> 2)); fprintf(fp, "%d\t%d\t%d\n\r\n\r", ((int16_t)(((fxas_data_1[((index % 7) + 1)] << 8) | fxas_data_1[((index % 7) + 2)]))), ((int16_t)(((fxas_data_1[((index % 7) + 3)] << 8) | fxas_data_1[((index % 7) + 4)]))), ((int16_t)(((fxas_data_1[((index % 7) + 5)] << 8) | fxas_data_1[((index % 7) + 6)])))); } fxos_data_flag_1 = 0; fxas_data_flag_1 = 0; test_index++; fprintf(fp, "\n\r\n\r\n\r\n\r\n\r\n\r"); fclose(fp); for (int i = 0; i < 139; i++){ fxos_data_1[i] = 0; fxas_data_1[i] = 0; } // printf("\n\rSafe to Remove SC Card\n\r"); } // if (fxos_data_flag_1 == 1){ // //Store data on SD card use ((x % 7) + 1) to skip place 0 but use 1 - 6 // fp = fopen("/sd/sensor_data/gyro.txt", "a"); // if(fp == NULL) { // error("Could not open file for write\n"); // } // // for (index = 1; index < 139; index += 7){ // //move data to SD card // if (index % 7 == 0){ // index++; // } // fprintf(fp, "%d\t%d\t%d\t\n\r\n\r", ((int16_t)(((fxos_data_1[((index % 7) + 1)] << 8) | fxos_data_1[((index % 7) + 2)])) >> 2), // ((int16_t)(((fxos_data_1[((index % 7) + 3)] << 8) | fxos_data_1[((index % 7) + 4)])) >> 2), // ((int16_t)(((fxos_data_1[((index % 7) + 5)] << 8) | fxos_data_1[((index % 7) + 6)])) >> 2)); // } // // fxos_data_flag_1 = 0; // test_index++; // fprintf(fp, "\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r"); // fclose(fp); // printf("\n\rSafe to Remove SC Card\n\r"); // } // // if (fxas_data_flag_1 == 1){ // //Store data on SD card use ((x % 7) + 1) to skip place 0 but use 1 - 6 // fp = fopen("/sd/sensor_data/acc.txt", "a"); // if(fp == NULL) { // error("Could not open file for write\n"); // } // // for (index = 1; index < 139; index += 7){ // //move data to SD card // if (index % 7 == 0){ // index++; // } // fprintf(fp, "%d\t%d\t%d\n\r\n\r", ((int16_t)(((fxas_data_1[((index % 7) + 1)] << 8) | fxas_data_1[((index % 7) + 2)]))), // ((int16_t)(((fxas_data_1[((index % 7) + 3)] << 8) | fxas_data_1[((index % 7) + 4)]))), // ((int16_t)(((fxas_data_1[((index % 7) + 5)] << 8) | fxas_data_1[((index % 7) + 6)])))); // } // // fxas_data_flag_1 = 0; // test_index++; // fprintf(fp, "\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r"); // fclose(fp); // printf("\n\rSafe to Remove SC Card\n\r"); // } } }
The commented code at the bottom was a separate attempt to write the data to two separate files but this too did not work as one set of data was written to the first file but the second set of data was not. /media/uploads/Kas_Lewis/data_1.txt
3 Answers
8 years, 8 months ago.
Line 273 fxos_data_flag_1 = 1; should be fxas_data_flag_1 = 1;
Also, one note on your approach. SD writes could take a long time, you may want to use larger buffers. Some writes will take longer than others due to the way writes can get buffered by the file system.
You should read from the sensor into a ram buffer on the interrupt rather than in the main loop so that data won't get lost if writing takes a long time, make your memory buffer significantly larger than a single transfer from the device so that you can queue up multiple reads and write them all at once if needed.
Normally the best solution is to use two buffers (or 2 per channel maybe in your case), once buffer 1 is say 20% full new data goes into buffer 2 while buffer 1 is written to the SD card. You then switch the buffers, and keep going.
Hello Andy,
Thank you for your help. The find on line 273 will probably resolve a good deal of my issues. As for the larger buffers I will give that a try and let you know it works, I will also try increasing the sensor FIFOs interrupt to 30 instead of 20 still giving a buffer zone of two samples (total FIFO is 32).
As for reading the FIFOs in the interrupt that causes another set of issues. Since the interrupts are not nested and both interrupts happen relatively close in time and you can only interrupt on a rise or fall and not on a high or low I end up missing interrupts from the sensors hence the flags being set and reading the FIFOs in the main loop. If you have a suggestion as how to get around this I would be more than happy to hear it.
At the moment it feels like I have bumped into a limitation of mbed and if I can find a relatively simple solution around it I would love to make it work.
Thankfully Kas
posted by 23 Jul 2015If you get an edge on a second interrupt while in an ISR you won't miss it, it gets queued up and called as soon as the first interrupt exits.
If for some reason you can only read data in the background loop I'd read it as soon as there is any data, that way the SD card write can take up to 31 sample periods before you lose data. You can still buffer up a certain amount of data before writing to the card since that will be more efficient.
posted by 23 Jul 2015Hello Andy,
Just changing line 273 and changing the || to an && helped a lot as can be seen in the screen grab below.
There is an issue with data correctness as can be seen in the attached file (all X data in a sample set is the same this applies to the Y and Z axis as well) /media/uploads/Kas_Lewis/data_1.txt but I can hopefully look into that more once this issue is resolved.
One thing you may be able to explain to me is the SPI clock at the bottom of that screen capture. Why are the widths all so different (active time), if I am writing the same amount of data each time. I would expect there to be the same amount of time needed for each transfer if the amount of data transmitted is the same.
I will also try implement a ping pong buffer system in the ISR using larger buffers and then to clearing of these buffers to the SD card in the main loop to see if this takes any more stress off the SD card and allows the system to operate more efficiently
Thank you for you patience and help. Kas
posted by 23 Jul 2015In the printfs that write to the SD card all of your index's are [index % 7 ] plus a constant so you are always outputing the first value in your buffer.
The time taken for flash erases and writes are non deterministic, the underlying memory structure of flash means that some sectors will write faster than others. The system will issue the command to write some data and then poll the card until it's complete which will take a different amount of time each time.
You may get a speed improvement by not closing the file and reopening it each loop. If you keep it open the file system will buffer until it has a full sector of data to write and then write it in one go which gives a more efficient system over all but more variability from an application point of view. If you do that you do need to make sure the file is closed before removing the card which for some applications is tricky.
posted by 23 Jul 20158 years, 8 months ago.
Hi Kasriel,
I would try with following approach:
- create Ticker with sample rate frequency you need for sensors (e.g. 50Hz)
Ticker tic_sample;
- create flag that will be set TRUE in ticker interrupt service routine, e.g.
bool is_set;
- in tic_sample ISR set the flag
... void tic_ISR(void) { is_set = TRUE; } ....
- attach ISR in main()
tic_sample.attach(&tic_ISR, 0.02); // 20ms for 50Hz
- in main within while(1) check if flag is set TRUE; if yes, set the flag FALSE, read the sensors, check if you have 20 samples and write them down to SD card
... int index=0; ... while(1) { ... if (is_set) { index++; // increase index to follow number of readings is_set = FALSE; read_sensor1(); read_sensor2(); if (index == 20) // if reached 20 readings, save data to SD card and reset index { save_data_to_SD(); index = 0; } } }
Regards, Miloje
Hello Miloje,
While I like the simplicity of your solution there is an issue with that approach, the internal sample clocks of the sensors do not appear to be all that accurate and I cannot start both sensors at the same time. Using a logic analyzer to look for the interrupts and then in code only clearing the interrupts over time you can see a clear drift of one interrupt to relative to the other. Over the period of a minute or so the one interrupt overtakes the other and the cycle continues.
Thank you for your help though I will think more about this approach to see if there is some way to use this method maybe in conjunction with others.
Thankfully Kas
posted by 23 Jul 20158 years, 8 months ago.
Try disabling the interrupts before running the SD card function, even setting a flag in an ISR will cause some disruption that can lead to read/write failures, SD card data file corruption and complete lock up.
Not sure on these devices, haven't used them but why do you need interrupts, can you not sequentially poll the devices and filter for changes in values to detect movement?
That isn't a problem. I've had about 6,000 interrupts a second coming in from 3 serial ports and not had any problems with corruption writing to an SD card at the same time.
posted by 23 Jul 2015So you have serviced 3 simultaneous serial port interrupts at the same time at whilst writing to a SD card? WOW! how did you do that? I can't run one serial Oled display with any interrupts otherwise it stops, perhaps the SD card is different.
posted by 23 Jul 2015