征程 6E/M 快速上手实战 Sample-Codec

征程 6E/M 快速上手实战 Sample-Codec

01 Codec 模块简述

Codec(Coder-Decoder)是指编解码器,用于压缩或解压缩视频、图像、音频等媒体数据;J6 Soc 中存在两种硬件编解码单元,分别是 VPU(Video process unit)和 JPU(Jpeg process unit),可提供 4K@90fps 的视频编解码能力和 4K@90fps 的图像编解码能力。

1.1 硬件特性

1.1.1 JPU 硬件特性:

image

1.1.2 VPU 硬件特性:

image

image

1.2 软件功能

MediaCodec 子系统会提供音视频和图像的编解码组件,原始流封装和视频录像等功能。该系统主要会封装底层 codec 硬件资源和软件编解码库,为上层提供编解码能力。开发者可以基于提供的编解码接口实现 H265 和 H264 视频的编解码功能,也可以使用 JPEG 编码功能将摄像头数据存成 JPEG 图片,还可以使用视频录像功能实现摄像头数据的录制。

1.2.1 整体框架:

image

1.2.2 控制接口:

hb_s32 hb_mm_mc_initialize(media_codec_context_t *context):初始化编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_INITIALIZED 状态。

hb_s32 hb_mm_mc_configure(media_codec_context_t *context):配置编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_CONFIGURED 状态。

hb_s32 hb_mm_mc_start(media_codec_context_t *context, const mc_av_codec_startup_params_t *info):启动编码/解码流程,MediaCodec 将创建编解码实例、设置序列或解析数据流、注册 Framebuffer、编码头信息等,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_STARTED 状态。

hb_s32 hb_mm_mc_stop(media_codec_context_t *context):停止编码/解码流程,退出所有子线程并释放相关资源,调用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 状态。

hb_s32 hb_mm_mc_release(media_codec_context_t *context):释放 MediaCodec 内部所有资源,用户需要在调用该函数前调用 hb_mm_mc_stop 来停止编解码,操作成功后 MediaCodec 进入 MEDIA_CODEC_STATE_UNINITIALIZED 状态。

hb_s32 hb_mm_mc_queue_input_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):填充需要处理的 buffer 到 MediaCodec 中。

hb_s32 hb_mm_mc_dequeue_input_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):获取输入的 buffer。

hb_s32 hb_mm_mc_queue_output_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, hb_s32 timeout):返还处理完的 output buffer 到 MediaCodec 中。

hb_s32 hb_mm_mc_dequeue_output_buffer(media_codec_context_t *context, media_codec_buffer_t *buffer, media_codec_output_buffer_info_t *info, hb_s32 timeout):获取输出的 buffer。

1.2.3 码率控制模式:

MediaCodec 支持对 H264/H265 和 MJPEG 协议的码率控制,分别支持 H264/H265 编码通道的 CBR、VBR、AVBR、FixQp 和 QpMap 五种码率控制方式,以及支持 MJPGE 编码通道的 FixQp 码率控制方式。

*1.2.3.1 CBR 说明:*

CBR 表示恒定码率,能够保证整体的编码码率稳定。下面是 CBR 模式下各个参数含义:

image

*1.2.3.2 VBR 说明:*

VBR 表示可变码率,简单场景分配比较大的 qp,压缩率小,质量高。复杂场景分配较小 qp,可以保证编码图像的质量稳定。下面是 VBR 模式下各个参数含义:

image

1.2.3.3 AVBR 说明:

ABR 表示恒定平均目标码率,简单场景分配较低码率,复杂场景分配足够码率,使得有限的码率能够在不同场景下合理分配,这类似 VBR。同时一定时间内,平均码率又接近设置的目标码率,这样可以控制输出文件的大小,这又类似 CBR。可以认为是 CBR 和 VBR 的折中方案,产生码率和图像质量相对稳定的码流。下面是 AVBR 模式下各个参数含义:

image

1.2.3.4 FixQp 说明:

FixQp 表示固定每一个 I 帧、P 帧的 QP 值,对于 I/P 帧可以分别设值。下面是 FixQp 模式下各个参数含义:

image

1.2.3.5 QPMAP 说明:

image

