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