From 0eb18e89b8a788a8fba7843dbe63e306c7bc55a1 Mon Sep 17 00:00:00 2001 From: pvvx Date: Wed, 27 Sep 2017 02:22:56 +0300 Subject: [PATCH] add sample mlx90614 --- ExampleHTM/dygraph/ws_test_mlx90614.html | 67 ++++ project.mk | 10 +- project/src/MLX90614/MLX90614.c | 421 +++++++++++++++++++++++ project/src/web/web_int_callbacks.c | 10 + project/src/web/web_websocket.c | 1 + 5 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 ExampleHTM/dygraph/ws_test_mlx90614.html create mode 100644 project/src/MLX90614/MLX90614.c diff --git a/ExampleHTM/dygraph/ws_test_mlx90614.html b/ExampleHTM/dygraph/ws_test_mlx90614.html new file mode 100644 index 0000000..9d477e1 --- /dev/null +++ b/ExampleHTM/dygraph/ws_test_mlx90614.html @@ -0,0 +1,67 @@ + + + + + Get data MLX90614 + + + + +

Read regs Ta & Tobj1 MLX90614

+
+ + + diff --git a/project.mk b/project.mk index e87d6d8..edc0215 100644 --- a/project.mk +++ b/project.mk @@ -1,7 +1,8 @@ #============================================= # SDK CONFIG #============================================= -WEB_INA219_DRV = 1 +#WEB_INA219_DRV = 1 +WEB_MLX90614_DRV = 1 #WEB_ADC_DRV = 1 #USE_SDCARD = 1 #USE_UVC = 1 @@ -62,6 +63,13 @@ ADD_SRC_C += project/src/ina219/ina219drv.c CFLAGS += -DWEB_INA219_DRV=1 endif +ifdef WEB_MLX90614_DRV +ADD_SRC_C += project/src/driver/i2c_drv.c +CFLAGS += -DUSE_I2C_CONSOLE=1 +ADD_SRC_C += project/src/MLX90614/MLX90614.c +CFLAGS += -DWEB_MLX90614_DRV=1 +endif + ifdef WEB_ADC_DRV ADD_SRC_C += project/src/driver/adc_drv.c ADD_SRC_C += project/src/adc_ws/adc_ws.c diff --git a/project/src/MLX90614/MLX90614.c b/project/src/MLX90614/MLX90614.c new file mode 100644 index 0000000..554d902 --- /dev/null +++ b/project/src/MLX90614/MLX90614.c @@ -0,0 +1,421 @@ +/* + * MLX90614drv.c + * + * Created on: 02/09/2017 + * Author: pvvx + */ +#include +#include "rtl8195a.h" +#include "device.h" +#include "PinNames.h" + +#include "basic_types.h" +#include "diag.h" +#include "osdep_api.h" +#include "timer_api.h" + +//#include "i2c_api.h" +//#include "i2c_ex_api.h" +#include "pinmap.h" +#include "rtl_lib.h" +#include "rtl8195a/rtl_libc.h" +#include "driver/i2c_drv.h" +#include "platform_stdlib.h" +#include "web_websocket.h" +#include "tcpsrv/tcp_srv_conn.h" + +#include "hal_com_reg.h" + +#define MLX90614_I2CADDR 0x5A +// RAM +#define MLX90614_RAWIR1 0x04 +#define MLX90614_RAWIR2 0x05 +#define MLX90614_TA 0x06 +#define MLX90614_TOBJ1 0x07 +#define MLX90614_TOBJ2 0x08 +// EEPROM +#define MLX90614_TOMAX 0x20 +#define MLX90614_TOMIN 0x21 +#define MLX90614_PWMCTRL 0x22 +#define MLX90614_TARANGE 0x23 +#define MLX90614_EMISS 0x24 +#define MLX90614_CONFIG 0x25 +#define MLX90614_ADDR 0x0E +#define MLX90614_ID1 0x3C +#define MLX90614_ID2 0x3D +#define MLX90614_ID3 0x3E +#define MLX90614_ID4 0x3F +#define MLX90614_SLEEP 0xFF + +typedef struct _MLX90614_data { + union { + signed short to1; // Tobj1 + unsigned char uc[2]; + } o; + union { + signed short ta; // Ta + unsigned char uc[2]; + } a; +} MLX90614DATA, *PMLX90614DATA; + +typedef struct _MLX90614drv { + unsigned char status; + unsigned char addr; // адрес MLX90614 на шине I2C (формат 7 bit) + signed char init; + unsigned char tmp; + + unsigned short config; // регистр конфигурации MLX90614 + unsigned short timetik; // время опроса таймером (в us) + + unsigned short count; // счетчик считанных значений + unsigned short overrun; // счет переполнений буфера + + unsigned short errs; // счет ошибок на I2C + unsigned short buf_idx; // объем буфера pbuf[buf_idx+1], максимальный индекс-номер замера + unsigned short buf_rx; // индекс-номер ещё не считанного замера + unsigned short buf_tx; // индекс-номер для записи следующего замера + PMLX90614DATA pbuf; + gtimer_t timer; + union { // буфер + unsigned char uc[4]; + unsigned short us[2]; + signed short ss[2]; + unsigned int ui; + } buf_i2c; + i2c_drv_t i2c; +} MLX90614DRV, *PMLX90614DRV; + + +#define MLX90614_I2C_PIN_SDA PC_4 +#define MLX90614_I2C_PIN_SCL PC_5 +#define MLX90614_I2C_BUS_CLK 50000 // The maximum frequency of the MLX90614 SMBus is 100 KHz and the minimum is 10 KHz. +#define MLX90614_TIMER TIMER3 // используемый таймер + +//#define ReadTSF_Lo32() (*((volatile unsigned int *)(WIFI_REG_BASE + REG_TSFTR))) +//#define ReadTSF_Hi32() (*((volatile unsigned int *)(WIFI_REG_BASE + REG_TSFTR1))) + +MLX90614DRV mlx90614drv = { + .addr = MLX90614_I2CADDR, + .timetik = 10000, // Время опроса таймером: 10000 us + .buf_idx = 709, // циклический буфер на 710 замеров (по 4 байт -> sizeof(MLX90614DATA)) + // Если шаг заполнения 1 ms -> буфер на 0.71 сек + // Оптимизация под TCP: (TCP_MSS*2 - 80)/4 = (1460*2 - 80)/4 = 710 + .i2c.status = DRV_I2C_OFF, + .i2c.idx = 1, // I2C1 + .i2c.io_sel = S0, // PC_4, PC_5 + .i2c.mode = DRV_I2C_SS_MODE // DRV_I2C_FS_MODE // DRV_I2C_HS_MODE +}; +/* +void mlx90614_write(unsigned char reg, unsigned short data) +{ + PMLX90614DRV p = &mlx90614drv; + p->buf_i2c.uc[0] = reg; + p->buf_i2c.uc[1] = (unsigned char)((unsigned short)(data >> 8)); + p->buf_i2c.uc[2] = (unsigned char)data; + _i2c_write(&p->i2c, p->addr, (const char *)p->buf_i2c.uc, 3, 1); + UBaseType_t f; + portBASE_TYPE d; +} + +unsigned int mlx90614_read(unsigned char reg) +{ + PMLX90614DRV p = &mlx90614drv; + p->buf_i2c.uc[0] = reg; + _i2c_write(&p->i2c, p->addr, (const char *)p->buf_i2c.uc, 1, 1); + p->buf_i2c.ui = 0; + _i2c_read(&p->i2c, p->addr, (const char *)p->buf_i2c.uc, 2, 1); + return (p->buf_i2c.uc[0] << 8) | p->buf_i2c.uc[1]; +} +*/ + +#define i2c_reg(r) *((volatile uint32 *)(pi2c->base_regs + r)) + +/* Пример непрерывного чтения регистров Tobj1 и Tobj2 + * MLX90614 по прерыванию таймера */ +void mlx_tick_handler(void *par) { + PMLX90614DRV p = &mlx90614drv; + i2c_drv_t *pi2c = &p->i2c; + switch(p->status) { + default: + // Disable controller. + i2c_reg(REG_DW_I2C_IC_ENABLE) = 0; + p->status = 1; + break; + case 1: + // Master Target Address + i2c_reg(REG_DW_I2C_IC_TAR) = p->addr; + // Enable controller. + i2c_reg(REG_DW_I2C_IC_ENABLE) = BIT_IC_ENABLE; + p->status = 3; // = 2; + break; + case 2: + // Заполним FIFO ic I2C командами инициализации MLX90614 ? +/* + // Заполним FIFO ic I2C командами чтения RAW данных + // Write Command. + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = MLX90614_RAWIR1 | BIT_IC_DATA_CMD_RESTART; + // Read command & data (3 bytes). + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_STOP; + // Write Command. + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = MLX90614_RAWIR2 | BIT_IC_DATA_CMD_RESTART; + // Read command & data (3 bytes). + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_STOP; // | BIT_IC_DATA_CMD_RESTART +*/ + p->status = 3; + break; + case 4: + if (i2c_reg(REG_DW_I2C_IC_RAW_INTR_STAT) & BIT_IC_RAW_INTR_STAT_TX_ABRT) { + (volatile uint32)i2c_reg(REG_DW_I2C_IC_CLR_INTR); + p->errs++; + p->status = 0; + break; + } else { + if(p->pbuf) { + PMLX90614DATA pd = p->pbuf + p->buf_tx; + // Считаем готовые значения из FIFO ic I2C + pd->o.uc[0] = i2c_reg(REG_DW_I2C_IC_DATA_CMD); + pd->o.uc[1] = i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + pd->a.uc[0] = i2c_reg(REG_DW_I2C_IC_DATA_CMD); + pd->a.uc[1] = i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + if(p->buf_tx >= p->buf_idx) p->buf_tx = 0; + else p->buf_tx++; + if(p->buf_rx == p->buf_tx) { + p->overrun++; // todo: if(p->overrun++ > 100000) deinit() ? + if(p->buf_rx >= p->buf_idx) p->buf_rx = 0; + else p->buf_rx++; + }; + } else { + // удаление из FIFO 6-ти байт данных + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + (volatile uint32)i2c_reg(REG_DW_I2C_IC_DATA_CMD); + }; + } + case 3: + // Заполним FIFO ic I2C командами чтения + // Write Command. + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = MLX90614_TOBJ1; // | BIT_IC_DATA_CMD_RESTART; + // Read command & data (3 bytes). + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_RESTART; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_STOP; + // Write Command. + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = MLX90614_TA; // | BIT_IC_DATA_CMD_RESTART; + // Read command & data (3 bytes). + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_RESTART; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD; + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = BIT_IC_DATA_CMD_CMD | BIT_IC_DATA_CMD_STOP; // | BIT_IC_DATA_CMD_RESTART + p->status = 4; + break; + } +} + +uint16 mlx90614_chkdata(uint16 cnt) +{ + PMLX90614DRV p = &mlx90614drv; + if(p->init <= 0) return 0; + int len = p->buf_tx - p->buf_rx; + if(len < 0) len += p->buf_idx + 1; + if(cnt > (uint16)len) cnt = (uint16)len; + return cnt; +} + +size_t mlx90614_getdata(void *pd, uint16 cnt) +{ + PMLX90614DRV p = &mlx90614drv; + if(p->init <= 0) return 0; +// cnt = mlx90614_chkdata(cnt); + unsigned short *pus = (unsigned short *) pd; + taskDISABLE_INTERRUPTS(); + uint16 buf_rx = p->buf_rx; + *pus++ = cnt; // кол-во замеров + *pus++ = p->count + p->overrun; // индекс замера для анализа пропусков на стороне приемника + // если не пропущено, то равен прошлому + кол-во считанных замеров в прошлом блоке + p->count += cnt; // p->overrun = 0; + unsigned char *puc = (unsigned char *) pus; + if(cnt) { + uint16 lend = buf_rx + cnt; + if(lend > p->buf_idx) { + lend -= p->buf_idx + 1; + p->buf_rx = lend; + } else { + p->buf_rx = lend; + lend = 0; + }; + size_t len = (cnt - lend) *sizeof(MLX90614DATA); + if(len) memcpy(puc, (void *)(p->pbuf + buf_rx), len); + if(lend) memcpy(puc + len, (void *)p->pbuf, lend *sizeof(MLX90614DATA)); + } + taskENABLE_INTERRUPTS(); + return cnt * sizeof(MLX90614DATA) + 4; +} + +//#define mMIN(a, b) ((ab)?a:b) + +#include "web_srv.h" +#include "websock.h" + +int mlx90614_ws(TCP_SERV_CONN *ts_conn, char cmd) +{ + PMLX90614DRV p = &mlx90614drv; + switch(cmd) { + case 'd': // deinit + if(p->init > 0) { + gtimer_stop(&p->timer); + gtimer_deinit(&p->timer); + _i2c_deinit(&p->i2c); + if(p->pbuf) { + free(p->pbuf); + p->pbuf = NULL; + } + p->init = -1; + return 0; + } + return 1; + case 'c': // get count + return mlx90614_chkdata(p->buf_idx + 1); + case 'i': // init + return p->init; + default: // get_data + if(p->init <= 0) { + p->status = 0; + p->count = 0; + p->overrun = 0; + p->errs = 0; + if(!p->pbuf) { + p->pbuf = zalloc((p->buf_idx + 1) * sizeof(MLX90614DATA)); + if(!p->pbuf) { + error_printf("Error create buffer!\n"); + return -1; + }; + p->buf_tx = 0; + p->buf_rx = 0; + }; + _i2c_init(&p->i2c); + gtimer_init(&p->timer, MLX90614_TIMER); + gtimer_start_periodical(&p->timer, p->timetik, (void*)mlx_tick_handler, (uint32_t)&mlx90614drv); + p->init = 1; +// return 0; + } + case 'g': // get + { + uint32 i = mlx90614_chkdata(p->buf_idx + 1); + if(i) { + WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd; + i = mMIN((web_conn->msgbufsize / sizeof(MLX90614DATA)), i); + if(websock_tx_frame(ts_conn, WS_OPCODE_BINARY | WS_FRAGMENT_FIN, web_conn->msgbuf, mlx90614_getdata(web_conn->msgbuf, i)) != ERR_OK) + return -1; + } + return i; + } + } + return -1; +} + +void mlx90614_init(void) +{ + PMLX90614DRV p = &mlx90614drv; + if(p->init <= 0) { + rtl_printf("Init MLX90614\n"); + p->status = 0; + p->count = 0; + p->errs = 0; + if(!p->pbuf) { + p->pbuf = zalloc((p->buf_idx + 1) * sizeof(MLX90614DATA)); + if(!p->pbuf) { + error_printf("Error create buffer!\n"); + return; + }; + p->buf_tx = 0; + p->buf_rx = 0; + }; +// (!) Установки драйвера I2C заданы в структуре mlx90614drv +// _i2c_setup(&p->i2c, MLX90614_I2C_PIN_SDA , MLX90614_I2C_PIN_SCL, DRV_I2C_FS_MODE); // == DRV_I2C_OK? + _i2c_init(&p->i2c); +// _i2c_set_speed(&p->i2c, MLX90614_I2C_BUS_CLK); + rtl_printf("I2C%d mode = %d, drvStatus = %d\n", p->i2c.idx, p->i2c.mode, p->i2c.status); +// (!) Инициализация MLX90614 перенесена в прерывание таймера + // Initial a periodical timer + gtimer_init(&p->timer, MLX90614_TIMER); + // Tick every 0.001 sec (p->timetik) + gtimer_start_periodical(&p->timer, p->timetik, (void*)mlx_tick_handler, (uint32_t)&mlx90614drv); + rtl_printf("MLX90614 Timer Period = %u us\n", p->timetik); + p->init = 1; + } +} + +void mlx90614_deinit(void) +{ + PMLX90614DRV p = &mlx90614drv; + i2c_drv_t *pi2c = &p->i2c; + if(p->init > 0) { + rtl_printf("Deinit MLX90614\n"); + gtimer_stop(&p->timer); + gtimer_deinit(&p->timer); +// (!) Не используется mlx90614_write / mlx90614_read для сокращения кода +// mlx90614_write(MLX90614_REG_CONFIG, MLX90614_CONFIG_MODE_POWERDOWN); + // Break controller. + i2c_reg(REG_DW_I2C_IC_ENABLE) |= 2; + vTaskDelay(2); // +WDT + // Disable controller. + i2c_reg(REG_DW_I2C_IC_ENABLE) = 0; +/* Exit from Sleep Mode > 250 ms ! + vTaskDelay(2); // +WDT + // Master Target Address + i2c_reg(REG_DW_I2C_IC_TAR) = p->addr; + // Enable controller. + i2c_reg(REG_DW_I2C_IC_ENABLE) = BIT_IC_ENABLE; + // Заполним FIFO ic I2C командой sleep MLX90614 + vTaskDelay(2); // +WDT + // MLX90614 Enter Sleep Mode + i2c_reg(REG_DW_I2C_IC_DATA_CMD) = MLX90614_SLEEP | BIT_IC_DATA_CMD_STOP; +*/ + vTaskDelay(2); // +WDT + _i2c_deinit(&p->i2c); + if(p->pbuf) { + free(p->pbuf); + p->pbuf = NULL; + } + } + p->init = 0; +} + +LOCAL void ShowMlx(void) +{ + PMLX90614DRV p = &mlx90614drv; + rtl_printf("MLX90614: %d, %d\n", p->buf_i2c.us[0], p->buf_i2c.ss[1]); + rtl_printf("MLX90614: Cnt = %u, Err = %u\n", p->count, p->errs); +} + +LOCAL void fATMLX(int argc, char *argv[]) +{ + if(argc > 1) { + if(atoi(argv[1])) { + mlx90614_init(); + vTaskDelay(10); // +WDT + } + else mlx90614_deinit(); + } + ShowMlx(); +} + + +MON_RAM_TAB_SECTION COMMAND_TABLE console_commands_mlx90614[] = { + {"ATMLX", 0, fATMLX, "=[0/1]: MLX90614 =1 start, =0 stop"} +}; +/* + * Test i2c: + * ati2c i + * ati2c g 5a 1 6 3 + * ati2c d + */ diff --git a/project/src/web/web_int_callbacks.c b/project/src/web/web_int_callbacks.c index 708c2eb..7ca3fe7 100644 --- a/project/src/web/web_int_callbacks.c +++ b/project/src/web/web_int_callbacks.c @@ -455,6 +455,16 @@ extern int ina219_ws(TCP_SERV_CONN *ts_conn, char cmd); } } #endif +#ifdef WEB_MLX90614_DRV + else ifcmp("mlx90614") { + if(CheckSCB(SCB_WEBSOC)) { +extern int mlx90614_ws(TCP_SERV_CONN *ts_conn, char cmd); + int x = mlx90614_ws(ts_conn, cstr[6]); + if(x < 0) SetSCB(SCB_FCLOSE|SCB_DISCONNECT); + else tcp_puts("%d", x); + } + } +#endif #ifdef WEB_ADC_DRV else ifcmp("adc") { if(CheckSCB(SCB_WEBSOC)) { diff --git a/project/src/web/web_websocket.c b/project/src/web/web_websocket.c index d1e752d..18ecf22 100644 --- a/project/src/web/web_websocket.c +++ b/project/src/web/web_websocket.c @@ -136,6 +136,7 @@ websock_rx_data(TCP_SERV_CONN *ts_conn) case sw_frs_text: #if DEBUGSOO > 1 os_printf("ws:txt "); + #if DEBUGSOO > 2 if(ws->frame_len != 0) { uint8 tt = pstr[len];