Skip to content

video: introduction of STM32 VENC driver for H264 hardware video compression #92884

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions boards/st/stm32n6570_dk/stm32n6570_dk_common.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <zephyr/dt-bindings/flash_controller/xspi.h>
#include <zephyr/dt-bindings/gpio/raspberrypi-csi-connector.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-sw.h>
#include <zephyr/dt-bindings/video/video-interfaces.h>
#include "arduino_r3_connector.dtsi"

Expand All @@ -21,6 +22,7 @@
zephyr,canbus = &fdcan1;
zephyr,display = &ltdc;
zephyr,touch = &gt911;
zephyr,videoenc = &venc;
spi-flash0 = &mx66uw1g45g;
zephyr,flash-controller = &mx66uw1g45g;
zephyr,flash = &mx66uw1g45g;
Expand All @@ -42,7 +44,7 @@
compatible = "zephyr,memory-region";
reg = <0x90000000 DT_SIZE_M(32)>;
zephyr,memory-region = "PSRAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) | DT_MEM_SW_ALLOC_NON_CACHE )>;
};

leds: leds {
Expand Down Expand Up @@ -376,7 +378,7 @@ zephyr_udc0: &usbotg_hs1 {
};

&mac {
status = "okay";
status = "disabled";
pinctrl-0 = <&eth1_rgmii_gtx_clk_pf0
&eth1_rgmii_clk125_pf2
&eth1_rgmii_rx_clk_pf7
Expand All @@ -396,7 +398,7 @@ zephyr_udc0: &usbotg_hs1 {
};

&mdio {
status = "okay";
status = "disabled";
pinctrl-0 = <&eth1_mdio_pd12 &eth1_mdc_pd1>;
pinctrl-names = "default";

Expand Down Expand Up @@ -469,3 +471,7 @@ csi_interface: &dcmipp {
};
};
};

&venc {
status = "okay";
};
1 change: 1 addition & 0 deletions drivers/video/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7725 ov7725.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV2640 ov2640.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_GC2145 gc2145.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_VENC video_stm32_venc.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov7670.c)
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV9655 ov9655.c)
Expand Down
16 changes: 16 additions & 0 deletions drivers/video/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ config VIDEO_I2C_RETRY_NUM
The default is to not retry. Board configuration files or user project can then
use the number of retries that matches their situation.

config VIDEO_BUFFER_USE_MEM_ATTR_HEAP
bool "Use mem attr api for video buffer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool "Use mem attr api for video buffer"
bool "Allocate video buffer from mem_attr heap"

+ maybe this should depends on MEM_ATTR_HEAP

default n

config VIDEO_BUFFER_MEM_SW_ATTRIBUTE
int "Mem SW attribute for video buffer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int "Mem SW attribute for video buffer"
int "Heap allocations attribute"

depends on VIDEO_BUFFER_USE_MEM_ATTR_HEAP
default 1
help
Mem SW attribute for video buffer:
1: ATTR_SW_ALLOC_CACHE
2: ATTR_SW_ALLOC_NON_CACHE
4: ATTR_SW_ALLOC_DMA
Comment on lines +70 to +73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best to avoid duplicating information from the header.
Proposal:

Suggested change
Mem SW attribute for video buffer:
1: ATTR_SW_ALLOC_CACHE
2: ATTR_SW_ALLOC_NON_CACHE
4: ATTR_SW_ALLOC_DMA
Attribute to request when performing allocations from mem_attr heap.
Refer to include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h for
the list of allowed values (one of ATTR_SW_*).
For example, if you want to use ATTR_SW_ALLOC_CACHE defined as:
#define ATTR_SW_ALLOC_CACHE BIT(0)
This symbol should be set equal to 1 (equal to (1 << 0)).


source "drivers/video/Kconfig.esp32_dvp"

source "drivers/video/Kconfig.mcux_csi"
Expand All @@ -76,6 +90,8 @@ source "drivers/video/Kconfig.ov2640"

source "drivers/video/Kconfig.stm32_dcmi"

source "drivers/video/Kconfig.stm32_venc"

source "drivers/video/Kconfig.ov5640"

