melexis / mlx90640-library

MLX90640 library functions
Apache License 2.0
241 stars 192 forks source link

RAM footprint is quite high #3

Closed adibacco closed 5 years ago

adibacco commented 6 years ago

Struct paramsMLX90640 is very big. Do you really need all those float arrays inside? Many STM32 MCUs have 20KB of RAM and it is very challenging accommodating such a big structure along with other variables.

Furthermore, it would be useful to use the const modifier when passing pointer to paramsMLX90640 because gives the user the info that a function cannot modify it and makes the struct eligible for being stored in flash.

Using C++ code is nice but why using constructs like the following? int a = int(c/2);

Using a normal cast would make it portable to platforms without C++ compilers.

abood91 commented 6 years ago

@adibacco Hi, Have you managed to ghet MLX90460 working on the STM32 processor you have. if so could you please direct me on how to do it ?

adibacco commented 6 years ago

I still have problems, I managed to get eeprom content and ram content but when I try to get temp for pixels I get some wrong values at least for odd numbered pixels

slavysis commented 6 years ago

Hi, sorry for the late response. I am considering minimizing the RAM footprint. This is not that straight forward though. It requires some trade off between memory allocation and speed/refresh rate. The const modifier will be implemented in the next update of the driver. So will be the normal cast. What are the wrong values that you get? I started preparing a sample data for verification as you suggested in the other issue you opened (thanks for the suggestion). I will upload it as soon as I have it - probably next Monday.

Best regards

abood91 commented 6 years ago

@adibacco @slavysis could you please share some code how did you get mlx90640 to work with STM32 ?

thanks a lot !

adibacco commented 6 years ago

@slavysis , about RAM footprint I found a way to circumvent the problem, at startup on my stm32l0 (20KB RAM and 192KB FLASH) I simply read eeprom and store into stm32 flash then I calculate params and store into flash. They will stay fixed as long as the MLX90640 is the same.

adibacco commented 6 years ago

@abood91 have a look here https://github.com/adibacco/LORA_MURATA_MELEXIS

slavysis commented 6 years ago

This is indeed a good solution. Unfortunately, not all MCUs have the same 'write to flash' routine and this should be a custom implementation. So I will still look for a more general solution. I have modified the code to use const for the paramsMLX90640 and removed the int() constructs.

Best regards

abood91 commented 6 years ago

@slavysis @adibacco could this driver be minimized to the bare minimal, I have STM32F3 with 64Kb and 16Kb Ram, basically the ram foot print is way too high, is there a way to minimize this driver to the bare minimal meaning that for example could the float arrays be converted to int arrays and also in

typedef struct
   {
       int16_t kVdd;
       int16_t vdd25;
       float KvPTAT;
       float KtPTAT;
       uint16_t vPTAT25;
       float alphaPTAT;
       int16_t gainEE;
       float tgc;
       float cpKv;
       float cpKta;
       uint8_t resolutionEE;
       uint8_t calibrationModeEE;
       float KsTa;
       float ksTo[4];
       int16_t ct[4];
       float alpha[768];
       int16_t offset[768];
       float kta[768];
       float kv[768];
       float cpAlpha[2];
       int16_t cpOffset[2];
       float ilChessC[3];
       uint16_t brokenPixels[5];
       uint16_t outlierPixels[5];
   } paramsMLX90640;

could

       float alpha[768];
       int16_t offset[768];
       float kta[768];
       float kv[768];

be removed or somehow that struct be minimized ?

slavysis commented 6 years ago

Is it an option for you to store the struct in the flash? If not you could modify the driver for your needs, by scaling the floats so that you store them as int. And after that in the formulas where you use the scaled values, you should re-scale back. This will certainly add up some calculation time causing a possible reduction of the refresh rate.

Best regards

abood91 commented 6 years ago

@slavysis could you please give me pointers on where to start ? what i mean could you point out what is the must have element in that structure ? and what are the must use function to get this working on bare minimal ?

slavysis commented 6 years ago

Well, as a first option, I would recommend putting the whole parameters structure in the flash as @adibacco has done. If this is not possible, I would recommend you to keep all the parameters and rescale kta and kv values so that they fit in 16 bits (int16_t). Note that this will most likely reduce the refresh rate as you will have to rescale the coefficients when calculating the object temperature. As a last resort, you could remove the kta and kv arrays and use a standard value for kta = 0.007 and kv = 0.38. This will affect the accuracy performance of the device and will distort the image a bit, but you should be able to still get a descent image. I would still not recommend the last option.

