diff --git a/F3:F303/MLX90640multi/i2c.c b/F3:F303/MLX90640multi/i2c.c index c0379c1..7407783 100644 --- a/F3:F303/MLX90640multi/i2c.c +++ b/F3:F303/MLX90640multi/i2c.c @@ -44,7 +44,7 @@ static volatile uint16_t dma_remain = 0; // remain bytes of DMA read/write static inline int isI2Cbusy(){ cntr = Tms; do{ - if(Tms - cntr > I2C_TIMEOUT){ U("Timeout, DMA transfer in progress?"); return 1;} + if(Tms - cntr > I2C_TIMEOUT){ USND("Timeout, DMA transfer in progress?"); return 1;} }while(I2Cbusy); return 0; } @@ -329,6 +329,7 @@ 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 || i2cbuflen < 1) return NULL; i2c_got_DMA = 0; i2cbuflen >>= 1; // for hexdump16 - now buffer have uint16_t! diff --git a/F3:F303/MLX90640multi/main.c b/F3:F303/MLX90640multi/main.c index d4ca7cc..f6697cc 100644 --- a/F3:F303/MLX90640multi/main.c +++ b/F3:F303/MLX90640multi/main.c @@ -44,7 +44,8 @@ int main(void){ i2c_setup(I2C_SPEED_100K); USB_setup(); USBPU_ON(); - uint32_t ctr = Tms, Tlastima = 0; + uint32_t ctr = Tms, Tlastima[N_SESORS] = {0}; + mlx_continue(); // init state machine while(1){ if(Tms - ctr > 499){ ctr = Tms; @@ -66,13 +67,13 @@ int main(void){ } } mlx_process(); - if(cartoon){ - uint32_t Tnow = mlx_lastimT(); - if(Tnow != Tlastima){ - fp_t *i = mlx_getimage(&Tnow); - if(i){ - U("Timage="); USND(u2str(Tnow)); drawIma(i); - Tlastima = Tnow; + if(cartoon) for(int i = 0; i < N_SESORS; ++i){ + uint32_t Tnow = mlx_lastimT(i); + if(Tnow != Tlastima[i]){ + fp_t *im = mlx_getimage(i); + if(im){ + 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 06ac044..330aaa2 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 2351fc2..1acf9b2 100644 --- a/F3:F303/MLX90640multi/mlx90640.c +++ b/F3:F303/MLX90640multi/mlx90640.c @@ -264,7 +264,8 @@ int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *pa fp_t *process_image(const MLX90640_params *params, 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<resolEE) / (1<<2); // ONLY DEFAULT! int16_t i16a; fp_t dvdd, dTa, Kgain, pixOS[2]; // values for both subpages // 11.2.2.2. Supply voltage value calculation diff --git a/F3:F303/MLX90640multi/mlx90640.creator.user b/F3:F303/MLX90640multi/mlx90640.creator.user index 5594cc8..87043fd 100644 --- a/F3:F303/MLX90640multi/mlx90640.creator.user +++ b/F3:F303/MLX90640multi/mlx90640.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/MLX90640multi/mlxproc.c b/F3:F303/MLX90640multi/mlxproc.c index 9ac2dc7..4986863 100644 --- a/F3:F303/MLX90640multi/mlxproc.c +++ b/F3:F303/MLX90640multi/mlxproc.c @@ -21,36 +21,44 @@ #include "i2c.h" #include "mlxproc.h" #include "mlx90640_regs.h" -//#include "usb_dev.h" -//#include "strfunc.h" +#include "usb_dev.h" +#include "strfunc.h" extern volatile uint32_t Tms; // current state and state before `stop` called -static mlx_state_t MLX_state = MLX_NOTINIT, MLX_oldstate = MLX_NOTINIT; -static MLX90640_params p; -static int parsrdy = 0; -static uint8_t MLX_address = 0x33 << 1; +static mlx_state_t MLX_state = MLX_RELAX, MLX_oldstate = MLX_RELAX; static int errctr = 0; // errors counter - cleared by mlx_continue -static uint32_t Tlastimage = 0; -static uint8_t resolution = 2; // default: 18bit +static uint32_t Tlastimage[N_SESORS] = {0}; -static int16_t subpage1[REG_IMAGEDATA_LEN]; +// subpages and configs of all sensors +static int16_t imdata[N_SESORS][REG_IMAGEDATA_LEN]; +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]; + +static int sensno = -1; // get current state mlx_state_t mlx_state(){ return MLX_state; } // set address -int mlx_setaddr(uint8_t addr){ +int mlx_setaddr(int n, uint8_t addr){ + if(n < 0 || n > N_SESORS) return 0; if(addr > 0x7f) return 0; - MLX_address = addr << 1; - Tlastimage = Tms; // refresh counter for autoreset I2C in case of error + sens_addresses[n] = addr << 1; + Tlastimage[n] = Tms; // refresh counter for autoreset I2C in case of error return 1; } -// temporary stop -void mlx_stop(){ +// pause state machine and stop +void mlx_pause(){ MLX_oldstate = MLX_state; MLX_state = MLX_RELAX; } +void mlx_stop(){ + MLX_oldstate = MLX_NOTINIT; + MLX_state = MLX_RELAX; +} + // continue processing void mlx_continue(){ errctr = 0; @@ -62,96 +70,145 @@ void mlx_continue(){ //case MLX_NOTINIT: //case MLX_WAITPARAMS: default: + memcpy(sensaddr, sens_addresses, sizeof(sens_addresses)); MLX_state = MLX_NOTINIT; + sensno = -1; break; } } +static int nextsensno(int s){ + if(mlx_nactive() == 0){ + mlx_stop(); + return -1; + } + 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"); + return next; +} + +// count active sensors +int mlx_nactive(){ + int N = 0; + for(int i = 0; i < N_SESORS; ++i) if(sensaddr[i]) ++N; + return N; +} + +/** + * @brief mlx_process - main state machine + * 1. Process conf data for each sensor + * 2. Start image processing and store subpage1 for each sensor + */ void mlx_process(){ + static uint32_t TT = 0; + if(Tms == TT) return; + TT = Tms; // static uint32_t Tlast = 0; static int subpage = 0; + if(MLX_state == MLX_RELAX) return; + if(sensno == -1){ // init + sensno = nextsensno(-1); + if(-1 == sensno) return; // no sensors found + } switch(MLX_state){ case MLX_NOTINIT: // start reading parameters - if(i2c_read_reg16(MLX_address, REG_CALIDATA, MLX_DMA_MAXLEN, 1)){ + if(i2c_read_reg16(sensaddr[sensno], REG_CALIDATA, MLX_DMA_MAXLEN, 1)){ + U(i2str(sensno)); USND(" 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; + if(i2c_dma_haderr()){ MLX_state = MLX_NOTINIT; USND("DMA err");} else{ uint16_t len, *buf = i2c_dma_getbuf(&len); - if(buf){ - if(len != MLX_DMA_MAXLEN) MLX_state = MLX_NOTINIT; - else if(get_parameters(buf, &p)){ - errctr = 0; - MLX_state = MLX_WAITSUBPAGE; // fine! we could wait subpage - parsrdy = 1; - } - } + if(buf) USND("READ"); + else break; + 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"); + int next = nextsensno(sensno); + errctr = 0; + if(next <= sensno) MLX_state = MLX_WAITSUBPAGE; // all configuration read + else MLX_state = MLX_NOTINIT; // read next + sensno = next; + return; } break; case MLX_WAITSUBPAGE: // wait for subpage 1 ready - {uint16_t *got = i2c_read_reg16(MLX_address, REG_STATUS, 1, 0); + {uint16_t *got = i2c_read_reg16(sensaddr[sensno], REG_STATUS, 1, 0); if(got && *got & REG_STATUS_NEWDATA){ if(subpage == (*got & REG_STATUS_SPNO)){ - if(subpage == 0){ subpage = 1; break; } - if(i2c_read_reg16(MLX_address, REG_IMAGEDATA, REG_IMAGEDATA_LEN, 1)){ + errctr = 0; + if(subpage == 0){ // omit zero subpage for each sensor + int next = nextsensno(sensno); + if(next <= sensno) subpage = 1; // all scanned - now wait for page 1 + break; + } + 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)); }else ++errctr; } - }} + }else ++errctr; + } break; case MLX_READSUBPAGE: // wait ends of DMA read and calculate subpage - if(i2c_dma_haderr()) MLX_state = MLX_NOTINIT; + if(i2c_dma_haderr()) MLX_state = MLX_WAITSUBPAGE; else{ uint16_t len, *buf = i2c_dma_getbuf(&len); if(buf){ // U("spread="); USND(u2str(Tms - Tlast)); if(len != REG_IMAGEDATA_LEN){ - MLX_state = MLX_WAITSUBPAGE; - }else{ + ++errctr; + }else{ // fine! we could check next sensor errctr = 0; - memcpy(subpage1, buf, REG_IMAGEDATA_LEN * sizeof(int16_t)); - MLX_state = MLX_WAITSUBPAGE; // fine! we could wait next subpage + memcpy(imdata[sensno], buf, REG_IMAGEDATA_LEN * sizeof(int16_t)); // U("spgot="); USND(u2str(Tms - Tlast)); - Tlastimage = Tms; - // U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms; + Tlastimage[sensno] = Tms; + // U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms; + int next = nextsensno(sensno); + if(next <= sensno) subpage = 0; // roll to start - omit page 0 for all } - subpage = 0; + MLX_state = MLX_WAITSUBPAGE; } } break; default: return; } - if(MLX_state != MLX_RELAX && Tms - Tlastimage > MLX_I2CERR_TMOUT){ i2c_setup(i2c_curspeed); Tlastimage = Tms; } - if(errctr > MLX_MAX_ERRORS) mlx_stop(); + 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 + sensno = nextsensno(sensno); + } } -// get parameters - memcpy to user's -int mlx_getparams(MLX90640_params *pars){ - if(!pars || !parsrdy) return 0; - memcpy(pars, &p, sizeof(p)); +// recalculate parameters +int mlx_getparams(int n, MLX90640_params *pars){ + if(!pars) return 0; + if(!get_parameters(confdata[n], pars)) return 0; return 1; } -uint32_t mlx_lastimT(){ return Tlastimage; } +uint32_t mlx_lastimT(int n){ return Tlastimage[n]; } -fp_t *mlx_getimage(uint32_t *Tgot){ - fp_t *ready_image = process_image(&p, subpage1); +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]); if(!ready_image) return NULL; - if(Tgot) *Tgot = Tlastimage; return ready_image; } -uint8_t mlx_getresolution(){ - return resolution; -} - -int mlx_sethwaddr(uint8_t addr){ +// this function can be run only when state machine is paused/stopped! +// WARNING: `MLX_address` is shifted, `addr` - NOT! +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; @@ -179,13 +236,3 @@ int mlx_sethwaddr(uint8_t addr){ return 1; } -int mlx_setresolution(uint8_t newresol){ - if(newresol > 3) return 0; - uint16_t data[2], *ptr; - if(!(ptr = i2c_read_reg16(MLX_address, REG_CONTROL, 1, 0))) return 0; - data[0] = REG_CONTROL; - data[1] = (*ptr & ~REG_CONTROL_RESMASK) | (newresol << 10); - if(!i2c_write(MLX_address, data, 2)) return 0; - resolution = newresol; - return 1; -} diff --git a/F3:F303/MLX90640multi/mlxproc.h b/F3:F303/MLX90640multi/mlxproc.h index f7a4006..a93032d 100644 --- a/F3:F303/MLX90640multi/mlxproc.h +++ b/F3:F303/MLX90640multi/mlxproc.h @@ -22,6 +22,9 @@ #include "mlx90640.h" +// amount of sensors processing +#define N_SESORS (5) + // maximal errors number to stop processing #define MLX_MAX_ERRORS (11) // if there's no new data by this time - reset bus @@ -35,14 +38,14 @@ typedef enum{ MLX_RELAX // do nothing - pause } mlx_state_t; -int mlx_setaddr(uint8_t addr); +int mlx_setaddr(int n, uint8_t addr); mlx_state_t mlx_state(); +int mlx_nactive(); +void mlx_pause(); void mlx_stop(); void mlx_continue(); void mlx_process(); -int mlx_getparams(MLX90640_params *pars); -fp_t *mlx_getimage(uint32_t *Tgot); -int mlx_setresolution(uint8_t newresol); -uint8_t mlx_getresolution(); -int mlx_sethwaddr(uint8_t addr); -uint32_t mlx_lastimT(); +int mlx_getparams(int sensno, MLX90640_params *pars); +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 6e2ce99..0fd60db 100644 --- a/F3:F303/MLX90640multi/proto.c +++ b/F3:F303/MLX90640multi/proto.c @@ -41,12 +41,12 @@ const char *helpstring = "d - draw image in ASCII\n" "i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n" "p - pause MLX\n" - "r0..3 - change resolution (0 - 16bit, 3 - 19-bit)\n" + "s - stop MLX (and start from zero @ 'c'\n" "t - show temperature map\n" "C - \"cartoon\" mode on/off (show each new image)\n" - "D - dump MLX parameters\n" + "Dn - dump MLX parameters for sensor number n\n" "G - get MLX state\n" - "Ia addr - set device address\n" + "Ia addr [n] - set device address for interactive work or (with n) change address of n'th sensor\n" "Ir reg n - read n words from 16-bit register\n" "Iw words - send words (hex/dec/oct/bin) to I2C\n" "Is - scan I2C bus\n" @@ -78,7 +78,7 @@ TRUE_INLINE const char *chhwaddr(const char *buf){ if(buf && *buf){ const char *nxt = getnum(buf, &a); if(nxt && nxt != buf){ - if(!mlx_sethwaddr(a)) return ERR; + if(!mlx_sethwaddr(I2Caddress, a)) return ERR; }else{ USND("Wrong number"); return ERR; @@ -90,24 +90,16 @@ TRUE_INLINE const char *chhwaddr(const char *buf){ return OK; } -TRUE_INLINE const char *chres(const char *buf){ - uint32_t r; - if(buf && *buf){ - const char *nxt = getnum(buf, &r); - if(nxt && nxt != buf) if(!mlx_setresolution(r)) return ERR; - } - r = mlx_getresolution(); - U("MLXRESOLUTION="); USND(u2str(r)); - return NULL; -} - TRUE_INLINE const char *chaddr(const char *buf){ - uint32_t addr; + uint32_t addr, num; const char *nxt = getnum(buf, &addr); if(nxt && nxt != buf){ if(addr > 0x7f) return ERR; - mlx_setaddr(addr); I2Caddress = (uint8_t) addr << 1; + buf = getnum(nxt, &num); + if(buf && nxt != buf && num < N_SESORS){ + mlx_setaddr(num, addr); + } }else addr = I2Caddress >> 1; U("I2CADDR="); USND(uhex2str(addr)); return NULL; @@ -163,9 +155,13 @@ static void dumpfarr(float *arr){ } } // dump MLX parameters -TRUE_INLINE void dumpparams(){ +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(¶ms)){ U(ERR); return; } + if(!mlx_getparams(N, ¶ms)){ U(ERR); return; } U("\nkVdd="); printi(params.kVdd); U("\nvdd25="); printi(params.vdd25); U("\nKvPTAT="); printfl(params.KvPTAT, 4); @@ -221,17 +217,35 @@ TRUE_INLINE void getst(){ USND(states[s]); } +// `draw`==1 - draw, ==0 - show T map +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){ + 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); + return NULL; + } + } + return ERR; +} + const char *parse_cmd(char *buf){ if(!buf || !*buf) return NULL; - uint32_t u32; if(buf[1]){ switch(*buf){ // "long" commands case 'a': return chhwaddr(buf + 1); case 'i': return setupI2C(buf + 1); - case 'r': - return chres(buf + 1); + case 'D': + dumpparams(buf + 1); + return; + break; case 'I': buf = omit_spaces(buf + 1); switch(*buf){ @@ -257,25 +271,19 @@ const char *parse_cmd(char *buf){ mlx_continue(); return OK; break; case 'd': - {fp_t *i = mlx_getimage(&u32); - if(i){ U("Timage="); USND(u2str(u32)); drawIma(i); } - else U(ERR);} + return drawimg(buf+1, 1); break; case 'i': return setupI2C(NULL); // current settings case 'p': - mlx_stop(); return OK; + mlx_pause(); return OK; break; - case 'r': return chres(NULL); + case 's': + mlx_stop(); return OK; case 't': - {fp_t *i = mlx_getimage(&u32); - if(i){ U("Timage="); USND(u2str(u32)); dumpIma(i); } - else U(ERR);} + return drawimg(buf+1, 0); break; case 'C': cartoon = !cartoon; return OK; - case 'D': - dumpparams(); - break; case 'G': getst(); break; diff --git a/F3:F303/MLX90640multi/version.inc b/F3:F303/MLX90640multi/version.inc index d495d31..b668fbf 100644 --- a/F3:F303/MLX90640multi/version.inc +++ b/F3:F303/MLX90640multi/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "14" -#define BUILD_DATE "2025-09-22" +#define BUILD_NUMBER "30" +#define BUILD_DATE "2025-09-23"