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