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