source "drivers/video/Kconfig.ov7670"
Expand Down
14 changes: 14 additions & 0 deletions drivers/video/Kconfig.stm32_venc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# STM32 VENC driver configuration options

# Copyright (c) 2025 Hugues Fruchet <hugues.fruchet@foss.st.com>
# SPDX-License-Identifier: Apache-2.0

config VIDEO_STM32_VENC
bool "STM32 video encoder (VENC) driver"
default y
depends on DT_HAS_ST_STM32_VENC_ENABLED
select HAS_STM32LIB
select USE_STM32_LL_VENC
select USE_STM32_HAL_RIF if SOC_SERIES_STM32N6X
help
Enable driver for STM32 video encoder peripheral.
11 changes: 11 additions & 0 deletions drivers/video/video_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ LOG_MODULE_REGISTER(video_common, CONFIG_VIDEO_LOG_LEVEL);
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
shared_multi_heap_aligned_alloc(CONFIG_VIDEO_BUFFER_SMH_ATTRIBUTE, align, size)
#define VIDEO_COMMON_FREE(block) shared_multi_heap_free(block)
#elif defined(CONFIG_VIDEO_BUFFER_USE_MEM_ATTR_HEAP)
#include <zephyr/mem_mgmt/mem_attr_heap.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>

#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
mem_attr_heap_aligned_alloc((CONFIG_VIDEO_BUFFER_MEM_SW_ATTRIBUTE << \
DT_MEM_SW_ATTR_SHIFT), align, size)
Comment on lines +33 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
mem_attr_heap_aligned_alloc((CONFIG_VIDEO_BUFFER_MEM_SW_ATTRIBUTE << \
DT_MEM_SW_ATTR_SHIFT), align, size)
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
mem_attr_heap_aligned_alloc(DT_MEM_SW(CONFIG_VIDEO_BUFFER_MEM_SW_ATTRIBUTE), \
align, size)

