#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; }