This repository has been archived on 2023-07-17. You can view files and clone it, but cannot push or open issues or pull requests.
bl_mcu_sdk/examples/camera/camera_lcd/main.c

292 lines
8.0 KiB
C
Raw Normal View History

2021-06-04 17:56:34 +08:00
/**
* @file main.c
2021-06-20 12:25:46 +08:00
* @brief
*
2021-06-04 17:56:34 +08:00
* Copyright (c) 2021 Bouffalolab team
2021-06-20 12:25:46 +08:00
*
2021-06-04 17:56:34 +08:00
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
2021-06-20 12:25:46 +08:00
*
2021-06-04 17:56:34 +08:00
* http://www.apache.org/licenses/LICENSE-2.0
2021-06-20 12:25:46 +08:00
*
2021-06-04 17:56:34 +08:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
2021-06-20 12:25:46 +08:00
*
2021-06-04 17:56:34 +08:00
*/
#include "bflb_platform.h"
#include "bsp_sf_psram.h"
#include "bsp_image_sensor.h"
#include "hal_spi.h"
#include "hal_gpio.h"
#include "hal_dma.h"
#include "bsp_il9341.h"
#include "picture.c"
2021-06-20 12:25:46 +08:00
#define CAMERA_RESOLUTION_X (240)
#define CAMERA_RESOLUTION_Y (320)
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
#define YUV422_FRAME_SIZE (CAMERA_RESOLUTION_X * CAMERA_RESOLUTION_Y * 2)
#define YUV420_FRAME_SIZE (CAMERA_RESOLUTION_X * CAMERA_RESOLUTION_Y * 2 * 3 / 4)
#define YUV400_FRAME_SIZE (CAMERA_RESOLUTION_X * CAMERA_RESOLUTION_Y)
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
#define RGB_FRAME_SIZE (CAMERA_RESOLUTION_X * CAMERA_RESOLUTION_Y * 3)
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
#define CAMERA_FRAME_SIZE (YUV422_FRAME_SIZE)
#define CAMERA_WRITE_ADDR (0x26000000)
#define CAMERA_BUFFER_SIZE (CAMERA_FRAME_SIZE)
#define CAMERA_WRITE_ADDR1 (0x26000000 + CAMERA_BUFFER_SIZE)
#define CAMERA_BUFFER_SIZE1 (0x200000)
#define YUV_USE (1)
2021-06-04 17:56:34 +08:00
// #define TEST_TIM
/* Turn 24-bit RGB color to 16-bit */
2021-06-20 12:25:46 +08:00
#define RGB(r, g, b) (((r >> 3) << 3 | (g >> 5) | (g >> 2) << 13 | (b >> 3) << 8) & 0xffff)
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
static cam_device_t camera_cfg = {
2021-06-04 17:56:34 +08:00
.software_mode = CAM_MANUAL_MODE,
2021-06-20 12:25:46 +08:00
.frame_mode = CAM_FRAME_INTERLEAVE_MODE,
.yuv_format = CAM_YUV_FORMAT_YUV422,
2021-06-04 17:56:34 +08:00
.cam_write_ram_addr = CAMERA_WRITE_ADDR,
.cam_write_ram_size = CAMERA_BUFFER_SIZE,
2021-06-20 12:25:46 +08:00
.cam_frame_size = CAMERA_FRAME_SIZE,
2021-06-04 17:56:34 +08:00
.cam_write_ram_addr1 = CAMERA_WRITE_ADDR1,
.cam_write_ram_size1 = CAMERA_BUFFER_SIZE1,
2021-06-20 12:25:46 +08:00
.cam_frame_size1 = CAMERA_FRAME_SIZE,
2021-06-04 17:56:34 +08:00
};
static mjpeg_device_t mjpeg_cfg;
2021-06-20 12:25:46 +08:00
#define RANGE_INT(iVal, iMin, iMax) (((iVal) > (iMin)) ? (((iVal) <= (iMax)) ? (iVal) : (iMax)) : (iMin))
#define ROUND_SHR_POSITIVE(Dividend, iShiftRightCount) (((Dividend) & (1 << ((iShiftRightCount)-1))) ? ((Dividend) >> (iShiftRightCount)) + 1 : ((Dividend) >> (iShiftRightCount)))
#define ROUND_SHR_NEGATIVE(Dividend, iShiftRightCount) (-(((-(Dividend)) & (1 << ((iShiftRightCount)-1))) ? ((-(Dividend)) >> (iShiftRightCount)) + 1 : ((-(Dividend)) >> (iShiftRightCount))))
#define ROUND_SHR(Dividend, iShiftRightCount) (((Dividend) >= 0) ? ROUND_SHR_POSITIVE(Dividend, iShiftRightCount) : ROUND_SHR_NEGATIVE(Dividend, iShiftRightCount))
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
/**
2021-06-21 14:45:33 +08:00
* @brief
*
* @param Y
* @param Cb
* @param Cr
* @param R
* @param G
* @param B
2021-06-20 12:25:46 +08:00
*/
void YCbCrConvertToRGB(int Y, int Cb, int Cr, int *R, int *G, int *B)
{
int iTmpR = 0;
int iTmpG = 0;
int iTmpB = 0;
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
iTmpR = (((int)Y) << 14) + 22970 * (((int)Cr) - 128);
iTmpG = (((int)Y) << 14) - 5638 * (((int)Cb) - 128) - 11700 * (((int)Cr) - 128);
iTmpB = (((int)Y) << 14) + 29032 * (((int)Cb) - 128);
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
iTmpR = ROUND_SHR(iTmpR, 14);
iTmpG = ROUND_SHR(iTmpG, 14);
iTmpB = ROUND_SHR(iTmpB, 14);
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
*R = (int)RANGE_INT(iTmpR, 0, 255);
*G = (int)RANGE_INT(iTmpG, 0, 255);
2021-06-04 17:56:34 +08:00
*B = (int)RANGE_INT(iTmpB, 0, 255);
}
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
static long U[256], V[256], Y1[256], Y2[256];
/**
2021-06-20 12:25:46 +08:00
* @brief
*
2021-06-04 17:56:34 +08:00
*/
void init_yuv422p_table(void)
{
int i;
// Initialize table
2021-06-20 12:25:46 +08:00
for (i = 0; i < 256; i++) {
V[i] = 15938 * i - 2221300;
U[i] = 20238 * i - 2771300;
2021-06-04 17:56:34 +08:00
Y1[i] = 11644 * i;
Y2[i] = 19837 * i - 311710;
}
}
/**
memory structure
w
+--------------------+
|Y0Y1Y2Y3... |
|... | h
|... |
| |
+--------------------+
|U0V0U1V1 |
|... | h
|... |
| |
+--------------------+
w/2
*/
/**
2021-06-20 12:25:46 +08:00
* @brief
*
* @param yuv422sp
* @param rgb
* @param width
* @param height
2021-06-04 17:56:34 +08:00
*/
2021-06-20 12:25:46 +08:00
void yuv422sp_to_rgb24(unsigned char *yuv422sp, unsigned char *rgb, int width, int height)
2021-06-04 17:56:34 +08:00
{
int y, cb, cr;
int r, g, b;
int i = 0;
2021-06-20 12:25:46 +08:00
unsigned char *p_y;
unsigned char *p_uv;
unsigned char *p_rgb;
static int init_yuv422sp = 0; // just do it once
2021-06-04 17:56:34 +08:00
p_y = yuv422sp;
2021-06-20 12:25:46 +08:00
p_uv = p_y + width * height;
2021-06-04 17:56:34 +08:00
p_rgb = rgb;
2021-06-20 12:25:46 +08:00
if (init_yuv422sp == 0) {
2021-06-04 17:56:34 +08:00
init_yuv422p_table();
init_yuv422sp = 1;
}
2021-06-20 12:25:46 +08:00
for (i = 0; i < width * height / 2; i++) {
y = p_y[0];
2021-06-04 17:56:34 +08:00
cb = p_uv[0];
2021-06-20 12:25:46 +08:00
cr = p_uv[1];
2021-06-04 17:56:34 +08:00
2021-06-20 12:25:46 +08:00
r = MAX(0, MIN(255, (V[cr] + Y1[y]) / 10000)); //R value
b = MAX(0, MIN(255, (U[cb] + Y1[y]) / 10000)); //B value
g = MAX(0, MIN(255, (Y2[y] - 5094 * (r)-1942 * (b)) / 10000)); //G value
2021-06-04 17:56:34 +08:00
// default rankRGB
p_rgb[0] = b;
p_rgb[1] = g;
p_rgb[2] = r;
2021-06-20 12:25:46 +08:00
y = p_y[1];
2021-06-04 17:56:34 +08:00
cb = p_uv[0];
cr = p_uv[1];
2021-06-20 12:25:46 +08:00
r = MAX(0, MIN(255, (V[cr] + Y1[y]) / 10000)); //R value
b = MAX(0, MIN(255, (U[cb] + Y1[y]) / 10000)); //B value
g = MAX(0, MIN(255, (Y2[y] - 5094 * (r)-1942 * (b)) / 10000)); //G value
2021-06-04 17:56:34 +08:00
p_rgb[3] = b;
p_rgb[4] = g;
p_rgb[5] = r;
p_y += 2;
p_uv += 2;
p_rgb += 6;
}
}
/**
2021-06-20 12:25:46 +08:00
* @brief
*
* @param rgb24
* @param rgb16
2021-06-04 17:56:34 +08:00
*/
void rgb24_to_rgb565(uint8_t *rgb24, uint8_t *rgb16)
{
2021-06-20 12:25:46 +08:00
int i = 0, j = 0;
for (i = 0; i < RGB_FRAME_SIZE; i += 3) {
rgb16[j + 1] = rgb24[i] >> 3; // B
rgb16[j + 1] |= ((rgb24[i + 1] & 0x1C) << 3); // G
rgb16[j] = rgb24[i + 2] & 0xF8; // R
rgb16[j] |= (rgb24[i + 1] >> 5); // G
2021-06-04 17:56:34 +08:00
j += 2;
}
}
/**
2021-06-20 12:25:46 +08:00
* @brief
*
* @return int
2021-06-04 17:56:34 +08:00
*/
int main(void)
{
2021-06-20 12:25:46 +08:00
uint8_t *picture;
#ifdef USE_YUV422
2021-06-04 17:56:34 +08:00
uint8_t *rgb_pic = (uint32_t *)(0x26500000);
uint8_t *rgb16_pic = (uint32_t *)(0x26800000);
#endif
uint32_t length;
#ifdef TEST_TIM
uint32_t timer_start = 0;
uint32_t timer_end = 0;
#endif
bflb_platform_init(0);
LCD_Init();
LCD_Clear(0);
bsp_sf_psram_init(1);
cam_clk_out();
2021-06-20 12:25:46 +08:00
if (SUCCESS != image_sensor_init(DISABLE, &camera_cfg, &mjpeg_cfg)) {
2021-06-04 17:56:34 +08:00
MSG("Init error!\n");
BL_CASE_FAIL;
while (1) {
}
2021-06-04 17:56:34 +08:00
}
cam_frame_area_t cfg;
cfg.x0 = 200;
cfg.x1 = CAMERA_RESOLUTION_X + 200;
cfg.y0 = 80;
cfg.y1 = CAMERA_RESOLUTION_Y + 80;
2021-06-20 12:25:46 +08:00
struct device *cam0 = device_find("camera0");
device_control(cam0, DEVICE_CTRL_CAM_FRAME_CUT, &cfg);
device_control(cam0, DEVICE_CTRL_RESUME, NULL);
2021-06-20 12:25:46 +08:00
LCD_Set_Addr(0, 0, CAMERA_RESOLUTION_X, CAMERA_RESOLUTION_Y);
while (1) {
2021-06-04 17:56:34 +08:00
#ifdef TEST_TIM
timer_start = bflb_platform_get_time_ms();
#endif
2021-06-20 12:25:46 +08:00
while (SUCCESS != cam_get_one_frame_interleave(&picture, &length)) {
2021-06-04 17:56:34 +08:00
}
2021-06-20 12:25:46 +08:00
device_control(cam0, DEVICE_CTRL_SUSPEND, NULL);
2021-06-20 12:25:46 +08:00
#ifdef USE_YUV422
2021-06-04 17:56:34 +08:00
yuv422sp_to_rgb24(picture, rgb_pic, CAMERA_RESOLUTION_X, CAMERA_RESOLUTION_Y);
rgb24_to_rgb565(rgb_pic, rgb16_pic);
LCD_DrawPicture_cam(0, 0, CAMERA_RESOLUTION_X, CAMERA_RESOLUTION_Y, picture);
#else
LCD_WR_SPI_DMA((uint16_t *)picture, (CAMERA_FRAME_SIZE));
2021-06-04 17:56:34 +08:00
#endif
device_control(cam0, DEVICE_CTRL_CAM_FRAME_DROP, NULL);
device_control(cam0, DEVICE_CTRL_RESUME, NULL);
2021-06-04 17:56:34 +08:00
#ifdef TEST_TIM
timer_end = bflb_platform_get_time_ms();
2021-06-20 12:25:46 +08:00
MSG("time:%d\r\n", (timer_end - timer_start));
2021-06-04 17:56:34 +08:00
#endif
}
}