1.2.4 编码效果:

根据当前客户使用 codec 进行视频编码的场景,多将码率模式设置为 CBR,当编码的场景较为复杂时,为了保证视频质量,硬件会自动提高码率值,导致输出的视频较预期更大。因此为了兼顾视频质量和实际码率,需要统筹 bit_rate 和 max_qp_I/P 值的设置。下面给出了全 I 帧模式下,不同复杂场景下,码率设置为 15000kbps 时,不同 max_qp_I 下实际码率和 qp 的情况(不同场景复杂程度不同,下列数据仅供参考):

image

H264/H265 编码支持 GOP 结构的设置,用户可从预置的 3 种 GOP 结构种选择,也可自定义 GOP 结构。

GOP 结构表可定义一组周期性的 GOP 结构,该 GOP 结构将用于整个编码过程。单个结构表中的元素如下表所示,其中可以指定该图像的参考帧,如果 IDR 帧后的其他帧指定的参考帧为 IDR 帧前的数据帧,编码器内部会自动处理这种情况使其不参考其他帧,用户无需关心这种情况。用户在自定义 GOP 结构时需要指明结构表的数量,最多可定义 3 个结构表,结构表的顺序需要按照解码顺序排列。下面表示了结构表中各个元素的含义:

image

征程6 中一共支持设置九种 GOP 预置结构:

image

02 Codec-Sample 使用

编码 yuv 图像, 生成 h264/h265 视频或 jpg 图片。

2.1 encoder

** **

2.1.1 调用流程

采用 MediaCodec 的 poll 模式来解耦输入和输出,可使编码帧率性能达到最优。在主线程中灌 YUV 数据:取出一个空的 input buffer,配置 YUV 数据的地址信息(如 phys addr),再 queue input buffer 并通知编码器处理该帧数据;另一个线程取输出码流:通过 select 接收硬件编码完成通知,取出一个硬件填满输出码流的 output buffer,将编码结果写到文件中后归还 output buffer。

image

check_and_init_test:打开输入文件(yuv),并打开内存管理模块申请内存缓冲;

hb_mm_mc_initialize:初始化编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_INITIALIZED 状态;

hb_mm_mc_configure:配置编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_CONFIGURED 状态;

hb_mm_mc_start:启动编码/解码流程,MediaCodec 将创建编解码实例、设置序列或解析数据流、注册 Framebuffer、编码头信息等,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_STARTED 状态;

hb_mm_mc_dequeue_input_buffer:获取输入的 buffer;

read_input_frames:从输入文件(yuv)中读取视频帧数据,并将其刷新到 buffer 中;

hb_mm_mc_queue_input_buffer:填充需要处理的 buffer 到 MediaCodec 中;

hb_mm_mc_dequeue_output_buffer:获取输出的 buffer;

write_output_streams:outputbuffer 写入 outFile 中;

hb_mm_mc_queue_output_buffer:返还处理完的 output buffer 到 MediaCodec 中;

hb_mm_mc_stop:停止编码/解码流程,退出所有子线程并释放相关资源,调用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 状态;

hb_mm_mc_release:释放 MediaCodec 内部所有资源,操作成功后 MediaCodec 进入 MEDIA_CODEC_STATE_UNINITIALIZED 状态。

2.1.2 源码主干:

#Sample源码路径
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/codec_sample

Encoder:

