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