57.1 初学者重要提示" ~/ [( @& d% l) p9 z! y7 f
由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。. C3 X, q/ p9 @2 b/ V* ]9 \/ W Q
测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。- h( _ o) h( o2 |0 w+ m5 i& R2 d2 f
JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
! G' P( f0 l+ W9 R( X 本章JPEG相关概念的介绍参考了wiki百科和百度百科。
5 G! G9 i. Q, c* d" x3 @57.2 硬件JPEG基础知识2 m! R6 {+ J8 z# [+ O
对于STM32H7的硬件JPEG了解到以下几点即可:
0 f- r0 O& h6 V! T/ p2 o 支持JPEG解码和编码。. V0 t. Y9 w) |0 l# C
对每个像素数据进行编解码只需一个时钟周期。: @, Z! \0 O: l
支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。( N9 m' z# k% `
编解码时每图像分量8位深度。
! ?" c& G+ W9 H% g7 p+ q" F2 E57.2.1 JPEG硬件框图) x. k! F# \2 W; n" ]! Z3 ^
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
i0 e6 \: c* E" k; `% f/ K* L0 q" V
- D5 t- u2 J1 r( ?2 T
+ A* E& N) @6 ?
通过这个框图,我们可以得到如下信息:. P' N+ H4 |! \" \# O
6 `" M! t7 `; P+ |5 x7 v JPEG硬件外设支持编码和解码# C/ s6 o' M# j/ x& i
并且对于输入数据和输出数据都有FIFO支持。
, { Z3 x+ I3 _2 c9 V. C3 d! o! J
' H& R4 B% w; ^6 r% ` I6 [ jpeg_hclk# E9 v1 m) T5 q* {! e) V
为JPEG内核和寄存器提供时钟。
' N3 r+ x A8 U0 P$ c: G" D% t! ^3 ~* J& q
jpeg_it* n4 r! i& a2 t% m- _! s9 O9 M
JPEG全局中断输出。 n# v" m, |* S* ^' i
8 X& A _$ Y/ I: ^! N' y jpeg_ift_trg
- z1 e* B5 c" \4 H: v6 {JPEG输入FIFO阈值信号,可触发MDMA。( ^3 Y* P/ U5 J3 Z
3 n( s7 i2 j. ?2 A
jpeg_ifnf_trg
" ^, t) V* H$ W- m6 [+ e7 eJPEG输入FIFO未满信号,可触发MDMA。
+ h/ U5 V6 p: ]3 y
* v0 Z0 l1 [6 M( f, N6 | jpeg_oft_trg
( P/ m: x+ z$ g! gJPEG输出FIFO阀值信号,可触发MDMA。) q/ {' |0 C$ ?3 R+ d7 f1 K
: ]5 r: r7 C4 g& E4 a
jpeg_ofne_trg4 P3 x# |1 D2 [5 R; g
JPEG输出FIFO非空信号,可触发MDMA。* f/ K1 u( o5 B) g& V5 G
3 a6 h- P- c: u8 l% ?& m" K
jpeg_oec_trg- G! G$ h" ]0 A) M& A$ F& e- p7 j
JPEG转换结束信号,可触发MDMA。
3 B. e. @% J; {; |$ @ Q* j+ V
57.2.2 YCbCr颜色格式+ e, y3 N( w! N$ g6 u$ n: b
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)
" M3 w B8 t/ c' c( L; ]) q% V0 h
1 w K6 O) L' e( x: ^4 Z7 \( V正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
8 b( E6 e8 ]# Z3 C u0 I* E" v `% s+ B, p9 y) U# z
YCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
* ?* Z3 ~: U8 C; a* f a. F1 a( m1 X. | l! v
在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
2 V! w. ]% l+ ?& B, p8 c6 }9 T$ B$ y
57.2.3 YCbCr采样格式: ?% F2 o) H8 [
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。+ |4 x7 b- j; W5 h+ {9 m
: i0 d ]( v1 }: u
4:2:06 m$ L" N5 p' q# k
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。4 `) E% J! o" W6 j
- A; [# ]7 T7 {& S9 Y
4:2:22 |, g$ i% F; z# N& f6 T- [8 ?
表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。* b3 g1 q7 x) s. s- r: i* e
- G1 s; Q5 N" p5 H* @. z
4:4:40 ~5 H1 B4 ]+ i. r+ B/ |8 |
表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。
+ \4 ]4 w2 \3 ]+ t9 {, R2 t) w$ ~$ H: _( p: Z3 \, g6 I' P9 L4 W1 Y
具体的采样方式如下图所示,以8个像素为一个单元进行采样:
* p% |7 P x+ H: L2 K
# U* J2 \$ Q4 f5 Z! y* a
' @% t% K' p, S8 E# D5 |+ |5 C( Q6 J2 f
/ Q! U0 U" F& ^0 S: v7 j由上面的截图可以了解到:- t1 ?8 a7 s9 Z" h
/ U4 }- Z% j4 ^, o4:4:4表示Y通道,Cb+Cr通道全部采样。& D; {% t3 l. @
; o4 \# M" K" F2 _4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。
; [# G: H5 f6 T, V! O+ m7 D7 p7 P3 }" I5 P4 w# [
4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。7 J# |5 b" |9 z: y4 E
" I V2 q, {. d) X% p% Z- u a下面是整体效果,方便大家更好的理解:5 o' B2 l1 s- v* z$ d
* ]0 m# v( |) t5 P. T1 v, q
7 m6 N) c% D) W. b; m* A: x% S
X8 F2 v# f1 ~& |6 X$ q" T J! d4 c2 ~1 n" T5 H8 y* i" k: O
5 I. s) ]5 M0 I; ^# h57.2.4 YCbCr的优势
# H# ]' E0 X6 B0 q8 [& VRGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
; a' i/ t6 O0 R- m! C& W- e, a3 A8 N& e: A: J
57.2.5 YCbCr和RGB互转
) r8 k6 L& A6 P0 K9 \% j为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。
1 E% l0 l7 G! @7 a0 f' s/ U- V4 O1 o9 r5 F+ s
C' n3 D7 z! x
+ _7 U0 L! O3 g. {0 B. _& Q/ P1 R下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
$ s1 @+ B! ^' z! N) k$ v) ?- z
6 O( P. c0 o) H, J8 e
$ Y8 g0 F; N; V4 [5 f4 Y, m+ _- G
57.2.6 JPEG编解码知识
5 n8 Y/ Q* ?3 f3 p4 J) N0 FJPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下。
# y/ Z. ^+ o4 j0 T/ N4 i
* y _7 ^ I$ q; K' z, m5 W0 g57.3 硬件JPEG的HAL库用法% o# f( T- H/ y4 w8 g1 p- {
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
9 y7 h0 {5 [. M4 X }* [! S$ C# D7 [
57.3.1 JPEG寄存器结构体JPEG_TypeDef
6 q! C% ~8 i2 x" j! SJPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
; B1 @7 P; L% k( Z2 l- H; c$ `! ]7 K2 ]. j. }6 {1 h; B/ L. k! x
- typedef struct
4 d# I/ L% b6 [3 Z; J6 C" @ - {' N9 q4 W7 R: m/ G# r# d+ |
- __IO uint32_t CONFR0; 3 W7 t' k8 U, u
- __IO uint32_t CONFR1;
6 F6 b6 y4 K1 L! v" v8 a, z - __IO uint32_t CONFR2;
0 v& [. t6 F1 c! U - __IO uint32_t CONFR3;
^% X3 o0 p' i+ T. S$ y' A$ A7 Y - __IO uint32_t CONFR4;
# m8 {1 ~* H2 u J7 ~* P - __IO uint32_t CONFR5;
& B J2 O8 d2 p: _ M - __IO uint32_t CONFR6; 8 v/ D. G" R; e6 N9 v9 _
- __IO uint32_t CONFR7;
% g ]: Q2 A2 ?+ R# V/ X0 Y% M - uint32_t Reserved20[4];
# G8 I5 S. ]1 b4 D- l; D - __IO uint32_t CR; ) b$ N2 W* O5 B# [3 X$ Y
- __IO uint32_t SR; / D$ h: ^% f7 Q2 Y: a, ]
- __IO uint32_t CFR;
* j8 a }( V# I0 P. U. _ - uint32_t Reserved3c;
, r+ Z, H% D5 o# a) g - __IO uint32_t DIR; ' J" ~) P$ O# ]# R: i% H
- __IO uint32_t DOR; 6 k2 w" C* s+ p/ R4 ?! L+ v" C
- uint32_t Reserved48[2];
; A% m* w. w0 J# k! @ G - __IO uint32_t QMEM0[16];
7 D; |4 [) T! Z c! ? V$ @ - __IO uint32_t QMEM1[16];
5 Z6 Z& }* t! | - __IO uint32_t QMEM2[16];
8 s# n% t% b: G* g - __IO uint32_t QMEM3[16]; & q, O# i7 R3 m1 y
- __IO uint32_t HUFFMIN[16];
$ V- ^$ T4 Z* y }5 a8 i - __IO uint32_t HUFFBASE[32];
0 j. Y, m+ u0 f; T" P7 o1 h - __IO uint32_t HUFFSYMB[84];
, ^0 Q' u. w$ N% { - __IO uint32_t DHTMEM[103]; 2 B: U8 f1 Y; |5 u
- uint32_t Reserved4FC; 4 Z- u0 q- n Y$ \# w0 x. z
- __IO uint32_t HUFFENC_AC0[88];
& X! P2 c- t) j8 V - __IO uint32_t HUFFENC_AC1[88];
l& _- _1 J. \8 y* D4 L7 o - __IO uint32_t HUFFENC_DC0[8];
" {# c& l3 ]- H; g9 h1 m- w - __IO uint32_t HUFFENC_DC1[8];
9 I d" v( a2 l - } JPEG_TypeDef;) Q& _; C% F# A; m$ _6 E
复制代码 ! c# `3 ~& s0 v, i. I, V+ u
7 k0 {, A9 Z( y: ^) e/ h
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:+ N2 E- x0 X! x. @2 d, ?0 t2 E2 J
v: m' ^% M, h4 r- f H g
- #define __O volatile /*!< Defines 'write only' permissions */$ F$ X; W3 Y# f7 o% H
- #define __IO volatile /*!< Defines 'read / write' permissions */
复制代码
. o6 b3 C- z/ ~/ S
2 \7 [ `: k: t
! O. C# x8 ^9 L$ ^下面我们再看JPEG的定义,在stm32h743xx.h文件。
# J4 | l8 N; y- o2 \0 s' S
. N! e' X* \) M8 \- #define PERIPH_BASE ((uint32_t)0x40000000)9 S' z- X# c" {3 `- j
- #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000)
' y1 a# ^+ w! c% u2 m) ? y - #define JPEG ((JPEG_TypeDef *) JPGDEC_BASE)% f# G& q, I/ _. C0 n. v0 N4 S. b
- #define JPGDEC_BASE (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码
5 F- T% S' r5 I. v: C
8 H' B- {- K5 o+ {1 i
3 J( e: Y; k; ^, P( D我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。
" I% j( k& c- I: F: b
3 U* f7 h5 P5 s. ^4 l57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
: g# b! l T' G! e7 v' }; r此结构体用于JPEG的编解码参数,具体定义如下:" q. b- q4 j! r8 ]9 V$ W
3 F4 [3 W& n$ L% k# a6 r
- typedef struct$ n4 x3 {3 R* m
- {8 Q# B, b2 l4 S ~; Z. o, Q H
- uint8_t ColorSpace; " z* b/ b8 @1 W7 ^$ U7 Q; @
- uint8_t ChromaSubsampling;
/ s1 c0 A/ h# K9 y; o - uint32_t ImageHeight;
0 v' j' `( C4 [$ w7 Q1 e - uint32_t ImageWidth;
8 u; T! J3 \/ G- y' W* T - uint8_t ImageQuality;
" G, L) _3 k3 {. I) ?: { - }JPEG_ConfTypeDef;
复制代码
3 A0 i4 i( F2 P" U- l9 N p下面将这几个参数逐一为大家做个说明:
, ]1 g' n. e4 k& X, ]( l6 b |- z5 |2 Q5 p! D+ y2 k. B2 Z* G
uint8_t ColorSpace3 v0 n0 c! x' A# z- T
此参数用于设置输出数据流中的量化表,具体支持的参数如下:
. O0 {; Y" }4 i2 q, S% {$ V5 x
. O1 T0 b9 ]! v, ~+ K* s- #define JPEG_GRAYSCALE_COLORSPACE ((uint32_t)0x00000000U) /* 灰度(1 个量化表)*/5 d: y) K& T1 V# y' n. S1 \5 x( s
- #define JPEG_YCBCR_COLORSPACE JPEG_CONFR1_COLORSPACE_0 /* YUV(2 个量化表) */ [9 c8 y' ?* u+ @: u# ?
- #define JPEG_CMYK_COLORSPACE JPEG_CONFR1_COLORSPACE /* CMYK(4 个量化表)*/
复制代码 . h; C8 H$ I: R
uint8_t ChromaSubsampling; n. y; c8 W+ L% h' N6 ^
此参数用于色度子采样,具体支持的参数如下:- z, O+ j/ |% L
. d2 n+ ^- @) Z( p$ k g4 N1 G- #define JPEG_444_SUBSAMPLING ((uint32_t)0x00000000U) /* 4:4:4 */. _8 [) _& @% n* q
- #define JPEG_420_SUBSAMPLING ((uint32_t)0x00000001U) /* 4:2:0 */5 Q3 B4 a! I5 i& c/ E h
- #define JPEG_422_SUBSAMPLING ((uint32_t)0x00000002U) /* 4:2:2 */
复制代码
; z8 I1 g: n* G/ u; \0 p uint32_t ImageHeight) W, L+ _- T. s! S, D v6 Z
此参数用于图像高度。4 S: \ B& @" E' ^" m+ G
) g% {: y) N7 C uint32_t ImageWidth
8 p& p$ w v, Z. f! J此参数用于图像宽度。- @" O; D8 v; j
7 J2 y3 k5 v1 o3 N, V uint8_t ImageQuality4 C$ i( [$ o( V$ R2 L
此参数用于图像质量,参数范围1 – 100,1最差,100最好。: Q0 Q+ ]; h6 I: V4 g( L1 X- L* z+ O% \
9 J# f; R! o5 \. M
57.3.3 JPEG结构体句柄JPEG_HandleTypeDef6 T1 B: D2 x- a1 }' @6 D8 R
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:
4 @; P- V; m5 g0 o) ?5 @( f) t( ^. N2 X( g& S6 Q: q5 o; O4 s5 [9 {: z
- typedef struct
+ h$ C$ j7 h" |- j - {( v+ x& i( v: u$ H& V
- JPEG_TypeDef *Instance;
0 }' n6 ^6 o' [* |9 }- N5 x - JPEG_ConfTypeDef Conf; ( r( \# ?9 A7 @& O$ w4 d( r0 i
- uint8_t *pJpegInBuffPtr;
( G$ p. Z b3 F) @ - uint8_t *pJpegOutBuffPtr;
' @' d% ~$ \( u - __IO uint32_t JpegInCount; ( C c e4 k, S2 w
- __IO uint32_t JpegOutCount;
/ m' B3 @; B: P5 t5 e1 `0 ]- i - uint32_t InDataLength; ' I! ]* @! D; f
- uint32_t OutDataLength;
F9 F6 p5 [9 c9 T, c - MDMA_HandleTypeDef *hdmain;
' S" {& m' }0 G j2 A4 ?( Y - MDMA_HandleTypeDef *hdmaout; , q7 R* y# V- ?5 s
- uint8_t CustomQuanTable; 8 o* d' a* J8 ?6 K
- uint8_t *QuantTable0; * R3 L+ b, b% A3 U/ W) D6 v# `4 t
- uint8_t *QuantTable1; 8 J" B$ K8 O z5 ?/ T3 A: i! E
- uint8_t *QuantTable2; % c% Z% w0 ]* l0 N
- uint8_t *QuantTable3;
, _2 I9 j: m8 X; ^1 w# K$ } - HAL_LockTypeDef Lock;
8 m! R0 g9 z# g/ a& W - __IO HAL_JPEG_STATETypeDef State;
1 j1 F, D0 Y) E6 V- }% e1 U2 c7 b. v - __IO uint32_t ErrorCode;
. x6 Y+ j; ?+ C: _. w) U+ T* W, U - __IO uint32_t Context;
2 D) Z0 y* O4 L, V; Q - }JPEG_HandleTypeDef;
复制代码 0 t2 s% k& h' X% W. t% |
下面将这几个参数逐一做个说明。5 p8 J, Y0 i5 U; e# _ h" R
% Z# c4 x& t& ?8 K; \+ O/ R JPEG_TypeDef *Instance1 m+ X3 R: ?1 d4 n
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。$ J7 A6 i% ^- d( i8 N5 f
3 f4 o. ?) T5 w+ |, L
JPEG_ConfTypeDef Conf r$ M, e( Z5 U4 r
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。
4 i/ y i/ H- e/ m6 y
' }* R# N7 F" Q# X- _ uint8_t *pJpegInBuffPtr6 Z/ N% ~2 h( j
JPEG编解码输入缓冲地址8 S/ h1 ^: G4 H% M) R7 [
% x2 J' _; ^" g/ ^ uint8_t *pJpegOutBuffPtr" o* d9 V) a/ c* s
JPEG编解码输出缓冲地址
; X; d; d% o* z0 @! s
% h4 @1 ^/ X- t* M9 _" o* y __IO uint32_t JpegInCount; ^- C$ u+ A! Z7 R4 Z( `7 d* f2 H
JPEG内部输入计数。
: R2 y* K/ E V/ h
3 M+ I# h3 \. _$ t s __IO uint32_t JpegOutCount9 J6 l9 V: H) G5 B
JPEG内部输出计数。/ Z; t/ ~; ~: c! w2 U
. O. D9 |9 P; u
uint32_t InDataLength4 k0 t; X) D' j4 w0 ]; b
JPEG输入缓冲区长度,单位字节
& \3 o% h: m0 d* \$ d8 z8 \ ?
2 J" B1 y5 n+ V7 h" w3 Q' A, x uint32_t OutDataLength) w z& G, r e. H( \
JPEG输出缓冲区长度,单位字节。
4 m$ c- P7 C+ x3 p1 I. I% k' D
/ B# C+ C: Y, U8 E2 R; ]& }( X MDMA_HandleTypeDef *hdmain9 T4 h# \1 p" z# @) r
MDMA_HandleTypeDef *hdmaout7 k# J7 q+ {7 R) g
MDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。- ~4 A- h5 n! M: C x
' w2 \: M. S5 Q6 f1 w: v3 U) c$ H! t
uint8_t CustomQuanTable
# N3 ~2 X$ Q& X M: O如果此参数设置为1,将使用用户设置的量化表。( t3 G% V" X# U% T# r+ v
: [: [ K$ D& d uint8_t *QuantTable0;
. p5 A' I+ U" R* D* U: U uint8_t *QuantTable1; # U& k/ O2 N* E
uint8_t *QuantTable2; 9 \: g; `6 N! \* @# E( F# v% h: W
uint8_t *QuantTable3;5 H2 o; Y$ ^3 L0 ?" v* G
指定量化表地址。 % B6 P, b" v4 L! o
4 u1 l9 V8 t* c; X% f HAL_LockTypeDef Lock
/ T, {9 P. h, @, b* q" n& J3 Z __IO HAL_JPEG_STATETypeDef State 7 h( t8 B/ m1 r6 H" e% s$ W( ?
__IO uint32_t ErrorCode
# z5 `# S" t% o! _- [这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。* ?, E+ ^4 v [3 k
; c/ U9 k; |: o% N: t8 Z4 P __IO uint32_t Context
. E2 z5 g; q) ]8 TJPEG上下文。/ V% y, ~: Z# d$ I% `+ ^1 q
3 @! e% q* A% Y4 H; r) P# r* F) Y57.3.4 JPEG初始化流程总结, N, t( Y2 m/ b) J8 r5 g2 V# U
使用方法由HAL库提供:
7 w* ~: ?3 @- s4 z6 G9 l1 l5 D& J2 D9 Z( b t; ~$ [: `+ n
第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。
$ M' C$ E; w) U* C! Q
3 D' ]8 b) F3 I如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、
1 H( A" }) U7 u; x, g$ S2 Y6 s/ L- n( U1 K2 O. P
第2步:调用编解码函数) F/ z, `0 P5 @) o3 _5 g
) D# o+ G( V; V
查询式编解码函数& v' F$ z# S+ W) ]+ }4 \1 j
HAL_JPEG_Encode( u/ ^ @$ n# J1 P5 u |. J
% P: u3 P; H# U2 q% ?0 R) P: e, C
HAL_JPEG_Decode' l. E( c0 L9 {" i
% h: ]9 d3 e* Z5 v9 A0 a" ]
中断方式
. q6 Q$ u/ t# E; i9 {: ^HAL_JPEG_Encode_IT; W+ P% p p9 v* h- s3 U8 A
/ h! f. g2 g9 n" _, o+ p
HAL_JPEG_Decode_IT
1 M: b0 [2 z0 a8 W8 Q4 V. U0 b8 T- d* U- P4 s" G! S
DMA方式
5 l- P" p! C; G+ r6 uHAL_JPEG_Encode_DMA
6 y: O, Z% D2 x3 M" h" d+ \2 @
) d M* J+ b/ ~9 D. FHAL_JPEG_Decode_DMA6 @ @7 {5 V N+ `
/ n' d! j5 s& N. \+ |' x# n) n3 y 第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback, z/ |- z6 D$ C: y
" J3 X; q0 @$ ~6 r- a* T
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。5 ~+ u7 j2 h$ e
' U6 b o& w, [, x3 O2 _* t8 W
如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
" e0 h9 k. H8 E j2 G: L(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
4 z. F9 |$ W5 z: D4 L0 j# p(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。4 ?' Y5 k$ |# ]7 L4 ~ T5 |
第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback
( u, _5 Q) }3 h2 V. D; W- ](1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。3 s' m; H8 F7 J. f4 I) f
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。5 a3 T) Z* u# V; U; ]! a- I
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。" d3 `" T% }* L; s; A2 v
第6步:其它相关函数: S$ `+ C) X9 e) R# o4 n4 U
JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。
/ c% x- ^" A K1 O: n JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
0 ^" k2 o8 f9 Y' G- x( E% ?9 s, { JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。. t r; p* Q$ k3 Y' N& O0 H6 C, n
操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
6 }1 t8 g+ J/ F; `; f HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。) w9 Y+ L' p$ K w8 X- O1 Y
通过函数HAL_JPEG_GetState可以获取JPEG状态。
; `" r. n7 A1 |1 k. S- K: {: H57.4 源文件stm32h7xx_hal_jpeg.c% s' k, N& u5 z J
这里把我们把如下几个常用到的函数做个说明:
8 @3 n/ C: y6 U1 g HAL_JPEG_Init
. ` ]0 W( ^# ` HAL_JPEG_GetInfo, Q* Y+ g& V4 I- V
HAL_JPEG_Decode_DMA2 G' t7 i2 Z5 u0 ]. `
HAL_JPEG_ConfigInputBuffer
! M% M0 {4 r4 C( P* T" @' q HAL_JPEG_ConfigOutputBuffer+ O& i' X* _- ^$ T
57.4.1 函数HAL_JPEG_Init
7 t) I& j' y! d6 i9 O6 r7 a; [( [函数原型:
9 G3 P4 a3 Z& @, A# K- k. S
5 O. a+ [0 \% ?: Y" T- HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg). K6 W( t1 J3 j, [4 y
- {2 Z( |& q1 S3 J' u# X+ Z) E
- uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);" h, D3 M7 u& }! U1 K
- uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);3 P! j' l, l, d2 ]5 {
- uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);6 }$ `+ ^7 t7 E5 [7 N0 A) J
- uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);3 y( R0 m$ }, o4 Y
- . l+ k) g& Y4 d( q- M
- /* 检测句柄是否有效 */" Q: { i8 ^8 s# n5 \# }
- if(hjpeg == NULL)2 @0 ^5 h$ \ u* L! C$ X1 B
- {
. R* K! V6 S+ [" u } - return HAL_ERROR;
# E8 p( A9 I. ^3 t+ o0 v. J9 F7 c/ _# d0 f - }$ Z! @: g" o: Y* x4 \
. q3 o2 K9 s: l( I- if(hjpeg->State == HAL_JPEG_STATE_RESET)! G4 ^- L+ G7 q" x
- {) E' n; }% e* w& B
- hjpeg->Lock = HAL_UNLOCKED;. f* A9 Y( z$ Q7 a4 }
/ ^ `8 n H2 C7 r0 W) s- /* 初始化GPIO,NVIC等 */
4 q" R) `% c5 Z! A0 F - HAL_JPEG_MspInit(hjpeg);
3 r2 K# O# K( P0 W5 [ - }
7 [* O( v* g( M" A. g
4 Z, g0 G9 E; K- /* 设置JPEG状态 */4 R4 m8 I% \# j7 L* B- A
- hjpeg->State = HAL_JPEG_STATE_BUSY;
: ?4 n2 M+ z/ s" b - - @4 m9 ?" M6 L# j4 U$ H) k
- /* 使能JPEG */6 y* E+ @% o! K, J0 [
- __HAL_JPEG_ENABLE(hjpeg);% v3 }* p6 o, f' B: x1 S
5 a3 f% @# n! Q! @3 @1 g) E& S- /* 关闭JPEG编解码处理 */
4 \% n9 D& i5 m9 z- T - hjpeg->Instance->CONFR0 &= ~JPEG_CONFR0_START;
2 v7 @, h$ |5 H: p - * D" x. q6 G5 h, [+ J3 k
- /* 关闭JPEG所有中断 */$ L1 V2 p2 A6 K+ K
- __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);8 i" _6 H( v1 L: q
- $ X( G2 T- B/ b9 v) i8 M1 r) q
- /* 清空输入输入FIFO缓冲 */9 _ k3 o, n$ |0 T# _* q7 v
- hjpeg->Instance->CR |= JPEG_CR_IFF;5 r, `" {; J; V+ a% j2 B! P0 p0 S
- hjpeg->Instance->CR |= JPEG_CR_OFF;
b( _6 `) O8 K: c4 o4 [/ e. O# X - $ h: s: y7 B$ J4 r6 E3 |
- /* 清除所有标志 */ i, Q8 [& q( W
- __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);4 m8 ~, B4 f: @. g
- ' w# f+ a. ^7 H" J# ]* V2 O. N+ v" d
- /* 初始化默认的量化表 */' J( @4 G6 T' e: e. [. W
- hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
; Y+ i* I( c$ u; R j - hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);. }! J; T& A _7 r% P
- hjpeg->QuantTable2 = NULL;
) k Z: w% k& {% A - hjpeg->QuantTable3 = NULL;
7 h* y7 Y: ?; Y& O* A
" |+ ~3 }( g; Z/ I+ R4 ^. S0 b! b# T8 H- /* 初始化默认的霍夫曼表 */0 X1 J2 U3 k. ]) s1 T
- if(JPEG_Set_HuffEnc_Mem(hjpeg, (JPEG_ACHuffTableTypeDef *)acLum_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcLum_huffmanTableAddr, (JPEG_ACHuffTableTypeDef *)acChrom_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcChrom_huffmanTableAddr) != HAL_OK)
: c, v; o6 `! Z y# _! I. @) y - {
3 u' n$ D5 V# L* i4 Y9 H% \3 }1 Q( K - hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;& S; W5 q% {" _" d- l; Y) z: l2 f& \
- + D, ~" Q1 ?' A
- return HAL_ERROR;$ W; g& ]# O/ o, U2 s) }2 l9 p/ C
- }
$ d, N6 d1 T# t: A( s V9 J8 S
3 h/ ^4 e" k% c) v- /* 使能文件头处理 */' n2 B8 z3 b# m, w6 b
- hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;2 G% n* \' i! ]; h! t0 D( D
# A/ ?6 _) f2 z& d' y6 s- /* 复位JPEG输入输出计数 */
4 T q2 j4 F ]4 K - hjpeg->JpegInCount = 0;; \7 a; r' X* F6 }% B( l5 p, A
- hjpeg->JpegOutCount = 0;. ^; q0 A1 A/ A$ i2 t
- $ Y- ^9 K! Z _7 h% s! w
- /* 设置JPEG就绪 */" ^' F( H: [5 v1 U' ]
- hjpeg->State = HAL_JPEG_STATE_READY;
4 g1 ~' V5 u' p2 d0 M
2 N- {6 i, ^2 j: ~/ U4 V- /* 设置无错误 Reset the JPEG ErrorCode */
- T$ c; L1 n1 _; u" h4 i - hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;2 R2 f7 E/ R7 }$ r- M
- 4 F# ^% p1 h; V0 a4 [& S& L
- /* 清除上下文 */' M# E% Z2 O) S3 C% c, U5 y
- hjpeg->Context = 0;
2 K4 j( r9 O4 d, d! C( E, f3 O- r - ; F0 k7 {# \" q X
- /* 返回HAL_OK */
8 g) Z" [- K( N; F; n - return HAL_OK;1 c2 s6 w" Q! k% }6 W
- }
复制代码 / l N( H9 {# U0 ?- G
# _1 s( Z6 h$ x6 O7 Y
, o3 P$ H, P. s. b, ^5 J( y函数描述:
& V% K/ h7 X0 W. j2 T6 p: Y/ N7 ^/ Y2 x ^. S
此函数用于初始化JPEG。
* M3 S$ s/ ?0 Z: u+ l7 ~ Y- t1 J9 P- O' ^
函数参数:0 }; M# f; n2 ~0 b+ d
- l$ Y" e" H# J8 k2 G( r2 _% | 第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
& M: s" F& i4 @6 Z5 Z0 |4 _ 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。0 O* b1 z% d7 O# b: U% G- \! t+ X* E( ~4 Z
注意事项:
3 k! P* q/ i% k: d* M0 V5 I3 M7 Y
函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
$ z& W% u2 n8 w$ v. p5 J: u如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。
( u4 r; F) P; L0 L/ h6 n r9 k对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET = 0x00U。4 L% [* H* q8 m) Q6 T
' K( q( F" d. b# e解决办法有三
W( k. p, q7 U9 G! a
' M6 h0 s& B, ]5 S- x) d方法1:用户自己初始JPEG底层。- }& V4 q$ H8 }* [) H0 e7 c% O) g
9 p5 K) k4 p- I* X0 H. T' U方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。
5 }, ]& G; B) c2 Z, Z3 D. Z. W
方法3:下面的方法0 V+ g$ L+ ?% u. s" C/ z: E- Y
# v3 c2 D* H+ N+ t1 I) g
- if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
, n m/ w4 o; ]9 T" f. j+ v - {
6 }5 [3 b8 J ]. [% M: r3 I - Error_Handler();! [6 l( V- J( N" B! u( Y
- }
W4 T3 x1 T, R$ s/ i- T - if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
6 `$ q/ z% p7 w/ y& w% n; h$ g - {2 O0 O9 ?. t' D$ X8 J2 k4 l0 x% q7 l
- Error_Handler();
+ S* F4 E1 E6 t$ Z - }
复制代码 . c; t$ ?; P3 s
使用举例:2 e' O. a5 ?2 d0 M
0 q |; F5 k: B2 V3 N" ~
- JPEG_HandleTypeDef JPEG_Handle;/ {8 p! @- `# K+ A3 I" O
- JPEG_Handle.Instance = JPEG;
( ~ J% K& A& R5 |4 f( Y - HAL_JPEG_Init(&JPEG_Handle);
复制代码 & J, T" J; p1 K+ h) y
57.4.2 函数HAL_JPEG_GetInfo
2 O) a7 v9 d$ F( ]) j$ |函数原型:
% \. ]3 R( `+ i7 e( h
5 o7 A: I T; ~- HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
4 |7 \" N' Z3 H, H# ^ - {
! l6 A1 _% W5 {' b3 j - uint32_t yblockNb, cBblockNb, cRblockNb;. _, x. \$ ^7 I; k0 H: f* Q
- , y: M, _6 a" X7 t
- /* 检测句柄是否有效 *// Y2 p- c m M' X* Q
- if((hjpeg == NULL) || (pInfo == NULL))' x- o% m# [" K9 w4 b# c
- {
- Y% N# \. B' E( n - return HAL_ERROR;# Z _; e) O( d" N/ c8 g4 }
- }
, y' h2 o- K5 V; P: I7 R - 7 v# I, r0 d# i1 P4 y( Y3 Q2 X
- /* 读取配置参数 */& S& k, F, s4 T/ G/ q
- if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
; `" f: |, _' j' M W5 N - {
& v: Q5 j) B5 {; o. T - pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;
# ]; B" ?9 ^. u: a# v, P - } / X" z$ A8 s) N: W
- else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)7 ?# i2 Q2 A$ i5 o0 j; o
- {
F, M. h/ [8 i- M) ] - pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
6 Z- |9 M# M, ^3 Z% K - }
6 i! [' ^$ t5 J* Y0 ?6 Q - else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF) J& I4 K' A( V. [
- {
! K# h4 E" f5 ] - pInfo->ColorSpace = JPEG_CMYK_COLORSPACE; % W9 F: @. y2 N! n' S5 l$ R- c9 }6 m
- }: @- F( ^! }4 T
- $ g* J ~$ H, e& K3 \
- pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
- @8 f0 v. L h& N - pInfo->ImageWidth = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
8 A/ ^: h, a5 F& D - ) U& e( V6 f2 f7 L$ M' j6 R
- if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
6 f7 G; k/ \3 @% \- {% h - {
# u+ _$ P: U1 }, @* y5 [( m - yblockNb = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
2 y! q: k0 g1 X0 G( ?+ Z - cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;! R M7 S9 w7 D2 y& s3 K! K
- cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
' T6 Q$ m, W, \1 s4 h" { - 3 E% V4 ~/ F9 C
- if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))1 y& d1 k. c+ Y6 X/ g0 Z
- {$ t5 V* F6 D4 F) A2 K3 M& Z
- pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/+ }3 \- z s+ A2 p2 F
- }7 y" {" O9 |, k% M. E2 O/ n* X
- else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
' @" K* x1 I8 K: K' j - {4 L# K+ n, X, O
- pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
( g7 | X' Q) P - }
3 T8 h0 F7 F& m4 u1 k ^ t, S - else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))9 S. f, _0 Y+ E6 Z
- {7 u2 X* G5 @/ P6 ]8 O& V2 t* T( Y
- pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
: _. ^4 r2 Y, I- e) M - }/ T* ?/ {9 l3 B8 x' F0 |0 S
- else /* 默认是 4:4:4*/
: U `2 K1 G3 f: z - {$ o: K' j, \4 q& ]8 s, ?
- pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
) D; d# O( D$ A! s0 s+ w0 R - } 6 U0 S8 W7 v* f
- }0 K% r6 y7 H C/ ?5 c
- else
/ k- t0 r+ f1 }8 G8 k# e% | - {. B) t* I5 ?; s0 C8 D
- pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
) ^9 f* J) ?5 b! X7 ` - }
' ?1 z; r. s0 _% l! M; @) t1 k - 6 L- ?5 Q% c6 C) ^& Q+ }% w" \
- pInfo->ImageQuality = JPEG_GetQuality(hjpeg);+ X0 {/ v" Q6 x/ s7 a# b
; p6 K. V; |; c" Y$ L* w- /* 返回HAL_OK */; C5 B0 t0 [1 {3 _+ j+ u1 [
- return HAL_OK;
: r( ?4 \$ ?! Q8 V5 ]' T - }
复制代码
6 G: L1 {- t) S" V- b函数描述:9 `# _4 w! R; D. M2 Z: Q, n
# i" n2 |2 i; f# `& r/ J此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
) \) [% g1 H* `+ A8 M) ~2 H# j6 J' L# \. c, x' i) H) w
函数参数:
2 v% F0 l% T9 V
, m f5 s7 _4 K8 H6 Q 第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。8 Z; E2 z/ x' o$ j
第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小
+ N8 |. v+ ~* V2 @3 Y 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。3 j, \, V( p/ h. N+ w
使用举例:
( l* l A: T( L0 r, @
) Y9 Y8 P- K# i+ e9 r V" F- JPEG_HandleTypeDef JPEG_Handle;
& l; U6 U# i1 t& P, d. F - JPEG_ConfTypeDef JPEG_Info;
2 d4 m8 t! ?% u2 y5 u
" U, O3 r+ O) G6 d& q: o$ _- HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);
复制代码 / J& n: Q2 v: k, A/ d% j; W
2 n! W# g9 P+ m( }) Z+ a( [% X' c& n! w4 y1 `
57.4.3 函数HAL_JPEG_Decode_DMA
* z$ J- R% ~: ^- M% d函数原型:; q" n3 M: u4 l, m R" e/ I0 d
9 N8 c: ^- V4 T' C$ s4 i% B
- HAL_StatusTypeDef HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength): X& |) C0 j6 k, y4 } b
- {
1 a3 U' m) W0 L0 M3 |8 J- c - /* 检测参数 */
, e3 X& ~& @( Y7 j: q0 n7 l E& A - assert_param((InDataLength >= 4));
3 D S3 d3 N5 k: g9 p# o - assert_param((OutDataLength >= 4));" ]1 D* ~$ m3 F2 J& V2 k1 s
& C) S/ g5 Z% ^/ e+ j- /* 检测参数 */
: h+ J' W4 `% @: @. _5 | - if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
0 z* V4 s4 ^5 E, F- q3 { - {
- H2 \' x: V9 V) `) J9 X, h; Z+ d8 s - return HAL_ERROR;
% ?' B" ?4 Y* e! {- x - }
8 V% E+ d# q. E ^0 a' }
6 K, D9 s! ~3 C- d- /* 上锁 */
8 _) N1 U2 K& | A- N - __HAL_LOCK(hjpeg);
! o. h) N- r0 \& i. t, u5 W" }
. T# z4 p* z1 z T: k# T+ m8 s/ {- if(hjpeg->State == HAL_JPEG_STATE_READY)
h3 y8 g- A% c0 C - {
2 e+ Q( k* F1 I8 w$ T* {4 P1 y - /* 设置JPEG忙 */; h6 O2 R, f, n8 K1 B0 Z6 f
- hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;
* l3 H' S+ X& u: l
- B9 v( W& l1 {9 q( L4 G- /* 设置JPEG上下文,工作在DMA界面状态 */
4 V+ f+ g& Q6 O, T3 \- A5 { - hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);& V1 Q4 @% q \( x& c
- hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA); 7 _% T3 \$ K" J1 w
- & j& x, q8 |! |. Q- l$ \' w
- /* 设置输入输出缓冲地址和大小 */( p. u8 P2 U l1 |$ L: J6 i8 c2 ^
- hjpeg->pJpegInBuffPtr = pDataIn;
1 T- j6 A& P8 ^' ?/ k5 F - hjpeg->pJpegOutBuffPtr = pDataOutMCU;
- k- T* v- O! W) X - hjpeg->InDataLength = InDataLength;
; k) e! Z$ }. y. ~( L" E - hjpeg->OutDataLength = OutDataLength;
$ C- R! ?+ s9 \; P( w
3 ?7 D8 O, i% i! x9 X6 D5 J- /* 复位输入输出缓冲计数 */
: `, T% U. o7 L - hjpeg->JpegInCount = 0;
3 e! v: Q/ A5 {; Z, g' p/ k* V+ t4 w - hjpeg->JpegOutCount = 0; ; Y+ \, z% I# X( F" d
' v% i" j+ I: F, Y- /* 初始化解码处理 */+ D. n- f+ s- @8 {
- JPEG_Init_Process(hjpeg);, n( J+ q: _( B4 b9 g1 u& e
. h! R# S4 v8 y& p/ b- /* 启动JPEG解码处理,使用DMA方式 */
0 K* e: L) D% j - JPEG_DMA_StartProcess(hjpeg);3 t t' p0 P6 _1 b/ \: v. u# [
- 7 u! I/ V$ e8 V5 S1 O
- }
9 ?, L% E6 N8 G/ p% ]! s9 @( ] - else
% Q3 t k e2 e# h6 O& Q, x- I - {
5 Q$ i! E0 a; o. a! m) q3 y - /* 解锁 */
i( K# d5 X9 p7 L; q) T - __HAL_UNLOCK(hjpeg);. [. \. K. l& R4 g1 X
h5 ^9 i9 v* d* V. f0 ~- return HAL_BUSY;7 h1 f c% J2 h+ m
- }
4 v+ f* s5 Q8 j( y
% {- ^4 h; T* Z7 J( t- /* 返回HAL_OK */
9 \9 Q! w' [1 \ i0 x, l+ V0 z/ P9 I - return HAL_OK;5 [5 E" J4 I% N
- }
复制代码 函数描述:! G( g' [8 ~4 o$ u% |
. y' @: e8 g. x% Y6 G( q
此函数用于启动JPEG的DMA方式解码。% K+ S, y" m! m2 }5 J2 {$ K
* v, \% I* v9 G+ `1 B( A4 N8 k函数参数:; }0 V! J7 q3 ^ q' f
: F# J# \% Q' Y7 i' Z5 M
第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
9 d5 R! l5 A6 ]" N- K) w 第2个参数是输入数据缓冲地址。
; y3 w1 Q9 U7 ? | R4 d 第3个参数输入数据大小,单位字节。
, `# m/ z3 {, W# x' X 第4个参数是输出缓冲地址。
* n! u* L+ @+ ^% y9 t 第5个参数是输出缓冲大小,单位字节。" I) t5 q1 j/ Q1 z" i( x/ M
返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
" {& u- d8 f! V* V% G l2 u使用举例:
$ w% x, n! k' X, p/ v
: W2 r/ {+ o$ ]9 N+ l8 r" U W- /*
" q+ F! }6 g/ R U3 t0 o" @5 \7 J - *********************************************************************************************************
! A7 l2 c. K H - * 函 数 名: JPEG_Decode_DMA
6 X9 m {" w3 M5 s - * 功能说明: JPEG解码( C& k+ @' S- d) T! @
- * 形 参: hjpeg JPEG_HandleTypeDef句柄指针' Z e1 P& Y- m8 A% C$ B- {- D+ R
- * FrameSourceAddress 数据地址& b; P$ O* [$ [ t! r: U
- * FrameSize 数据大小 h# ?" r1 [7 i
- * DestAddress 目的数据地址8 H. Q' J$ g- l$ {) Z
- * 返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功
5 Y0 S- s+ ~0 L$ r: K - * HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出! a) i$ @0 e8 D
- *********************************************************************************************************
1 O, B, E& o; ]! a b" m# M4 m8 I - */) q3 @0 c% o- b7 \& ~; k4 `0 X
- uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
( g8 O7 l; o4 e! o: Q# r/ Y6 R - {
" g' X3 D+ ]' B7 l( ~ - JPEGSourceAddress = FrameSourceAddress ;
2 P" N$ \: o/ }3 K8 X. O, f - FrameBufferAddress = DestAddress;3 w/ ?: p( a2 N6 ^, ~
- Input_frameIndex = 0;, o& z/ F- G) t( ~" z: }0 D( Z
- Input_frameSize = FrameSize;
& G0 Q. Q z( f3 V) O/ S - 6 Y; X% d- s8 V$ V
- /* 设置标志,0表示开始解码,1表示解码完成 */3 B+ \; x3 v8 U- @1 L
- Jpeg_HWDecodingEnd = 0;
; ?8 c/ u( \9 P; k1 B8 K( L1 u- ?3 X
* U/ Z4 Y8 {3 p* {$ e3 k/ }- /* 启动JPEG解码 */
) `% R5 \& s4 k1 D7 K - HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
$ e0 X9 P. l9 Q - (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
& Y3 e4 \% r; _, C/ ]: t - & w& l+ V7 k0 l% R& y& ]/ W
- return HAL_OK;
' [& s7 I3 l- N+ }% w9 h5 z6 w. Q - }6 t. R4 g( z& F% a! r
复制代码 4 _2 @ X% c/ M5 s( B. D
57.4.4 函数HAL_JPEG_ConfigInputBuffer
! M+ U% O5 m8 [1 y$ j. X9 B函数原型:
( B- w2 t8 r* u! g$ G7 R4 b* t0 O' @6 M
- void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)
$ z* [) N3 _- |+ s6 E* @ - {
r; b) c* U; ?; u8 O/ G6 g - hjpeg->pJpegInBuffPtr = pNewInputBuffer;
5 K( V6 a1 c% l& F - hjpeg->InDataLength = InDataLength;6 n* m0 y8 k, d( P! G' V
- }
: l- a, L4 s/ T4 r
复制代码 % D! E/ S% A, A& m
函数描述:
% X) c n% \' Y- I/ @
( c& G( o9 M% g, r" c0 H7 t; V此函数用于配置编解码输入缓冲地址和数据大小。8 b; K# L/ h% O# f1 I6 }+ S/ }. P# R
9 q" Z" m4 L d2 T
函数参数:5 K1 y* q7 ?: f2 Y) Y% K- s+ p
; t8 e. J' O0 }+ L) Q3 v 第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。0 l6 w8 _/ u5 n Q9 O$ c- ^+ v' _
第2个参数是输入缓冲地址。
* V3 u$ j5 P1 F# O& F2 l 第3个参数是输入缓冲大小,单位字节。7 w0 d0 o" \1 X1 I: f- J
返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
, j' p: k. K- W: C6 D" W: N; z使用举例:
& w' u7 e$ x) q' z) |) z; C
; F9 H- u% p/ j- /*. U& K! ^- j: @, _
- *********************************************************************************************************
) W& Q. U" {3 b2 t+ q2 y$ K7 l - * 函 数 名: HAL_JPEG_GetDataCallback' j% m& h2 X5 G4 g5 O0 K
- * 功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
$ x" }$ X; _9 x: N2 ?, M - * 形 参: hjpeg JPEG_HandleTypeDef 句柄指针" t- Z. w5 D" i2 g; i3 S# ^
- * NbDecodedData 上一轮已经解码的数据大小,单位字节
C( M% E' ^, f8 M; }* I5 o/ [ - * 返 回 值: 无
% A% S8 a; u5 q% I: ?6 u/ n# y - ********************************************************************************************************* \3 T; Z& G3 E
- */
8 f, U2 w6 _& G6 Q) S7 _+ s$ S4 c - void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)! D8 r) o, F0 T) `8 P7 a( |; y* ^
- {& L9 h: U! `3 I
- uint32_t inDataLength;
8 P \' g" c3 `2 P+ s$ A. I$ b - ! ^* _/ D% L ^( N6 w6 L0 w
- /* 更新已经解码的数据大小 */; V/ {# Z; s' E. T8 B, i" ~1 `
- Input_frameIndex += NbDecodedData;: d2 r, x% K% A/ r3 U {4 w' R! `2 R' l
/ S& m8 ]. n9 v# f G' I- /* 如果当前已经解码的数据小于总文件大小,继续解码 */8 e% J8 h. h0 l6 h: I7 R- Y
- if( Input_frameIndex < Input_frameSize)7 h$ }: M& l/ |( B8 D/ @! r& f: O
- {% \: }- ]: @' v$ b" w; V
- /* 更新解码数据位置 */
# P/ D( C3 r4 q- [0 e; p - JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
! z; M+ \$ u3 T0 m
0 U- e2 ^1 N/ L5 Q$ k- /* 更新下一轮要解码的数据大小 */7 i' ?9 l r, a/ e3 ~, j/ W% }8 |
- if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
( Y2 P* `$ |4 j; o/ D/ y8 K" t! E - {1 V i, \& V K. R/ k
- inDataLength = CHUNK_SIZE_IN;
% K" I3 o! n. m* I0 A - }
Z$ T# G$ }# e+ _2 v/ ^6 Y - else' i" O4 I7 j+ F( U
- {3 E! B0 m$ C5 m- }% P8 Y
- inDataLength = Input_frameSize - Input_frameIndex;
2 \! m! P! ~6 Y9 \0 v - }
0 |' H/ L! M3 M/ F, x% M - }4 L% |; k J6 N( f& c2 P/ y
- else
$ M+ g5 r f, d - {- T0 H# H z% t5 T6 @% N) B; W2 x
- inDataLength = 0; 7 ?5 J" @* b T& e4 E; o& P
- }
7 @, ^$ e% J$ X2 @
& N5 b% I3 `9 n7 F- /* 更新输入缓冲 */$ @6 o+ o7 p6 d$ o
- HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength); 2 X7 @7 o7 o" B. Z4 X+ S0 S+ W. q
- }- m# M/ w5 ^+ k3 x* [( }
复制代码 ( p3 ^' O0 _9 P- q6 S# h
1 ~& P$ k3 B1 i e$ C0 H+ w6 |/ S
57.4.5 函数HAL_JPEG_ConfigOutputBuffer
+ I( t1 o* [( B; o, S函数原型:
; K. C" I* V. u$ O, Y( u1 N8 F; A; h6 Z+ P, L
- void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
$ p2 l" Q* j, Q1 g - {( {- }$ P: [1 H$ R) d* R0 _
- hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;6 [4 l0 v. i! b7 i# n+ o+ B h
- hjpeg->OutDataLength = OutDataLength; ; V, `0 X" d9 t, s2 k2 |
- }
复制代码
' x# D9 ]1 A" Y& n u函数描述:
. `) n4 B- m8 F) L4 }+ m
1 [- ~4 E* L- C% i* Y* s此函数用于配置编解码输出缓冲地址和数据大小。% P+ Q0 t& u& `: w
7 i' p* |4 q* Y# n4 ^
函数参数:
! k1 _3 U; \. R, n# R, W- A1 Z* j" i, I3 D+ Q3 s6 D
第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
+ B8 C% H! h& t/ T8 e! i$ X4 D 第2个参数是输出缓冲地址。
7 y4 t% x; @8 s6 K7 O 第3个参数是输出缓冲大小,单位字节。
1 k& V' u9 G, }% _( ^; q' R 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
( s/ v% Y8 J+ K% n! e3 S使用举例:
4 L0 t1 D$ p: E2 e7 L
" b# f+ y# ]; s9 Y- `8 B N- /*
7 U6 |8 X6 |4 p( z3 O& E - *********************************************************************************************************
6 w4 Q1 S# C4 U3 ? - * 函 数 名: HAL_JPEG_DataReadyCallback7 H, x2 e5 I6 X* L! P
- * 功能说明: JPEG回调函数,用于输出缓冲地址更新; b* s; w+ D3 o" C* G, ^* K7 ~
- * 形 参: hjpeg JPEG_HandleTypeDef 句柄指针6 j% P) ]0 C8 w4 u
- * pDataOut 输出数据缓冲
( N6 A. B; x0 b) A- D0 P1 o, n. y - * OutDataLength 输出数据大小,单位字节
: m; z$ A. ?' z7 W - * 返 回 值: 无
+ t2 h% N3 x f3 L - *********************************************************************************************************9 m" o; A$ h9 |* H4 e" b3 o# f
- */
7 X& T. J6 X. D9 k- x* j8 c - void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)4 K E8 Z- o6 D
- {
) h) c7 ~( v( y) v$ o/ w3 v# d" [+ r: K - /* 更新JPEG输出地址 */
: ~/ c8 q, V0 C; w: r - FrameBufferAddress += OutDataLength;* h. G7 t! S( a4 e1 m3 f2 k
- D5 ~& @) `$ F3 z/ _! M
- HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
# q; m& J) U5 [' m { - }
/ x' R) X) s( m5 B# ]9 M0 }4 `) d8 Q
复制代码
0 X. G$ O4 b7 z3 n0 x) h
& q6 I# V2 f9 R( ~57.5 总结
2 S& v2 b" {% S- n' q; u2 p本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。! \+ q8 D% O& _2 ?' n- }7 u8 I
" t; r4 m+ i$ f- Z* A1 r
! f' _ D: d! u& w( W1 Y% n* h0 m9 w& c( Z5 e
: x" \7 W% L+ W% O3 v+ D- ~3 g8 N9 k4 N |