Compare commits

...

2 Commits

Author SHA1 Message Date
Edward Emelianov
96d0b3987a fixed header in help 2025-09-24 23:39:44 +03:00
Edward Emelianov
ca0b52493f Works for 5 sensors 2025-09-24 23:36:46 +03:00
12 changed files with 250 additions and 173 deletions

View File

@ -33,6 +33,7 @@ static volatile int I2Cbusy = 0, goterr = 0; // busy==1 when DMA active, goterr=
static uint16_t I2Cbuf[I2C_BUFSIZE]; static uint16_t I2Cbuf[I2C_BUFSIZE];
static uint16_t i2cbuflen = 0; // buffer for DMA rx and its len static uint16_t i2cbuflen = 0; // buffer for DMA rx and its len
static volatile uint16_t dma_remain = 0; // remain bytes of DMA read/write static volatile uint16_t dma_remain = 0; // remain bytes of DMA read/write
static uint8_t dmaaddr = 0; // address to continuous read by DMA
// macros for I2C rx/tx // macros for I2C rx/tx
#define DMARXCCR (DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE) #define DMARXCCR (DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE)
@ -271,6 +272,7 @@ static uint8_t dmard(uint8_t addr, uint16_t nbytes){
(void) I2C1->RXDR; // avoid wrong first byte (void) I2C1->RXDR; // avoid wrong first byte
DMA1_Channel7->CCR = DMARXCCR | DMA_CCR_EN; // init DMA before START sequence DMA1_Channel7->CCR = DMARXCCR | DMA_CCR_EN; // init DMA before START sequence
if(!i2c_startr(addr, nbytes, 1)) return 0; if(!i2c_startr(addr, nbytes, 1)) return 0;
dmaaddr = addr;
dma_remain = nbytes > 255 ? nbytes - 255 : 0; // remainder after first read finish dma_remain = nbytes > 255 ? nbytes - 255 : 0; // remainder after first read finish
I2Cbusy = 1; I2Cbusy = 1;
return 1; return 1;
@ -329,7 +331,8 @@ void i2c_bufdudump(){
// get DMA buffer with conversion to little-endian (if transfer was for 16-bit) // get DMA buffer with conversion to little-endian (if transfer was for 16-bit)
uint16_t *i2c_dma_getbuf(uint16_t *len){ uint16_t *i2c_dma_getbuf(uint16_t *len){
if(i2c_got_DMA) USND("DMA GOT!"); //if(i2c_got_DMA) USND("DMA GOT!");
//U("T="); U(u2str(Tms)); U("; cndtr: "); USND(u2str(DMA1_Channel7->CNDTR));
if(!i2c_got_DMA || i2cbuflen < 1) return NULL; if(!i2c_got_DMA || i2cbuflen < 1) return NULL;
i2c_got_DMA = 0; i2c_got_DMA = 0;
i2cbuflen >>= 1; // for hexdump16 - now buffer have uint16_t! i2cbuflen >>= 1; // for hexdump16 - now buffer have uint16_t!
@ -358,7 +361,7 @@ static void I2C_isr(int rx){
uint16_t len = (dma_remain > 255) ? 255 : dma_remain; uint16_t len = (dma_remain > 255) ? 255 : dma_remain;
ch->CNDTR = len; ch->CNDTR = len;
if(rx){ if(rx){
if(!i2c_startr(0, dma_remain, 0)){ if(!i2c_startr(dmaaddr, dma_remain, 0)){
goterr = 1; goto ret; goterr = 1; goto ret;
} }
ch->CMAR += 255; ch->CMAR += 255;

View File

@ -41,7 +41,7 @@ int main(void){
} }
USBPU_OFF(); USBPU_OFF();
hw_setup(); hw_setup();
i2c_setup(I2C_SPEED_100K); i2c_setup(I2C_SPEED_400K);
USB_setup(); USB_setup();
USBPU_ON(); USBPU_ON();
uint32_t ctr = Tms, Tlastima[N_SESORS] = {0}; uint32_t ctr = Tms, Tlastima[N_SESORS] = {0};
@ -49,6 +49,7 @@ int main(void){
while(1){ while(1){
if(Tms - ctr > 499){ if(Tms - ctr > 499){
ctr = Tms; ctr = Tms;
if(!mlx_nactive()){ mlx_stop(); mlx_continue(); }
pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0
} }
int l = USB_receivestr(inbuff, MAXSTRLEN); int l = USB_receivestr(inbuff, MAXSTRLEN);
@ -72,7 +73,8 @@ int main(void){
if(Tnow != Tlastima[i]){ if(Tnow != Tlastima[i]){
fp_t *im = mlx_getimage(i); fp_t *im = mlx_getimage(i);
if(im){ if(im){
U("Timage="); USND(u2str(Tnow)); drawIma(im); U(Sensno); USND(i2str(i));
U(Timage); USND(u2str(Tnow)); drawIma(im);
Tlastima[i] = Tnow; Tlastima[i] = Tnow;
} }
} }

Binary file not shown.

View File

@ -31,7 +31,10 @@
// tolerance of floating point comparison // tolerance of floating point comparison
#define FP_TOLERANCE (1e-3) #define FP_TOLERANCE (1e-3)
// 3072 bytes
static fp_t mlx_image[MLX_PIXNO] = {0}; // ready image static fp_t mlx_image[MLX_PIXNO] = {0}; // ready image
// 10100 bytes:
static MLX90640_params params; // calculated parameters (in heap, not stack!) for other functions
void dumpIma(const fp_t im[MLX_PIXNO]){ void dumpIma(const fp_t im[MLX_PIXNO]){
for(int row = 0; row < MLX_H; ++row){ for(int row = 0; row < MLX_H; ++row){
@ -100,29 +103,29 @@ static void occacc(int8_t *arr, int l, const uint16_t *regstart){
} }
// get all parameters' values from `dataarray`, return FALSE if something failed // get all parameters' values from `dataarray`, return FALSE if something failed
int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params){ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
#define CREG_VAL(reg) dataarray[CREG_IDX(reg)] #define CREG_VAL(reg) dataarray[CREG_IDX(reg)]
int8_t i8; int8_t i8;
int16_t i16; int16_t i16;
uint16_t *pu16; uint16_t *pu16;
uint16_t val = CREG_VAL(REG_VDD); uint16_t val = CREG_VAL(REG_VDD);
i8 = (int8_t) (val >> 8); i8 = (int8_t) (val >> 8);
params->kVdd = i8 * 32; // keep sign params.kVdd = i8 * 32; // keep sign
if(params->kVdd == 0) return FALSE; if(params.kVdd == 0){USND("kvdd=0"); return NULL;}
i16 = val & 0xFF; i16 = val & 0xFF;
params->vdd25 = ((i16 - 0x100) * 32) - (1<<13); params.vdd25 = ((i16 - 0x100) * 32) - (1<<13);
val = CREG_VAL(REG_KVTPTAT); val = CREG_VAL(REG_KVTPTAT);
i16 = (val & 0xFC00) >> 10; i16 = (val & 0xFC00) >> 10;
if(i16 > 0x1F) i16 -= 0x40; if(i16 > 0x1F) i16 -= 0x40;
params->KvPTAT = (fp_t)i16 / (1<<12); params.KvPTAT = (fp_t)i16 / (1<<12);
i16 = (val & 0x03FF); i16 = (val & 0x03FF);
if(i16 > 0x1FF) i16 -= 0x400; if(i16 > 0x1FF) i16 -= 0x400;
params->KtPTAT = (fp_t)i16 / 8.; params.KtPTAT = (fp_t)i16 / 8.;
params->vPTAT25 = (int16_t) CREG_VAL(REG_PTAT); params.vPTAT25 = (int16_t) CREG_VAL(REG_PTAT);
val = CREG_VAL(REG_APTATOCCS) >> 12; val = CREG_VAL(REG_APTATOCCS) >> 12;
params->alphaPTAT = val / 4. + 8.; params.alphaPTAT = val / 4. + 8.;
params->gainEE = (int16_t)CREG_VAL(REG_GAIN); params.gainEE = (int16_t)CREG_VAL(REG_GAIN);
if(params->gainEE == 0) return FALSE; if(params.gainEE == 0){USND("gainee=0"); return NULL;}
int8_t occRow[MLX_H]; int8_t occRow[MLX_H];
int8_t occColumn[MLX_W]; int8_t occColumn[MLX_W];
occacc(occRow, MLX_H, &CREG_VAL(REG_OCCROW14)); occacc(occRow, MLX_H, &CREG_VAL(REG_OCCROW14));
@ -150,11 +153,11 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa
// so index of ktaavg is 2*(row&1)+(col&1) // so index of ktaavg is 2*(row&1)+(col&1)
val = CREG_VAL(REG_KTAVSCALE); val = CREG_VAL(REG_KTAVSCALE);
uint8_t scale1 = ((val & 0xFF)>>4) + 8, scale2 = (val&0xF); uint8_t scale1 = ((val & 0xFF)>>4) + 8, scale2 = (val&0xF);
if(scale1 == 0 || scale2 == 0) return FALSE; if(scale1 == 0 || scale2 == 0){USND("scale1/2=0"); return NULL;}
fp_t mul = (fp_t)(1<<scale2), div = (fp_t)(1<<scale1); // kta_scales fp_t mul = (fp_t)(1<<scale2), div = (fp_t)(1<<scale1); // kta_scales
uint16_t a_r = CREG_VAL(REG_SENSIVITY); // alpha_ref uint16_t a_r = CREG_VAL(REG_SENSIVITY); // alpha_ref
val = CREG_VAL(REG_SCALEACC); val = CREG_VAL(REG_SCALEACC);
fp_t *a = params->alpha; fp_t *a = params.alpha;
uint32_t diva32 = 1 << (val >> 12); uint32_t diva32 = 1 << (val >> 12);
fp_t diva = (fp_t)(diva32); fp_t diva = (fp_t)(diva32);
diva *= (fp_t)(1<<30); // alpha_scale diva *= (fp_t)(1<<30); // alpha_scale
@ -162,8 +165,8 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa
accColumnScale = 1<<((val & 0x00f0)>>4), accColumnScale = 1<<((val & 0x00f0)>>4),
accRemScale = 1<<(val & 0x0f); accRemScale = 1<<(val & 0x0f);
pu16 = (uint16_t*)&CREG_VAL(REG_OFFAK1); pu16 = (uint16_t*)&CREG_VAL(REG_OFFAK1);
fp_t *kta = params->kta, *offset = params->offset; fp_t *kta = params.kta, *offset = params.offset;
uint8_t *ol = params->outliers; uint8_t *ol = params.outliers;
for(int row = 0; row < MLX_H; ++row){ for(int row = 0; row < MLX_H; ++row){
int idx = (row&1)<<1; int idx = (row&1)<<1;
for(int col = 0; col < MLX_W; ++col){ for(int col = 0; col < MLX_W; ++col){
@ -197,59 +200,59 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa
ktaavg[2] = (int8_t)i16; // odd col, even row ktaavg[2] = (int8_t)i16; // odd col, even row
i16 = val & 0x0F; if(i16 > 0x07) i16 -= 0x10; i16 = val & 0x0F; if(i16 > 0x07) i16 -= 0x10;
ktaavg[3] = (int8_t)i16; // even col, even row ktaavg[3] = (int8_t)i16; // even col, even row
for(int i = 0; i < 4; ++i) params->kv[i] = ktaavg[i] / div; for(int i = 0; i < 4; ++i) params.kv[i] = ktaavg[i] / div;
val = CREG_VAL(REG_CPOFF); val = CREG_VAL(REG_CPOFF);
params->cpOffset[0] = (val & 0x03ff); params.cpOffset[0] = (val & 0x03ff);
if(params->cpOffset[0] > 0x1ff) params->cpOffset[0] -= 0x400; if(params.cpOffset[0] > 0x1ff) params.cpOffset[0] -= 0x400;
params->cpOffset[1] = val >> 10; params.cpOffset[1] = val >> 10;
if(params->cpOffset[1] > 0x1f) params->cpOffset[1] -= 0x40; if(params.cpOffset[1] > 0x1f) params.cpOffset[1] -= 0x40;
params->cpOffset[1] += params->cpOffset[0]; params.cpOffset[1] += params.cpOffset[0];
val = ((CREG_VAL(REG_KTAVSCALE) & 0xF0) >> 4) + 8; val = ((CREG_VAL(REG_KTAVSCALE) & 0xF0) >> 4) + 8;
i8 = (int8_t)(CREG_VAL(REG_KVTACP) & 0xFF); i8 = (int8_t)(CREG_VAL(REG_KVTACP) & 0xFF);
params->cpKta = (fp_t)i8 / (1<<val); params.cpKta = (fp_t)i8 / (1<<val);
val = (CREG_VAL(REG_KTAVSCALE) & 0x0F00) >> 8; val = (CREG_VAL(REG_KTAVSCALE) & 0x0F00) >> 8;
i16 = CREG_VAL(REG_KVTACP) >> 8; i16 = CREG_VAL(REG_KVTACP) >> 8;
if(i16 > 0x7F) i16 -= 0x100; if(i16 > 0x7F) i16 -= 0x100;
params->cpKv = (fp_t)i16 / (1<<val); params.cpKv = (fp_t)i16 / (1<<val);
i16 = CREG_VAL(REG_KSTATGC) & 0xFF; i16 = CREG_VAL(REG_KSTATGC) & 0xFF;
if(i16 > 0x7F) i16 -= 0x100; if(i16 > 0x7F) i16 -= 0x100;
params->tgc = (fp_t)i16; params.tgc = (fp_t)i16;
params->tgc /= 32.; params.tgc /= 32.;
val = (CREG_VAL(REG_SCALEACC)>>12); // alpha_scale_CP val = (CREG_VAL(REG_SCALEACC)>>12); // alpha_scale_CP
i16 = CREG_VAL(REG_ALPHA)>>10; // cp_P1_P0_ratio i16 = CREG_VAL(REG_ALPHA)>>10; // cp_P1_P0_ratio
if(i16 > 0x1F) i16 -= 0x40; if(i16 > 0x1F) i16 -= 0x40;
div = (fp_t)(1<<val); div = (fp_t)(1<<val);
div *= (fp_t)(1<<27); div *= (fp_t)(1<<27);
params->cpAlpha[0] = (fp_t)(CREG_VAL(REG_ALPHA) & 0x03FF) / div; params.cpAlpha[0] = (fp_t)(CREG_VAL(REG_ALPHA) & 0x03FF) / div;
div = (fp_t)(1<<7); div = (fp_t)(1<<7);
params->cpAlpha[1] = params->cpAlpha[0] * (1. + (fp_t)i16/div); params.cpAlpha[1] = params.cpAlpha[0] * (1. + (fp_t)i16/div);
i8 = (int8_t)(CREG_VAL(REG_KSTATGC) >> 8); i8 = (int8_t)(CREG_VAL(REG_KSTATGC) >> 8);
params->KsTa = (fp_t)i8/(1<<13); params.KsTa = (fp_t)i8/(1<<13);
div = 1<<((CREG_VAL(REG_CT34) & 0x0F) + 8); // kstoscale div = 1<<((CREG_VAL(REG_CT34) & 0x0F) + 8); // kstoscale
val = CREG_VAL(REG_KSTO12); val = CREG_VAL(REG_KSTO12);
i8 = (int8_t)(val & 0xFF); i8 = (int8_t)(val & 0xFF);
params->KsTo[0] = i8 / div; params.KsTo[0] = i8 / div;
i8 = (int8_t)(val >> 8); i8 = (int8_t)(val >> 8);
params->KsTo[1] = i8 / div; params.KsTo[1] = i8 / div;
val = CREG_VAL(REG_KSTO34); val = CREG_VAL(REG_KSTO34);
i8 = (int8_t)(val & 0xFF); i8 = (int8_t)(val & 0xFF);
params->KsTo[2] = i8 / div; params.KsTo[2] = i8 / div;
i8 = (int8_t)(val >> 8); i8 = (int8_t)(val >> 8);
params->KsTo[3] = i8 / div; params.KsTo[3] = i8 / div;
// CT1 = -40, CT2 = 0 -> start from zero index, so CT[0] is CT2, CT[1] is CT3, CT[2] is CT4 // CT1 = -40, CT2 = 0 -> start from zero index, so CT[0] is CT2, CT[1] is CT3, CT[2] is CT4
params->CT[0] = 0.; // 0degr - between ranges 1 and 2 params.CT[0] = 0.; // 0degr - between ranges 1 and 2
val = CREG_VAL(REG_CT34); val = CREG_VAL(REG_CT34);
mul = ((val & 0x3000)>>12)*10.; // step mul = ((val & 0x3000)>>12)*10.; // step
params->CT[1] = ((val & 0xF0)>>4)*mul; // CT3 - between ranges 2 and 3 params.CT[1] = ((val & 0xF0)>>4)*mul; // CT3 - between ranges 2 and 3
params->CT[2] = ((val & 0x0F00) >> 8)*mul + params->CT[1]; // CT4 - between ranges 3 and 4 params.CT[2] = ((val & 0x0F00) >> 8)*mul + params.CT[1]; // CT4 - between ranges 3 and 4
// alphacorr for each range: 11.1.11 // alphacorr for each range: 11.1.11
params->alphacorr[0] = 1./(1. + params->KsTo[0] * 40.); params.alphacorr[0] = 1./(1. + params.KsTo[0] * 40.);
params->alphacorr[1] = 1.; params.alphacorr[1] = 1.;
params->alphacorr[2] = (1. + params->KsTo[1] * params->CT[1]); params.alphacorr[2] = (1. + params.KsTo[1] * params.CT[1]);
params->alphacorr[3] = (1. + params->KsTo[2] * (params->CT[2] - params->CT[1])) * params->alphacorr[2]; params.alphacorr[3] = (1. + params.KsTo[2] * (params.CT[2] - params.CT[1])) * params.alphacorr[2];
params->resolEE = (uint8_t)((CREG_VAL(REG_KTAVSCALE) & 0x3000) >> 12); params.resolEE = (uint8_t)((CREG_VAL(REG_KTAVSCALE) & 0x3000) >> 12);
// Don't forget to check 'outlier' flags for wide purpose // Don't forget to check 'outlier' flags for wide purpose
return TRUE; return &params;
#undef CREG_VAL #undef CREG_VAL
} }
@ -261,37 +264,37 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa
* @param subpageno * @param subpageno
* @return * @return
*/ */
fp_t *process_image(const MLX90640_params *params, const int16_t subpage1[REG_IMAGEDATA_LEN]){ fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]){
#define IMD_VAL(reg) subpage1[IMD_IDX(reg)] #define IMD_VAL(reg) subpage1[IMD_IDX(reg)]
// 11.2.2.1. Resolution restore // 11.2.2.1. Resolution restore
//fp_t resol_corr = (fp_t)(1<<params->resolEE) / (1<<mlx_getresolution()); // calibrated resol/current resol //fp_t resol_corr = (fp_t)(1<<params.resolEE) / (1<<mlx_getresolution()); // calibrated resol/current resol
fp_t resol_corr = (fp_t)(1<<params->resolEE) / (1<<2); // ONLY DEFAULT! fp_t resol_corr = (fp_t)(1<<params.resolEE) / (1<<2); // ONLY DEFAULT!
int16_t i16a; int16_t i16a;
fp_t dvdd, dTa, Kgain, pixOS[2]; // values for both subpages fp_t dvdd, dTa, Kgain, pixOS[2]; // values for both subpages
// 11.2.2.2. Supply voltage value calculation // 11.2.2.2. Supply voltage value calculation
i16a = (int16_t)IMD_VAL(REG_IVDDPIX); i16a = (int16_t)IMD_VAL(REG_IVDDPIX);
//U("rval="); USND(i2str(i16a)); //U("rval="); USND(i2str(i16a));
dvdd = resol_corr*i16a - params->vdd25; dvdd = resol_corr*i16a - params.vdd25;
dvdd /= params->kVdd; dvdd /= params.kVdd;
//U("dvdd="); USND(float2str(dvdd, 2)); //U("dvdd="); USND(float2str(dvdd, 2));
fp_t dV = i16a - params->vdd25; // for next step fp_t dV = i16a - params.vdd25; // for next step
dV /= params->kVdd; dV /= params.kVdd;
// 11.2.2.3. Ambient temperature calculation // 11.2.2.3. Ambient temperature calculation
i16a = (int16_t)IMD_VAL(REG_ITAPTAT); i16a = (int16_t)IMD_VAL(REG_ITAPTAT);
int16_t i16b = (int16_t)IMD_VAL(REG_ITAVBE); int16_t i16b = (int16_t)IMD_VAL(REG_ITAVBE);
dTa = (fp_t)i16a / (i16a * params->alphaPTAT + i16b); // vptatart dTa = (fp_t)i16a / (i16a * params.alphaPTAT + i16b); // vptatart
dTa *= (fp_t)(1<<18); dTa *= (fp_t)(1<<18);
dTa = (dTa / (1. + params->KvPTAT*dV)) - params->vPTAT25; dTa = (dTa / (1. + params.KvPTAT*dV)) - params.vPTAT25;
dTa = dTa / params->KtPTAT; // without 25degr - Ta0 dTa = dTa / params.KtPTAT; // without 25degr - Ta0
// 11.2.2.4. Gain parameter calculation // 11.2.2.4. Gain parameter calculation
i16a = (int16_t)IMD_VAL(REG_IGAIN); i16a = (int16_t)IMD_VAL(REG_IGAIN);
Kgain = params->gainEE / (fp_t)i16a; Kgain = params.gainEE / (fp_t)i16a;
// 11.2.2.6.1 // 11.2.2.6.1
pixOS[0] = ((int16_t)IMD_VAL(REG_ICPSP0))*Kgain; // pix_OS_CP_SPx pixOS[0] = ((int16_t)IMD_VAL(REG_ICPSP0))*Kgain; // pix_OS_CP_SPx
pixOS[1] = ((int16_t)IMD_VAL(REG_ICPSP1))*Kgain; pixOS[1] = ((int16_t)IMD_VAL(REG_ICPSP1))*Kgain;
// 11.2.2.6.2 // 11.2.2.6.2
for(int sp = 0; sp < 2; ++sp) for(int sp = 0; sp < 2; ++sp)
pixOS[sp] -= params->cpOffset[sp]*(1. + params->cpKta*dTa)*(1. + params->cpKv*dvdd); pixOS[sp] -= params.cpOffset[sp]*(1. + params.cpKta*dTa)*(1. + params.cpKv*dvdd);
// now make first approximation to image // now make first approximation to image
uint16_t pixno = 0; // current pixel number - for indexing in parameters etc uint16_t pixno = 0; // current pixel number - for indexing in parameters etc
for(int row = 0, rowidx = 0; row < MLX_H; ++row, rowidx ^= 2){ for(int row = 0, rowidx = 0; row < MLX_H; ++row, rowidx ^= 2){
@ -300,34 +303,34 @@ fp_t *process_image(const MLX90640_params *params, const int16_t subpage1[REG_IM
// 11.2.2.5.1 // 11.2.2.5.1
fp_t curval = (fp_t)(subpage1[pixno]) * Kgain; // gain compensation fp_t curval = (fp_t)(subpage1[pixno]) * Kgain; // gain compensation
// 11.2.2.5.3 // 11.2.2.5.3
curval -= params->offset[pixno] * (1. + params->kta[pixno]*dTa) * curval -= params.offset[pixno] * (1. + params.kta[pixno]*dTa) *
(1. + params->kv[idx]*dvdd); // add offset (1. + params.kv[idx]*dvdd); // add offset
// now `curval` is pix_OS == V_IR_emiss_comp (we can divide it by `emissivity` to compensate for it) // now `curval` is pix_OS == V_IR_emiss_comp (we can divide it by `emissivity` to compensate for it)
// 11.2.2.7: 'Pattern' is just subpage number! // 11.2.2.7: 'Pattern' is just subpage number!
fp_t IRcompens = curval - params->tgc * pixOS[sp]; // 11.2.2.8. Normalizing to sensitivity fp_t IRcompens = curval - params.tgc * pixOS[sp]; // 11.2.2.8. Normalizing to sensitivity
// 11.2.2.8 // 11.2.2.8
fp_t alphaComp = params->alpha[pixno] - params->tgc * params->cpAlpha[sp]; fp_t alphaComp = params.alpha[pixno] - params.tgc * params.cpAlpha[sp];
alphaComp *= 1. + params->KsTa * dTa; alphaComp *= 1. + params.KsTa * dTa;
// 11.2.2.9: calculate To for basic range // 11.2.2.9: calculate To for basic range
fp_t Tar = dTa + 273.15 + 25.; // Ta+273.15 fp_t Tar = dTa + 273.15 + 25.; // Ta+273.15
Tar = Tar*Tar*Tar*Tar; // T_aK4 (when \epsilon==1 this is T_{a-r} too) Tar = Tar*Tar*Tar*Tar; // T_aK4 (when \epsilon==1 this is T_{a-r} too)
fp_t ac3 = alphaComp*alphaComp*alphaComp; fp_t ac3 = alphaComp*alphaComp*alphaComp;
fp_t Sx = ac3*IRcompens + alphaComp*ac3*Tar; fp_t Sx = ac3*IRcompens + alphaComp*ac3*Tar;
Sx = params->KsTo[1] * SQRT(SQRT(Sx)); Sx = params.KsTo[1] * SQRT(SQRT(Sx));
fp_t To4 = IRcompens / (alphaComp * (1. - 273.15*params->KsTo[1]) + Sx) + Tar; fp_t To4 = IRcompens / (alphaComp * (1. - 273.15*params.KsTo[1]) + Sx) + Tar;
curval = SQRT(SQRT(To4)) - 273.15; curval = SQRT(SQRT(To4)) - 273.15;
// 11.2.2.9.1.3. Extended To range calculation // 11.2.2.9.1.3. Extended To range calculation
int r = 0; // range 1 by default int r = 0; // range 1 by default
fp_t ctx = -40.; fp_t ctx = -40.;
if(curval > params->CT[2]){ // range 4 if(curval > params.CT[2]){ // range 4
r = 3; ctx = params->CT[2]; r = 3; ctx = params.CT[2];
}else if(curval > params->CT[1]){ // range 3 }else if(curval > params.CT[1]){ // range 3
r = 2; ctx = params->CT[1]; r = 2; ctx = params.CT[1];
}else if(curval > params->CT[0]){ // range 2, default }else if(curval > params.CT[0]){ // range 2, default
r = 1; ctx = params->CT[0]; r = 1; ctx = params.CT[0];
} }
if(r != 1){ // recalculate for extended range if we are out of standard range if(r != 1){ // recalculate for extended range if we are out of standard range
To4 = IRcompens / (alphaComp * params->alphacorr[r] * (1. + params->KsTo[r]*(curval - ctx))) + Tar; To4 = IRcompens / (alphaComp * params.alphacorr[r] * (1. + params.KsTo[r]*(curval - ctx))) + Tar;
curval = SQRT(SQRT(To4)) - 273.15; curval = SQRT(SQRT(To4)) - 273.15;
} }
mlx_image[pixno] = curval; mlx_image[pixno] = curval;
@ -337,26 +340,3 @@ fp_t *process_image(const MLX90640_params *params, const int16_t subpage1[REG_IM
#undef IMD_VAL #undef IMD_VAL
} }
/*
int MLXtest(){
MLX90640_params p;
USB_sendstr(" Extract parameters - ");
if(!get_parameters(EEPROM, &p)) return 2;
USB_sendstr(OK);
dump_parameters(&p, &extracted_parameters);
fp_t *sp;
for(int i = 0; i < 2; ++i){
USB_sendstr(" 100 times process subpage - "); printi(i); USB_putbyte(' ');
uint32_t Tstart = Tms;
for(int _ = 0; _ < 100; ++_){
sp = process_subpage(&p, DataFrame[i], i, 2);
if(!sp) return 1;
}
USB_sendstr(OKs); printfl((Tms - Tstart)/100.f, 3); USB_sendstr(" ms\n");
dumpIma(sp);
chkImage(sp, ToFrame[i]);
}
drawIma(sp);
return 0;
}
*/

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 17.0.1, 2025-09-23T22:23:26. --> <!-- Written by QtCreator 17.0.1, 2025-09-24T23:35:56. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@ -59,7 +59,7 @@ typedef struct{
} MLX90640_params; } MLX90640_params;
int ch_resolution(uint8_t newresol); int ch_resolution(uint8_t newresol);
int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params); MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]);
fp_t *process_image(const MLX90640_params *params, const int16_t subpage1[REG_IMAGEDATA_LEN]); fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]);
void dumpIma(const fp_t im[MLX_PIXNO]); void dumpIma(const fp_t im[MLX_PIXNO]);
void drawIma(const fp_t im[MLX_PIXNO]); void drawIma(const fp_t im[MLX_PIXNO]);

View File

@ -21,8 +21,20 @@
#include "i2c.h" #include "i2c.h"
#include "mlxproc.h" #include "mlxproc.h"
#include "mlx90640_regs.h" #include "mlx90640_regs.h"
//#define DEBUGPROC
#ifdef DEBUGPROC
#include "usb_dev.h" #include "usb_dev.h"
#include "strfunc.h" #include "strfunc.h"
#define D(x) U(x)
#define DN(x) USND(x)
#define DB(x) USB_putbute(x)
#else
#define D(x)
#define DN(x)
#define DB(x)
#endif
extern volatile uint32_t Tms; extern volatile uint32_t Tms;
@ -32,11 +44,19 @@ static int errctr = 0; // errors counter - cleared by mlx_continue
static uint32_t Tlastimage[N_SESORS] = {0}; static uint32_t Tlastimage[N_SESORS] = {0};
// subpages and configs of all sensors // subpages and configs of all sensors
// 8320 bytes:
static int16_t imdata[N_SESORS][REG_IMAGEDATA_LEN]; static int16_t imdata[N_SESORS][REG_IMAGEDATA_LEN];
// 8340 bytes:
static uint16_t confdata[N_SESORS][MLX_DMA_MAXLEN]; static uint16_t confdata[N_SESORS][MLX_DMA_MAXLEN];
static uint8_t sens_addresses[N_SESORS] = {0x10<<1, 0x11<<1, 0x12<<1, 0x13<<1, 0x14<<1}; // addresses of all sensors (if 0 - omit this one) static uint8_t sens_addresses[N_SESORS] = {0x10<<1, 0x11<<1, 0x12<<1, 0x13<<1, 0x14<<1}; // addresses of all sensors (if 0 - omit this one)
static uint8_t sensaddr[N_SESORS]; static uint8_t sensaddr[N_SESORS];
// get compile-time size: (gcc shows it in error message)
//char (*__kaboom)[sizeof( confdata )] = 1;
// return `sensaddr`
uint8_t *mlx_activeids(){return sensaddr;}
static int sensno = -1; static int sensno = -1;
// get current state // get current state
@ -54,12 +74,14 @@ void mlx_pause(){
MLX_oldstate = MLX_state; MLX_oldstate = MLX_state;
MLX_state = MLX_RELAX; MLX_state = MLX_RELAX;
} }
// TODO: add here power management
void mlx_stop(){ void mlx_stop(){
MLX_oldstate = MLX_NOTINIT; MLX_oldstate = MLX_NOTINIT;
MLX_state = MLX_RELAX; MLX_state = MLX_RELAX;
} }
// continue processing // continue processing
// TODO: add here power management
void mlx_continue(){ void mlx_continue(){
errctr = 0; errctr = 0;
switch(MLX_oldstate){ switch(MLX_oldstate){
@ -70,6 +92,7 @@ void mlx_continue(){
//case MLX_NOTINIT: //case MLX_NOTINIT:
//case MLX_WAITPARAMS: //case MLX_WAITPARAMS:
default: default:
i2c_setup(i2c_curspeed); // restart I2C (what if there was errors?)
memcpy(sensaddr, sens_addresses, sizeof(sens_addresses)); memcpy(sensaddr, sens_addresses, sizeof(sens_addresses));
MLX_state = MLX_NOTINIT; MLX_state = MLX_NOTINIT;
sensno = -1; sensno = -1;
@ -85,7 +108,7 @@ static int nextsensno(int s){
int next = s + 1; int next = s + 1;
for(; next < N_SESORS; ++next) if(sensaddr[next]) break; for(; next < N_SESORS; ++next) if(sensaddr[next]) break;
if(next == N_SESORS) return nextsensno(-1); // roll to start if(next == N_SESORS) return nextsensno(-1); // roll to start
U(i2str(next)); USND(" - new sensor number"); D(i2str(next)); DB('('); D(i2str(s)); DB(')'); DN(" - new sensor number");
return next; return next;
} }
@ -115,20 +138,20 @@ void mlx_process(){
switch(MLX_state){ switch(MLX_state){
case MLX_NOTINIT: // start reading parameters case MLX_NOTINIT: // start reading parameters
if(i2c_read_reg16(sensaddr[sensno], REG_CALIDATA, MLX_DMA_MAXLEN, 1)){ if(i2c_read_reg16(sensaddr[sensno], REG_CALIDATA, MLX_DMA_MAXLEN, 1)){
U(i2str(sensno)); USND(" wait conf"); D(i2str(sensno)); DN(" wait conf");
errctr = 0; errctr = 0;
MLX_state = MLX_WAITPARAMS; MLX_state = MLX_WAITPARAMS;
}else ++errctr; }else ++errctr;
break; break;
case MLX_WAITPARAMS: // check DMA ends and calculate parameters case MLX_WAITPARAMS: // check DMA ends and calculate parameters
if(i2c_dma_haderr()){ MLX_state = MLX_NOTINIT; USND("DMA err");} if(i2c_dma_haderr()){ MLX_state = MLX_NOTINIT; DN("DMA err");}
else{ else{
uint16_t len, *buf = i2c_dma_getbuf(&len); uint16_t len, *buf = i2c_dma_getbuf(&len);
if(buf) USND("READ"); if(!buf) break;
else break; DN("READ");
if(len != MLX_DMA_MAXLEN){ MLX_state = MLX_NOTINIT; break; } if(len != MLX_DMA_MAXLEN){ MLX_state = MLX_NOTINIT; break; }
memcpy(confdata[sensno], buf, MLX_DMA_MAXLEN * sizeof(uint16_t)); memcpy(confdata[sensno], buf, MLX_DMA_MAXLEN * sizeof(uint16_t));
U(i2str(sensno)); USND(" got conf"); D(i2str(sensno)); DN(" got conf");
int next = nextsensno(sensno); int next = nextsensno(sensno);
errctr = 0; errctr = 0;
if(next <= sensno) MLX_state = MLX_WAITSUBPAGE; // all configuration read if(next <= sensno) MLX_state = MLX_WAITSUBPAGE; // all configuration read
@ -143,14 +166,20 @@ void mlx_process(){
if(subpage == (*got & REG_STATUS_SPNO)){ if(subpage == (*got & REG_STATUS_SPNO)){
errctr = 0; errctr = 0;
if(subpage == 0){ // omit zero subpage for each sensor if(subpage == 0){ // omit zero subpage for each sensor
DN("omit 0 -> next sens");
int next = nextsensno(sensno); int next = nextsensno(sensno);
if(next <= sensno) subpage = 1; // all scanned - now wait for page 1 if(next <= sensno){ // all scanned - now wait for page 1
subpage = 1;
DN("Wait for 1");
}
sensno = next;
break; break;
} }
D(i2str(sensno)); DN(" - ask for image");
if(i2c_read_reg16(sensaddr[sensno], REG_IMAGEDATA, REG_IMAGEDATA_LEN, 1)){ if(i2c_read_reg16(sensaddr[sensno], REG_IMAGEDATA, REG_IMAGEDATA_LEN, 1)){
errctr = 0; errctr = 0;
MLX_state = MLX_READSUBPAGE; MLX_state = MLX_READSUBPAGE;
// U("spstart"); USB_putbyte('0'+subpage); USB_putbyte('='); USND(u2str(Tms - Tlast)); // D("spstart"); DB('0'+subpage); DB('='); DN(u2str(Tms - Tlast));
}else ++errctr; }else ++errctr;
} }
}else ++errctr; }else ++errctr;
@ -161,17 +190,21 @@ void mlx_process(){
else{ else{
uint16_t len, *buf = i2c_dma_getbuf(&len); uint16_t len, *buf = i2c_dma_getbuf(&len);
if(buf){ if(buf){
// U("spread="); USND(u2str(Tms - Tlast)); // D("spread="); DN(u2str(Tms - Tlast));
if(len != REG_IMAGEDATA_LEN){ if(len != REG_IMAGEDATA_LEN){
++errctr; ++errctr;
}else{ // fine! we could check next sensor }else{ // fine! we could check next sensor
errctr = 0; errctr = 0;
memcpy(imdata[sensno], buf, REG_IMAGEDATA_LEN * sizeof(int16_t)); memcpy(imdata[sensno], buf, REG_IMAGEDATA_LEN * sizeof(int16_t));
// U("spgot="); USND(u2str(Tms - Tlast)); // D("spgot="); DN(u2str(Tms - Tlast));
Tlastimage[sensno] = Tms; Tlastimage[sensno] = Tms;
// U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms; // D("imgot="); DN(u2str(Tms - Tlast)); Tlast = Tms;
int next = nextsensno(sensno); int next = nextsensno(sensno);
if(next <= sensno) subpage = 0; // roll to start - omit page 0 for all if(next <= sensno){
subpage = 0; // roll to start - omit page 0 for all
DN("All got -> start from 0");
}
sensno = next;
} }
MLX_state = MLX_WAITSUBPAGE; MLX_state = MLX_WAITSUBPAGE;
} }
@ -180,7 +213,7 @@ void mlx_process(){
default: default:
return; return;
} }
if(MLX_state != MLX_RELAX && Tms - Tlastimage[sensno] > MLX_I2CERR_TMOUT){ i2c_setup(i2c_curspeed); Tlastimage[sensno] = Tms; } //if(MLX_state != MLX_RELAX && Tms - Tlastimage[sensno] > MLX_I2CERR_TMOUT){ i2c_setup(i2c_curspeed); Tlastimage[sensno] = Tms; }
if(errctr > MLX_MAX_ERRORS){ if(errctr > MLX_MAX_ERRORS){
errctr = 0; errctr = 0;
sensaddr[sensno] = 0; // throw out this value sensaddr[sensno] = 0; // throw out this value
@ -189,19 +222,18 @@ void mlx_process(){
} }
// recalculate parameters // recalculate parameters
int mlx_getparams(int n, MLX90640_params *pars){ MLX90640_params *mlx_getparams(int n){
if(!pars) return 0; MLX90640_params *p = get_parameters(confdata[n]);
if(!get_parameters(confdata[n], pars)) return 0; return p;
return 1;
} }
uint32_t mlx_lastimT(int n){ return Tlastimage[n]; } uint32_t mlx_lastimT(int n){ return Tlastimage[n]; }
fp_t *mlx_getimage(int n){ fp_t *mlx_getimage(int n){
if(n < 0 || n >= N_SESORS || !sensaddr[n]) return NULL; if(n < 0 || n >= N_SESORS || !sensaddr[n]) return NULL;
MLX90640_params p; MLX90640_params *p = get_parameters(confdata[n]);
if(!get_parameters(confdata[n], &p)) return NULL; if(!p) return NULL;
fp_t *ready_image = process_image(&p, imdata[n]); fp_t *ready_image = process_image(imdata[n]);
if(!ready_image) return NULL; if(!ready_image) return NULL;
return ready_image; return ready_image;
} }
@ -212,7 +244,7 @@ int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr){
if(addr > 0x7f) return 0; if(addr > 0x7f) return 0;
uint16_t data[2], *ptr; uint16_t data[2], *ptr;
if(!(ptr = i2c_read_reg16(MLX_address, REG_MLXADDR, 1, 0))) return 0; if(!(ptr = i2c_read_reg16(MLX_address, REG_MLXADDR, 1, 0))) return 0;
//U("Old address: "); USND(uhex2str(*ptr)); //D("Old address: "); DN(uhex2str(*ptr));
data[0] = REG_MLXADDR; data[1] = 0; data[0] = REG_MLXADDR; data[1] = 0;
uint16_t oldreg = *ptr; uint16_t oldreg = *ptr;
if(!i2c_write(MLX_address, data, 2)) return 0; // clear address if(!i2c_write(MLX_address, data, 2)) return 0; // clear address
@ -227,11 +259,11 @@ int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr){
} }
data[0] = REG_MLXADDR; // i2c_write swaps bytes, so we need init data again data[0] = REG_MLXADDR; // i2c_write swaps bytes, so we need init data again
data[1] = (oldreg & ~REG_MLXADDR_MASK) | addr; data[1] = (oldreg & ~REG_MLXADDR_MASK) | addr;
//U("Write address: "); U(uhex2str(data[0])); U(", "); USND(uhex2str(data[1])); //D("Write address: "); D(uhex2str(data[0])); D(", "); DN(uhex2str(data[1]));
if(!i2c_write(MLX_address, data, 2)) return 0; if(!i2c_write(MLX_address, data, 2)) return 0;
while(Tms - Told < 10); while(Tms - Told < 10);
if(!(ptr = i2c_read_reg16(MLX_address, REG_MLXADDR, 1, 0))) return 0; if(!(ptr = i2c_read_reg16(MLX_address, REG_MLXADDR, 1, 0))) return 0;
//U("Got address: "); USND(uhex2str(*ptr)); //D("Got address: "); DN(uhex2str(*ptr));
if((*ptr & REG_MLXADDR_MASK) != addr) return 0; if((*ptr & REG_MLXADDR_MASK) != addr) return 0;
return 1; return 1;
} }

View File

@ -41,11 +41,12 @@ typedef enum{
int mlx_setaddr(int n, uint8_t addr); int mlx_setaddr(int n, uint8_t addr);
mlx_state_t mlx_state(); mlx_state_t mlx_state();
int mlx_nactive(); int mlx_nactive();
uint8_t *mlx_activeids();
void mlx_pause(); void mlx_pause();
void mlx_stop(); void mlx_stop();
void mlx_continue(); void mlx_continue();
void mlx_process(); void mlx_process();
int mlx_getparams(int sensno, MLX90640_params *pars); MLX90640_params *mlx_getparams(int sensno);
fp_t *mlx_getimage(int sensno); fp_t *mlx_getimage(int sensno);
int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr); int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr);
uint32_t mlx_lastimT(int sensno); uint32_t mlx_lastimT(int sensno);

View File

@ -32,17 +32,24 @@ static uint8_t I2Caddress = 0x33 << 1;
extern volatile uint32_t Tms; extern volatile uint32_t Tms;
uint8_t cartoon = 0; // "cartoon" mode: refresh image each time we get new uint8_t cartoon = 0; // "cartoon" mode: refresh image each time we get new
// common names for frequent keys
const char *Timage = "TIMAGE=";
const char *Sensno = "SENSNO=";
static const char *OK = "OK\n", *ERR = "ERR\n"; static const char *OK = "OK\n", *ERR = "ERR\n";
const char *helpstring = const char *helpstring =
"https://github.com/eddyem/stm32samples/tree/master/F3:F303/mlx90640 build#" BUILD_NUMBER " @ " BUILD_DATE "\n" "https://github.com/eddyem/stm32samples/tree/master/F3:F303/MLX90640multi build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
" management of single IR bolometer MLX90640\n" " management of single IR bolometer MLX90640\n"
"aa - change I2C address to a (a should be non-shifted value!!!)\n" "aa - change I2C address to a (a should be non-shifted value!!!)\n"
"c - continue MLX\n" "c - continue MLX\n"
"d - draw image in ASCII\n" "dn - draw nth image in ASCII\n"
"gn - get nth image 'as is' - float array of 768x4 bytes\n"
"i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n" "i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n"
"l - list active sensors IDs\n"
"tn - show temperature map of nth image\n"
"p - pause MLX\n" "p - pause MLX\n"
"s - stop MLX (and start from zero @ 'c'\n" "s - stop MLX (and start from zero @ 'c'\n"
"t - show temperature map\n" "tn - show nth image aquisition time\n"
"C - \"cartoon\" mode on/off (show each new image)\n" "C - \"cartoon\" mode on/off (show each new image)\n"
"Dn - dump MLX parameters for sensor number n\n" "Dn - dump MLX parameters for sensor number n\n"
"G - get MLX state\n" "G - get MLX state\n"
@ -90,16 +97,23 @@ TRUE_INLINE const char *chhwaddr(const char *buf){
return OK; return OK;
} }
// read sensor's number from `buf`; return -1 if error
static int getsensnum(const char *buf){
if(!buf || !*buf) return -1;
uint32_t num;
const char *nxt = getnum(buf, &num);
if(!nxt || nxt == buf || num >= N_SESORS) return -1;
return (int) num;
}
TRUE_INLINE const char *chaddr(const char *buf){ TRUE_INLINE const char *chaddr(const char *buf){
uint32_t addr, num; uint32_t addr;
const char *nxt = getnum(buf, &addr); const char *nxt = getnum(buf, &addr);
if(nxt && nxt != buf){ if(nxt && nxt != buf){
if(addr > 0x7f) return ERR; if(addr > 0x7f) return ERR;
I2Caddress = (uint8_t) addr << 1; I2Caddress = (uint8_t) addr << 1;
buf = getnum(nxt, &num); int n = getsensnum(nxt);
if(buf && nxt != buf && num < N_SESORS){ if(n > -1) mlx_setaddr(n, addr);
mlx_setaddr(num, addr);
}
}else addr = I2Caddress >> 1; }else addr = I2Caddress >> 1;
U("I2CADDR="); USND(uhex2str(addr)); U("I2CADDR="); USND(uhex2str(addr));
return NULL; return NULL;
@ -156,21 +170,20 @@ static void dumpfarr(float *arr){
} }
// dump MLX parameters // dump MLX parameters
TRUE_INLINE void dumpparams(const char *buf){ TRUE_INLINE void dumpparams(const char *buf){
uint32_t N = 0; int N = getsensnum(buf);
const char *nxt = getnum(buf, &N); if(N < 0){ U(ERR); return; }
U(u2str(N)); USND("sn"); MLX90640_params *params = mlx_getparams(N);
if(!nxt || buf == nxt || N > N_SESORS){ U(ERR); return; } if(!params){ U(ERR); return; }
MLX90640_params params; U(Sensno); USND(i2str(N));
if(!mlx_getparams(N, &params)){ U(ERR); return; } U("\nkVdd="); printi(params->kVdd);
U("\nkVdd="); printi(params.kVdd); U("\nvdd25="); printi(params->vdd25);
U("\nvdd25="); printi(params.vdd25); U("\nKvPTAT="); printfl(params->KvPTAT, 4);
U("\nKvPTAT="); printfl(params.KvPTAT, 4); U("\nKtPTAT="); printfl(params->KtPTAT, 4);
U("\nKtPTAT="); printfl(params.KtPTAT, 4); U("\nvPTAT25="); printi(params->vPTAT25);
U("\nvPTAT25="); printi(params.vPTAT25); U("\nalphaPTAT="); printfl(params->alphaPTAT, 2);
U("\nalphaPTAT="); printfl(params.alphaPTAT, 2); U("\ngainEE="); printi(params->gainEE);
U("\ngainEE="); printi(params.gainEE);
U("\nPixel offset parameters:\n"); U("\nPixel offset parameters:\n");
float *offset = params.offset; float *offset = params->offset;
for(int row = 0; row < 24; ++row){ for(int row = 0; row < 24; ++row){
for(int col = 0; col < 32; ++col){ for(int col = 0; col < 32; ++col){
printfl(*offset++, 2); USB_putbyte(' '); printfl(*offset++, 2); USB_putbyte(' ');
@ -178,28 +191,28 @@ TRUE_INLINE void dumpparams(const char *buf){
newline(); newline();
} }
U("K_talpha:\n"); U("K_talpha:\n");
dumpfarr(params.kta); dumpfarr(params->kta);
U("Kv: "); U("Kv: ");
for(int i = 0; i < 4; ++i){ for(int i = 0; i < 4; ++i){
printfl(params.kv[i], 2); USB_putbyte(' '); printfl(params->kv[i], 2); USB_putbyte(' ');
} }
U("\ncpOffset="); U("\ncpOffset=");
printi(params.cpOffset[0]); U(", "); printi(params.cpOffset[1]); printi(params->cpOffset[0]); U(", "); printi(params->cpOffset[1]);
U("\ncpKta="); printfl(params.cpKta, 2); U("\ncpKta="); printfl(params->cpKta, 2);
U("\ncpKv="); printfl(params.cpKv, 2); U("\ncpKv="); printfl(params->cpKv, 2);
U("\ntgc="); printfl(params.tgc, 2); U("\ntgc="); printfl(params->tgc, 2);
U("\ncpALpha="); printfl(params.cpAlpha[0], 2); U("\ncpALpha="); printfl(params->cpAlpha[0], 2);
U(", "); printfl(params.cpAlpha[1], 2); U(", "); printfl(params->cpAlpha[1], 2);
U("\nKsTa="); printfl(params.KsTa, 2); U("\nKsTa="); printfl(params->KsTa, 2);
U("\nAlpha:\n"); U("\nAlpha:\n");
dumpfarr(params.alpha); dumpfarr(params->alpha);
U("\nCT3="); printfl(params.CT[1], 2); U("\nCT3="); printfl(params->CT[1], 2);
U("\nCT4="); printfl(params.CT[2], 2); U("\nCT4="); printfl(params->CT[2], 2);
for(int i = 0; i < 4; ++i){ for(int i = 0; i < 4; ++i){
U("\nKsTo"); USB_putbyte('0'+i); USB_putbyte('='); U("\nKsTo"); USB_putbyte('0'+i); USB_putbyte('=');
printfl(params.KsTo[i], 2); printfl(params->KsTo[i], 2);
U("\nalphacorr"); USB_putbyte('0'+i); USB_putbyte('='); U("\nalphacorr"); USB_putbyte('0'+i); USB_putbyte('=');
printfl(params.alphacorr[i], 2); printfl(params->alphacorr[i], 2);
} }
newline(); newline();
} }
@ -217,34 +230,81 @@ TRUE_INLINE void getst(){
USND(states[s]); USND(states[s]);
} }
// `draw`==1 - draw, ==0 - show T map // `draw`==1 - draw, ==0 - show T map, 2 - send raw float array with prefix 'SENSNO=x\nTimage=y\n' and postfix "ENDIMAGE\n"
static const char *drawimg(const char *buf, int draw){ static const char *drawimg(const char *buf, int draw){
uint32_t sensno; int sensno = getsensnum(buf);
const char *nxt = getnum(buf, &sensno); if(sensno > -1){
if(nxt && nxt != buf && sensno < N_SESORS){
uint32_t T = mlx_lastimT(sensno); uint32_t T = mlx_lastimT(sensno);
fp_t *img = mlx_getimage(sensno); fp_t *img = mlx_getimage(sensno);
if(img){ if(img){
U("Timage="); USND(u2str(T)); U(Sensno); USND(u2str(sensno));
if(draw) drawIma(img); U(Timage); USND(u2str(T));
else dumpIma(img); switch(draw){
case 0:
dumpIma(img);
break;
case 1:
drawIma(img);
break;
case 2:
{
uint8_t *d = (uint8_t*)img;
uint32_t _2send = MLX_PIXNO * sizeof(float);
// send by portions of 256 bytes (as image is larger than ringbuffer)
while(_2send){
uint32_t portion = (_2send > 256) ? 256 : _2send;
USB_send(d, portion);
_2send -= portion;
d += portion;
}
}
USND("ENDIMAGE");
}
return NULL; return NULL;
} }
} }
return ERR; return ERR;
} }
TRUE_INLINE void listactive(){
int N = mlx_nactive();
if(!N){ USND("No active sensors found!"); return; }
uint8_t *ids = mlx_activeids();
U("Found "); USB_putbyte('0'+N); USND(" active sensors:");
for(int i = 0; i < N_SESORS; ++i)
if(ids[i]){
U("SENSID"); U(u2str(i)); USB_putbyte('=');
U(uhex2str(ids[i] >> 1));
newline();
}
}
static void getimt(const char *buf){
int sensno = getsensnum(buf);
if(sensno > -1){
U(Timage); USND(u2str(mlx_lastimT(sensno)));
}else U(ERR);
}
const char *parse_cmd(char *buf){ const char *parse_cmd(char *buf){
if(!buf || !*buf) return NULL; if(!buf || !*buf) return NULL;
if(buf[1]){ if(buf[1]){
switch(*buf){ // "long" commands switch(*buf){ // "long" commands
case 'a': case 'a':
return chhwaddr(buf + 1); return chhwaddr(buf + 1);
case 'd':
return drawimg(buf+1, 1);
case 'g':
return drawimg(buf+1, 2);
case 'i': case 'i':
return setupI2C(buf + 1); return setupI2C(buf + 1);
case 'm':
return drawimg(buf+1, 0);
case 't':
getimt(buf + 1); return NULL;
case 'D': case 'D':
dumpparams(buf + 1); dumpparams(buf + 1);
return; return NULL;
break; break;
case 'I': case 'I':
buf = omit_spaces(buf + 1); buf = omit_spaces(buf + 1);
@ -270,18 +330,15 @@ const char *parse_cmd(char *buf){
case 'c': case 'c':
mlx_continue(); return OK; mlx_continue(); return OK;
break; break;
case 'd':
return drawimg(buf+1, 1);
break;
case 'i': return setupI2C(NULL); // current settings case 'i': return setupI2C(NULL); // current settings
case 'l':
listactive();
break;
case 'p': case 'p':
mlx_pause(); return OK; mlx_pause(); return OK;
break; break;
case 's': case 's':
mlx_stop(); return OK; mlx_stop(); return OK;
case 't':
return drawimg(buf+1, 0);
break;
case 'C': case 'C':
cartoon = !cartoon; return OK; cartoon = !cartoon; return OK;
case 'G': case 'G':

View File

@ -18,5 +18,7 @@
#pragma once #pragma once
extern const char *Timage, *Sensno;
extern uint8_t cartoon; extern uint8_t cartoon;
char *parse_cmd(char *buf); char *parse_cmd(char *buf);

View File

@ -44,7 +44,7 @@ void linecoding_handler(usb_LineCoding *lc);
// sizes of ringbuffers for outgoing and incoming data // sizes of ringbuffers for outgoing and incoming data
#define RBOUTSZ (1024) #define RBOUTSZ (1024)
#define RBINSZ (1024) #define RBINSZ (128)
#define newline() USB_putbyte('\n') #define newline() USB_putbyte('\n')
#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) #define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0)

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "30" #define BUILD_NUMBER "66"
#define BUILD_DATE "2025-09-23" #define BUILD_DATE "2025-09-24"