This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

NRF52833DK Persistent Hard Faults

I am developing an NRF52833 application that reads from the I2C sensor MLX90641. Below is the code I am using to test. MLX90641_I2C_Driver.c was originally written for Mbed and is meant to be adapted to the target platform. It isn't important to understand MLX90641_API.c, the important part is in main and MLX90641_I2C_Driver.c, where you can see the arguments passed as they are outputted to printk. This is all running on NRF52833DK with NCS v1.8.

main.c:

#include <zephyr.h>
#include <sys/printk.h>

#include "MLX90641_API.h"
#include "MLX90641_I2C_Driver.h"

#define TA_SHIFT 8 //Default shift for MLX90641 in open air

static float mlx90641To[768];
paramsMLX90641 mlx90641;

void main(void)
{
	printk("Running sensor_testing on %s\n", CONFIG_BOARD);

	MLX90641_I2CInit();

	int status;
    uint16_t eeMLX90641[832];
    status = MLX90641_DumpEE(MLX90641_ADDR, eeMLX90641);
    if (status != 0) {
        printk("Failed to load system parameters\n");
    }

    status = MLX90641_ExtractParameters(eeMLX90641, &mlx90641);
    if (status != 0) {
        printk("Parameter extraction failed\n");
    }

	while(1) {
		for (uint8_t x = 0 ; x < 2 ; x++) { //Read both subpages
			uint16_t mlx90641Frame[834];
			int status = MLX90641_GetFrameData(MLX90641_ADDR, mlx90641Frame);
			if (status < 0) {
				printk("GetFrame Error: %d\n", status);
			}

			float vdd = MLX90641_GetVdd(mlx90641Frame, &mlx90641);
			float Ta = MLX90641_GetTa(mlx90641Frame, &mlx90641);

			float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
			float emissivity = 0.95;

			MLX90641_CalculateTo(mlx90641Frame, &mlx90641, emissivity, tr, mlx90641To);
    	}

		for (int x = 0 ; x < 10 ; x++) {
			printk("Pixel %d: %fC\n", x, mlx90641To[x]);
		}

		k_sleep(K_SECONDS(1));
	}
}

MLX90641_API.c: (not important to understand)

#include "MLX90641_I2C_Driver.h"
#include "MLX90641_API.h"
#include <math.h>

void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641);
int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641);
int CheckEEPROMValid(uint16_t *eeData); 
int HammingDecode(uint16_t *eeData);  
int ValidateFrameData(uint16_t *frameData);
int ValidateAuxData(uint16_t *auxData);

//------------------------------------------------------------------------------
  
int MLX90641_DumpEE(uint8_t slaveAddr, uint16_t *eeData)
{
     int error = 1;
     error = MLX90641_I2CRead(slaveAddr, 0x2400, 832, eeData);
     if (error == 0)
     {
        error = HammingDecode(eeData);  
     }
         
     return error;
}

//------------------------------------------------------------------------------

int HammingDecode(uint16_t *eeData)
{
    int error = 0;
    int16_t parity[5];
    int8_t D[16];
    int16_t check;
    uint16_t data;
    uint16_t mask;
    
    for (int addr=16; addr<832; addr++)
    {   
        parity[0] = -1;
        parity[1] = -1;
        parity[2] = -1;
        parity[3] = -1;
        parity[4] = -1;
        
        data = eeData[addr];
        
        mask = 1;
        for( int i = 0; i < 16; i++)
        {          
          D[i] = (data & mask) >> i;
          mask = mask << 1;
        }
        
        parity[0] = D[0]^D[1]^D[3]^D[4]^D[6]^D[8]^D[10]^D[11];
        parity[1] = D[0]^D[2]^D[3]^D[5]^D[6]^D[9]^D[10]^D[12];
        parity[2] = D[1]^D[2]^D[3]^D[7]^D[8]^D[9]^D[10]^D[13];
        parity[3] = D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[14];
        parity[4] = D[0]^D[1]^D[2]^D[3]^D[4]^D[5]^D[6]^D[7]^D[8]^D[9]^D[10]^D[11]^D[12]^D[13]^D[14]^D[15];
        
        
        if ((parity[0]!=0) || (parity[1]!=0) || (parity[2]!=0) || (parity[3]!=0) || (parity[4]!=0))
        {        
            check = (parity[0]<<0) + (parity[1]<<1) + (parity[2]<<2) + (parity[3]<<3) + (parity[4]<<4);
    
            if ((check > 15)&&(check < 32))
            {
                switch (check)
                {    
                    case 16:
                        D[15] = 1 - D[15];
                        break;
                    
                    case 24:
                        D[14] = 1 - D[14];
                        break;
                        
                    case 20:
                        D[13] = 1 - D[13];
                        break;
                        
                    case 18:
                        D[12] = 1 - D[12];
                        break;                                
                        
                    case 17:
                        D[11] = 1 - D[11];
                        break;
                        
                    case 31:
                        D[10] = 1 - D[10];
                        break;
                        
                    case 30:
                        D[9] = 1 - D[9];
                        break;
                    
                    case 29:
                        D[8] = 1 - D[8];
                        break;                
                    
                    case 28:
                        D[7] = 1 - D[7];
                        break;
                        
                    case 27:
                        D[6] = 1 - D[6];
                        break;
                            
                    case 26:
                        D[5] = 1 - D[5];
                        break;    
                        
                    case 25:
                        D[4] = 1 - D[4];
                        break;     
                        
                    case 23:
                        D[3] = 1 - D[3];
                        break; 
                        
                    case 22:
                        D[2] = 1 - D[2];
                        break; 
                            
                    case 21:
                        D[1] = 1 - D[1];
                        break; 
                        
                    case 19:
                        D[0] = 1 - D[0];
                        break;     
                                     
                }
               
                if(error == 0)
                {
                    error = -9;
                   
                }
                
                data = 0;
                mask = 1;
                for( int i = 0; i < 16; i++)
                {                    
                    data = data + D[i]*mask;
                    mask = mask << 1;
                }
       
            }
            else
            {
                error = -10;                
            }   
        }
        
        eeData[addr] = data & 0x07FF;
    }
    
    return error;
}

