diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/CMakeLists.txt b/examples/peripherals/mjpeg/mjpeg_cam_normal/CMakeLists.txt new file mode 100644 index 00000000..c08e2752 --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.15) + +include(proj.conf) + +find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE}) + +target_sources(app PRIVATE jpeg_head.c) +sdk_set_main_file(main.c) + +project(mjpeg_cam_normal) diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/Makefile b/examples/peripherals/mjpeg/mjpeg_cam_normal/Makefile new file mode 100644 index 00000000..44367c02 --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/Makefile @@ -0,0 +1,13 @@ +SDK_DEMO_PATH ?= . +BL_SDK_BASE ?= $(SDK_DEMO_PATH)/../../../.. + +export BL_SDK_BASE + +CHIP ?= bl616 +BOARD ?= bl616dk +CROSS_COMPILE ?= riscv64-unknown-elf- + +# add custom cmake definition +#cmake_definition+=-Dxxx=sss + +include $(BL_SDK_BASE)/project.build diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/README.md b/examples/peripherals/mjpeg/mjpeg_cam_normal/README.md new file mode 100644 index 00000000..5eec3cd3 --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/README.md @@ -0,0 +1,43 @@ +# cam_normal + + +## Support CHIP + +| CHIP | Remark | +|:----------------:|:------:| +|BL702/BL704/BL706 | | +|BL616/BL618 | | +|BL808 | | + +## Compile + +- BL602/BL604 + +``` +make CHIP=bl602 BOARD=bl602dk +``` + +- BL702/BL704/BL706 + +``` +make CHIP=bl702 BOARD=bl702dk +``` + +- BL616/BL618 + +``` +make CHIP=bl616 BOARD=bl616dk +``` + +- BL808 + +``` +make CHIP=bl808 BOARD=bl808dk CPU_ID=m0 +make CHIP=bl808 BOARD=bl808dk CPU_ID=d0 +``` + +## Flash + +``` +make flash CHIP=chip_name COMX=xxx # xxx is your com name +``` \ No newline at end of file diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/flash_prog_cfg.ini b/examples/peripherals/mjpeg/mjpeg_cam_normal/flash_prog_cfg.ini new file mode 100644 index 00000000..17fcdebe --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/flash_prog_cfg.ini @@ -0,0 +1,11 @@ +[cfg] +# 0: no erase, 1:programmed section erase, 2: chip erase +erase = 1 +# skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated +skip_mode = 0x0, 0x0 +# 0: not use isp mode, #1: isp mode +boot2_isp_mode = 0 + +[FW] +filedir = ./build/build_out/mjpeg*_$(CHIPNAME).bin +address = 0x000000 \ No newline at end of file diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.c b/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.c new file mode 100644 index 00000000..376f591e --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.c @@ -0,0 +1,195 @@ +#include "jpeg_head.h" + +static const uint8_t tableQy[] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; + +static const uint8_t tableQuv[] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +static const uint8_t tableHuffman[] = { + 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, + + 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, + 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, + 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, + 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, + 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, + 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, + 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + + 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, + + 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, + 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, + 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, + 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, + 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0X2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, + 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, + 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA +}; + +static void QCalc(const uint8_t *in, uint8_t *out, uint8_t q) +{ + float tq, result; + int i; + + if (q < 1) + tq = 5000.0f; + else if (q <= 50) + tq = 5000.0f / q; + else if (q <= 100) + tq = 200.0f - 2.0f * q; + else + tq = 0.0f; + tq = tq / 100.0f; + + for (i = 0; i < 64; i++) + { + result = in[i] * tq; + if (result > 255.0f) + out[i] = 255; + else if (result < 1.0f) + out[i] = 1; + else + out[i] = (uint8_t)(result + 0.5f); + } +} + +uint32_t JpegHeadCreate(uint8_t type, uint8_t q, int width, int height, uint8_t *out) +{ + uint32_t index = 0; + uint32_t i; + /* start of jpeg file */ + out[index++] = 0xFF; + out[index++] = 0xD8; + + /* define quality table */ + out[index++] = 0xFF; + out[index++] = 0xDB; + out[index++] = 0x00; + out[index++] = 0x43; //=3+N, N=64 + out[index++] = 0x00; + QCalc(tableQy, out + index, q); //Y quality table + index += 64; + out[index++] = 0xFF; + out[index++] = 0xDB; + out[index++] = 0x00; + out[index++] = 0x43; //=3+N, N=64 + out[index++] = 0x01; + QCalc(tableQuv, out + index, q); //UV quality table + index += 64; + + /* basic information of mjpeg */ + out[index++] = 0xFF; + out[index++] = 0xC0; + out[index++] = 0x00; + if(type==YUV_MODE_400) + out[index++] = 0x0B; //length:2 + bits:1 + height:2 + width:2 + num:1 + 3 * part=1 + else + out[index++] = 0x11; //length:2 + bits:1 + height:2 + width:2 + num:1 + 3 * part=3 + out[index++] = 0x08; + out[index++] = (uint8_t)((height >> 8) & 0xFF); + out[index++] = (uint8_t)(height & 0xFF); + out[index++] = (uint8_t)((width >> 8) & 0xFF); + out[index++] = (uint8_t)(width & 0xFF); + if (type == YUV_MODE_400) + { + out[index++] = 0x01; //number of part + out[index++] = 0x01; //the first part id + out[index++] = 0x11; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x00; //id of quality tab + } + else if (type == YUV_MODE_420) + { + out[index++] = 0x03; //number of part + out[index++] = 0x01; //the first part id + out[index++] = 0x22; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x00; //id of quality tab + out[index++] = 0x02; //the second part id + out[index++] = 0x11; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x01; //id of quality tab + out[index++] = 0x03; //the third part id + out[index++] = 0x11; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x01; //id of quality tab + } + else if (type == YUV_MODE_422) + { + out[index++] = 0x03; //number of part + out[index++] = 0x01; //the first part id + out[index++] = 0x21; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x00; //id of quality tab + out[index++] = 0x02; //the second part id + out[index++] = 0x11; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x01; //id of quality tab + out[index++] = 0x03; //the third part id + out[index++] = 0x11; //[0:3]vertical sample coefficient, [4:7]horizontal sample coefficient + out[index++] = 0x01; //id of quality tab + } + + /* define Huffman table */ + for (i = 0; i < sizeof(tableHuffman); i++) + { + out[index++] = tableHuffman[i]; + } + + /* start of scan*/ + out[index++] = 0xFF; + out[index++] = 0xDA; + if (type == YUV_MODE_400) + { + out[index++] = 0x00; + out[index++] = 0x08; //length + out[index++] = 0x01; + out[index++] = 0x01; + out[index++] = 0x00; + out[index++] = 0x02; + out[index++] = 0x3F; + out[index++] = 0x00; + } + else + { + out[index++] = 0x00; + out[index++] = 0x0C; //length + out[index++] = 0x03; + out[index++] = 0x01; + out[index++] = 0x00; + out[index++] = 0x02; + out[index++] = 0x11; + out[index++] = 0x03; + out[index++] = 0x11; + out[index++] = 0x00; + out[index++] = 0x3F; + out[index++] = 0x00; + } + return index; +} diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.h b/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.h new file mode 100644 index 00000000..6cf7ca0c --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/jpeg_head.h @@ -0,0 +1,12 @@ +#ifndef __JPEG_HEAD_H__ +#define __JPEG_HEAD_H__ + +#include "stdint.h" + +#define YUV_MODE_400 1 +#define YUV_MODE_420 2 +#define YUV_MODE_422 3 + +extern uint32_t JpegHeadCreate(uint8_t type, uint8_t q, int width, int height, uint8_t *out); + +#endif /* __JPEG_HEAD_H__ */ \ No newline at end of file diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/main.c b/examples/peripherals/mjpeg/mjpeg_cam_normal/main.c new file mode 100644 index 00000000..54d5e0b3 --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/main.c @@ -0,0 +1,133 @@ +#include "bflb_mtimer.h" +#include "bflb_i2c.h" +#include "bflb_cam.h" +#include "bflb_mjpeg.h" +#include "image_sensor.h" +#include "board.h" +#include "jpeg_head.h" + +#define BLOCK_NUM 2 +#define ROW_NUM (8 * BLOCK_NUM) +#define CAM_FRAME_COUNT_USE 50 + +static struct bflb_device_s *i2c0; +static struct bflb_device_s *cam0; + +static struct bflb_device_s *mjpeg; + +volatile uint32_t pic_count = 0; +volatile uint32_t pic_addr[CAM_FRAME_COUNT_USE] = { 0 }; +volatile uint32_t pic_len[CAM_FRAME_COUNT_USE] = { 0 }; + +void mjpeg_isr(int irq, void *arg) +{ + uint8_t *pic; + uint32_t jpeg_len; + + uint32_t intstatus = bflb_mjpeg_get_intstatus(mjpeg); + if (intstatus & MJPEG_INTSTS_ONE_FRAME) { + bflb_mjpeg_int_clear(mjpeg, MJPEG_INTCLR_ONE_FRAME); + jpeg_len = bflb_mjpeg_get_frame_info(mjpeg, &pic); + pic_addr[pic_count] = (uint32_t)pic; + pic_len[pic_count] = jpeg_len; + pic_count++; + bflb_mjpeg_pop_one_frame(mjpeg); + if (pic_count == CAM_FRAME_COUNT_USE) { + bflb_cam_stop(cam0); + bflb_mjpeg_stop(mjpeg); + } + } +} + +uint8_t jpg_head_buf[800] = { 0 }; +uint32_t jpg_head_len; + +uint8_t MJPEG_QUALITY = 50; + +#define SIZE_BUFFER (4 * 1024 * 1024) + +void bflb_mjpeg_dump_hex(uint8_t *data, uint32_t len) +{ + uint32_t i = 0; + + for (i = 0; i < len; i++) { + if (i % 16 == 0) { + printf("\r\n"); + } + + printf("%02x ", data[i]); + } + + printf("\r\n"); +} + +int main(void) +{ + struct bflb_cam_config_s cam_config; + struct image_sensor_config_s *sensor_config; + + board_init(); + board_dvp_gpio_init(); + + i2c0 = bflb_device_get_by_name("i2c0"); + cam0 = bflb_device_get_by_name("cam0"); + + if (image_sensor_scan(i2c0, &sensor_config)) { + printf("\r\nSensor name: %s\r\n", sensor_config->name); + } else { + printf("\r\nError! Can't identify sensor!\r\n"); + while (1) { + } + } + + memcpy(&cam_config, sensor_config, IMAGE_SENSOR_INFO_COPY_SIZE); + cam_config.with_mjpeg = true; + cam_config.input_source = CAM_INPUT_SOURCE_DVP; + cam_config.output_format = CAM_OUTPUT_FORMAT_AUTO; + cam_config.output_bufaddr = BFLB_PSRAM_BASE; + cam_config.output_bufsize = cam_config.resolution_x * 2 * ROW_NUM; + + bflb_cam_init(cam0, &cam_config); + bflb_cam_start(cam0); + + mjpeg = bflb_device_get_by_name("mjpeg"); + + struct bflb_mjpeg_config_s config; + + config.format = MJPEG_FORMAT_YUV422_YUYV; + config.quality = MJPEG_QUALITY; + config.rows = ROW_NUM; + config.resolution_x = cam_config.resolution_x; + config.resolution_y = cam_config.resolution_y; + config.input_bufaddr0 = (uint32_t)BFLB_PSRAM_BASE; + config.input_bufaddr1 = 0; + config.output_bufaddr = (uint32_t)BFLB_PSRAM_BASE + cam_config.resolution_x * 2 * ROW_NUM; + config.output_bufsize = SIZE_BUFFER - cam_config.resolution_x * 2 * ROW_NUM; + config.input_yy_table = NULL; /* use default table */ + config.input_uv_table = NULL; /* use default table */ + + bflb_mjpeg_init(mjpeg, &config); + + jpg_head_len = JpegHeadCreate(YUV_MODE_422, MJPEG_QUALITY, cam_config.resolution_x, cam_config.resolution_y, jpg_head_buf); + bflb_mjpeg_fill_jpeg_header_tail(mjpeg, jpg_head_buf, jpg_head_len); + + bflb_mjpeg_tcint_mask(mjpeg, false); + bflb_irq_attach(mjpeg->irq_num, mjpeg_isr, NULL); + bflb_irq_enable(mjpeg->irq_num); + + bflb_mjpeg_start(mjpeg); + + while (pic_count < CAM_FRAME_COUNT_USE) { + printf("pic count:%d\r\n", pic_count); + bflb_mtimer_delay_ms(200); + } + + for (uint8_t i = 0; i < CAM_FRAME_COUNT_USE; i++) { + printf("jpg addr:%08x ,jpg size:%d\r\n", pic_addr[i], pic_len[i]); + //bflb_mjpeg_dump_hex((uint8_t *)pic_addr[i], pic_len[i]); + } + + while (1) { + bflb_mtimer_delay_ms(1000); + } +} diff --git a/examples/peripherals/mjpeg/mjpeg_cam_normal/proj.conf b/examples/peripherals/mjpeg/mjpeg_cam_normal/proj.conf new file mode 100644 index 00000000..806d830a --- /dev/null +++ b/examples/peripherals/mjpeg/mjpeg_cam_normal/proj.conf @@ -0,0 +1,2 @@ +set(CONFIG_BSP_IMAGE_SENSOR 1) +set(CONFIG_PSRAM 1) \ No newline at end of file diff --git a/examples/peripherals/mjpeg/mjpeg_no_camera/main.c b/examples/peripherals/mjpeg/mjpeg_no_camera/main.c index e18d3b43..a63a364f 100644 --- a/examples/peripherals/mjpeg/mjpeg_no_camera/main.c +++ b/examples/peripherals/mjpeg/mjpeg_no_camera/main.c @@ -6,8 +6,10 @@ static struct bflb_device_s *mjpeg; -#define X 64 -#define Y 64 +#define X 64 +#define Y 64 + +#define ROW_NUM (Y * MJPEG_MAX_FRAME_COUNT) volatile uint32_t pic_count = 0; volatile uint32_t pic_addr[MJPEG_MAX_FRAME_COUNT] = { 0 }; @@ -34,12 +36,6 @@ uint32_t jpg_head_len; uint8_t MJPEG_QUALITY = 50; -#if defined(BL616) -#define BSP_PSRAM_BASE 0xA8000000 -#elif defined(BL808) -#define BSP_PSRAM_BASE 0x50000000 -#endif - #define SIZE_BUFFER (4 * 1024 * 1024) void bflb_mjpeg_dump_hex(uint8_t *data, uint32_t len) @@ -67,12 +63,13 @@ int main(void) config.format = MJPEG_FORMAT_YUV422_YUYV; config.quality = MJPEG_QUALITY; + config.rows = ROW_NUM; config.resolution_x = X; config.resolution_y = Y; config.input_bufaddr0 = (uint32_t)test_64x64; config.input_bufaddr1 = 0; - config.output_bufaddr = (uint32_t)BSP_PSRAM_BASE + MJPEG_MAX_FRAME_COUNT * X * Y * 2; - config.output_bufsize = SIZE_BUFFER - MJPEG_MAX_FRAME_COUNT * X * Y * 2; + config.output_bufaddr = (uint32_t)BFLB_PSRAM_BASE + X * 2 * ROW_NUM; + config.output_bufsize = SIZE_BUFFER - X * 2 * ROW_NUM; config.input_yy_table = NULL; /* use default table */ config.input_uv_table = NULL; /* use default table */