common: Add the framebuffer instance to csi struct.

This commit is contained in:
iabdalkader 2025-04-21 18:00:17 +02:00
parent 3d90961c21
commit f468c12f74
2 changed files with 66 additions and 61 deletions

View File

@ -128,6 +128,8 @@ uint16_t resolution[][2] = {
{2592, 1944}, /* WQXGA2 */ {2592, 1944}, /* WQXGA2 */
}; };
omv_csi_t csi = {0};
__weak void omv_csi_init0() { __weak void omv_csi_init0() {
// Reset the csi state // Reset the csi state
memset(&csi, 0, sizeof(omv_csi_t)); memset(&csi, 0, sizeof(omv_csi_t));
@ -198,13 +200,13 @@ __weak int omv_csi_reset() {
omv_i2c_enable(&csi.i2c_bus, true); omv_i2c_enable(&csi.i2c_bus, true);
// Call csi-specific reset function // Call csi-specific reset function
if (csi.reset != NULL if (csi.reset != NULL &&
&& csi.reset(&csi) != 0) { csi.reset(&csi) != 0) {
return OMV_CSI_ERROR_CTL_FAILED; return OMV_CSI_ERROR_CTL_FAILED;
} }
// Reset framebuffers // Reset framebuffers
framebuffer_flush_buffers(true); framebuffer_flush_buffers(csi.fb, true);
return 0; return 0;
} }
@ -671,11 +673,11 @@ __weak int omv_csi_set_pixformat(pixformat_t pixformat) {
// Some sensor drivers automatically switch to BAYER to reduce the frame size if it does not fit in RAM. // Some sensor drivers automatically switch to BAYER to reduce the frame size if it does not fit in RAM.
// If the current format is BAYER (1BPP), and the target format is color and (2BPP), and the frame does not // If the current format is BAYER (1BPP), and the target format is color and (2BPP), and the frame does not
// fit in RAM it will just be switched back again to BAYER, so we keep the current format unchanged. // fit in RAM it will just be switched back again to BAYER, so we keep the current format unchanged.
uint32_t size = framebuffer_get_buffer_size(); uint32_t size = framebuffer_get_buffer_size(csi.fb);
if ((csi.pixformat == PIXFORMAT_BAYER) && if ((csi.pixformat == PIXFORMAT_BAYER) &&
((pixformat == PIXFORMAT_RGB565) || (pixformat == PIXFORMAT_YUV422)) && ((pixformat == PIXFORMAT_RGB565) || (pixformat == PIXFORMAT_YUV422)) &&
(MAIN_FB()->u * MAIN_FB()->v * 2 > size) && (csi.fb->u * csi.fb->v * 2 > size) &&
(MAIN_FB()->u * MAIN_FB()->v * 1 <= size)) { (csi.fb->u * csi.fb->v * 1 <= size)) {
return 0; return 0;
} }
@ -689,7 +691,7 @@ __weak int omv_csi_set_pixformat(pixformat_t pixformat) {
omv_csi_abort(true, false); omv_csi_abort(true, false);
// Flush previous frame. // Flush previous frame.
framebuffer_update_jpeg_buffer(); framebuffer_update_jpeg_buffer(csi.fb);
// Check if the control is supported. // Check if the control is supported.
if (csi.set_pixformat == NULL) { if (csi.set_pixformat == NULL) {
@ -709,7 +711,7 @@ __weak int omv_csi_set_pixformat(pixformat_t pixformat) {
csi.pixformat = pixformat; csi.pixformat = pixformat;
// Reset pixel format to skip the first frame. // Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID; csi.fb->pixfmt = PIXFORMAT_INVALID;
// Auto-adjust the number of frame buffers. // Auto-adjust the number of frame buffers.
omv_csi_set_framebuffers(-1); omv_csi_set_framebuffers(-1);
@ -728,7 +730,7 @@ __weak int omv_csi_set_framesize(omv_csi_framesize_t framesize) {
omv_csi_abort(true, false); omv_csi_abort(true, false);
// Flush previous frame. // Flush previous frame.
framebuffer_update_jpeg_buffer(); framebuffer_update_jpeg_buffer(csi.fb);
// Call the sensor specific function // Call the sensor specific function
if (csi.set_framesize == NULL) { if (csi.set_framesize == NULL) {
@ -747,16 +749,16 @@ __weak int omv_csi_set_framesize(omv_csi_framesize_t framesize) {
csi.framesize = framesize; csi.framesize = framesize;
// Set x and y offsets. // Set x and y offsets.
MAIN_FB()->x = 0; csi.fb->x = 0;
MAIN_FB()->y = 0; csi.fb->y = 0;
// Set width and height. // Set width and height.
MAIN_FB()->w = resolution[framesize][0]; csi.fb->w = resolution[framesize][0];
MAIN_FB()->h = resolution[framesize][1]; csi.fb->h = resolution[framesize][1];
// Set backup width and height. // Set backup width and height.
MAIN_FB()->u = resolution[framesize][0]; csi.fb->u = resolution[framesize][0];
MAIN_FB()->v = resolution[framesize][1]; csi.fb->v = resolution[framesize][1];
// Reset pixel format to skip the first frame. // Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID; csi.fb->pixfmt = PIXFORMAT_INVALID;
// Auto-adjust the number of frame buffers. // Auto-adjust the number of frame buffers.
omv_csi_set_framebuffers(-1); omv_csi_set_framebuffers(-1);
@ -776,8 +778,8 @@ __weak int omv_csi_set_framerate(int framerate) {
} }
// If the csi implements framerate control use it. // If the csi implements framerate control use it.
if (csi.set_framerate != NULL if (csi.set_framerate != NULL &&
&& csi.set_framerate(&csi, framerate) != 0) { csi.set_framerate(&csi, framerate) != 0) {
return OMV_CSI_ERROR_CTL_FAILED; return OMV_CSI_ERROR_CTL_FAILED;
} else { } else {
// Otherwise use software framerate control. // Otherwise use software framerate control.
@ -807,10 +809,10 @@ __weak void omv_csi_throttle_framerate() {
__weak bool omv_csi_get_cropped() { __weak bool omv_csi_get_cropped() {
if (csi.framesize != OMV_CSI_FRAMESIZE_INVALID) { if (csi.framesize != OMV_CSI_FRAMESIZE_INVALID) {
return (MAIN_FB()->x != 0) || return (csi.fb->x != 0) ||
(MAIN_FB()->y != 0) || (csi.fb->y != 0) ||
(MAIN_FB()->u != resolution[csi.framesize][0]) || (csi.fb->u != resolution[csi.framesize][0]) ||
(MAIN_FB()->v != resolution[csi.framesize][1]); (csi.fb->v != resolution[csi.framesize][1]);
} }
return false; return false;
} }
@ -848,8 +850,8 @@ __weak uint32_t omv_csi_get_dst_bpp() {
__weak int omv_csi_set_windowing(int x, int y, int w, int h) { __weak int omv_csi_set_windowing(int x, int y, int w, int h) {
// Check if the value has changed. // Check if the value has changed.
if ((MAIN_FB()->x == x) && (MAIN_FB()->y == y) && if ((csi.fb->x == x) && (csi.fb->y == y) &&
(MAIN_FB()->u == w) && (MAIN_FB()->v == h)) { (csi.fb->u == w) && (csi.fb->v == h)) {
return 0; return 0;
} }
@ -861,19 +863,19 @@ __weak int omv_csi_set_windowing(int x, int y, int w, int h) {
omv_csi_abort(true, false); omv_csi_abort(true, false);
// Flush previous frame. // Flush previous frame.
framebuffer_update_jpeg_buffer(); framebuffer_update_jpeg_buffer(csi.fb);
// Set x and y offsets. // Set x and y offsets.
MAIN_FB()->x = x; csi.fb->x = x;
MAIN_FB()->y = y; csi.fb->y = y;
// Set width and height. // Set width and height.
MAIN_FB()->w = w; csi.fb->w = w;
MAIN_FB()->h = h; csi.fb->h = h;
// Set backup width and height. // Set backup width and height.
MAIN_FB()->u = w; csi.fb->u = w;
MAIN_FB()->v = h; csi.fb->v = h;
// Reset pixel format to skip the first frame. // Reset pixel format to skip the first frame.
MAIN_FB()->pixfmt = PIXFORMAT_INVALID; csi.fb->pixfmt = PIXFORMAT_INVALID;
// Auto-adjust the number of frame buffers. // Auto-adjust the number of frame buffers.
omv_csi_set_framebuffers(-1); omv_csi_set_framebuffers(-1);
@ -1205,7 +1207,7 @@ __weak int omv_csi_set_framebuffers(int count) {
omv_csi_abort(true, false); omv_csi_abort(true, false);
// Flush previous frame. // Flush previous frame.
framebuffer_update_jpeg_buffer(); framebuffer_update_jpeg_buffer(csi.fb);
if (csi.pixformat == PIXFORMAT_INVALID) { if (csi.pixformat == PIXFORMAT_INVALID) {
return OMV_CSI_ERROR_INVALID_PIXFORMAT; return OMV_CSI_ERROR_INVALID_PIXFORMAT;
@ -1217,12 +1219,12 @@ __weak int omv_csi_set_framebuffers(int count) {
#if OMV_CSI_HW_CROP_ENABLE #if OMV_CSI_HW_CROP_ENABLE
// If hardware cropping is supported, use window size. // If hardware cropping is supported, use window size.
MAIN_FB()->frame_size = MAIN_FB()->u * MAIN_FB()->v * 2; csi.fb->frame_size = csi.fb->u * csi.fb->v * 2;
#else #else
// Otherwise, use the real frame size. // Otherwise, use the real frame size.
MAIN_FB()->frame_size = resolution[csi.framesize][0] * resolution[csi.framesize][1] * 2; csi.fb->frame_size = resolution[csi.framesize][0] * resolution[csi.framesize][1] * 2;
#endif #endif
return framebuffer_set_buffers(count); return framebuffer_set_buffers(csi.fb, count);
} }
__weak int omv_csi_set_special_effect(omv_csi_sde_t sde) { __weak int omv_csi_set_special_effect(omv_csi_sde_t sde) {
@ -1302,21 +1304,21 @@ __weak const uint16_t *omv_csi_get_color_palette() {
__weak int omv_csi_check_framebuffer_size() { __weak int omv_csi_check_framebuffer_size() {
uint32_t bpp = omv_csi_get_dst_bpp(); uint32_t bpp = omv_csi_get_dst_bpp();
uint32_t size = framebuffer_get_buffer_size(); uint32_t size = framebuffer_get_buffer_size(csi.fb);
return (((MAIN_FB()->u * MAIN_FB()->v * bpp) <= size) ? 0 : -1); return (((csi.fb->u * csi.fb->v * bpp) <= size) ? 0 : -1);
} }
__weak int omv_csi_auto_crop_framebuffer() { __weak int omv_csi_auto_crop_framebuffer() {
uint32_t bpp = omv_csi_get_dst_bpp(); uint32_t bpp = omv_csi_get_dst_bpp();
uint32_t size = framebuffer_get_buffer_size(); uint32_t size = framebuffer_get_buffer_size(csi.fb);
// If the pixformat is NULL/JPEG there we can't do anything to check if it fits before hand. // If the pixformat is NULL/JPEG there we can't do anything to check if it fits before hand.
if (!bpp) { if (!bpp) {
return 0; return 0;
} }
// MAIN_FB() fits, we are done. // csi.fb fits, we are done.
if ((MAIN_FB()->u * MAIN_FB()->v * bpp) <= size) { if ((csi.fb->u * csi.fb->v * bpp) <= size) {
return 0; return 0;
} }
@ -1325,14 +1327,14 @@ __weak int omv_csi_auto_crop_framebuffer() {
omv_csi_set_pixformat(PIXFORMAT_BAYER); omv_csi_set_pixformat(PIXFORMAT_BAYER);
bpp = 1; bpp = 1;
// MAIN_FB() fits, we are done (bpp is 1). // csi.fb fits, we are done (bpp is 1).
if ((MAIN_FB()->u * MAIN_FB()->v) <= size) { if ((csi.fb->u * csi.fb->v) <= size) {
return 0; return 0;
} }
} }
int window_w = MAIN_FB()->u; int window_w = csi.fb->u;
int window_h = MAIN_FB()->v; int window_h = csi.fb->v;
// We need to shrink the frame buffer. We can do this by cropping. So, we will subtract columns // We need to shrink the frame buffer. We can do this by cropping. So, we will subtract columns
// and rows from the frame buffer until it fits within the frame buffer. // and rows from the frame buffer until it fits within the frame buffer.
@ -1373,20 +1375,20 @@ __weak int omv_csi_auto_crop_framebuffer() {
} }
// Crop the frame buffer while keeping the aspect ratio and keeping the width/height even. // Crop the frame buffer while keeping the aspect ratio and keeping the width/height even.
while (((MAIN_FB()->u * MAIN_FB()->v * bpp) > size) || (MAIN_FB()->u % 2) || (MAIN_FB()->v % 2)) { while (((csi.fb->u * csi.fb->v * bpp) > size) || (csi.fb->u % 2) || (csi.fb->v % 2)) {
MAIN_FB()->u -= u_sub; csi.fb->u -= u_sub;
MAIN_FB()->v -= v_sub; csi.fb->v -= v_sub;
} }
// Center the new window using the previous offset and keep the offset even. // Center the new window using the previous offset and keep the offset even.
MAIN_FB()->x += (window_w - MAIN_FB()->u) / 2; csi.fb->x += (window_w - csi.fb->u) / 2;
MAIN_FB()->y += (window_h - MAIN_FB()->v) / 2; csi.fb->y += (window_h - csi.fb->v) / 2;
if (MAIN_FB()->x % 2) { if (csi.fb->x % 2) {
MAIN_FB()->x -= 1; csi.fb->x -= 1;
} }
if (MAIN_FB()->y % 2) { if (csi.fb->y % 2) {
MAIN_FB()->y -= 1; csi.fb->y -= 1;
} }
// Auto-adjust the number of frame buffers. // Auto-adjust the number of frame buffers.
@ -1395,13 +1397,13 @@ __weak int omv_csi_auto_crop_framebuffer() {
} }
#define copy_transposed_line(dstp, srcp) \ #define copy_transposed_line(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ for (int i = csi.fb->u, h = csi.fb->v; i; i--) { \
*dstp = *srcp++; \ *dstp = *srcp++; \
dstp += h; \ dstp += h; \
} }
#define copy_transposed_line_rev16(dstp, srcp) \ #define copy_transposed_line_rev16(dstp, srcp) \
for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ for (int i = csi.fb->u, h = csi.fb->v; i; i--) { \
*dstp = __REV16(*srcp++); \ *dstp = __REV16(*srcp++); \
dstp += h; \ dstp += h; \
} }
@ -1421,7 +1423,7 @@ __weak int omv_csi_copy_line(void *dma, uint8_t *src, uint8_t *dst) {
} }
#endif #endif
if (!csi.transpose) { if (!csi.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u); unaligned_memcpy(dst, src, csi.fb->u);
} else { } else {
copy_transposed_line(dst, src); copy_transposed_line(dst, src);
} }
@ -1435,14 +1437,14 @@ __weak int omv_csi_copy_line(void *dma, uint8_t *src, uint8_t *dst) {
if (csi.mono_bpp == 1) { if (csi.mono_bpp == 1) {
// 1BPP GRAYSCALE. // 1BPP GRAYSCALE.
if (!csi.transpose) { if (!csi.transpose) {
unaligned_memcpy(dst, src, MAIN_FB()->u); unaligned_memcpy(dst, src, csi.fb->u);
} else { } else {
copy_transposed_line(dst, src); copy_transposed_line(dst, src);
} }
} else { } else {
// Extract Y channel from YUV. // Extract Y channel from YUV.
if (!csi.transpose) { if (!csi.transpose) {
unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u); unaligned_2_to_1_memcpy(dst, src16, csi.fb->u);
} else { } else {
copy_transposed_line(dst, src16); copy_transposed_line(dst, src16);
} }
@ -1460,14 +1462,14 @@ __weak int omv_csi_copy_line(void *dma, uint8_t *src, uint8_t *dst) {
} else if ((csi.pixformat == PIXFORMAT_RGB565 && csi.rgb_swap) || } else if ((csi.pixformat == PIXFORMAT_RGB565 && csi.rgb_swap) ||
(csi.pixformat == PIXFORMAT_YUV422 && csi.yuv_swap)) { (csi.pixformat == PIXFORMAT_YUV422 && csi.yuv_swap)) {
if (!csi.transpose) { if (!csi.transpose) {
unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u); unaligned_memcpy_rev16(dst16, src16, csi.fb->u);
} else { } else {
copy_transposed_line_rev16(dst16, src16); copy_transposed_line_rev16(dst16, src16);
} }
#endif #endif
} else { } else {
if (!csi.transpose) { if (!csi.transpose) {
unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t)); unaligned_memcpy(dst16, src16, csi.fb->u * sizeof(uint16_t));
} else { } else {
copy_transposed_line(dst16, src16); copy_transposed_line(dst16, src16);
} }

View File

@ -35,6 +35,7 @@
#include <stdarg.h> #include <stdarg.h>
#include "omv_i2c.h" #include "omv_i2c.h"
#include "imlib.h" #include "imlib.h"
#include "framebuffer.h"
#define OV2640_SLV_ADDR (0x60) #define OV2640_SLV_ADDR (0x60)
#define OV5640_SLV_ADDR (0x78) #define OV5640_SLV_ADDR (0x78)
@ -320,6 +321,8 @@ typedef struct _omv_csi {
omv_i2c_t i2c_bus; // SCCB/I2C bus. omv_i2c_t i2c_bus; // SCCB/I2C bus.
framebuffer_t *fb; // Frame buffer pointer
#ifdef OMV_CSI_PORT_BITS #ifdef OMV_CSI_PORT_BITS
// Additional port-specific members like device base pointer, // Additional port-specific members like device base pointer,
// dma handles, more I/Os etc... are included directly here, // dma handles, more I/Os etc... are included directly here,