//------------------------------------------------------------------------------

int MLX90641_SynchFrame(uint8_t slaveAddr)
{
    uint16_t dataReady = 0;
    uint16_t statusRegister;
    int error = 1;
    
    error = MLX90641_I2CWrite(slaveAddr, 0x8000, 0x0030);
    if(error == -1)
    {
        return error;
    }
    
    while(dataReady == 0)
    {
        error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
        if(error != 0)
        {
            return error;
        }    
        dataReady = statusRegister & 0x0008;
    }      
    
   return 0;   
}

//------------------------------------------------------------------------------

int MLX90641_TriggerMeasurement(uint8_t slaveAddr)
{
    int error = 1;
    uint16_t ctrlReg;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &ctrlReg);
    
    if ( error != 0) 
    {
        return error;
    }    
                                                
    ctrlReg |= 0x8000;
    error = MLX90641_I2CWrite(slaveAddr, 0x800D, ctrlReg);
    
    if ( error != 0)
    {
        return error;
    }    
    
    error = MLX90641_I2CGeneralReset();
    
    if ( error != 0)
    {
        return error;
    }    
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &ctrlReg);
    
    if ( error != 0)
    {
        return error;
    }    
    
    if ((ctrlReg & 0x8000) != 0)
    {
        return -11;
    }
    
    return 0;    
}

//------------------------------------------------------------------------------

int MLX90641_GetFrameData(uint8_t slaveAddr, uint16_t *frameData)
{
    uint16_t dataReady = 1;
    uint16_t controlRegister1;
    uint16_t statusRegister;
    uint16_t data[48];
    int error = 1;
    uint8_t cnt = 0;
    uint8_t subPage = 0;
    
    dataReady = 0;
    while(dataReady == 0)
    {
        error = MLX90641_I2CRead(slaveAddr, 0x8000, 1, &statusRegister);
        if(error != 0)
        {
            return error;
        }    
        dataReady = statusRegister & 0x0008;
    }   
    subPage = statusRegister & 0x0001;
        
    error = MLX90641_I2CWrite(slaveAddr, 0x8000, 0x0030);
    if(error == -1)
    {
        return error;
    }
                
    if(subPage == 0)
    { 
        error = MLX90641_I2CRead(slaveAddr, 0x0400, 32, frameData); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0440, 32, frameData+32); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0480, 32, frameData+64); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x04C0, 32, frameData+96); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0500, 32, frameData+128); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0540, 32, frameData+160); 
        if(error != 0)
        {
            return error;
        }
    }    
    else
    {
        error = MLX90641_I2CRead(slaveAddr, 0x0420, 32, frameData); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0460, 32, frameData+32); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x04A0, 32, frameData+64); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x04E0, 32, frameData+96); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0520, 32, frameData+128); 
        if(error != 0)
        {
            return error;
        }
        error = MLX90641_I2CRead(slaveAddr, 0x0560, 32, frameData+160); 
        if(error != 0)
        {
            return error;
        }
    }   
    
    error = MLX90641_I2CRead(slaveAddr, 0x0580, 48, data); 
    if(error != 0)
    {
        return error;
    }            
    
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    frameData[240] = controlRegister1;
    frameData[241] = subPage;

    if(error != 0)
    {
        return error;
    }
    
    error = ValidateAuxData(data);
    if(error == 0)
    {
        for(cnt=0; cnt<48; cnt++)
        {
            frameData[cnt+192] = data[cnt];
        }
    }        
    
    error = ValidateFrameData(frameData);
    if (error != 0)
    {
        return error;
    }                                 
    
    return frameData[241];    
}

int ValidateFrameData(uint16_t *frameData)
{
    uint8_t line = 0;
    
    for(int i=0; i<192; i+=16)
    {
        if(frameData[i] == 0x7FFF) return -8;
        line = line + 1;
    }    
        
    return 0;    
}

int ValidateAuxData(uint16_t *auxData) 
{
    
    if(auxData[0] == 0x7FFF) return -8;    
    
    for(int i=8; i<19; i++)
    {
        if(auxData[i] == 0x7FFF) return -8;
    }
    
    for(int i=20; i<23; i++)
    {
        if(auxData[i] == 0x7FFF) return -8;
    }
    
    for(int i=24; i<33; i++)
    {
        if(auxData[i] == 0x7FFF) return -8;
    }
    
    for(int i=40; i<48; i++)
    {
        if(auxData[i] == 0x7FFF) return -8;
    }
    
    return 0;
    
}

//------------------------------------------------------------------------------

