Compare commits

..

No commits in common. "96d0b3987aec863d7a1b1941c1e7a0693081e26f" and "02c6bd124f16bb9a401216b9064b88deacdd0e7c" have entirely different histories.

12 changed files with 173 additions and 250 deletions

View File

@ -33,7 +33,6 @@ 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)
@ -272,7 +271,6 @@ 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;
@ -331,8 +329,7 @@ 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!
@ -361,7 +358,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(dmaaddr, dma_remain, 0)){ if(!i2c_startr(0, 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_400K); i2c_setup(I2C_SPEED_100K);
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,7 +49,6 @@ 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);
@ -73,8 +72,7 @@ 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(Sensno); USND(i2str(i)); U("Timage="); USND(u2str(Tnow)); drawIma(im);
U(Timage); USND(u2str(Tnow)); drawIma(im);
Tlastima[i] = Tnow; Tlastima[i] = Tnow;
} }
} }

Binary file not shown.

View File

@ -31,10 +31,7 @@
// 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){
@ -103,29 +100,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
MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params){
#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){USND("kvdd=0"); return NULL;} if(params->kVdd == 0) return FALSE;
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){USND("gainee=0"); return NULL;} if(params->gainEE == 0) return FALSE;
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));
@ -153,11 +150,11 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
// 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){USND("scale1/2=0"); return NULL;} if(scale1 == 0 || scale2 == 0) return FALSE;
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
@ -165,8 +162,8 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
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){
@ -200,59 +197,59 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
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 &params; return TRUE;
#undef CREG_VAL #undef CREG_VAL
} }
@ -264,37 +261,37 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){
* @param subpageno * @param subpageno
* @return * @return
*/ */
fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]){ fp_t *process_image(const MLX90640_params *params, 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){
@ -303,34 +300,34 @@ fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]){
// 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;
@ -340,3 +337,26 @@ fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]){
#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-24T23:35:56. --> <!-- Written by QtCreator 17.0.1, 2025-09-23T22:23:26. -->
<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);
MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]); int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params);
fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]); fp_t *process_image(const MLX90640_params *params, 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,20 +21,8 @@
#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;
@ -44,19 +32,11 @@ 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
@ -74,14 +54,12 @@ 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){
@ -92,7 +70,6 @@ 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;
@ -108,7 +85,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
D(i2str(next)); DB('('); D(i2str(s)); DB(')'); DN(" - new sensor number"); U(i2str(next)); USND(" - new sensor number");
return next; return next;
} }
@ -138,20 +115,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)){
D(i2str(sensno)); DN(" wait conf"); U(i2str(sensno)); USND(" 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; DN("DMA err");} if(i2c_dma_haderr()){ MLX_state = MLX_NOTINIT; USND("DMA err");}
else{ else{
uint16_t len, *buf = i2c_dma_getbuf(&len); uint16_t len, *buf = i2c_dma_getbuf(&len);
if(!buf) break; if(buf) USND("READ");
DN("READ"); else break;
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));
D(i2str(sensno)); DN(" got conf"); U(i2str(sensno)); USND(" 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
@ -166,20 +143,14 @@ 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){ // all scanned - now wait for page 1 if(next <= sensno) subpage = 1; // 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;
// D("spstart"); DB('0'+subpage); DB('='); DN(u2str(Tms - Tlast)); // U("spstart"); USB_putbyte('0'+subpage); USB_putbyte('='); USND(u2str(Tms - Tlast));
}else ++errctr; }else ++errctr;
} }
}else ++errctr; }else ++errctr;
@ -190,21 +161,17 @@ 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){
// D("spread="); DN(u2str(Tms - Tlast)); // U("spread="); USND(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));
// D("spgot="); DN(u2str(Tms - Tlast)); // U("spgot="); USND(u2str(Tms - Tlast));
Tlastimage[sensno] = Tms; Tlastimage[sensno] = Tms;
// D("imgot="); DN(u2str(Tms - Tlast)); Tlast = Tms; // U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms;
int next = nextsensno(sensno); int next = nextsensno(sensno);
if(next <= sensno){ if(next <= sensno) subpage = 0; // roll to start - omit page 0 for all
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;
} }
@ -213,7 +180,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
@ -222,18 +189,19 @@ void mlx_process(){
} }
// recalculate parameters // recalculate parameters
MLX90640_params *mlx_getparams(int n){ int mlx_getparams(int n, MLX90640_params *pars){
MLX90640_params *p = get_parameters(confdata[n]); if(!pars) return 0;
return p; if(!get_parameters(confdata[n], pars)) return 0;
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 = get_parameters(confdata[n]); MLX90640_params p;
if(!p) return NULL; if(!get_parameters(confdata[n], &p)) return NULL;
fp_t *ready_image = process_image(imdata[n]); fp_t *ready_image = process_image(&p, imdata[n]);
if(!ready_image) return NULL; if(!ready_image) return NULL;
return ready_image; return ready_image;
} }
@ -244,7 +212,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;
//D("Old address: "); DN(uhex2str(*ptr)); //U("Old address: "); USND(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
@ -259,11 +227,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;
//D("Write address: "); D(uhex2str(data[0])); D(", "); DN(uhex2str(data[1])); //U("Write address: "); U(uhex2str(data[0])); U(", "); USND(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;
//D("Got address: "); DN(uhex2str(*ptr)); //U("Got address: "); USND(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,12 +41,11 @@ 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();
MLX90640_params *mlx_getparams(int sensno); int mlx_getparams(int sensno, MLX90640_params *pars);
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,24 +32,17 @@ 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/MLX90640multi build#" BUILD_NUMBER " @ " BUILD_DATE "\n" "https://github.com/eddyem/stm32samples/tree/master/F3:F303/mlx90640 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"
"dn - draw nth image in ASCII\n" "d - draw 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"
"tn - show nth image aquisition time\n" "t - show temperature map\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"
@ -97,23 +90,16 @@ 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; uint32_t addr, num;
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;
int n = getsensnum(nxt); buf = getnum(nxt, &num);
if(n > -1) mlx_setaddr(n, addr); if(buf && nxt != buf && num < N_SESORS){
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;
@ -170,20 +156,21 @@ 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){
int N = getsensnum(buf); uint32_t N = 0;
if(N < 0){ U(ERR); return; } const char *nxt = getnum(buf, &N);
MLX90640_params *params = mlx_getparams(N); U(u2str(N)); USND("sn");
if(!params){ U(ERR); return; } if(!nxt || buf == nxt || N > N_SESORS){ U(ERR); return; }
U(Sensno); USND(i2str(N)); MLX90640_params params;
U("\nkVdd="); printi(params->kVdd); if(!mlx_getparams(N, &params)){ U(ERR); return; }
U("\nvdd25="); printi(params->vdd25); U("\nkVdd="); printi(params.kVdd);
U("\nKvPTAT="); printfl(params->KvPTAT, 4); U("\nvdd25="); printi(params.vdd25);
U("\nKtPTAT="); printfl(params->KtPTAT, 4); U("\nKvPTAT="); printfl(params.KvPTAT, 4);
U("\nvPTAT25="); printi(params->vPTAT25); U("\nKtPTAT="); printfl(params.KtPTAT, 4);
U("\nalphaPTAT="); printfl(params->alphaPTAT, 2); U("\nvPTAT25="); printi(params.vPTAT25);
U("\ngainEE="); printi(params->gainEE); U("\nalphaPTAT="); printfl(params.alphaPTAT, 2);
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(' ');
@ -191,28 +178,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();
} }
@ -230,81 +217,34 @@ TRUE_INLINE void getst(){
USND(states[s]); USND(states[s]);
} }
// `draw`==1 - draw, ==0 - show T map, 2 - send raw float array with prefix 'SENSNO=x\nTimage=y\n' and postfix "ENDIMAGE\n" // `draw`==1 - draw, ==0 - show T map
static const char *drawimg(const char *buf, int draw){ static const char *drawimg(const char *buf, int draw){
int sensno = getsensnum(buf); uint32_t sensno;
if(sensno > -1){ const char *nxt = getnum(buf, &sensno);
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(Sensno); USND(u2str(sensno)); U("Timage="); USND(u2str(T));
U(Timage); USND(u2str(T)); if(draw) drawIma(img);
switch(draw){ else dumpIma(img);
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 NULL; return;
break; break;
case 'I': case 'I':
buf = omit_spaces(buf + 1); buf = omit_spaces(buf + 1);
@ -330,15 +270,18 @@ const char *parse_cmd(char *buf){
case 'c': case 'c':
mlx_continue(); return OK; mlx_continue(); return OK;
break; break;
case 'i': return setupI2C(NULL); // current settings case 'd':
case 'l': return drawimg(buf+1, 1);
listactive();
break; break;
case 'i': return setupI2C(NULL); // current settings
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,7 +18,5 @@
#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 (128) #define RBINSZ (1024)
#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 "66" #define BUILD_NUMBER "30"
#define BUILD_DATE "2025-09-24" #define BUILD_DATE "2025-09-23"