#define VIDEO_COMMON_FREE(block) mem_attr_heap_free(block)
#else
K_HEAP_DEFINE(video_buffer_pool, CONFIG_VIDEO_BUFFER_POOL_SZ_MAX*CONFIG_VIDEO_BUFFER_POOL_NUM_MAX);
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
Expand All @@ -47,6 +55,9 @@ struct video_buffer *video_buffer_aligned_alloc(size_t size, size_t align, k_tim
struct mem_block *block;
int i;

#if defined(CONFIG_VIDEO_BUFFER_USE_MEM_ATTR_HEAP)
mem_attr_heap_pool_init();
#endif
Comment on lines +58 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: should check that return value is 0 or -EALREADY

/* find available video buffer */
for (i = 0; i < ARRAY_SIZE(video_buf); i++) {
if (video_buf[i].buffer == NULL) {
Expand Down
56 changes: 47 additions & 9 deletions drivers/video/video_stm32_dcmipp.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,25 @@ void HAL_DCMIPP_PIPE_VsyncEventCallback(DCMIPP_HandleTypeDef *hdcmipp, uint32_t
return;
}

/*
* TODO - we only support 1 buffer formats for the time being, setting of
* MEMORY_ADDRESS_1 and MEMORY_ADDRESS_2 required depending on the pixelformat
* for Pipe1
*/
ret = HAL_DCMIPP_PIPE_SetMemoryAddress(&dcmipp->hdcmipp, Pipe, DCMIPP_MEMORY_ADDRESS_0,
(uint32_t)pipe->next->buffer);
if (ret != HAL_OK) {
LOG_ERR("Failed to update memory address");
return;
}

if (pipe->fmt.pixelformat == VIDEO_PIX_FMT_NV12) {
uint32_t addr = (uint32_t)pipe->next->buffer +
pipe->fmt.width * pipe->fmt.height;

ret = HAL_DCMIPP_PIPE_SetMemoryAddress(&dcmipp->hdcmipp, Pipe,
DCMIPP_MEMORY_ADDRESS_1,
addr);
if (ret != HAL_OK) {
LOG_ERR("Failed to update second memory address");
return;
}
}
}

#if defined(STM32_DCMIPP_HAS_CSI)
Expand Down Expand Up @@ -432,6 +440,7 @@ static const struct stm32_dcmipp_mapping {
PIXEL_PIPE_FMT(RGB565, RGB565_1, 0, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(YUYV, YUV422_1, 0, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(YVYU, YUV422_1, 1, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(NV12, YUV420_2, 0, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(GREY, MONO_Y8_G8_1, 0, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(RGB24, RGB888_YUV444_1, 1, (BIT(1) | BIT(2))),
PIXEL_PIPE_FMT(BGR24, RGB888_YUV444_1, 0, (BIT(1) | BIT(2))),
Expand Down Expand Up @@ -460,7 +469,7 @@ static const struct stm32_dcmipp_mapping {
((fmt) == VIDEO_PIX_FMT_GREY || \
(fmt) == VIDEO_PIX_FMT_YUYV || (fmt) == VIDEO_PIX_FMT_YVYU || \
(fmt) == VIDEO_PIX_FMT_VYUY || (fmt) == VIDEO_PIX_FMT_UYVY || \
(fmt) == VIDEO_PIX_FMT_XYUV32) ? VIDEO_COLORSPACE_YUV : \
(fmt) == VIDEO_PIX_FMT_XYUV32 || (fmt) == VIDEO_PIX_FMT_NV12) ? VIDEO_COLORSPACE_YUV : \
\
VIDEO_COLORSPACE_RAW)

Expand All @@ -481,6 +490,9 @@ static inline void stm32_dcmipp_compute_fmt_pitch(uint32_t pipe_id, struct video
{
fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE;
#if defined(STM32_DCMIPP_HAS_PIXEL_PIPES)
if (fmt->pixelformat == VIDEO_PIX_FMT_NV12)
fmt->pitch = fmt->width;

if (pipe_id == DCMIPP_PIPE1 || pipe_id == DCMIPP_PIPE2) {
/* On Pipe1 and Pipe2, the pitch must be multiple of 16 bytes */
fmt->pitch = ROUND_UP(fmt->pitch, 16);
Expand Down Expand Up @@ -1044,9 +1056,21 @@ static int stm32_dcmipp_stream_enable(const struct device *dev)
}
#if defined(STM32_DCMIPP_HAS_CSI)
else if (config->bus_type == VIDEO_BUS_TYPE_CSI2_DPHY) {
ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id, DCMIPP_VIRTUAL_CHANNEL0,
(uint32_t)pipe->next->buffer,
DCMIPP_MODE_CONTINUOUS);
uint32_t addr = (uint32_t)pipe->next->buffer;

if (pipe->fmt.pixelformat == VIDEO_PIX_FMT_NV12) {
DCMIPP_SemiPlanarDstAddressTypeDef spaddr;

spaddr.YAddress = addr;
spaddr.UVAddress = addr + pipe->fmt.width * pipe->fmt.height;
ret = HAL_DCMIPP_CSI_PIPE_SemiPlanarStart(&dcmipp->hdcmipp,
pipe->id, DCMIPP_VIRTUAL_CHANNEL0,
&spaddr, DCMIPP_MODE_CONTINUOUS);
} else {
ret = HAL_DCMIPP_CSI_PIPE_Start(&dcmipp->hdcmipp, pipe->id,
DCMIPP_VIRTUAL_CHANNEL0,
addr, DCMIPP_MODE_CONTINUOUS);
}
}
#endif
else {
Expand Down Expand Up @@ -1193,6 +1217,20 @@ static int stm32_dcmipp_enqueue(const struct device *dev, struct video_buffer *v
LOG_ERR("Failed to update memory address");
return -EIO;
}

if (pipe->fmt.pixelformat == VIDEO_PIX_FMT_NV12) {
uint32_t addr = (uint32_t)pipe->next->buffer +
pipe->fmt.width * pipe->fmt.height;

ret = HAL_DCMIPP_PIPE_SetMemoryAddress(&dcmipp->hdcmipp, pipe->id,
DCMIPP_MEMORY_ADDRESS_1,
addr);
if (ret != HAL_OK) {
LOG_ERR("Failed to update second memory address");
return -EIO;
}
}

if (pipe->id == DCMIPP_PIPE0) {
SET_BIT(dcmipp->hdcmipp.Instance->P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
}
Expand Down
Loading
Loading