int MLX90641_ExtractParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int error = CheckEEPROMValid(eeData);
    
    if(error == 0)
    {
        ExtractVDDParameters(eeData, mlx90641);
        ExtractPTATParameters(eeData, mlx90641);
        ExtractGainParameters(eeData, mlx90641);
        ExtractTgcParameters(eeData, mlx90641);
        ExtractEmissivityParameters(eeData, mlx90641);
        ExtractResolutionParameters(eeData, mlx90641);
        ExtractKsTaParameters(eeData, mlx90641);
        ExtractKsToParameters(eeData, mlx90641);
        ExtractCPParameters(eeData, mlx90641);
        ExtractAlphaParameters(eeData, mlx90641);
        ExtractOffsetParameters(eeData, mlx90641);
        ExtractKtaPixelParameters(eeData, mlx90641);
        ExtractKvPixelParameters(eeData, mlx90641);        
        error = ExtractDeviatingPixels(eeData, mlx90641);  
    }
    
    return error;

}

//------------------------------------------------------------------------------

int MLX90641_SetResolution(uint8_t slaveAddr, uint8_t resolution)
{
    uint16_t controlRegister1;
    int value;
    int error;
    
    value = (resolution & 0x03) << 10;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    
    if(error == 0)
    {
        value = (controlRegister1 & 0xF3FF) | value;
        error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);        
    }    
    
    return error;
}

//------------------------------------------------------------------------------

int MLX90641_GetCurResolution(uint8_t slaveAddr)
{
    uint16_t controlRegister1;
    int resolutionRAM;
    int error;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error != 0)
    {
        return error;
    }    
    resolutionRAM = (controlRegister1 & 0x0C00) >> 10;
    
    return resolutionRAM; 
}

//------------------------------------------------------------------------------

int MLX90641_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate)
{
    uint16_t controlRegister1;
    int value;
    int error;
    
    value = (refreshRate & 0x07)<<7;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error == 0)
    {
        value = (controlRegister1 & 0xFC7F) | value;
        error = MLX90641_I2CWrite(slaveAddr, 0x800D, value);
    }    
    
    return error;
}

//------------------------------------------------------------------------------

int MLX90641_GetRefreshRate(uint8_t slaveAddr)
{
    uint16_t controlRegister1;
    int refreshRate;
    int error;
    
    error = MLX90641_I2CRead(slaveAddr, 0x800D, 1, &controlRegister1);
    if(error != 0)
    {
        return error;
    }    
    refreshRate = (controlRegister1 & 0x0380) >> 7;
    
    return refreshRate;
}

//------------------------------------------------------------------------------

void MLX90641_CalculateTo(uint16_t *frameData, const paramsMLX90641 *params, float emissivity, float tr, float *result)
{
    float vdd;
    float ta;
    float ta4;
    float tr4;
    float taTr;
    float gain;
    float irDataCP;
    float irData;
    float alphaCompensated;
    float Sx;
    float To;
    float alphaCorrR[8];
    int8_t range;
    uint16_t subPage;
    float ktaScale;
    float kvScale;
    float alphaScale;
    float kta;
    float kv;
    
    subPage = frameData[241];
    vdd = MLX90641_GetVdd(frameData, params);
    ta = MLX90641_GetTa(frameData, params);    
    ta4 = (ta + 273.15);
    ta4 = ta4 * ta4;
    ta4 = ta4 * ta4;
    tr4 = (tr + 273.15);
    tr4 = tr4 * tr4;
    tr4 = tr4 * tr4;
    
    taTr = tr4 - (tr4-ta4)/emissivity;
    
    ktaScale = pow(2,(double)params->ktaScale);
    kvScale = pow(2,(double)params->kvScale);
    alphaScale = pow(2,(double)params->alphaScale);
    
    alphaCorrR[1] = 1 / (1 + params->ksTo[1] * 20);
    alphaCorrR[0] = alphaCorrR[1] / (1 + params->ksTo[0] * 20);
    alphaCorrR[2] = 1 ;
    alphaCorrR[3] = (1 + params->ksTo[2] * params->ct[3]);
    alphaCorrR[4] = alphaCorrR[3] * (1 + params->ksTo[3] * (params->ct[4] - params->ct[3]));
    alphaCorrR[5] = alphaCorrR[4] * (1 + params->ksTo[4] * (params->ct[5] - params->ct[4]));
    alphaCorrR[6] = alphaCorrR[5] * (1 + params->ksTo[5] * (params->ct[6] - params->ct[5]));
    alphaCorrR[7] = alphaCorrR[6] * (1 + params->ksTo[6] * (params->ct[7] - params->ct[6]));
    
//------------------------- Gain calculation -----------------------------------    
    gain = frameData[202];
    if(gain > 32767)
    {
        gain = gain - 65536;
    }
    
    gain = params->gainEE / gain; 
  
//------------------------- To calculation -------------------------------------        
    irDataCP = frameData[200];  
    if(irDataCP > 32767)
    {
        irDataCP = irDataCP - 65536;
    }
    irDataCP = irDataCP * gain;

    irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
    
    for( int pixelNumber = 0; pixelNumber < 192; pixelNumber++)
    {      
        irData = frameData[pixelNumber];
        if(irData > 32767)
        {
            irData = irData - 65536;
        }
        irData = irData * gain;
        
        kta = (float)params->kta[pixelNumber]/ktaScale;
        kv = (float)params->kv[pixelNumber]/kvScale;
            
        irData = irData - params->offset[subPage][pixelNumber]*(1 + kta*(ta - 25))*(1 + kv*(vdd - 3.3));                
    
        irData = irData - params->tgc * irDataCP;
        
        irData = irData / emissivity;
        
        alphaCompensated = SCALEALPHA*alphaScale/params->alpha[pixelNumber];
        alphaCompensated = alphaCompensated*(1 + params->KsTa * (ta - 25));
        
        Sx = alphaCompensated * alphaCompensated * alphaCompensated * (irData + alphaCompensated * taTr);
        Sx = sqrt(sqrt(Sx)) * params->ksTo[2];
        
        To = sqrt(sqrt(irData/(alphaCompensated * (1 - params->ksTo[2] * 273.15) + Sx) + taTr)) - 273.15;
                
        if(To < params->ct[1])
        {
            range = 0;
        }
        else if(To < params->ct[2])   
        {
            range = 1;            
        }   
        else if(To < params->ct[3])
        {
            range = 2;            
        }
        else if(To < params->ct[4])
        {
            range = 3;            
        }
        else if(To < params->ct[5])
        {
            range = 4;            
        }
        else if(To < params->ct[6])
        {
            range = 5;            
        }
        else if(To < params->ct[7])
        {
            range = 6;            
        }
        else
        {
            range = 7;            
        }      
        
        To = sqrt(sqrt(irData / (alphaCompensated * alphaCorrR[range] * (1 + params->ksTo[range] * (To - params->ct[range]))) + taTr)) - 273.15;
        
        result[pixelNumber] = To;
    }
}

