mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 02:35:23 +03:00
It works!
This commit is contained in:
parent
9b0ee87891
commit
dc2897e783
35
F3:F303/MLX90640/Readme.md
Normal file
35
F3:F303/MLX90640/Readme.md
Normal file
@ -0,0 +1,35 @@
|
||||
Works with single MLX90640 sensor
|
||||
=================================
|
||||
|
||||
When attached, udev will create symlink /dev/mlx_sensor0. This is the udev rule:
|
||||
|
||||
```
|
||||
|
||||
ACTION=="add", ENV{USB_IDS}=="0483:5740", ATTRS{interface}=="?*", PROGRAM="/bin/bash -c \"ls /dev | grep $attr{interface} | wc -l \"", SYMLINK+="$attr{interface}%c", MODE="0666", GROUP="tty"
|
||||
|
||||
```
|
||||
|
||||
Protocol:
|
||||
|
||||
```
|
||||
|
||||
aa - change I2C address to a (a should be non-shifted value!!!)
|
||||
c - continue MLX
|
||||
d - draw image in ASCII
|
||||
i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)
|
||||
p - pause MLX
|
||||
r0..3 - change resolution (0 - 16bit, 3 - 19-bit)
|
||||
t - show temperature map
|
||||
C - "cartoon" mode on/off (show each new image)
|
||||
D - dump MLX parameters
|
||||
G - get MLX state
|
||||
Ia addr - set device address
|
||||
Ir reg n - read n words from 16-bit register
|
||||
Iw words - send words (hex/dec/oct/bin) to I2C
|
||||
Is - scan I2C bus
|
||||
T - print current Tms
|
||||
|
||||
|
||||
```
|
||||
|
||||
To call this help just print '?', 'h' or 'H' in terminal.
|
||||
@ -43,7 +43,7 @@ int i2c_busy();
|
||||
|
||||
uint8_t *i2c_read(uint8_t addr, uint16_t nbytes);
|
||||
uint8_t i2c_read_dma16(uint8_t addr, uint16_t nwords);
|
||||
uint16_t *i2c_read_reg16(uint8_t addr, uint16_t reg16, uint16_t nbytes, uint8_t isdma);
|
||||
uint16_t *i2c_read_reg16(uint8_t addr, uint16_t reg16, uint16_t nwords, uint8_t isdma);
|
||||
|
||||
uint8_t i2c_write(uint8_t addr, uint16_t *data, uint8_t nwords);
|
||||
uint8_t i2c_write_dma16(uint8_t addr, uint16_t *data, uint8_t nwords);
|
||||
|
||||
@ -44,7 +44,7 @@ int main(void){
|
||||
i2c_setup(I2C_SPEED_100K);
|
||||
USB_setup();
|
||||
USBPU_ON();
|
||||
uint32_t ctr = Tms;
|
||||
uint32_t ctr = Tms, Tlastima = 0;
|
||||
while(1){
|
||||
if(Tms - ctr > 499){
|
||||
ctr = Tms;
|
||||
@ -66,5 +66,13 @@ int main(void){
|
||||
}
|
||||
}
|
||||
mlx_process();
|
||||
if(cartoon){
|
||||
uint32_t Tnow;
|
||||
fp_t *i = mlx_getimage(&Tnow);
|
||||
if(i && Tnow != Tlastima){
|
||||
U("Timage="); USND(u2str(Tnow)); drawIma(i);
|
||||
Tlastima = Tnow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -24,6 +24,7 @@
|
||||
|
||||
#include "mlx90640.h"
|
||||
#include "mlx90640_regs.h"
|
||||
#include "mlxproc.h"
|
||||
|
||||
// static const char *OK = "OK\n", *OKs = "OK ", *NOTEQ = "NOT equal!\n", *NOTEQi = "NOT equal on index ";
|
||||
|
||||
@ -57,15 +58,17 @@ void drawIma(const fp_t im[MLX_PIXNO]){
|
||||
}
|
||||
}
|
||||
fp_t range = max_val - min_val;
|
||||
U("RANGE="); USND(float2str(range, 3));
|
||||
U("MIN="); USND(float2str(min_val, 3));
|
||||
U("MAX="); USND(float2str(max_val, 3));
|
||||
if(fabsf(range) < 0.001) range = 1.; // solid fill -> blank
|
||||
// Generate and print ASCII art
|
||||
iptr = im;
|
||||
newline();
|
||||
for(int row = 0; row < MLX_H; ++row){
|
||||
for(int col = 0; col < MLX_W; ++col){
|
||||
fp_t normalized = ((*iptr++) - min_val) / range;
|
||||
// Map to character index (0 to 15)
|
||||
int index = (int)(normalized * (GRAY_LEVELS-1) + 0.5);
|
||||
int index = (int)(normalized * GRAY_LEVELS);
|
||||
// Ensure we stay within bounds
|
||||
if(index < 0) index = 0;
|
||||
else if(index > (GRAY_LEVELS-1)) index = (GRAY_LEVELS-1);
|
||||
@ -259,9 +262,7 @@ fp_t *process_subpage(MLX90640_params *params, const int16_t Frame[MLX_DMA_MAXLE
|
||||
#define IMD_VAL(reg) Frame[IMD_IDX(reg)]
|
||||
// 11.2.2.1. Resolution restore
|
||||
// temporary:
|
||||
fp_t resol_corr = (fp_t)(1<<params->resolEE) / (1<<2); // calibrated resol/current resol
|
||||
//fp_t resol_corr = (fp_t)(1<<params->resolEE) / (1<<((reg_control_val[subpageno]&0x0C00)>>10)); // calibrated resol/current resol
|
||||
//DBG("resolEE=%d, resolCur=%d", params->resolEE, ((reg_control_val[subpageno]&0x0C00)>>10));
|
||||
fp_t resol_corr = (fp_t)(1<<params->resolEE) / (1<<mlx_getresolution()); // calibrated resol/current resol
|
||||
// 11.2.2.2. Supply voltage value calculation
|
||||
int16_t i16a = (int16_t)IMD_VAL(REG_IVDDPIX);
|
||||
fp_t dvdd = resol_corr*i16a - params->vdd25;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 17.0.1, 2025-09-20T23:21:28. -->
|
||||
<!-- Written by QtCreator 17.0.1, 2025-09-21T21:27:05. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
@ -59,6 +59,7 @@ typedef struct{
|
||||
// full amount of IMAGE data + EXTRA data (counts of uint16_t!)
|
||||
#define MLX_DMA_MAXLEN (834)
|
||||
|
||||
int ch_resolution(uint8_t newresol);
|
||||
int get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN], MLX90640_params *params);
|
||||
fp_t *process_subpage(MLX90640_params *params, const int16_t Frame[MLX_DMA_MAXLEN], int subpageno, int simpleimage);
|
||||
void dumpIma(const fp_t im[MLX_PIXNO]);
|
||||
|
||||
@ -43,6 +43,8 @@
|
||||
#define REG_CONTROL_SUBPSEL (1<<3)
|
||||
#define REG_CONTROL_DATAHOLD (1<<2)
|
||||
#define REG_CONTROL_SUBPEN (1<<0)
|
||||
#define REG_MLXADDR 0x8010
|
||||
#define REG_MLXADDR_MASK (0xff)
|
||||
|
||||
// default value
|
||||
#define REG_CONTROL_DEFAULT (REG_CONTROL_CHESS|REG_CONTROL_RES18|REG_CONTROL_REFR_2HZ|REG_CONTROL_SUBPEN)
|
||||
|
||||
@ -21,6 +21,10 @@
|
||||
#include "i2c.h"
|
||||
#include "mlxproc.h"
|
||||
#include "mlx90640_regs.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;
|
||||
@ -29,6 +33,8 @@ static int parsrdy = 0;
|
||||
static fp_t *ready_image = NULL; // will be pointer to `mlx_image` after both subpages process
|
||||
static uint8_t MLX_address = 0x33 << 1;
|
||||
static int errctr = 0; // errors counter - cleared by mlx_continue
|
||||
static uint32_t Tlastimage = 0;
|
||||
static uint8_t resolution = 2; // default: 18bit
|
||||
|
||||
// get current state
|
||||
mlx_state_t mlx_state(){ return MLX_state; }
|
||||
@ -36,6 +42,7 @@ mlx_state_t mlx_state(){ return MLX_state; }
|
||||
int mlx_setaddr(uint8_t addr){
|
||||
if(addr > 0x7f) return 0;
|
||||
MLX_address = addr << 1;
|
||||
Tlastimage = Tms; // refresh counter for autoreset I2C in case of error
|
||||
return 1;
|
||||
}
|
||||
// temporary stop
|
||||
@ -60,12 +67,14 @@ void mlx_continue(){
|
||||
}
|
||||
|
||||
void mlx_process(){
|
||||
//static int subpageno = 0; // wait for given subpage
|
||||
static int subpageno = 0; // wait for given subpage
|
||||
// static uint32_t Tlast = 0;
|
||||
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(MLX_address, REG_CALIDATA, MLX_DMA_MAXLEN, 1)){
|
||||
errctr = 0;
|
||||
MLX_state = MLX_WAITPARAMS;
|
||||
else ++errctr;
|
||||
}else ++errctr;
|
||||
break;
|
||||
case MLX_WAITPARAMS: // check DMA ends and calculate parameters
|
||||
if(i2c_dma_haderr()) MLX_state = MLX_NOTINIT;
|
||||
@ -74,6 +83,7 @@ void mlx_process(){
|
||||
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;
|
||||
}
|
||||
@ -81,14 +91,40 @@ void mlx_process(){
|
||||
}
|
||||
break;
|
||||
case MLX_WAITSUBPAGE: // wait for subpage N ready
|
||||
;
|
||||
{uint16_t *got = i2c_read_reg16(MLX_address, REG_STATUS, 1, 0);
|
||||
if(got && *got & REG_STATUS_NEWDATA){
|
||||
if(subpageno == (*got & REG_STATUS_SPNO)){
|
||||
if(i2c_read_reg16(MLX_address, REG_IMAGEDATA, MLX_DMA_MAXLEN, 1)){
|
||||
errctr = 0;
|
||||
MLX_state = MLX_READSUBPAGE;
|
||||
//U("spstart="); USND(u2str(Tms - Tlast));
|
||||
}else ++errctr;
|
||||
}
|
||||
}}
|
||||
break;
|
||||
case MLX_READSUBPAGE: // wait ends of DMA read and calculate subpage
|
||||
;
|
||||
if(i2c_dma_haderr()) MLX_state = MLX_NOTINIT;
|
||||
else{
|
||||
uint16_t len, *buf = i2c_dma_getbuf(&len);
|
||||
if(buf){
|
||||
//U("spread="); USND(u2str(Tms - Tlast));
|
||||
if(len != MLX_DMA_MAXLEN) MLX_state = MLX_WAITSUBPAGE;
|
||||
else if((ready_image = process_subpage(&p, (int16_t*)buf, subpageno, 2))){
|
||||
errctr = 0;
|
||||
MLX_state = MLX_WAITSUBPAGE; // fine! we could wait subpage
|
||||
//U("spgot="); USND(u2str(Tms - Tlast));
|
||||
if(subpageno){ Tlastimage = Tms;
|
||||
/*U("imgot="); USND(u2str(Tms - Tlast)); Tlast = Tms; */
|
||||
}
|
||||
subpageno = !subpageno;
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@ -99,6 +135,32 @@ int mlx_getparams(MLX90640_params *pars){
|
||||
return 1;
|
||||
}
|
||||
|
||||
fp_t *mlx_getimage(){
|
||||
fp_t *mlx_getimage(uint32_t *Tgot){
|
||||
if(Tgot) *Tgot = Tlastimage;
|
||||
return ready_image;
|
||||
}
|
||||
|
||||
uint8_t mlx_getresolution(){
|
||||
return resolution;
|
||||
}
|
||||
|
||||
int mlx_sethwaddr(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;
|
||||
data[0] = REG_MLXADDR;
|
||||
data[1] = (*ptr & ~REG_MLXADDR_MASK) | addr;
|
||||
if(!i2c_write(MLX_address, data, 2)) return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
|
||||
// maximal errors number to stop processing
|
||||
#define MLX_MAX_ERRORS (11)
|
||||
// if there's no new data by this time - reset bus
|
||||
#define MLX_I2CERR_TMOUT (5000)
|
||||
|
||||
typedef enum{
|
||||
MLX_NOTINIT, // just start - need to get parameters
|
||||
@ -39,3 +41,7 @@ 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);
|
||||
|
||||
@ -30,12 +30,20 @@
|
||||
static uint16_t locBuffer[LOCBUFFSZ];
|
||||
static uint8_t I2Caddress = 0x33 << 1;
|
||||
extern volatile uint32_t Tms;
|
||||
uint8_t cartoon = 0; // "cartoon" mode: refresh image each time we get new
|
||||
|
||||
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"
|
||||
"i0..3 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n"
|
||||
"aa - change I2C address to a (a should be non-shifted value!!!)\n"
|
||||
"c - continue MLX\n"
|
||||
"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"
|
||||
"t - show temperature map\n"
|
||||
"C - \"cartoon\" mode on/off (show each new image)\n"
|
||||
"D - dump MLX parameters\n"
|
||||
"G - get MLX state\n"
|
||||
"Ia addr - set device address\n"
|
||||
@ -65,6 +73,26 @@ TRUE_INLINE const char *setupI2C(char *buf){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRUE_INLINE const char *chhwaddr(const char *buf){
|
||||
uint32_t a;
|
||||
if(buf && *buf){
|
||||
const char *nxt = getnum(buf, &a);
|
||||
if(nxt && nxt != buf) if(!mlx_sethwaddr(a)) return ERR;
|
||||
} else return ERR;
|
||||
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;
|
||||
const char *nxt = getnum(buf, &addr);
|
||||
@ -187,10 +215,15 @@ TRUE_INLINE void getst(){
|
||||
|
||||
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 'I':
|
||||
buf = omit_spaces(buf + 1);
|
||||
switch(*buf){
|
||||
@ -212,7 +245,26 @@ const char *parse_cmd(char *buf){
|
||||
}
|
||||
}
|
||||
switch(*buf){ // "short" (one letter) commands
|
||||
case 'c':
|
||||
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);}
|
||||
break;
|
||||
case 'i': return setupI2C(NULL); // current settings
|
||||
case 'p':
|
||||
mlx_stop(); return OK;
|
||||
break;
|
||||
case 'r': return chres(NULL);
|
||||
case 't':
|
||||
{fp_t *i = mlx_getimage(&u32);
|
||||
if(i){ U("Timage="); USND(u2str(u32)); dumpIma(i); }
|
||||
else U(ERR);}
|
||||
break;
|
||||
case 'C':
|
||||
cartoon = !cartoon; return OK;
|
||||
case 'D':
|
||||
dumpparams();
|
||||
break;
|
||||
|
||||
@ -18,5 +18,5 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
extern uint8_t cartoon;
|
||||
char *parse_cmd(char *buf);
|
||||
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "22"
|
||||
#define BUILD_DATE "2025-09-20"
|
||||
#define BUILD_NUMBER "38"
|
||||
#define BUILD_DATE "2025-09-21"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user