Files
system-design/software-copyright/12-writech-pen-firmware/driver/camera_driver.c
T
2026-03-22 15:24:40 +08:00

325 lines
8.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 自然写智能点阵笔嵌入式固件软件 V1.0
* camera_driver.c - CMOS摄像头传感器驱动
*
* 功能说明:
* 1. CMOS图像传感器SPI通信驱动
* 2. 传感器寄存器配置(曝光、增益、帧率)
* 3. 图像采集触发与数据读取
* 4. 传感器电源管理(开/关/低功耗)
* 5. 自检与故障检测
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal_spi.h"
#include "hal_gpio.h"
/* ========== 传感器寄存器地址 ========== */
/* 芯片ID寄存器(只读) */
#define REG_CHIP_ID 0x00
/* 系统控制寄存器 */
#define REG_SYS_CTRL 0x01
#define SYS_CTRL_RESET 0x80 /* 软复位 */
#define SYS_CTRL_SLEEP 0x40 /* 睡眠模式 */
#define SYS_CTRL_ENABLE 0x01 /* 使能采集 */
/* 曝光时间寄存器(高/低字节) */
#define REG_EXPOSURE_H 0x02
#define REG_EXPOSURE_L 0x03
/* 模拟增益寄存器 */
#define REG_GAIN 0x04
/* 帧率控制寄存器 */
#define REG_FRAME_RATE 0x05
/* 像素数据起始寄存器(读取时自动递增) */
#define REG_PIXEL_DATA 0x10
/* 帧就绪状态位 */
#define REG_STATUS 0x0F
#define STATUS_FRAME_READY 0x01
/* 预期芯片ID值 */
#define EXPECTED_CHIP_ID 0xA5
/* ========== 传感器模式枚举 ========== */
#define CAMERA_MODE_SINGLE 0 /* 单帧模式 */
#define CAMERA_MODE_CONTINUOUS 1 /* 连续帧模式 */
/* ========== GPIO引脚定义 ========== */
#define GPIO_CAMERA_POWER 12 /* 传感器电源控制引脚 */
#define GPIO_CAMERA_CS 15 /* SPI片选引脚 */
#define GPIO_CAMERA_LED 16 /* 红外LED照明引脚 */
/* ========== SPI通信 ========== */
/* SPI端口号 */
#define CAMERA_SPI_PORT SPI_PORT_1
/* 读寄存器标志位 */
#define SPI_READ_FLAG 0x80
/* ========== 静态变量 ========== */
/* 传感器是否已初始化 */
static bool s_camera_initialized = false;
/* 传感器是否已上电 */
static bool s_camera_powered = false;
/* 当前工作模式 */
static uint8_t s_camera_mode = CAMERA_MODE_SINGLE;
/* ========== SPI底层读写 ========== */
/**
* SPI写单个寄存器
* @param reg_addr 寄存器地址(7位)
* @param value 写入值
*/
static void camera_write_reg(uint8_t reg_addr, uint8_t value) {
uint8_t tx[2];
tx[0] = reg_addr & 0x7F; /* 最高位0=写操作 */
tx[1] = value;
hal_gpio_write(GPIO_CAMERA_CS, 0); /* 拉低CS */
hal_spi_transfer(CAMERA_SPI_PORT, tx, NULL, 2);
hal_gpio_write(GPIO_CAMERA_CS, 1); /* 拉高CS */
}
/**
* SPI读单个寄存器
* @param reg_addr 寄存器地址
* @return 读取的值
*/
static uint8_t camera_read_reg(uint8_t reg_addr) {
uint8_t tx[2], rx[2];
tx[0] = reg_addr | SPI_READ_FLAG; /* 最高位1=读操作 */
tx[1] = 0x00; /* 空字节用于接收数据 */
hal_gpio_write(GPIO_CAMERA_CS, 0);
hal_spi_transfer(CAMERA_SPI_PORT, tx, rx, 2);
hal_gpio_write(GPIO_CAMERA_CS, 1);
return rx[1];
}
/**
* SPI批量读取像素数据
* 使用DMA方式高速读取整帧图像数据
*
* @param buffer 接收缓冲区
* @param length 读取字节数
*/
static void camera_read_pixels(uint8_t *buffer, uint16_t length) {
uint8_t cmd = REG_PIXEL_DATA | SPI_READ_FLAG;
hal_gpio_write(GPIO_CAMERA_CS, 0);
/* 先发送寄存器地址 */
hal_spi_transfer(CAMERA_SPI_PORT, &cmd, NULL, 1);
/* 然后连续读取像素数据 */
hal_spi_receive(CAMERA_SPI_PORT, buffer, length);
hal_gpio_write(GPIO_CAMERA_CS, 1);
}
/* ========== 传感器初始化 ========== */
/**
* 初始化CMOS图像传感器
* 配置GPIO、验证芯片ID、设置初始参数
*
* @return 0成功, -1芯片ID错误, -2通信失败
*/
int camera_driver_init(void) {
/* 配置控制GPIO为输出 */
hal_gpio_config_output(GPIO_CAMERA_POWER);
hal_gpio_config_output(GPIO_CAMERA_CS);
hal_gpio_config_output(GPIO_CAMERA_LED);
/* CS默认高电平(不选中) */
hal_gpio_write(GPIO_CAMERA_CS, 1);
/* 上电 */
hal_gpio_write(GPIO_CAMERA_POWER, 1);
s_camera_powered = true;
/* 等待传感器启动(典型10ms) */
for (volatile int i = 0; i < 100000; i++);
/* 软复位 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_RESET);
for (volatile int i = 0; i < 50000; i++);
/* 验证芯片ID */
uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
if (chip_id != EXPECTED_CHIP_ID) {
s_camera_initialized = false;
return -1;
}
/* 设置默认参数 */
camera_write_reg(REG_EXPOSURE_H, 0x00);
camera_write_reg(REG_EXPOSURE_L, 0x80); /* 曝光值128 */
camera_write_reg(REG_GAIN, 0x40); /* 增益64 */
camera_write_reg(REG_FRAME_RATE, 100); /* 100Hz帧率 */
/* 使能传感器 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);
s_camera_initialized = true;
return 0;
}
/* ========== 参数配置 ========== */
/**
* 设置曝光时间
* @param exposure 曝光值(0-255,映射到传感器实际曝光时间)
*/
void camera_set_exposure(uint8_t exposure) {
if (!s_camera_initialized) return;
camera_write_reg(REG_EXPOSURE_H, 0x00);
camera_write_reg(REG_EXPOSURE_L, exposure);
}
/**
* 设置模拟增益
* @param gain 增益值(0-255
*/
void camera_set_gain(uint8_t gain) {
if (!s_camera_initialized) return;
camera_write_reg(REG_GAIN, gain);
}
/**
* 设置工作模式
* @param mode CAMERA_MODE_SINGLE 或 CAMERA_MODE_CONTINUOUS
*/
void camera_set_mode(uint8_t mode) {
s_camera_mode = mode;
}
/* ========== 图像采集 ========== */
/**
* 触发单帧采集
* 在连续模式下,传感器会自动拍摄
* 在单帧模式下,需要每次手动触发
*/
void camera_trigger_capture(void) {
if (!s_camera_initialized || !s_camera_powered) return;
if (s_camera_mode == CAMERA_MODE_SINGLE) {
/* 单帧模式:写触发位 */
uint8_t ctrl = camera_read_reg(REG_SYS_CTRL);
camera_write_reg(REG_SYS_CTRL, ctrl | 0x02);
}
/* 开启红外LED照明(点阵图案需要红外光照射才能看到) */
hal_gpio_write(GPIO_CAMERA_LED, 1);
}
/**
* 等待帧就绪
* @param timeout_ms 超时毫秒数
* @return true帧已就绪, false超时
*/
bool camera_wait_frame_ready(uint16_t timeout_ms) {
uint16_t elapsed = 0;
while (elapsed < timeout_ms) {
uint8_t status = camera_read_reg(REG_STATUS);
if (status & STATUS_FRAME_READY) {
return true;
}
/* 简单延时 */
for (volatile int i = 0; i < 1000; i++);
elapsed++;
}
return false;
}
/**
* 获取传感器数据寄存器地址(用于DMA配置)
*/
uint32_t camera_get_data_register(void) {
/* 返回SPI数据寄存器的内存映射地址 */
return hal_spi_get_data_addr(CAMERA_SPI_PORT);
}
/* ========== 电源管理 ========== */
/**
* 传感器上电
*/
void camera_power_on(void) {
if (s_camera_powered) return;
hal_gpio_write(GPIO_CAMERA_POWER, 1);
s_camera_powered = true;
/* 等待传感器稳定 */
for (volatile int i = 0; i < 100000; i++);
/* 重新使能 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_ENABLE);
}
/**
* 传感器断电(最低功耗)
*/
void camera_power_off(void) {
if (!s_camera_powered) return;
/* 关闭红外LED */
hal_gpio_write(GPIO_CAMERA_LED, 0);
/* 传感器进入睡眠 */
camera_write_reg(REG_SYS_CTRL, SYS_CTRL_SLEEP);
/* 切断电源 */
hal_gpio_write(GPIO_CAMERA_POWER, 0);
s_camera_powered = false;
}
/**
* 传感器自检
* 检查SPI通信是否正常、芯片ID是否正确
*
* @return 0正常, -1通信故障, -2芯片ID异常
*/
int camera_self_test(void) {
if (!s_camera_powered) {
return -1;
}
uint8_t chip_id = camera_read_reg(REG_CHIP_ID);
if (chip_id != EXPECTED_CHIP_ID) {
return -2;
}
/* 写读测试:写入一个可写寄存器并读回验证 */
uint8_t test_val = 0x55;
camera_write_reg(REG_GAIN, test_val);
uint8_t read_back = camera_read_reg(REG_GAIN);
if (read_back != test_val) {
return -1;
}
/* 恢复原始增益值 */
camera_write_reg(REG_GAIN, 0x40);
return 0;
}