//------------------------------------------------------------------------------

void MLX90641_GetImage(uint16_t *frameData, const paramsMLX90641 *params, float *result)
{
    float vdd;
    float ta;
    float gain;
    float irDataCP;
    float irData;
    float alphaCompensated;
    float image;
    uint16_t subPage;
    float ktaScale;
    float kvScale;
    float kta;
    float kv;
    
    subPage = frameData[241];
    
    vdd = MLX90641_GetVdd(frameData, params);
    ta = MLX90641_GetTa(frameData, params);
    ktaScale = pow(2,(double)params->ktaScale);
    kvScale = pow(2,(double)params->kvScale);
    
//------------------------- Gain calculation -----------------------------------    
    gain = frameData[202];
    if(gain > 32767)
    {
        gain = gain - 65536;
    }
    
    gain = params->gainEE / gain; 
  
//------------------------- Image calculation -------------------------------------    
    irDataCP = frameData[200];  
    if(irDataCP > 32767)
    {
        irDataCP = irDataCP - 65536;
    }
    irDataCP = irDataCP * gain;

    irDataCP = irDataCP - params->cpOffset * (1 + params->cpKta * (ta - 25)) * (1 + params->cpKv * (vdd - 3.3));
    
    for( int pixelNumber = 0; pixelNumber < 192; pixelNumber++)
    {
        irData = frameData[pixelNumber];
        if(irData > 32767)
        {
            irData = irData - 65536;
        }
        irData = irData * gain;
        
        kta = (float)params->kta[pixelNumber]/ktaScale;
        kv = (float)params->kv[pixelNumber]/kvScale;
            
        irData = irData - params->offset[subPage][pixelNumber]*(1 + kta*(ta - 25))*(1 + kv*(vdd - 3.3));                
        
        irData = irData - params->tgc * irDataCP;
            
        alphaCompensated = (params->alpha[pixelNumber] - params->tgc * params->cpAlpha);
            
        image = irData*alphaCompensated;
            
        result[pixelNumber] = image;
    }
}

//------------------------------------------------------------------------------

float MLX90641_GetVdd(uint16_t *frameData, const paramsMLX90641 *params)
{
    float vdd;
    float resolutionCorrection;
    
    int resolutionRAM;    
    
    vdd = frameData[234];
    if(vdd > 32767)
    {
        vdd = vdd - 65536;
    }
    resolutionRAM = (frameData[240] & 0x0C00) >> 10;
    resolutionCorrection = pow(2, (double)params->resolutionEE) / pow(2, (double)resolutionRAM);
    vdd = (resolutionCorrection * vdd - params->vdd25) / params->kVdd + 3.3;
    
    return vdd;
}

//------------------------------------------------------------------------------

float MLX90641_GetTa(uint16_t *frameData, const paramsMLX90641 *params)
{
    float ptat;
    float ptatArt;
    float vdd;
    float ta;
    
    vdd = MLX90641_GetVdd(frameData, params);
    
    ptat = frameData[224];
    if(ptat > 32767)
    {
        ptat = ptat - 65536;
    }
    
    ptatArt = frameData[192];
    if(ptatArt > 32767)
    {
        ptatArt = ptatArt - 65536;
    }
    ptatArt = (ptat / (ptat * params->alphaPTAT + ptatArt)) * pow(2, (double)18);
    
    ta = (ptatArt / (1 + params->KvPTAT * (vdd - 3.3)) - params->vPTAT25);
    ta = ta / params->KtPTAT + 25;
    
    return ta;
}

//------------------------------------------------------------------------------

int MLX90641_GetSubPageNumber(uint16_t *frameData)
{
    return frameData[241];    

}    