The functions that you should use would be: MLX90640_I2CFreqSet(400); status = MLX90640_DumpEE(slaveAddress, pEE); MLX90640_I2CFreqSet(1000); status = MLX90640_ExtractParameters(pEE, pParam); status = MLX90640_GetFrameData(slaveAddress, pFrame); eTa = MLX90640_GetTa(pFrame,pParam) - TA_SHIFT; MLX90640_CalculateTo(pFrame, pParam, emissivity, eTa, mlx90640To);

abood91 commented 6 years ago

@slavysis Thanks for the pointers that is a great help.

I am actually working on this right now. i could save the eeprom data to the flash and that can be stored there. from ram point of view. i am working on idea to segment the image into 16 regions. meaning that i will read segment by segment. what do you think about that idea. is it possible to implement with the melexis ? or who the reading rate on the 12c buss will be effected by that ?


  typedef struct
    {
        int16_t kVdd;
        int16_t vdd25;
        float KvPTAT;
        float KtPTAT;
        uint16_t vPTAT25;
        float alphaPTAT;
        int16_t gainEE;
        float tgc;
        float cpKv;
        float cpKta;
        uint8_t resolutionEE;
        uint8_t calibrationModeEE;
        float KsTa;
        float ksTo[4];
        int16_t ct[4];

        float cpAlpha[2];
        int16_t cpOffset[2];
        float ilChessC[3];
        uint16_t brokenPixels[5];
        uint16_t outlierPixels[5];
    } paramsMLX90640;

this is my new struct and then i have

    typedef struct
      {
          float alpha[48];
          int16_t offset[48];
          float kta[48];
          float kv[48];
      } calcArraysMLX90640;

how do you see such implementation ?

also a suggestion that if you can provide an example of implementing this on low memory MCU (like STM32F0xxx or STM32F3xxx). that would be helpful for future implementation by others :)

slavysis commented 6 years ago

If you are going to store it in the flash, why would you need to reduce the paramsMLX90640 memory footprint? Please note that you do not need to store the EEPROM content. Once you have the parameters extracted, you can simply overwrite the memory that was holding the EEPROM content. Why do you want to have 16 segments? Is it just to save 1.5kb of RAM? How are you planning to process the data later on? I think it would be much easier if you use the memory allocated for the frame data and store to the same location the calculated temperatures.

It is possible to read the frame data in 16 regions, but I see some major issues with that:

  1. You should make sure that your readout time plus the calculation time is a lot less than the refresh period. Other wise you will end up having segments from different frames/subframes. This would most likely mean you would have to work at lower refresh rate settings.
  2. You will have to recalculate parameters for each segment in order to fill the calcArraysMLX90640 struct which also means reduced refresh rate
  3. Image processing having 1/16 of the image would be much harder than having the whole image
  4. The whole driver should be modified in order to adopt that type of reading and processing the data As a minimum:
  5. MLX90640_getFrameData - it should not wait for new frame data - at least not everytime (maybe this should be an input parameter) because it actually has to read 16 times per refresh period.
  6. A new function should be implement to extract the appropriate calcArraysMLX90640 parameters
  7. Of course the MLX90640_CalculateTo function should be modified in order to be able to calculate the desired number of pixels (this is the easiest one).

For a low memory MCU I would suggest the following: 1.Define an union to share uint16 needed for EEPROM/frame data and float needed for To. There are other ways to indicate that the same location is going to be used for different data types storage. 2.Read the EEPROM in the allocated memory 3.Extract the parameters and store them into the flash 4.Read the frame data in the allocated memory (the same as the one for the EEPROM) 5.Calculate the temperatures and write the calculated values in the allocated memory (the same as the one used for the EEPROM and the frame data)

MLX90640_I2CFreqSet(400); status = MLX90640_DumpEE(slaveAddress, pMem); MLX90640_I2CFreqSet(1000); status = MLX90640_ExtractParameters(pEE, pParam); status = MLX90640_GetFrameData(slaveAddress, pMem); eTa = MLX90640_GetTa(pMem,pParam) - TA_SHIFT; MLX90640_CalculateTo(pMem, pParam, emissivity, eTa, pMem);

As the float type is 32 bit, this approach would need around 3kb of memory. If this is still too much, you could have an array of 832 uint16 values for a total memory of around 1.5kb. In this case you would need to modify the MLX90640_CalculateTo function, so that the returned value is a uint16 type. This could be done by represensting the data as K100 -> Tok = (uint16_t)(100(To+273.15)).

abood91 commented 6 years ago

@slavysis Thanks a lot for the help, I think i will listen to you and use your approach

slavysis commented 5 years ago

A new version with significantly reduced RAM footprint is available