void do_sync_encoding(void *arg)
{hb_s32 ret = 0;MediaCodecTestContext *ctx = (MediaCodecTestContext *)arg;media_codec_context_t *context = NULL;media_codec_buffer_t inputBuffer;media_codec_buffer_t outputBuffer;media_codec_output_buffer_info_t info;ret = check_and_init_test(ctx);if (ret != 0) {printf("check_and_init_test failed(%d).\n", ret);return;}context = ctx->context;ret = hb_mm_mc_initialize(context);if (ret != 0) {printf("hb_mm_mc_initialize failed(%d).\n", ret);return;}// set_message(ctx);ret = hb_mm_mc_configure(context);if (ret != 0) {printf("hb_mm_mc_configure failed(%d).\n", ret);hb_mm_mc_release(context);return;}mc_av_codec_startup_params_t startup_params;startup_params.video_enc_startup_params.receive_frame_number = 0;ret = hb_mm_mc_start(context, &startup_params);if (ret != 0) {printf("hb_mm_mc_start failed(%d).\n", ret);hb_mm_mc_release(context);return;}do {// process input buffersmemset(&inputBuffer, 0x00, sizeof(media_codec_buffer_t));ret = hb_mm_mc_dequeue_input_buffer(context, &inputBuffer, 3000);if (ret == 0) {ret = read_input_frames(ctx, &inputBuffer);if (ret <= 0) {printf("There is no more input data(ret=%d)!\n", ret);inputBuffer.vframe_buf.size = 0;inputBuffer.vframe_buf.frame_end = TRUE;}ctx->input_num++;// ASSERT_EQ(do_encode_params_setting(ctx, &inputBuffer), 0);ret = hb_mm_mc_queue_input_buffer(context, &inputBuffer, 100);if (ret != 0) {break;}} else {printf("dequeue input buffer fail(%d).\n", ret);if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {break;}}// process output buffersmemset(&outputBuffer, 0x00, sizeof(media_codec_buffer_t));memset(&info, 0x00, sizeof(media_codec_output_buffer_info_t));ret = hb_mm_mc_dequeue_output_buffer(context, &outputBuffer, &info, 3000);if (ret == 0) {write_output_streams(ctx, &outputBuffer);ret = hb_mm_mc_queue_output_buffer(context, &outputBuffer, 100);if (outputBuffer.vstream_buf.stream_end) {printf("There is no more output data!\n");break;}if (ret) {break;}} else {printf("dequeue output buffer fail(ret=0x%x).\n", ret);if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {break;}}} while(TRUE);ret = hb_mm_mc_stop(context);if (ret != 0) {printf("hb_mm_mc_stop failed(%d).\n", ret);}ret = hb_mm_mc_release(context);if (ret != 0) {printf("hb_mm_mc_release failed(%d).\n", ret);}check_and_release_test(ctx);}

2.2 decoder

VPU/JPU 从 DDR 中获得 H265/H264/JPG 输入源,经过硬件解码后生成 yuv 图像

2.2.1 调用流程

image

check_and_init_test:打开输入文件(h265),并打开内存管理模块申请内存缓冲;

hb_mm_mc_initialize:初始化编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_INITIALIZED 状态;

hb_mm_mc_configure:配置编码或解码器,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_CONFIGURED 状态;

hb_mm_mc_start:启动编码/解码流程,MediaCodec 将创建编解码实例、设置序列或解析数据流、注册 Framebuffer、编码头信息等,调用成功后 MediaCodec 进入 MEDIA_CODEC_STATE_STARTED 状态;

hb_mm_mc_dequeue_input_buffer:获取输入的 buffer;

hb_mm_mc_dequeue_output_buffer:获取输出的 buffer;

write_output_streams:outputbuffer 写入 outFile 中;

hb_mm_mc_queue_output_buffer:返还处理完的 output buffer 到 MediaCodec 中;

hb_mm_mc_stop:停止编码/解码流程,退出所有子线程并释放相关资源,调用成功后 MediaCodec 回到 MEDIA_CODEC_STATE_INITIALIZED 状态;

hb_mm_mc_release:释放 MediaCodec 内部所有资源,操作成功后 MediaCodec 进入 MEDIA_CODEC_STATE_UNINITIALIZED 状态。

** **

2.2.2 源码主干:

void do_sync_decoding(void *arg)
{int ret = 0;MediaCodecTestContext *ctx = (MediaCodecTestContext *)arg;media_codec_context_t *context = NULL;media_codec_buffer_t inputBuffer;media_codec_buffer_t outputBuffer;media_codec_output_buffer_info_t info;ret = check_and_init_test(ctx);if (ret != 0) {printf("check_and_init_test failed(%d).\n", ret);return;}   context = ctx->context;context = ctx->context;ret = hb_mm_mc_initialize(context);if (ret != 0) {printf("hb_mm_mc_initialize failed(%d).\n", ret);return;}ret = hb_mm_mc_configure(context);if (ret != 0) {printf("hb_mm_mc_configure failed(%d).\n", ret);hb_mm_mc_release(context);return;}mc_av_codec_startup_params_t startup_params;startup_params.video_enc_startup_params.receive_frame_number = 0;ret = hb_mm_mc_start(context, &startup_params);if (ret != 0) {printf("hb_mm_mc_start failed(%d).\n", ret);hb_mm_mc_release(context);return;}do {// process input buffersret = hb_mm_mc_dequeue_input_buffer(context, &inputBuffer, 3000);if (ret == 0) {ret = read_input_streams(ctx, &inputBuffer);if (ret <= 0) {printf("There is no more input data(ret=%d)!\n", ret);inputBuffer.vstream_buf.stream_end = TRUE;inputBuffer.vstream_buf.size = 0;ctx->lastStream = 1;}ret = hb_mm_mc_queue_input_buffer(context, &inputBuffer, 100);if (ret != 0) {break;}} else {if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {char info[256];hb_mm_strerror(ret, info, 256);printf("dequeue input buffer fail.(%s)\n", info);break;}}// process output buffersmemset(&outputBuffer, 0x00, sizeof(media_codec_buffer_t));memset(&info, 0x00, sizeof(media_codec_output_buffer_info_t));ret = hb_mm_mc_dequeue_output_buffer(context, &outputBuffer, &info, 100);if (ret == 0) {printf("info.video_frame_info.nalu_type %d\n", info.video_frame_info.nalu_type);write_output_frames(ctx, &outputBuffer);if (ctx->enable_get_userdata) {mc_user_data_buffer_t userdata = {0};ret = hb_mm_mc_get_user_data(context, &userdata, 0);if (!ret) {printf("Get userdata %d:\n", userdata.size);for (uint32_t i = 0; i < userdata.size; i++) {if (i < 16) {printf("userdata[i]:%x\n", userdata.virt_addr[i]);} else {printf("userdata[i]:%c\n", userdata.virt_addr[i]);}}ret = hb_mm_mc_release_user_data(context, &userdata);} else {ret = 0;}}ret = hb_mm_mc_queue_output_buffer(context, &outputBuffer, 100);if (outputBuffer.vframe_buf.frame_end) {printf("There is no more output data!\n");break;}if (ret) {break;}} else {char info[256];hb_mm_strerror(ret, info, 256);printf("dequeue output buffer fail.(%s)\n", info);if (ret != (int32_t)HB_MEDIA_ERR_WAIT_TIMEOUT) {break;}}} while (TRUE);ret = hb_mm_mc_stop(context);if (ret != 0) {printf("hb_mm_mc_stop failed(%d).\n", ret);}ret = hb_mm_mc_release(context);if (ret != 0) {printf("hb_mm_mc_release failed(%d).\n", ret);}check_and_release_test(ctx);
}

2.3 编译&运行

获取 AppSDK 包后,进入 appuser 执行:

*其中 hbrootfs-sdk_0.0.1.XXX_all.deb 是地平线自己的库和头文件,rootfs-sdk-focal_0.0.1.XXX_all.deb 是系统库,aarch64-linux-hb-gcc_12.2.0_amd64.deb 是 gcc 12.2.0 工具链,目前在 ubuntu22.04 非 docker 环境下运行正常。其它环境不能保证。

dpkg-deb -x rootfs-sdk*.deb ./sdk
dpkg-deb -x hbrootfs-sdk*.deb ./sdk
##移动sdk库路径,本文档放入/usr/lib中
sudo mv sdk/ /usr/lib

进入 toolchain 执行:

dpkg -x aarch64-linux-hb-gcc_12.2.0_amd64.deb ./arm-gnu-toolchain
##移动toolchain库路径,本文档放入/usr/lib中
sudo mv arm-gnu-toolchain/ /usr/lib
nano ~/.bashrc
##添加系统路径
export PATH="/usr/lib/arm-gnu-toolchain/bin:$PATH"
export LD_LIBRARY_PATH="/usr/lib/arm-gnu-toolchain/lib:$LD_LIBRARY_PATH"
##
source ~/.bashrc

Sample 代码路径:

#Sample源码路径
/test/samples/platform_samples/source/S83_Sample/S83E04_Module/codec_sample

运行参数说明:

image

复制/src 源码到新建文件夹 codec 并构建新 Makefile:

codec
├── Makefile
└── src├── sample.c├── sample_common.c├── sample.h├── sample_vdec.c└── sample_venc.c

Makefile:

CROSS_COMPILE = aarch64-none-linux-gnu-
OUTPUT_HBROOTFS_DIR = /usr/lib/sdkCXX := ${CROSS_COMPILE}gccINC_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/include
INC_DIR += ${OUTPUT_HBROOTFS_DIR}/include
LIB_DIR := ${OUTPUT_HBROOTFS_DIR}/usr/hobot/lib 
LIB_DIR += ${OUTPUT_HBROOTFS_DIR}/usr/lib/aarch64-linux-gnu
LIBS += -lpthread -ldl -lhbmem -lalog  -lmultimedia
LIBS += -lavformat -lavcodec -lavutil -lswresample
CXXFLAGS := -Wall -O2 $(foreach dir,$(INC_DIR),-I$(dir))
LDFLAGS := $(addprefix -L, $(LIB_DIR)) $(LIBS)SRC_DIR := src
TARGET := program
SRCS := $(wildcard $(SRC_DIR)/*.c)OBJS := $(SRCS:.c=.o)$(TARGET): $(OBJS)$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
%.o: %.c$(CXX) $(CXXFLAGS) -c $< -o $@
clean:rm -f $(OBJS) $(TARGET)

执行 make 完成编译,生成的文件为。/program

image

使用 WinScp 将 program 传输到单板上。*需要 encode 的 yuv 文件请用户自行准备,本文档使用 PYM 生成的 yuv 文件。

*WinScp 使用方法请参考征程 6E/M 底软开发 Sample-IPC 2.1.2

通过 ssh 或串口进入/home/hobot/执行:*w 和 h 需要进行 16 字节对齐,如原始 yuv 不支持则会出现数据丢失

chmod +x program
#encode
#代码可参考源码目录中的codec_sample.sh
./program -m 0 -c 3 -w 3840 -h 2160 -p 1 -i 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv -o ./3840x2160.jpg
./program -m 0 -c 1 -w 3840 -h 2160 -p 1 -i 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv -o ./3840x2160.h265

Sample 运行时日志:

g_samplemode = 0
g_codecid = 3
g_width = 3840
g_height = 2160
g_pixfmt = 1
g_pixfmt = 1
g_inputfilename = 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv
g_outputfilename = ./3840x2160.jpg
InputFileName = 3840x2160_pipe0_pym_ds0_f0_roi_1.yuv
OutputFileName = ./3840x2160.jpg
Thread use internal buffer mode, 0 rc mode
Failed to read input file (size=12441600)
There is no more input data(ret=0)!
There is no more output data!

生成的缩放 jpg 文件存放在指定-o 目录下。

生成的 Jpeg 效果如下:

image

*有关 jpg 工具查看 1080p 图片时出现绿边问题:

image

问题说明:这是因为当前 ip 进行编码时按照 16 位对齐进行,假如到最后如果是 8 位对齐而不是 16 位对齐,那么编码器就会在后面补齐,这部分补齐的数据是随机产生的,不属于有效数据;

#decode
#使用上述生成的3840x2160.h265为例
./program -m 1 -c 1 -w 3840 -h 2160 -p 1 -i 3840x2160.h265 -o ./3840x2160.yuv

image

使用 YUView 打开生成的 3840x2160.yuv:

image

*注意配置 offset:

image

image

附件:

1、[codec.7z]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/797099.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【触想智能】工控一体机在船舶航运上应用的优势和应用场景分析

随着船舶航运业的发展,工控一体机在船舶航运领域上的应用越来越广泛。工控一体机的功能和性能可以加强船舶航运领域的自动化和智能化水平。下面,触想智能小编针对工控一体机在船舶航运领域上应用的优势和应用场景进行简单分析,给大家借鉴参考。一、船舶管理工控一体机可以通…

工控机维修

工控机维修是一个涉及硬件和软件多方面知识的综合性工作,针对工控机可能出现的各种故障,以下是一些常见的维修方法和注意事项: 一、常见故障原因及维修方法 电源故障 故障现象:电源指示灯不亮或闪烁,无法启动机器。 解决方法: 检查电源插头是否插紧,电源线是否损坏。 尝…

SAP B1 Web Client MS Teams App集成连载一:先决条件/Prerequisites

一、先决条件/Prerequisites 在设置 SAP Business One 应用之前,确保您已具备以下各项: Before you set up the SAP Business One app, make sure you have acquired the following: 1.Microsoft Teams 管理员账户/A Microsoft Teams admin account您需要使用此账户为贵组织上…

异构仿真:打造更可靠的综合化航空电子软件

​综合化航空电子系统是一类典型的安全关键系统,具有分布式、异构、计算资源和物理资源强耦合等特征。随着IMA(Integrated Modular Avionics,综合模块化航空电子)系统趋于复杂化和智能化,系统的功能越来越多地采用软件来实现,如何打造更为可靠的综合化航空电子软件成为一…

Halo 开发者指南——项目运行、构建

准备工作 环境要求OpenJDK 17 LTS Node.js 20 LTS pnpm 9 IntelliJ IDEA Git Docker(可选)名词解释 工作目录 指 Halo 所依赖的工作目录,在 Halo 运行的时候会在系统当前用户目录下产生一个 halo-next 的文件夹,绝对路径为 ~/halo-next。里面通常包含下列目录或文件:​db​…

react-pdf预览在线PDF的使用

记录在PC端和移动端使用react-pdf插件预览pdf文件的使用1、在react项目中安装react-pdf依赖包 建议安装8.0.2版本的react-pdf,如果安装更高版本的可能出现一些浏览器的兼容性问题;npm install react-pdf@8.0.2 -S 1、PC端的使用 1.1、封装一个组件:PdfViewModal.tsximport …

数业智能心大陆探索生成式AIGC创新前沿

近日,数业智能心大陆参与了第九届“创客中国”生成式人工智能(AIGC)中小企业创新创业大赛。在这场汇聚了众多创新力量的研讨过程中,广东数业智能科技有限公司基于多智能体的心理健康技术探索与应用成果,从众多参赛者中脱颖而出。彰显了公司在技术创新领域的深厚实力,也为…

CSS 设置中英文和数字文本的换行

CSS 设置中英文和数字文本的换行CSS 设置中英文和数字文本的换行 在 CSS 中,可以使用不同的规则来控制中文、英文、数字等文本的换行行为。以下是一些常用的 CSS 属性和技巧,用于处理不同类型文本的换行。 1. 中文自动换行 中文字符之间通常不需要额外处理即可自动换行。不过…

ADC_DMA_双buffer传输

ADC有很多通道,但是只有一个寄存器,在使用过程中,常常使用DMA去传输,速度非常快,该文探究了在RTOS下使用两个线程以及DMA的中断,之间去同步,从而确保对ADC采集的连续性和快速性。ADC_DMA_双buffer传输线程A切换buffer地址 开启ADC转换,并使用DMA传输 等待获取DMA中断的…

ubuntu下stlink烧录stm32代码

ubuntu下stlink烧录stm32代码ubuntu下stlink烧录stm32代码,记录备忘 0、环境一、下载stlink驱动 二、编译 三、 安装stlink驱动 四、验证安装成功 usb口接stlink后,查到设备五、 烧录 六、其它

高等数学 2.2 函数的求导法则

目录1、常数和基本初等函数的导数公式2、函数的和、差、积、商的求导法则3、反函数的求导法则4、复合函数的求导法则 1、常数和基本初等函数的导数公式公式 公式(1) \((C) = 0\) (2)\((x^{\mu}) = \mu x^{\mu - 1}\)(3)\((\sin x) = \cos x\) (4)\((\cos x) = - \sin x…

自尽氚气出题人+rui 之 氚荠甲苯二酸 代码

运输计划 显然我们可以处理出每个区间正方向和反方向走的代价,那么最后的问题可以转化为每个点选择 \(0/1\) 之一,要求区间的选择两两不冲突,在这个基础上最小化代价之和。 则,可以参考 \(2-SAT\) 的思路,处理出每个点选择 \(0/1\) 两两的限制状况,不难发现这种限制应该是…