diff --git a/F3:F303/MLX90640multi/i2c.c b/F3:F303/MLX90640multi/i2c.c index 7407783..32a115a 100644 --- a/F3:F303/MLX90640multi/i2c.c +++ b/F3:F303/MLX90640multi/i2c.c @@ -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 i2cbuflen = 0; // buffer for DMA rx and its len 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 #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 DMA1_Channel7->CCR = DMARXCCR | DMA_CCR_EN; // init DMA before START sequence if(!i2c_startr(addr, nbytes, 1)) return 0; + dmaaddr = addr; dma_remain = nbytes > 255 ? nbytes - 255 : 0; // remainder after first read finish I2Cbusy = 1; return 1; @@ -329,7 +331,8 @@ void i2c_bufdudump(){ // get DMA buffer with conversion to little-endian (if transfer was for 16-bit) 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; i2c_got_DMA = 0; 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; ch->CNDTR = len; if(rx){ - if(!i2c_startr(0, dma_remain, 0)){ + if(!i2c_startr(dmaaddr, dma_remain, 0)){ goterr = 1; goto ret; } ch->CMAR += 255; diff --git a/F3:F303/MLX90640multi/main.c b/F3:F303/MLX90640multi/main.c index f6697cc..52d1b9a 100644 --- a/F3:F303/MLX90640multi/main.c +++ b/F3:F303/MLX90640multi/main.c @@ -41,7 +41,7 @@ int main(void){ } USBPU_OFF(); hw_setup(); - i2c_setup(I2C_SPEED_100K); + i2c_setup(I2C_SPEED_400K); USB_setup(); USBPU_ON(); uint32_t ctr = Tms, Tlastima[N_SESORS] = {0}; @@ -49,6 +49,7 @@ int main(void){ while(1){ if(Tms - ctr > 499){ ctr = Tms; + if(!mlx_nactive()){ mlx_stop(); mlx_continue(); } pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 } int l = USB_receivestr(inbuff, MAXSTRLEN); @@ -72,7 +73,8 @@ int main(void){ if(Tnow != Tlastima[i]){ fp_t *im = mlx_getimage(i); if(im){ - U("Timage="); USND(u2str(Tnow)); drawIma(im); + U(Sensno); USND(i2str(i)); + U(Timage); USND(u2str(Tnow)); drawIma(im); Tlastima[i] = Tnow; } } diff --git a/F3:F303/MLX90640multi/mlx90640.bin b/F3:F303/MLX90640multi/mlx90640.bin index 330aaa2..2145dfa 100755 Binary files a/F3:F303/MLX90640multi/mlx90640.bin and b/F3:F303/MLX90640multi/mlx90640.bin differ diff --git a/F3:F303/MLX90640multi/mlx90640.c b/F3:F303/MLX90640multi/mlx90640.c index 1acf9b2..365dc50 100644 --- a/F3:F303/MLX90640multi/mlx90640.c +++ b/F3:F303/MLX90640multi/mlx90640.c @@ -31,7 +31,10 @@ // tolerance of floating point comparison #define FP_TOLERANCE (1e-3) +// 3072 bytes 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]){ 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 -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)] int8_t i8; int16_t i16; uint16_t *pu16; uint16_t val = CREG_VAL(REG_VDD); i8 = (int8_t) (val >> 8); - params->kVdd = i8 * 32; // keep sign - if(params->kVdd == 0) return FALSE; + params.kVdd = i8 * 32; // keep sign + if(params.kVdd == 0){USND("kvdd=0"); return NULL;} i16 = val & 0xFF; - params->vdd25 = ((i16 - 0x100) * 32) - (1<<13); + params.vdd25 = ((i16 - 0x100) * 32) - (1<<13); val = CREG_VAL(REG_KVTPTAT); i16 = (val & 0xFC00) >> 10; if(i16 > 0x1F) i16 -= 0x40; - params->KvPTAT = (fp_t)i16 / (1<<12); + params.KvPTAT = (fp_t)i16 / (1<<12); i16 = (val & 0x03FF); if(i16 > 0x1FF) i16 -= 0x400; - params->KtPTAT = (fp_t)i16 / 8.; - params->vPTAT25 = (int16_t) CREG_VAL(REG_PTAT); + params.KtPTAT = (fp_t)i16 / 8.; + params.vPTAT25 = (int16_t) CREG_VAL(REG_PTAT); val = CREG_VAL(REG_APTATOCCS) >> 12; - params->alphaPTAT = val / 4. + 8.; - params->gainEE = (int16_t)CREG_VAL(REG_GAIN); - if(params->gainEE == 0) return FALSE; + params.alphaPTAT = val / 4. + 8.; + params.gainEE = (int16_t)CREG_VAL(REG_GAIN); + if(params.gainEE == 0){USND("gainee=0"); return NULL;} int8_t occRow[MLX_H]; int8_t occColumn[MLX_W]; 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) val = CREG_VAL(REG_KTAVSCALE); 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<alpha; + fp_t *a = params.alpha; uint32_t diva32 = 1 << (val >> 12); fp_t diva = (fp_t)(diva32); 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), accRemScale = 1<<(val & 0x0f); pu16 = (uint16_t*)&CREG_VAL(REG_OFFAK1); - fp_t *kta = params->kta, *offset = params->offset; - uint8_t *ol = params->outliers; + fp_t *kta = params.kta, *offset = params.offset; + uint8_t *ol = params.outliers; for(int row = 0; row < MLX_H; ++row){ int idx = (row&1)<<1; 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 i16 = val & 0x0F; if(i16 > 0x07) i16 -= 0x10; 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); - params->cpOffset[0] = (val & 0x03ff); - if(params->cpOffset[0] > 0x1ff) params->cpOffset[0] -= 0x400; - params->cpOffset[1] = val >> 10; - if(params->cpOffset[1] > 0x1f) params->cpOffset[1] -= 0x40; - params->cpOffset[1] += params->cpOffset[0]; + params.cpOffset[0] = (val & 0x03ff); + if(params.cpOffset[0] > 0x1ff) params.cpOffset[0] -= 0x400; + params.cpOffset[1] = val >> 10; + if(params.cpOffset[1] > 0x1f) params.cpOffset[1] -= 0x40; + params.cpOffset[1] += params.cpOffset[0]; val = ((CREG_VAL(REG_KTAVSCALE) & 0xF0) >> 4) + 8; i8 = (int8_t)(CREG_VAL(REG_KVTACP) & 0xFF); - params->cpKta = (fp_t)i8 / (1<> 8; i16 = CREG_VAL(REG_KVTACP) >> 8; if(i16 > 0x7F) i16 -= 0x100; - params->cpKv = (fp_t)i16 / (1< 0x7F) i16 -= 0x100; - params->tgc = (fp_t)i16; - params->tgc /= 32.; + params.tgc = (fp_t)i16; + params.tgc /= 32.; val = (CREG_VAL(REG_SCALEACC)>>12); // alpha_scale_CP i16 = CREG_VAL(REG_ALPHA)>>10; // cp_P1_P0_ratio if(i16 > 0x1F) i16 -= 0x40; div = (fp_t)(1<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); - 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); - params->KsTa = (fp_t)i8/(1<<13); + params.KsTa = (fp_t)i8/(1<<13); div = 1<<((CREG_VAL(REG_CT34) & 0x0F) + 8); // kstoscale val = CREG_VAL(REG_KSTO12); i8 = (int8_t)(val & 0xFF); - params->KsTo[0] = i8 / div; + params.KsTo[0] = i8 / div; i8 = (int8_t)(val >> 8); - params->KsTo[1] = i8 / div; + params.KsTo[1] = i8 / div; val = CREG_VAL(REG_KSTO34); i8 = (int8_t)(val & 0xFF); - params->KsTo[2] = i8 / div; + params.KsTo[2] = i8 / div; 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 - 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); mul = ((val & 0x3000)>>12)*10.; // step - 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[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 // alphacorr for each range: 11.1.11 - params->alphacorr[0] = 1./(1. + params->KsTo[0] * 40.); - params->alphacorr[1] = 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->resolEE = (uint8_t)((CREG_VAL(REG_KTAVSCALE) & 0x3000) >> 12); + params.alphacorr[0] = 1./(1. + params.KsTo[0] * 40.); + params.alphacorr[1] = 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.resolEE = (uint8_t)((CREG_VAL(REG_KTAVSCALE) & 0x3000) >> 12); // Don't forget to check 'outlier' flags for wide purpose - return TRUE; + return ¶ms; #undef CREG_VAL } @@ -261,37 +264,37 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa * @param subpageno * @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)] // 11.2.2.1. Resolution restore - //fp_t resol_corr = (fp_t)(1<resolEE) / (1<resolEE) / (1<<2); // ONLY DEFAULT! + //fp_t resol_corr = (fp_t)(1< - + EnvironmentId diff --git a/F3:F303/MLX90640multi/mlx90640.h b/F3:F303/MLX90640multi/mlx90640.h index 1db012e..da60814 100644 --- a/F3:F303/MLX90640multi/mlx90640.h +++ b/F3:F303/MLX90640multi/mlx90640.h @@ -59,7 +59,7 @@ typedef struct{ } MLX90640_params; int ch_resolution(uint8_t newresol); -int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params); -fp_t *process_image(const MLX90640_params *params, const int16_t subpage1[REG_IMAGEDATA_LEN]); +MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]); +fp_t *process_image(const int16_t subpage1[REG_IMAGEDATA_LEN]); void dumpIma(const fp_t im[MLX_PIXNO]); void drawIma(const fp_t im[MLX_PIXNO]); diff --git a/F3:F303/MLX90640multi/mlxproc.c b/F3:F303/MLX90640multi/mlxproc.c index 4986863..8c0719a 100644 --- a/F3:F303/MLX90640multi/mlxproc.c +++ b/F3:F303/MLX90640multi/mlxproc.c @@ -21,8 +21,20 @@ #include "i2c.h" #include "mlxproc.h" #include "mlx90640_regs.h" + +//#define DEBUGPROC + +#ifdef DEBUGPROC #include "usb_dev.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; @@ -32,11 +44,19 @@ static int errctr = 0; // errors counter - cleared by mlx_continue static uint32_t Tlastimage[N_SESORS] = {0}; // subpages and configs of all sensors +// 8320 bytes: static int16_t imdata[N_SESORS][REG_IMAGEDATA_LEN]; +// 8340 bytes: 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 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; // get current state @@ -54,12 +74,14 @@ void mlx_pause(){ MLX_oldstate = MLX_state; MLX_state = MLX_RELAX; } +// TODO: add here power management void mlx_stop(){ MLX_oldstate = MLX_NOTINIT; MLX_state = MLX_RELAX; } // continue processing +// TODO: add here power management void mlx_continue(){ errctr = 0; switch(MLX_oldstate){ @@ -70,6 +92,7 @@ void mlx_continue(){ //case MLX_NOTINIT: //case MLX_WAITPARAMS: default: + i2c_setup(i2c_curspeed); // restart I2C (what if there was errors?) memcpy(sensaddr, sens_addresses, sizeof(sens_addresses)); MLX_state = MLX_NOTINIT; sensno = -1; @@ -85,7 +108,7 @@ static int nextsensno(int s){ int next = s + 1; for(; next < N_SESORS; ++next) if(sensaddr[next]) break; 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; } @@ -115,20 +138,20 @@ void mlx_process(){ switch(MLX_state){ case MLX_NOTINIT: // start reading parameters 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; MLX_state = MLX_WAITPARAMS; }else ++errctr; break; 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{ uint16_t len, *buf = i2c_dma_getbuf(&len); - if(buf) USND("READ"); - else break; + if(!buf) break; + DN("READ"); if(len != MLX_DMA_MAXLEN){ MLX_state = MLX_NOTINIT; break; } 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); errctr = 0; if(next <= sensno) MLX_state = MLX_WAITSUBPAGE; // all configuration read @@ -143,14 +166,20 @@ void mlx_process(){ if(subpage == (*got & REG_STATUS_SPNO)){ errctr = 0; if(subpage == 0){ // omit zero subpage for each sensor + DN("omit 0 -> next sens"); 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; } + D(i2str(sensno)); DN(" - ask for image"); if(i2c_read_reg16(sensaddr[sensno], REG_IMAGEDATA, REG_IMAGEDATA_LEN, 1)){ errctr = 0; 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; @@ -161,17 +190,21 @@ void mlx_process(){ else{ uint16_t len, *buf = i2c_dma_getbuf(&len); if(buf){ - // U("spread="); USND(u2str(Tms - Tlast)); + // D("spread="); DN(u2str(Tms - Tlast)); if(len != REG_IMAGEDATA_LEN){ ++errctr; }else{ // fine! we could check next sensor errctr = 0; 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; - // U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms; + // D("imgot="); DN(u2str(Tms - Tlast)); Tlast = Tms; 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; } @@ -180,7 +213,7 @@ void mlx_process(){ default: 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){ errctr = 0; sensaddr[sensno] = 0; // throw out this value @@ -189,19 +222,18 @@ void mlx_process(){ } // recalculate parameters -int mlx_getparams(int n, MLX90640_params *pars){ - if(!pars) return 0; - if(!get_parameters(confdata[n], pars)) return 0; - return 1; +MLX90640_params *mlx_getparams(int n){ + MLX90640_params *p = get_parameters(confdata[n]); + return p; } uint32_t mlx_lastimT(int n){ return Tlastimage[n]; } fp_t *mlx_getimage(int n){ if(n < 0 || n >= N_SESORS || !sensaddr[n]) return NULL; - MLX90640_params p; - if(!get_parameters(confdata[n], &p)) return NULL; - fp_t *ready_image = process_image(&p, imdata[n]); + MLX90640_params *p = get_parameters(confdata[n]); + if(!p) return NULL; + fp_t *ready_image = process_image(imdata[n]); if(!ready_image) return NULL; return ready_image; } @@ -212,7 +244,7 @@ int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr){ if(addr > 0x7f) return 0; uint16_t data[2], *ptr; 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; uint16_t oldreg = *ptr; 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[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; while(Tms - Told < 10); 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; return 1; } diff --git a/F3:F303/MLX90640multi/mlxproc.h b/F3:F303/MLX90640multi/mlxproc.h index a93032d..c67e759 100644 --- a/F3:F303/MLX90640multi/mlxproc.h +++ b/F3:F303/MLX90640multi/mlxproc.h @@ -41,11 +41,12 @@ typedef enum{ int mlx_setaddr(int n, uint8_t addr); mlx_state_t mlx_state(); int mlx_nactive(); +uint8_t *mlx_activeids(); void mlx_pause(); void mlx_stop(); void mlx_continue(); void mlx_process(); -int mlx_getparams(int sensno, MLX90640_params *pars); +MLX90640_params *mlx_getparams(int sensno); fp_t *mlx_getimage(int sensno); int mlx_sethwaddr(uint8_t MLX_address, uint8_t addr); uint32_t mlx_lastimT(int sensno); diff --git a/F3:F303/MLX90640multi/proto.c b/F3:F303/MLX90640multi/proto.c index 0fd60db..ce42124 100644 --- a/F3:F303/MLX90640multi/proto.c +++ b/F3:F303/MLX90640multi/proto.c @@ -32,17 +32,24 @@ static uint8_t I2Caddress = 0x33 << 1; extern volatile uint32_t Tms; 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"; const char *helpstring = "https://github.com/eddyem/stm32samples/tree/master/F3:F303/mlx90640 build#" BUILD_NUMBER " @ " BUILD_DATE "\n" " management of single IR bolometer MLX90640\n" "aa - change I2C address to a (a should be non-shifted value!!!)\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" + "l - list active sensors IDs\n" + "tn - show temperature map of nth image\n" "p - pause MLX\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" "Dn - dump MLX parameters for sensor number n\n" "G - get MLX state\n" @@ -90,16 +97,23 @@ TRUE_INLINE const char *chhwaddr(const char *buf){ 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){ - uint32_t addr, num; + uint32_t addr; const char *nxt = getnum(buf, &addr); if(nxt && nxt != buf){ if(addr > 0x7f) return ERR; I2Caddress = (uint8_t) addr << 1; - buf = getnum(nxt, &num); - if(buf && nxt != buf && num < N_SESORS){ - mlx_setaddr(num, addr); - } + int n = getsensnum(nxt); + if(n > -1) mlx_setaddr(n, addr); }else addr = I2Caddress >> 1; U("I2CADDR="); USND(uhex2str(addr)); return NULL; @@ -156,21 +170,20 @@ static void dumpfarr(float *arr){ } // dump MLX parameters TRUE_INLINE void dumpparams(const char *buf){ - uint32_t N = 0; - const char *nxt = getnum(buf, &N); - U(u2str(N)); USND("sn"); - if(!nxt || buf == nxt || N > N_SESORS){ U(ERR); return; } - MLX90640_params params; - if(!mlx_getparams(N, ¶ms)){ U(ERR); return; } - U("\nkVdd="); printi(params.kVdd); - U("\nvdd25="); printi(params.vdd25); - U("\nKvPTAT="); printfl(params.KvPTAT, 4); - U("\nKtPTAT="); printfl(params.KtPTAT, 4); - U("\nvPTAT25="); printi(params.vPTAT25); - U("\nalphaPTAT="); printfl(params.alphaPTAT, 2); - U("\ngainEE="); printi(params.gainEE); + int N = getsensnum(buf); + if(N < 0){ U(ERR); return; } + MLX90640_params *params = mlx_getparams(N); + if(!params){ U(ERR); return; } + U(Sensno); USND(i2str(N)); + U("\nkVdd="); printi(params->kVdd); + U("\nvdd25="); printi(params->vdd25); + U("\nKvPTAT="); printfl(params->KvPTAT, 4); + U("\nKtPTAT="); printfl(params->KtPTAT, 4); + U("\nvPTAT25="); printi(params->vPTAT25); + U("\nalphaPTAT="); printfl(params->alphaPTAT, 2); + U("\ngainEE="); printi(params->gainEE); U("\nPixel offset parameters:\n"); - float *offset = params.offset; + float *offset = params->offset; for(int row = 0; row < 24; ++row){ for(int col = 0; col < 32; ++col){ printfl(*offset++, 2); USB_putbyte(' '); @@ -178,28 +191,28 @@ TRUE_INLINE void dumpparams(const char *buf){ newline(); } U("K_talpha:\n"); - dumpfarr(params.kta); + dumpfarr(params->kta); U("Kv: "); for(int i = 0; i < 4; ++i){ - printfl(params.kv[i], 2); USB_putbyte(' '); + printfl(params->kv[i], 2); USB_putbyte(' '); } U("\ncpOffset="); - printi(params.cpOffset[0]); U(", "); printi(params.cpOffset[1]); - U("\ncpKta="); printfl(params.cpKta, 2); - U("\ncpKv="); printfl(params.cpKv, 2); - U("\ntgc="); printfl(params.tgc, 2); - U("\ncpALpha="); printfl(params.cpAlpha[0], 2); - U(", "); printfl(params.cpAlpha[1], 2); - U("\nKsTa="); printfl(params.KsTa, 2); + printi(params->cpOffset[0]); U(", "); printi(params->cpOffset[1]); + U("\ncpKta="); printfl(params->cpKta, 2); + U("\ncpKv="); printfl(params->cpKv, 2); + U("\ntgc="); printfl(params->tgc, 2); + U("\ncpALpha="); printfl(params->cpAlpha[0], 2); + U(", "); printfl(params->cpAlpha[1], 2); + U("\nKsTa="); printfl(params->KsTa, 2); U("\nAlpha:\n"); - dumpfarr(params.alpha); - U("\nCT3="); printfl(params.CT[1], 2); - U("\nCT4="); printfl(params.CT[2], 2); + dumpfarr(params->alpha); + U("\nCT3="); printfl(params->CT[1], 2); + U("\nCT4="); printfl(params->CT[2], 2); for(int i = 0; i < 4; ++i){ 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('='); - printfl(params.alphacorr[i], 2); + printfl(params->alphacorr[i], 2); } newline(); } @@ -217,34 +230,81 @@ TRUE_INLINE void getst(){ 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){ - uint32_t sensno; - const char *nxt = getnum(buf, &sensno); - if(nxt && nxt != buf && sensno < N_SESORS){ + int sensno = getsensnum(buf); + if(sensno > -1){ uint32_t T = mlx_lastimT(sensno); fp_t *img = mlx_getimage(sensno); if(img){ - U("Timage="); USND(u2str(T)); - if(draw) drawIma(img); - else dumpIma(img); + U(Sensno); USND(u2str(sensno)); + U(Timage); USND(u2str(T)); + 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 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){ if(!buf || !*buf) return NULL; if(buf[1]){ switch(*buf){ // "long" commands case 'a': return chhwaddr(buf + 1); + case 'd': + return drawimg(buf+1, 1); + case 'g': + return drawimg(buf+1, 2); case 'i': return setupI2C(buf + 1); + case 'm': + return drawimg(buf+1, 0); + case 't': + getimt(buf + 1); return NULL; case 'D': dumpparams(buf + 1); - return; + return NULL; break; case 'I': buf = omit_spaces(buf + 1); @@ -270,18 +330,15 @@ const char *parse_cmd(char *buf){ case 'c': mlx_continue(); return OK; break; - case 'd': - return drawimg(buf+1, 1); - break; case 'i': return setupI2C(NULL); // current settings + case 'l': + listactive(); + break; case 'p': mlx_pause(); return OK; break; case 's': mlx_stop(); return OK; - case 't': - return drawimg(buf+1, 0); - break; case 'C': cartoon = !cartoon; return OK; case 'G': diff --git a/F3:F303/MLX90640multi/proto.h b/F3:F303/MLX90640multi/proto.h index 1d48512..f3afdb7 100644 --- a/F3:F303/MLX90640multi/proto.h +++ b/F3:F303/MLX90640multi/proto.h @@ -18,5 +18,7 @@ #pragma once +extern const char *Timage, *Sensno; + extern uint8_t cartoon; char *parse_cmd(char *buf); diff --git a/F3:F303/MLX90640multi/usb_dev.h b/F3:F303/MLX90640multi/usb_dev.h index f787b12..b8a0808 100644 --- a/F3:F303/MLX90640multi/usb_dev.h +++ b/F3:F303/MLX90640multi/usb_dev.h @@ -44,7 +44,7 @@ void linecoding_handler(usb_LineCoding *lc); // sizes of ringbuffers for outgoing and incoming data #define RBOUTSZ (1024) -#define RBINSZ (1024) +#define RBINSZ (128) #define newline() USB_putbyte('\n') #define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) diff --git a/F3:F303/MLX90640multi/version.inc b/F3:F303/MLX90640multi/version.inc index b668fbf..d50b410 100644 --- a/F3:F303/MLX90640multi/version.inc +++ b/F3:F303/MLX90640multi/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "30" -#define BUILD_DATE "2025-09-23" +#define BUILD_NUMBER "65" +#define BUILD_DATE "2025-09-24"