//------------------------------------------------------------------------------
void MLX90641_BadPixelsCorrection(uint16_t pixel, float *to)
{   
    float ap[2];
    uint8_t line;
    uint8_t column;
    
    if(pixel<192)
    {
        line = pixel>>4;
        column = pixel - (line<<4);
               
        if(column == 0)
        {
            to[pixel] = to[pixel+1];            
        }
        else if(column == 1 || column == 14)
        {
            to[pixel] = (to[pixel-1]+to[pixel+1])/2.0;                
        } 
        else if(column == 15)
        {
            to[pixel] = to[pixel-1];
        } 
        else
        {            
            ap[0] = to[pixel+1] - to[pixel+2];
            ap[1] = to[pixel-1] - to[pixel-2];
            if(fabs(ap[0]) > fabs(ap[1]))
            {
                to[pixel] = to[pixel-1] + ap[1];                        
            }
            else
            {
                to[pixel] = to[pixel+1] + ap[0];                        
            }
                    
        }                      
    }   
}    

//------------------------------------------------------------------------------
void ExtractVDDParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int16_t kVdd;
    int16_t vdd25;
    
    kVdd = eeData[39];
    if(kVdd > 1023)
    {
        kVdd = kVdd - 2048;
    }
    kVdd = 32 * kVdd;
    
    vdd25 = eeData[38];
    if(vdd25 > 1023)
    {
        vdd25 = vdd25 - 2048;
    }
    vdd25 = 32 * vdd25;
    
    mlx90641->kVdd = kVdd;
    mlx90641->vdd25 = vdd25; 
}

//------------------------------------------------------------------------------

void ExtractPTATParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float KvPTAT;
    float KtPTAT;
    int16_t vPTAT25;
    float alphaPTAT;
    
    KvPTAT = eeData[43];
    if(KvPTAT > 1023)
    {
        KvPTAT = KvPTAT - 2048;
    }
    KvPTAT = KvPTAT/4096;
    
    KtPTAT = eeData[42];
    if(KtPTAT > 1023)
    {
        KtPTAT = KtPTAT - 2048;
    }
    KtPTAT = KtPTAT/8;
    
    vPTAT25 = 32 * eeData[40] + eeData[41];
    
    alphaPTAT = eeData[44] / 128.0f;
    
    mlx90641->KvPTAT = KvPTAT;
    mlx90641->KtPTAT = KtPTAT;    
    mlx90641->vPTAT25 = vPTAT25;
    mlx90641->alphaPTAT = alphaPTAT;   
}

//------------------------------------------------------------------------------

void ExtractGainParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int16_t gainEE;
    
    gainEE = 32 * eeData[36] + eeData[37];

    mlx90641->gainEE = gainEE;    
}

//------------------------------------------------------------------------------

void ExtractTgcParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float tgc;
    tgc = eeData[51] & 0x01FF;
    if(tgc > 255)
    {
        tgc = tgc - 512;
    }
    tgc = tgc / 64.0f;
    
    mlx90641->tgc = tgc;        
}

//------------------------------------------------------------------------------

void ExtractEmissivityParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float emissivity;
    emissivity = eeData[35];
       
    if(emissivity > 1023)
    {
        emissivity = emissivity - 2048;
    }
    emissivity = emissivity/512;
    
    mlx90641->emissivityEE = emissivity;
}
    
//------------------------------------------------------------------------------

void ExtractResolutionParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t resolutionEE;
    resolutionEE = (eeData[51] & 0x0600) >> 9;    
    
    mlx90641->resolutionEE = resolutionEE;
}

//------------------------------------------------------------------------------

void ExtractKsTaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float KsTa;
    KsTa = eeData[34];
    if(KsTa > 1023)
    {
        KsTa = KsTa - 2048;
    }
    KsTa = KsTa / 32768.0f;
    
    mlx90641->KsTa = KsTa;
}

//------------------------------------------------------------------------------

void ExtractKsToParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int KsToScale;
    
    mlx90641->ct[0] = -40;
    mlx90641->ct[1] = -20;
    mlx90641->ct[2] = 0;
    mlx90641->ct[3] = 80;
    mlx90641->ct[4] = 120;
    mlx90641->ct[5] = eeData[58];
    mlx90641->ct[6] = eeData[60];
    mlx90641->ct[7] = eeData[62];
     
    KsToScale = eeData[52];
    KsToScale = 1 << KsToScale;
    
    mlx90641->ksTo[0] = eeData[53];
    mlx90641->ksTo[1] = eeData[54];
    mlx90641->ksTo[2] = eeData[55];
    mlx90641->ksTo[3] = eeData[56];
    mlx90641->ksTo[4] = eeData[57];
    mlx90641->ksTo[5] = eeData[59];
    mlx90641->ksTo[6] = eeData[61];
    mlx90641->ksTo[7] = eeData[63];
    
    
    for(int i = 0; i < 8; i++)
    {
        if(mlx90641->ksTo[i] > 1023)
        {
            mlx90641->ksTo[i] = mlx90641->ksTo[i] - 2048;
        }
        mlx90641->ksTo[i] = mlx90641->ksTo[i] / KsToScale;
    } 
}

//------------------------------------------------------------------------------

void ExtractAlphaParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float rowMaxAlphaNorm[6];
    uint16_t scaleRowAlpha[6];
    uint8_t alphaScale;
    float alphaTemp[192];
    float temp;
    int p = 0;

    scaleRowAlpha[0] = (eeData[25] >> 5) + 20;
    scaleRowAlpha[1] = (eeData[25] & 0x001F) + 20;
    scaleRowAlpha[2] = (eeData[26] >> 5) + 20;
    scaleRowAlpha[3] = (eeData[26] & 0x001F) + 20;
    scaleRowAlpha[4] = (eeData[27] >> 5) + 20;
    scaleRowAlpha[5] = (eeData[27] & 0x001F) + 20;

    
    for(int i = 0; i < 6; i++)
    {
        rowMaxAlphaNorm[i] = eeData[28 + i] / pow(2,(double)scaleRowAlpha[i]);
        rowMaxAlphaNorm[i] = rowMaxAlphaNorm[i] / 2047.0f;
    }

    for(int i = 0; i < 6; i++)
    {
        for(int j = 0; j < 32; j ++)
        {
            p = 32 * i +j;
            alphaTemp[p] = eeData[256 + p] * rowMaxAlphaNorm[i]; 
            alphaTemp[p] = alphaTemp[p] - mlx90641->tgc * mlx90641->cpAlpha;
            alphaTemp[p] = SCALEALPHA/alphaTemp[p];
        }
    }
    
    temp = alphaTemp[0];
    for(int i = 1; i < 192; i++)
    {
        if (alphaTemp[i] > temp)
        {
            temp = alphaTemp[i];
        }
    }
    
    alphaScale = 0;
    while(temp < 32768)
    {
        temp = temp*2;
        alphaScale = alphaScale + 1;
    } 
    
    for(int i = 0; i < 192; i++)
    {
        temp = alphaTemp[i] * pow(2,(double)alphaScale);        
        mlx90641->alpha[i] = (temp + 0.5);        
        
    } 
    
    mlx90641->alphaScale = alphaScale;      
}

//------------------------------------------------------------------------------

void ExtractOffsetParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    int scaleOffset;
    int16_t offsetRef;
    int16_t tempOffset; 
    
    scaleOffset = eeData[16] >> 5;
    scaleOffset = 1 << scaleOffset;

    offsetRef = 32 * eeData[17] + eeData[18];
    if (offsetRef > 32767)
    {
        offsetRef = offsetRef - 65536;
    }

    for(int i = 0; i < 192; i++)
    {
        tempOffset = eeData[64 + i];
        if(tempOffset > 1023)
        {
           tempOffset = eeData[64 + i] - 2048; 
        }
        mlx90641->offset[0][i] = tempOffset * scaleOffset + offsetRef;
        
        tempOffset = eeData[640 + i];
        if(tempOffset > 1023)
        {
           tempOffset = eeData[640 + i] - 2048; 
        }
        mlx90641->offset[1][i] = tempOffset * scaleOffset + offsetRef;
    }
}

//------------------------------------------------------------------------------

void ExtractKtaPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t ktaScale1;
    uint8_t ktaScale2;
    int16_t ktaAvg;
    int16_t tempKta;
    float ktaTemp[192];
    float temp;

    ktaAvg = eeData[21];
    if (ktaAvg > 1023)
    {
        ktaAvg = ktaAvg - 2048;
    }
  
    ktaScale1 = eeData[22] >> 5;
    ktaScale2 = eeData[22] & 0x001F;

    for(int i = 0; i < 192; i++)
    {
        tempKta = (eeData[448 + i] >> 5);
        if (tempKta > 31)
        {
            tempKta = tempKta - 64;
        }

        ktaTemp[i] = tempKta * pow(2,(double)ktaScale2);
        ktaTemp[i] = ktaTemp[i] + ktaAvg;
        ktaTemp[i] = ktaTemp[i] / pow(2,(double)ktaScale1);
    }
    
    temp = fabs(ktaTemp[0]);
    for(int i = 1; i < 192; i++)
    {
        if (fabs(ktaTemp[i]) > temp)
        {
            temp = fabs(ktaTemp[i]);
        }
    }
    
    ktaScale1 = 0;
    while(temp < 64)
    {
        temp = temp*2;
        ktaScale1 = ktaScale1 + 1;
    }    
     
    for(int i = 0; i < 192; i++)
    {
        temp = ktaTemp[i] * pow(2,(double)ktaScale1);
        if (temp < 0)
        {
            mlx90641->kta[i] = (temp - 0.5);
        }
        else
        {
            mlx90641->kta[i] = (temp + 0.5);
        }        
        
    } 
    
    mlx90641->ktaScale = ktaScale1;
}

//------------------------------------------------------------------------------

void ExtractKvPixelParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint8_t kvScale1;
    uint8_t kvScale2;
    int16_t kvAvg;
    int16_t tempKv;
    float kvTemp[192];
    float temp;

    kvAvg = eeData[23];
    if (kvAvg > 1023)
    {
        kvAvg = kvAvg - 2048;
    }
  
    kvScale1 = eeData[24] >> 5;
    kvScale2 = eeData[24] & 0x001F;

    for(int i = 0; i < 192; i++)
    {
        tempKv = (eeData[448 + i] & 0x001F);
        if (tempKv > 15)
        {
            tempKv = tempKv - 32;
        }

        kvTemp[i] = tempKv * pow(2,(double)kvScale2);
        kvTemp[i] = kvTemp[i] + kvAvg;
        kvTemp[i] = kvTemp[i] / pow(2,(double)kvScale1);
    }
    
    temp = fabs(kvTemp[0]);
    for(int i = 1; i < 192; i++)
    {
        if (fabs(kvTemp[i]) > temp)
        {
            temp = fabs(kvTemp[i]);
        }
    }
    
    kvScale1 = 0;
    while(temp < 64)
    {
        temp = temp*2;
        kvScale1 = kvScale1 + 1;
    }    
     
    for(int i = 0; i < 192; i++)
    {
        temp = kvTemp[i] * pow(2,(double)kvScale1);
        if (temp < 0)
        {
            mlx90641->kv[i] = (temp - 0.5);
        }
        else
        {
            mlx90641->kv[i] = (temp + 0.5);
        }        
        
    } 
    
    mlx90641->kvScale = kvScale1;        
}

