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