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