//------------------------------------------------------------------------------

void ExtractCPParameters(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    float alphaCP;
    int16_t offsetCP;
    float cpKv;
    float cpKta;
    uint8_t alphaScale;
    uint8_t ktaScale1;
    uint8_t kvScale;

    alphaScale = eeData[46];
    
    offsetCP = 32 * eeData[47] + eeData[48];
    if (offsetCP > 32767)
    {
        offsetCP = offsetCP - 65536;
    }
       
    alphaCP = eeData[45];
    if (alphaCP > 1023)
    {
        alphaCP = alphaCP - 2048;
    }
    
    alphaCP = alphaCP /  pow(2,(double)alphaScale);
    
    
    cpKta = eeData[49] & 0x003F;
    if (cpKta > 31)
    {
        cpKta = cpKta - 64;
    }
    ktaScale1 = eeData[49] >> 6;    
    mlx90641->cpKta = cpKta / pow(2,(double)ktaScale1);
    
    cpKv = eeData[50] & 0x003F;
    if (cpKv > 31)
    {
        cpKv = cpKv - 64;
    }
    kvScale = eeData[50] >> 6;
    mlx90641->cpKv = cpKv / pow(2,(double)kvScale);
       
    mlx90641->cpAlpha = alphaCP;
    mlx90641->cpOffset = offsetCP;
}

//------------------------------------------------------------------------------

float MLX90641_GetEmissivity(const paramsMLX90641 *mlx90641)
{
    return  mlx90641->emissivityEE;
}

//------------------------------------------------------------------------------

int ExtractDeviatingPixels(uint16_t *eeData, paramsMLX90641 *mlx90641)
{
    uint16_t pixCnt = 0;
    uint16_t brokenPixCnt = 0;

    int warn = 0;
    
    mlx90641->brokenPixel = 0xFFFF;
        
    pixCnt = 0;    
    while (pixCnt < 192 && brokenPixCnt < 2)
    {
        if((eeData[pixCnt+64] == 0) && (eeData[pixCnt+256] == 0) && (eeData[pixCnt+448] == 0) && (eeData[pixCnt+640] == 0))
        {
            mlx90641->brokenPixel = pixCnt;
            brokenPixCnt = brokenPixCnt + 1;
        }    
        
        pixCnt = pixCnt + 1;
    } 
    
    if(brokenPixCnt > 1)  
    {
        warn = -3;
    }         
    
    return warn;
       
}
 
 //------------------------------------------------------------------------------
 
 int CheckEEPROMValid(uint16_t *eeData)  
 {
     int deviceSelect;
     deviceSelect = eeData[10] & 0x0040;
     if(deviceSelect != 0)
     {
         return 0;
     }
     
     return -7;    
 }        

MLX90641_I2C_Driver.c: (where the crash happens)

#include <zephyr.h>
#include <errno.h>
#include <device.h>
#include <drivers/i2c.h>

#include "MLX90641_I2C_Driver.h"

const struct device *i2c_dev;

void MLX90641_I2CInit()
{   
    //i2c.stop();
    i2c_dev = DEVICE_DT_GET(DT_NODELABEL(i2c0));
}

int MLX90641_I2CGeneralReset(void)
{    
    int ack;
    char cmd[2] = {0,0};
    
    cmd[0] = 0x00;
    cmd[1] = 0x06;    

    //i2c.stop();
    //wait_us(5);
    k_sleep(K_USEC(5));    
    //ack = i2c.write(cmd[0], &cmd[1], 1, 0);
    ack = i2c_write(i2c_dev, &cmd[1], 1, cmd[0]);
    
    if (ack != 0x00)
    {
        return -1;
    }         
    //i2c.stop();   
    
    //wait_us(50);   
    k_sleep(K_USEC(50));
    
    return 0;
}

int MLX90641_I2CRead(uint8_t slaveAddr, uint16_t startAddress, uint16_t nMemAddressRead, uint16_t *data)
{
    printk("slaveAddr: %d startAddress: %d nMemAddressRead: %d *data: %p\n", slaveAddr, startAddress, nMemAddressRead, data);

    //uint8_t sa;                           
    int ack = 0;                               
    int cnt = 0;
    int i = 0;
    char cmd[2] = {0,0};
    char i2cData[1664] = {0};
    uint16_t *p;
    
    p = data;
    //sa = (slaveAddr << 1);
    cmd[0] = startAddress >> 8;
    cmd[1] = startAddress & 0x00FF;

    //printk("sa: %d\n", sa);
    
    //i2c.stop();
    //wait_us(5); 
    k_sleep(K_USEC(5));

    //ack = i2c.write(sa, cmd, 2, 1);
    i2c_write(i2c_dev, cmd, 2, slaveAddr);
    
    if (ack != 0x00)
    {
        return -1;
    }
             
    //sa = sa | 0x01;
    //ack = i2c.read(sa, i2cData, 2*nMemAddressRead, 0);
    i2c_read(i2c_dev, i2cData, 2*nMemAddressRead, slaveAddr);
    
    if (ack != 0x00)
    {
        return -1; 
    }          
    //i2c.stop();   
    
    for(cnt=0; cnt < nMemAddressRead; cnt++)
    {
        i = cnt << 1;
        *p++ = (uint16_t)i2cData[i]*256 + (uint16_t)i2cData[i+1];   // THIS CAUSES THE CRASH
        printk("cnt: %d i: %d *p: %p\n", cnt, i, p);
        //thread_analyzer_print();
    }
    
    return 0;   
} 

