This commit is contained in:
zhoujie 2026-03-14 20:13:44 +08:00
parent cde0bd8243
commit 49605367e9
3 changed files with 135 additions and 3 deletions

View File

@ -48,6 +48,10 @@ static const uint8_t CMD_SHUTTER[] =
static const uint8_t CMD_QUERY_DIGITAL[] = static const uint8_t CMD_QUERY_DIGITAL[] =
{0x55, 0xAA, 0x07, 0x02, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x84, 0xF0}; {0x55, 0xAA, 0x07, 0x02, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x84, 0xF0};
/* Query: status page (simplest query, always works) */
static const uint8_t CMD_QUERY_STATUS[] =
{0x55, 0xAA, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0xF0};
/* ============================================================ /* ============================================================
* Low-level UART helpers * Low-level UART helpers
* ============================================================ */ * ============================================================ */
@ -142,8 +146,9 @@ static void Sensor_FlushRx(void)
* ============================================================ */ * ============================================================ */
volatile uint8_t sensor_init_ok = 0; volatile uint8_t sensor_init_ok = 0;
volatile uint8_t sensor_init_fail = 0; volatile uint8_t sensor_init_fail = 0;
volatile uint8_t sensor_last_resp[8] = {0}; volatile uint8_t sensor_last_resp[32] = {0};
volatile uint8_t sensor_last_resp_len = 0; volatile uint8_t sensor_last_resp_len = 0;
volatile uint8_t sensor_comm_test = 0;
int Mini212G2_SendCmd(const uint8_t *cmd, uint8_t len) int Mini212G2_SendCmd(const uint8_t *cmd, uint8_t len)
{ {
@ -154,7 +159,7 @@ int Mini212G2_SendCmd(const uint8_t *cmd, uint8_t len)
int n = Sensor_ReadResp(resp, sizeof(resp), 200); int n = Sensor_ReadResp(resp, sizeof(resp), 200);
/* Save last response for debugger inspection */ /* Save last response for debugger inspection */
sensor_last_resp_len = (uint8_t)n; sensor_last_resp_len = (uint8_t)n;
for (int j = 0; j < n && j < 8; j++) for (int j = 0; j < n && j < 32; j++)
sensor_last_resp[j] = resp[j]; sensor_last_resp[j] = resp[j];
if (n == ACK_LEN && memcmp(resp, ACK_PATTERN, ACK_LEN) == 0) if (n == ACK_LEN && memcmp(resp, ACK_PATTERN, ACK_LEN) == 0)
@ -185,6 +190,20 @@ int Mini212G2_Init(void)
printf("[Sensor] Waiting 3s for sensor boot...\r\n"); printf("[Sensor] Waiting 3s for sensor boot...\r\n");
Delay_Ms(3000); Delay_Ms(3000);
/* === Communication test: send status query === */
{
uint8_t test_resp[32];
Sensor_FlushRx();
Sensor_SendBytes(CMD_QUERY_STATUS, sizeof(CMD_QUERY_STATUS));
int tn = Sensor_ReadResp(test_resp, sizeof(test_resp), 500);
sensor_last_resp_len = (uint8_t)tn;
for (int j = 0; j < tn && j < 32; j++)
sensor_last_resp[j] = test_resp[j];
sensor_comm_test = (tn > 0) ? 1 : 0xFF;
/* Breakpoint here to check sensor_comm_test and sensor_last_resp */
}
Delay_Ms(200);
printf("[Sensor] Configuring CMOS/DVP output...\r\n"); printf("[Sensor] Configuring CMOS/DVP output...\r\n");
/* 1. Shutter compensation */ /* 1. Shutter compensation */

View File

@ -35,8 +35,10 @@ int Mini212G2_Init(void);
* sensor_last_resp_len: length of last response */ * sensor_last_resp_len: length of last response */
extern volatile uint8_t sensor_init_ok; extern volatile uint8_t sensor_init_ok;
extern volatile uint8_t sensor_init_fail; extern volatile uint8_t sensor_init_fail;
extern volatile uint8_t sensor_last_resp[8]; extern volatile uint8_t sensor_last_resp[32];
extern volatile uint8_t sensor_last_resp_len; extern volatile uint8_t sensor_last_resp_len;
/* sensor_comm_test: 0=not run, 1=got response, 0xFF=no response (timeout) */
extern volatile uint8_t sensor_comm_test;
#if SENSOR_UART_ENABLE #if SENSOR_UART_ENABLE
/** /**

View File

@ -10,6 +10,13 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
/* ============================================================
* TEST MODE: Generate simulated sensor data without real hardware.
* Set to 1 to enable test pattern generation (no sensor/DVP needed).
* Set to 0 for normal operation with real Mini212G2 sensor.
* ============================================================ */
#define TEST_PATTERN_MODE 1
#define MAX_TCP_PAYLOAD_SIZE 10240 #define MAX_TCP_PAYLOAD_SIZE 10240
uint8_t g_TxNetBuffer_A_Mem[MAX_TCP_PAYLOAD_SIZE]; uint8_t g_TxNetBuffer_A_Mem[MAX_TCP_PAYLOAD_SIZE];
uint8_t g_TxNetBuffer_B_Mem[MAX_TCP_PAYLOAD_SIZE]; uint8_t g_TxNetBuffer_B_Mem[MAX_TCP_PAYLOAD_SIZE];
@ -208,9 +215,15 @@ static void task_heartbeat_entry(void *pvParameters)
uint32_t cnt = 0; uint32_t cnt = 0;
while (1) while (1)
{ {
#if TEST_PATTERN_MODE
printf("[HB] %d tick=%d TEST_MODE frm=%d\r\n",
(int)cnt++, (int)xTaskGetTickCount(),
(int)dvp_frame_count);
#else
printf("[HB] %d tick=%d dvp_frm=%d row_irq=%d\r\n", printf("[HB] %d tick=%d dvp_frm=%d row_irq=%d\r\n",
(int)cnt++, (int)xTaskGetTickCount(), (int)cnt++, (int)xTaskGetTickCount(),
(int)dvp_frame_count, (int)dvp_row_irq_cnt); (int)dvp_frame_count, (int)dvp_row_irq_cnt);
#endif
vTaskDelay(pdMS_TO_TICKS(2000)); vTaskDelay(pdMS_TO_TICKS(2000));
} }
} }
@ -240,6 +253,94 @@ static uint8_t burst_active = 0; /* 1 = currently in burst */
static uint8_t burst_remaining = 0; /* frames left to capture */ static uint8_t burst_remaining = 0; /* frames left to capture */
static uint32_t burst_next_time_ms = 0; /* next burst frame time */ static uint32_t burst_next_time_ms = 0; /* next burst frame time */
#if TEST_PATTERN_MODE
/* ============================================================
* Test Pattern Generator
* Generates simulated 256x192 Y16 thermal images at ~10 FPS.
* Pattern cycles through several types so all pipeline paths
* can be exercised.
*
* Pattern 0: Gradient (25.00~45.00°C) baseline, no trigger
* Pattern 1: Hot center spot (90.00°C) should trigger alarm
* Pattern 2: Uniform warm (35.00°C) no trigger
* Pattern 3: Checkerboard with hot cells tests ROI search
* ============================================================ */
#define TEST_FPS_DELAY_MS 100 /* ~10 FPS */
#define TEMP_RAW(deg_c) ((uint16_t)((deg_c) * 100)) /* e.g. 35.00°C → 3500 */
static void test_fill_gradient(uint16_t *buf, uint16_t w, uint16_t h)
{
/* Top-to-bottom gradient: 25°C at top → 45°C at bottom */
for (uint16_t y = 0; y < h; y++) {
uint16_t temp = TEMP_RAW(25.0) + (uint16_t)((uint32_t)y * TEMP_RAW(20.0) / h);
for (uint16_t x = 0; x < w; x++)
buf[y * w + x] = temp;
}
}
static void test_fill_hotspot(uint16_t *buf, uint16_t w, uint16_t h)
{
/* Background 30°C, center 32x32 block at 90°C */
for (uint16_t y = 0; y < h; y++)
for (uint16_t x = 0; x < w; x++)
buf[y * w + x] = TEMP_RAW(30.0);
uint16_t cx = w / 2, cy = h / 2;
for (uint16_t y = cy - 16; y < cy + 16; y++)
for (uint16_t x = cx - 16; x < cx + 16; x++)
buf[y * w + x] = TEMP_RAW(90.0);
}
static void test_fill_uniform(uint16_t *buf, uint16_t w, uint16_t h)
{
for (uint16_t y = 0; y < h; y++)
for (uint16_t x = 0; x < w; x++)
buf[y * w + x] = TEMP_RAW(35.0);
}
static void test_fill_checker(uint16_t *buf, uint16_t w, uint16_t h)
{
/* 32x32 checkerboard: alternating 30°C and 85°C blocks */
for (uint16_t y = 0; y < h; y++)
for (uint16_t x = 0; x < w; x++) {
uint8_t cell = ((y / 32) + (x / 32)) & 1;
buf[y * w + x] = cell ? TEMP_RAW(85.0) : TEMP_RAW(30.0);
}
}
static void task_test_pattern_entry(void *pvParameters)
{
(void)pvParameters;
uint32_t frame_num = 0;
uint8_t pattern_idx = 0;
/* Cycle: gradient x20, hotspot x5, uniform x10, checker x5 */
const uint8_t pattern_seq[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3};
const uint8_t seq_len = sizeof(pattern_seq);
while (1)
{
uint16_t *buf = (uint16_t *)FrameBuffer;
switch (pattern_seq[pattern_idx % seq_len]) {
case 0: test_fill_gradient(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break;
case 1: test_fill_hotspot(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break;
case 2: test_fill_uniform(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break;
case 3: test_fill_checker(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break;
}
pattern_idx++;
if (pattern_idx >= seq_len) pattern_idx = 0;
frame_num++;
dvp_frame_count = frame_num;
Ready_Frame_Count = frame_num;
Frame_Ready_Flag = 1;
vTaskDelay(pdMS_TO_TICKS(TEST_FPS_DELAY_MS));
}
}
#endif /* TEST_PATTERN_MODE */
static void task_business_entry(void *pvParameters) static void task_business_entry(void *pvParameters)
{ {
(void)pvParameters; (void)pvParameters;
@ -253,7 +354,9 @@ static void task_business_entry(void *pvParameters)
g_ng_off_time = 0; g_ng_off_time = 0;
} }
#if !TEST_PATTERN_MODE
DVP_Task(); DVP_Task();
#endif
if (Frame_Ready_Flag) if (Frame_Ready_Flag)
{ {
@ -348,8 +451,13 @@ int main(void)
for (i = 0; i < 6; i++) printf("%x ", MACAddr[i]); for (i = 0; i < 6; i++) printf("%x ", MACAddr[i]);
printf("\n"); printf("\n");
#if TEST_PATTERN_MODE
printf("=== TEST PATTERN MODE === No sensor/DVP hardware needed\r\n");
/* Skip Mini212G2_Init() and DVP_Init() */
#else
Mini212G2_Init(); /* Configure sensor for CMOS/DVP Y16 output */ Mini212G2_Init(); /* Configure sensor for CMOS/DVP Y16 output */
DVP_Init(); DVP_Init();
#endif
TIM2_Init(); TIM2_Init();
NG_GPIO_Init(); NG_GPIO_Init();
@ -377,6 +485,9 @@ int main(void)
xTaskCreate(task_wchnet_entry, "wchnet", 512, NULL, 6, NULL); xTaskCreate(task_wchnet_entry, "wchnet", 512, NULL, 6, NULL);
xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL); xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL);
xTaskCreate(task_heartbeat_entry, "hb", 256, NULL, 3, NULL); xTaskCreate(task_heartbeat_entry, "hb", 256, NULL, 3, NULL);
#if TEST_PATTERN_MODE
xTaskCreate(task_test_pattern_entry, "testpat", 256, NULL, 4, NULL);
#endif
DBG_APP("Starting scheduler\r\n"); DBG_APP("Starting scheduler\r\n");
vTaskStartScheduler(); vTaskStartScheduler();