This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
@@ -0,0 +1,547 @@
#include "system/includes.h"
#include "app_config.h"
#include "software_jpegenc.h"
#include "spi.h"
#include "generic/lbuf.h"
#include "camera_queue_buf.h"
#include "camera_manager.h"
#include "bf30a2_cfg.h"
#include "avilib.h"
#include "asm/dma_copy.h"
#define LOG_TAG_CONST CAMERA_MANAGER
#define LOG_TAG "[CAMERA_MANAGER]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CHAR_ENABLE //log_char enable
#define LOG_CLI_ENABLE
#include "debug.h"
#define offsetof(type, memb) \
((unsigned long)(&((type *)0)->memb))
// SPI
#define SPI_FEND_SIZE 4 // 包头
#define SPI_LEND_SIZE 4 // 包尾
#define SPI_FHEAD_SIZE 4 // 行头
#define SPI_LHEAD_SIZE 4 // 行尾
#define SPI_ID HW_SPI1 // SPI ID号,spi2可能用于nandflash
#define QBUF_EXT_SIZE 4//qbuf拓展数据
// 接收队列BUF总大小 DMA_REVC_SIZE * DMA_REVC_BUF_NUM
#define INPUT_WIDTH 240
#define OUTPUT_HEIGHT 320
#define DMA_LINE_SIZE ( INPUT_WIDTH* 2 + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE) // 摄像头一行大小 格式:YUVY
#define DMA_CAMERA_SIZE (16) // 一次SPI DMA接收的行数
#define DMA_REVC_SIZE (DMA_LINE_SIZE * DMA_CAMERA_SIZE + SPI_FEND_SIZE) // 一次SPI DMA接收的大小,帧头、帧尾会多四个字节
#define DMA_REVC_BUF_NUM (20) // 接收BUF的数量
// JPEG缓存
#define JPEG_LBUF_SIZE (100 * 1024) // LBUF总大小,编码出的jpeg存放在lbuf中
#define ONE_JPEG_MAX_SIZE (10 * 1024) // 单张JPEG的大小,申请LBUF缓存时用到,可根据情况调整
#define JPEG_QVAL 50 // jpeg编码默认Q值(0-100)
enum {
SPI_NEW_CHUNK = 1,
SPI_DROP_FRAME,
JPEG_TASK_KILL,
};
struct lbuf_data_head {
int len;
u8 data[0];
};
struct camera_handle {
//设备驱动
struct camera_device *dev;
// JPEG 编码线程
char task_name[32];
u8 task_runing;
OS_SEM task_kill_sem;
// SPI接收行数统计
int spi_recv_line_cnt;
// jpeg lbuf
u8 *lbuf_ptr;
struct lbuff_head *lbuf_handle;
// yuv buf 队列
struct queue_buf *qbuf;
// SPI DMA 接收buf,中转buf,接收完后拷贝到队列buf
u8 *dma_recv_buf[2];
int dma_recv_buf_index;
};
static struct camera_handle *camera_hdl;
#define __this (camera_hdl)
AT(.spi.text.cache.L1)
__attribute__((interrupt("")))
static void camera_hw_spi_isr()
{
/*
在不可屏蔽中断调用,此函数及调用的子函数均需要放ram
特别注意打印。
否则在写flash的时候,会触发死机
*/
JL_SPI_TypeDef *SPI_REG = (SPI_ID == HW_SPI1) ? JL_SPI1 : JL_SPI2;
//clr pnd
SPI_REG->CON |= BIT(14);
if (SPI_REG->CON & BIT(21)) {
// slave rx dma overflow
SPI_REG->CON &= ~BIT(20); // clr
/* log_char('O'); */
}
if (SPI_REG->CON & BIT(18)) {
// slave tx dma underflow
SPI_REG->CON &= ~BIT(17); // clr
/* log_char('U'); */
}
// dma copy buf
u8 *recv_done_buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
u8 *chunk = queue_buf_get_isr(__this->qbuf);
if (chunk) {
dma_memcpy_async_inirq(chunk, recv_done_buf, DMA_REVC_SIZE);
//标记行号
chunk[DMA_REVC_SIZE + 0] = 0x55;
chunk[DMA_REVC_SIZE + 1] = 0xaa;
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
*chunk_rec_line = __this->spi_recv_line_cnt;
queue_buf_push_isr(__this->qbuf);
}
/* memcpy(chunk, recv_done_buf, DMA_REVC_SIZE); */
__this->dma_recv_buf_index = (__this->dma_recv_buf_index + 1) % ARRAY_SIZE(__this->dma_recv_buf);
__this->spi_recv_line_cnt = (DMA_CAMERA_SIZE + __this->spi_recv_line_cnt) % (__this->dev->height);
// 帧中间,减去帧头or帧尾的长度
u32 recv_cnt = DMA_REVC_SIZE - SPI_LEND_SIZE;
if (__this->spi_recv_line_cnt == 0 || __this->spi_recv_line_cnt == (__this->dev->height - DMA_CAMERA_SIZE)) {
recv_cnt = DMA_REVC_SIZE;
}
u8 *buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
SPI_REG->CON |= BIT(12);
SPI_REG->ADR = (u32)buf;
SPI_REG->CNT = recv_cnt;
}
static void camera_jpeg_dec_task(void *priv)
{
log_debug("%s enter>>>>>>>>>>>>>>>>>!\n", __func__);
struct camera_handle *hdl = (struct camera_handle *)priv;
u8 jpeg_qval = JPEG_QVAL;
log_debug("%s dev:%x", __func__, (u32)__this->dev);
void *jpegenc_hdl = software_jpegenc_init(
__this->dev->width,
__this->dev->height,
__this->dev->width + SPI_FHEAD_SIZE,
jpeg_qval);
if (!jpegenc_hdl) {
log_error("software jpegenc init err \n");
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
struct lbuf_data_head *lbuf_data = NULL;
int ret = 0;
int jpeg_buf_size = ONE_JPEG_MAX_SIZE;
int line_cnt = 0;
u8 *cur_bits = NULL;
int total_bits = 0;
u8 fps = 0;
u32 fps_time = jiffies_msec();
u32 enc_time;
while (hdl->task_runing) {
u8 *chunk = NULL;
/* dma_memcpy_wait_idle(); */
chunk = queue_buf_pop(__this->qbuf);
if (!chunk) {//pass
log_char('P');
os_time_dly(1);
continue;
}
if ((chunk[DMA_REVC_SIZE + 0]) == 0x55 && (chunk[DMA_REVC_SIZE + 1] == 0xaa)) {
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
if (*chunk_rec_line == line_cnt) {
//正常执行
} else {
//pass当前帧
queue_buf_reset(__this->qbuf);
line_cnt = 0;
log_warn("pop[c:%d l:%d]", (*chunk_rec_line), line_cnt);
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
os_time_dly(1);
continue;
}
}
} else {
log_error("%s line_cnt:%d", __func__, line_cnt);
put_buf(chunk + DMA_CAMERA_SIZE, 4);
}
//帧首,申请jpeg lbuf
if (line_cnt == 0) {
while (!lbuf_data) {
lbuf_data = lbuf_alloc(__this->lbuf_handle, jpeg_buf_size);
if (!lbuf_data) {
log_char('L');
lbuf_data = lbuf_pop(__this->lbuf_handle, BIT(0));
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
}
continue;
}
}
total_bits = 0;
enc_time = jiffies_msec();
}
cur_bits = lbuf_data->data + total_bits;
int remain_size = jpeg_buf_size - total_bits;
int out_bits_size = 0;
u8 *in_buf = line_cnt ? chunk + SPI_FHEAD_SIZE :
chunk + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE;
if (software_jpegenc_line(jpegenc_hdl, cur_bits, remain_size,
in_buf, DMA_CAMERA_SIZE, line_cnt, &out_bits_size)) {
log_error("software jpgenc line err \n");
continue;
}
total_bits += out_bits_size;
line_cnt += DMA_CAMERA_SIZE;
queue_buf_release(__this->qbuf);
//帧尾 push jpeg_buf
if (line_cnt == __this->dev->height) {
lbuf_data->len = total_bits;
lbuf_push(lbuf_data, BIT(0));
lbuf_data = NULL;
line_cnt = 0;
//fps info
fps++;
if ((jiffies_msec() - fps_time) > 1000) {
log_info("jpeg fps:%d enc_time:%lu \n", fps, jiffies_msec() - enc_time);
fps = 0;
fps_time = jiffies_msec();
}
}
}
log_debug("%s exit>>>>>>>>>>>>>>>>!\n", __func__);
software_jpegenc_exit(jpegenc_hdl);
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
int camera_spi_init()
{
int ret = 0;
hw_spi_dev spi = SPI_ID;
struct spi_platform_data spix_p_data = {
.port = {
IO_PORTC_01, // clk any io
IO_PORTC_02, // do any io
IO_PORTC_02, // di any io
0xff, // d2 any io
0xff, // d3 any io
0xff, // cs any io(主机不操作cs)
},
.role = SPI_ROLE_SLAVE,
.mode = SPI_MODE_BIDIR_1BIT, // SPI_MODE_UNIDIR_2BIT,//SPI_MODE_BIDIR_1BIT,
.bit_mode = SPI_FIRST_BIT_MSB,
.cpol = 0, // clk level in idle state:0:low, 1:high
.cpha = 0, // sampling edge:0:first, 1:second
.ie_en = 0, // ie enbale:0:disable, 1:enable
.irq_priority = 3,
.spi_isr_callback = NULL,
.clk = 24000000L,
};
ret = spi_open(spi, &spix_p_data);
if (ret < 0) {
log_error("spi master init error(%d)!", ret);
return ret;
}
spi_set_ie(spi, 1);
if (spi == HW_SPI1) {
request_irq(IRQ_SPI1_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI1_IDX, 0, 0);
} else {
request_irq(IRQ_SPI2_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI2_IDX, 0, 0);
}
os_time_dly(2);
u8 *buf = __this->dma_recv_buf[0];
spi_dma_transmit_for_isr(spi, (void *)buf, DMA_REVC_SIZE, 1);
return 0;
}
int camera_spi_deinit()
{
hw_spi_dev spi = SPI_ID;
spi_deinit(spi);
return 0;
}
int camera_manager_start(void)
{
int ret = 0;
mem_stats();
struct camera_device *dev = __this->dev;
memset(__this, 0x00, sizeof(struct camera_handle));
__this->dev = dev;
__this->qbuf = queue_buf_create(DMA_REVC_SIZE + QBUF_EXT_SIZE, DMA_REVC_BUF_NUM);
if (!__this->qbuf) {
return -1;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
__this->dma_recv_buf[i] = malloc(DMA_REVC_SIZE);
if (!__this->dma_recv_buf[i]) {
log_error("dma recv buf malloc fail \n");
goto __err;
}
}
__this->lbuf_ptr = malloc_psram(JPEG_LBUF_SIZE);
if (!__this->lbuf_ptr) {
log_error("jpeg lbuf_ptr malloc fail \n");
goto __err;
}
__this->lbuf_handle = lbuf_init(__this->lbuf_ptr, JPEG_LBUF_SIZE, 4, sizeof(struct lbuf_data_head));
os_sem_create(&__this->task_kill_sem, 0);
__this->task_runing = 1;
snprintf(__this->task_name, sizeof(__this->task_name), "camera_jpeg_task");
if (os_task_create(camera_jpeg_dec_task, __this, 10, 1024, 1024, __this->task_name)) {
log_error(" read task create fail \n");
__this->task_runing = 0;
goto __err;
}
if (camera_spi_init()) {
goto __err;
}
camera_manager_resume();
return 0;
__err:
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return -1;
}
int camera_manager_stop(void)
{
printf("%s %d", __func__, __LINE__);
camera_manager_suspend();
camera_spi_deinit();
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return 0;
}
void camera_manager_resume(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->resume) {
return ;
}
__this->dev->resume();
}
void camera_manager_suspend(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->supend) {
return ;
}
__this->dev->supend();
}
static int camera_manager_dev_check(void)
{
struct camera_device *dev = NULL;
list_for_each_camera_device_module(dev) {
if (dev->check) {
if (!dev->check()) {
log_debug("%s find device:%x\n", __func__, (u32)dev);
__this->dev = dev;
return 0;
}
}
}
return -1;
}
int camera_manager_init(void)
{
ASSERT(!__this);
__this = malloc(sizeof(struct camera_handle));
camera_manager_dev_check();
if (!__this->dev) {
return -1;
}
if (!__this->dev->init) {
return -1;
}
return __this->dev->init();
}
int camera_manager_deinit(void)
{
if (!__this) {
return -1;
}
if (!__this->dev) {
return -1;
}
if (!__this->dev->deinit) {
return -1;
}
int ret = __this->dev->deinit();
free(__this);
__this = NULL;
return ret;
}
int camera_manager_data_read(u8 **pp_data, int *p_len)
{
struct lbuf_data_head *node;
if (!pp_data || !p_len) {
log_error("camera read ptr err \n");
return -1;
}
node = lbuf_pop(__this->lbuf_handle, BIT(0));
if (!node) {
return -2;
}
*pp_data = node->data;
*p_len = node->len;
return 0;
}
int camera_manager_read_done(u8 *data_buf)
{
struct lbuf_data_head *node;
if (!data_buf) {
log_error("camera read done ptr err \n");
return -1;
}
node = (struct lbuf_data_head *)((u8 *)data_buf - offsetof(struct lbuf_data_head, data));
lbuf_free(node);
return 0;
}
int camera_manager_get_dev_width_height(int *width, int *height)
{
if (__this && __this->dev) {
*width = __this->dev->width;
*height = __this->dev->height;
return 0;
}
return -1;
}
int camera_manager_get_dev_fps(int *fps)
{
if (__this && __this->dev) {
*fps = __this->dev->fps;
return 0;
}
return -1;
}