void MLX90641_I2CFreqSet(int freq)  // seems like this function isn't used
{
    //i2c.frequency(1000*freq);
}

int MLX90641_I2CWrite(uint8_t slaveAddr, uint16_t writeAddress, uint16_t data)
{
    //uint8_t sa;
    int ack = 0;
    char cmd[4] = {0,0,0,0};
    static uint16_t dataCheck;
    

    //sa = (slaveAddr << 1);
    cmd[0] = writeAddress >> 8;
    cmd[1] = writeAddress & 0x00FF;
    cmd[2] = data >> 8;
    cmd[3] = data & 0x00FF;

    //i2c.stop();
    //wait_us(5);    
    k_sleep(K_USEC(5));

    //ack = i2c.write(sa, cmd, 4, 0);
    ack = i2c_write(i2c_dev, cmd, 4, slaveAddr);
    
    if (ack != 0x00)
    {
        return -1;
    }         
    //i2c.stop();   
    
    MLX90641_I2CRead(slaveAddr,writeAddress,1, &dataCheck);
    
    if ( dataCheck != data)
    {
        return -2;
    }    
    
    return 0;
}

prj.conf:

CONFIG_I2C=y

CONFIG_TINYCBOR=y
CONFIG_CBOR_FLOATING_POINT=y

CONFIG_LOG=y
CONFIG_LOG2_MODE_IMMEDIATE=y

#CONFIG_MAIN_STACK_SIZE=2048
#CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
#CONFIG_IDLE_STACK_SIZE=1024
#CONFIG_THREAD_ANALYZER=y
#CONFIG_THREAD_ANALYZER_USE_PRINTK=y

The I2C itself seems to work fine writing and reading, but then when the read data is copied from a char array in the I2C function (1664 length) into a uint16_t array in main() (832 length) I always get the same crash, when the pointer to the uint16_t reaches address 0x20001b60. Using printk and addr2line I traced the problem to line 86 in MLX90641_I2C_Driver.c, where the data is copied inside a for loop.

When I try setting CONFIG_MAIN_STACK_SIZE=2048, I instead get a "Bus Fault" before the program even prints anything. The crash address is traced to the zephyr uart_console.c line 94.

I then removed the stack size config and tried using the Thread Analyzer, which causes a bus fault traced to the zephyr kernel thread.c line 946 and thread_analyzer.c line 84. The thread analyzer output shows the thread stacks aren't anywhere close to overflowing.

I am pretty stumped here and would greatly appreciate any help. Thanks!

Parents
  • I randomly added another LOG_INF output outside of the function that crashes, and the crash changed to "Usage Fault" and it seems the function gets slightly further along although the crash happens at a lower memory address as can be seen below.

    Instruction addresses traceback to random NRF/Zephyr files.

    And now, even weirder, when I comment out everything below line 24 in main.c, the program does not run at all and crashes with another different message seen below. How is this possible if the crash happens in the first function? I don't see how removing code after this point should change anything, since it never even runs. It must be some obscure ridiculous memory issue causing these crashes?

    Once again, the faulting instruction addresses in r15 and r14 trace back to random zephyr code (log_output.c and cbprintf_complete.c)

  • Hi,

    Could you try setting these, and see what information you get then.

    CONFIG_DEBUG_OPTIMIZATIONS=y
    CONFIG_DEBUG=y
    CONFIG_HW_STACK_PROTECTION=y

  • Similar crash output, the addresses traceback to random zephyr source files related to timing:

    I also just installed NCS v1.9.1 and created a fresh VS Code workspace to recreate the project, pretty much the same errors still.

Reply
  • Similar crash output, the addresses traceback to random zephyr source files related to timing:

    I also just installed NCS v1.9.1 and created a fresh VS Code workspace to recreate the project, pretty much the same errors still.

Children
  • 1) the function MLX90641_I2CRead() is called from main thread context? correct?

    2) Any difference if you set CONFIG_LOG2_MODE_IMMEDIATE=n ?

    3) Have you tried setting stack and heap to some very high numbers? e.g.

    # Stacks and heaps
    CONFIG_MAIN_STACK_SIZE=16384
    CONFIG_HEAP_MEM_POOL_SIZE=16384

  • CONFIG_MAIN_STACK_SIZE=16384

    This did the job, 8192 is enough and anything below that crashes. So weird because I tried increasing to 2048 and 4096 initially and both caused the program to crash earlier than with 1024 so I never tried increasing it more.

    One last question, if main stack size was the culprit, why did the thread analyzer say that main stack was only at 28% usage when the crashes were happening?

  • rm_89 said:
    This did the job, 8192 is enough and anything below that crashes.

    Great!

    rm_89 said:
    One last question, if main stack size was the culprit, why did the thread analyzer say that main stack was only at 28% usage when the crashes were happening?

    I assume that there was a sudden peak in the stack usage, this caused the crash, and that the thread analyzer did not have time to register or report this increase before the crash.

Related