你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7硬件JPEG编解码基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示/ J; R( n( U) n6 ^1 J5 ]
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。& R. `; }. Z2 p
  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。8 @' R% j+ d' d" o% U
  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。% B# C4 D+ v0 r, S; z+ t  K
  本章JPEG相关概念的介绍参考了wiki百科和百度百科。
% e; B) w: u; k8 _, ~- O& v57.2 硬件JPEG基础知识
# ~* O- q8 q0 x) ~) B
对于STM32H7的硬件JPEG了解到以下几点即可:
# r; V# [# s# I; k' S7 Q9 S8 p2 b. S& C( x
  支持JPEG解码和编码。
! z" n+ Q  o7 f! @* k- |  对每个像素数据进行编解码只需一个时钟周期。
; W. Y8 X7 i& Z- j$ `  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。. z' R$ k5 j' [' c, }
  编解码时每图像分量8位深度。( D8 Q) e1 I6 X4 s" p  h
0 _9 l& X6 {$ ^2 ]
57.2.1 JPEG硬件框图% _# H" i4 N4 F* K
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
9 G9 J$ ^& S: p( M0 p) `
& U# h0 S8 L. ?$ }! c. n5 |! ~+ ^; `' l
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
( _/ R; w8 A) |) X! T! v; L
- h1 G' L5 C1 G
通过这个框图,我们可以得到如下信息:+ R0 `& S6 z8 V

9 e4 [( X9 q- y6 U/ l; u  JPEG硬件外设支持编码和解码+ m; n2 D2 z7 X/ E+ _6 m
并且对于输入数据和输出数据都有FIFO支持。
2 C1 g" A; Z+ e5 x1 D. X! L1 n7 S. u& G! k* ]2 I8 c' A) T: d8 O4 E- {
  jpeg_hclk/ R4 i8 }$ {" n6 ~
为JPEG内核和寄存器提供时钟。
) X# N, @& T% S8 I. n8 F- G3 [" N# ^2 R- x) |, C
  jpeg_it
) c5 V1 G5 q& G4 s, [JPEG全局中断输出。
7 C  e* ~+ ?* [' P% }( n) W' @" p0 H
  jpeg_ift_trg
# L: D* Y5 n8 z0 y* uJPEG输入FIFO阈值信号,可触发MDMA。# e4 o% B  d) u/ u  D0 Z
, W2 j4 T1 H, \& Q8 ~: c
  jpeg_ifnf_trg$ v- y" V1 v1 @# H$ e$ m
JPEG输入FIFO未满信号,可触发MDMA。
3 ]6 A& q8 ]! c0 g8 d0 L2 O: ], p5 F7 R+ I- ^6 }# G
  jpeg_oft_trg- f: l% y2 K  |! |# ]% p
JPEG输出FIFO阀值信号,可触发MDMA。+ r* @: H. P; H) `( b; T
5 M7 E, M' ~2 v3 [& m, W' M5 r9 G
  jpeg_ofne_trg" p3 `2 A  K( T7 C4 u. _" Y' @
JPEG输出FIFO非空信号,可触发MDMA。
" b! W. g5 c+ T0 n" m1 p
9 w; B3 q( T4 T- h+ O1 T  jpeg_oec_trg
0 R' k/ C$ L3 C6 lJPEG转换结束信号,可触发MDMA。
9 s4 p7 _0 a; p0 [1 t$ H7 W* J% m4 I' [( s" w* ?
57.2.2 YCbCr颜色格式" [& p) b4 \: c1 x
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)
6 J9 w0 Z# [+ S* w# N7 j4 \# J2 J1 K# ?* ~/ c
正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。0 C  w, B' T! S
& O9 X8 u' T! U4 F$ O
YCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
7 x# u! }+ |* W# f* o: Z$ X, N
. @, J0 `# G+ U8 R  K在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。( [5 _- E9 P) K9 {3 J: G
8 V+ Y! U+ }( I' F$ V
57.2.3 YCbCr采样格式" W+ p9 H5 ?7 o1 A
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。
  V1 Q- ?& I- q% m
& T* J' H' Q' Q- l$ e( d  4:2:0
# l" P! D) z& A# Y7 p' w( G表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
1 l+ X1 Z# L+ @$ x  z
1 \* w0 F" J% P( k) i8 h9 F  4:2:2; L. `3 L0 Y8 ~) R  G. h3 ~0 P2 p
表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
4 G9 ^* U: Q  n9 b, I/ F$ e8 E) A) Z4 v: _# Z. w2 G
  4:4:4
( }  i% e+ f. F1 C, ^7 e% G表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。
& ]! F: j5 X: F/ C4 I* f1 I6 ~: D% S/ C2 q4 ?3 Y! p
具体的采样方式如下图所示,以8个像素为一个单元进行采样:
+ X7 s  r( ]' t. N& o# [3 O! _$ f5 A# J( D2 I5 D+ n# @, f1 r
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

9 o/ U0 B( m8 w
) W) w5 ?8 ~: G4 G  \# X% U由上面的截图可以了解到:
. @' f* \! ?9 l" o& J. f: X# Q; V3 p6 M! {8 a' V8 P7 _, N7 b
4:4:4表示Y通道,Cb+Cr通道全部采样。" Q/ \2 `" O3 U5 ~3 D8 W, y

' [4 ]8 h6 q- b* A# a7 l4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。
2 `6 F! e" r) n$ H* |
7 D4 i- W1 y/ ?& Y; e* E4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。
% k( i0 H! H6 K: g4 c# R9 K) W3 t/ c( |" K0 j; U- i% c6 P. l! C
下面是整体效果,方便大家更好的理解:' w+ G+ ]( q! P, _! c

' x9 f- r; H0 j7 {7 y) G
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
8 d$ A- M4 e- m6 E8 H3 Q
/ o1 D- t' ]8 c8 t# f6 @
. e( D/ P1 p% u" F8 r" K

1 Y4 A* m0 J# f  l/ q4 A+ @) e+ X, A57.2.4 YCbCr的优势  `+ `( h7 H9 t) L0 H3 I
RGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。- h( S; }3 k$ s3 c
! Z# C! \5 ^6 [# l& H* o* C
57.2.5 YCbCr和RGB互转

" h0 ]. P4 `3 U为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。, F( K3 _1 ]2 E+ _

$ P; T7 B: L* ]# D# Y' y% q2 I
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

+ p/ r. s$ q  L: k3 u+ Z/ K" V' `9 _% o" T: @& M/ @' x
下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
$ l( O2 h/ c- g+ A8 s1 d: ~) n8 Q$ a( G/ u" ]' Y. F( N, q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

- ?7 ^5 [$ o' \( k: B- A7 F4 X+ ?, S) u$ A% A* z& z6 @( q
57.2.6 JPEG编解码知识2 u3 A: G. ?. l4 x
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)
& `1 i3 T  N8 B( W2 @, D# M6 |' ~% V' ]
57.3 硬件JPEG的HAL库用法3 M$ v7 c# g& `9 @) E4 h
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
7 B, d1 W6 [7 z7 y( U0 q& k# }' x
1 [/ r% @' O! C$ d4 b  J( S57.3.1 JPEG寄存器结构体JPEG_TypeDef1 g  x1 ~/ j) u. ]7 M- Z
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:! G. A+ j6 A* k4 V

7 x7 Z' q5 u3 y1 }% f. N' U
  1. typedef struct8 ~* _0 E- p2 D7 b2 t% ^
  2. {+ E& M$ u* R# Q9 ], I
  3.   __IO uint32_t CONFR0;         
    7 Y: o6 e  j4 C2 n" r9 [+ d
  4.   __IO uint32_t CONFR1;         
    4 }( ~5 Z" O1 R5 B' O
  5.   __IO uint32_t CONFR2;        
    8 O' b- J$ }+ W% v, H' c
  6.   __IO uint32_t CONFR3;        & x$ u2 R. b% J- H  t
  7.   __IO uint32_t CONFR4;         
    1 L, s  D# w% y3 Z% [; G6 m
  8.   __IO uint32_t CONFR5;       / Q5 V) D9 F2 [, D9 @6 N
  9.   __IO uint32_t CONFR6;       + u' n: u; X7 g  r6 e
  10.   __IO uint32_t CONFR7;        ) \+ m& V+ c) L! K0 L
  11.   uint32_t  Reserved20[4];      
    . m: T5 A2 H5 Z; O) V- O% G# A
  12.   __IO uint32_t CR;            
    3 n, P! b% E2 F4 w
  13.   __IO uint32_t SR;             ! N9 j% i; S5 R8 a3 S
  14.   __IO uint32_t CFR;            
    . O& }& e; z+ k
  15.   uint32_t  Reserved3c;        
    9 X- L4 r  y1 a) F- N1 D
  16.   __IO uint32_t DIR;          ' A, r; v; s0 b2 W+ N% a
  17.   __IO uint32_t DOR;            2 t/ k5 l( M' [2 e# _" A/ a
  18.   uint32_t  Reserved48[2];      
    0 d; M& T6 c& g0 F7 _5 e
  19.   __IO uint32_t QMEM0[16];     ) e: J7 h! {' L1 _3 l; b
  20.   __IO uint32_t QMEM1[16];       : t+ P6 L; y! Z, H( [/ r
  21.   __IO uint32_t QMEM2[16];      
    & z$ E+ C- P  b$ u
  22.   __IO uint32_t QMEM3[16];       * h0 T9 h- q( A9 f# W( i7 Y
  23.   __IO uint32_t HUFFMIN[16];   
    : I- e$ ]" v( t
  24.   __IO uint32_t HUFFBASE[32];   
    5 F1 i/ _# }; n) y  h/ U3 A
  25.   __IO uint32_t HUFFSYMB[84];   
    : [4 S  O8 g. C
  26.   __IO uint32_t DHTMEM[103];   8 i4 V8 {) }* \) `/ T
  27.   uint32_t  Reserved4FC;      ' i& K" o$ P8 `' [/ Z
  28.   __IO uint32_t HUFFENC_AC0[88]; ( W) ?6 _  m$ N9 K3 C8 s
  29.   __IO uint32_t HUFFENC_AC1[88]; ! S# w( u6 @$ k, u1 Q* U" r6 E
  30.   __IO uint32_t HUFFENC_DC0[8];  
      F+ s8 S! N3 U1 y! }! r4 M
  31.   __IO uint32_t HUFFENC_DC1[8];
    . n, t3 b/ t" }  R
  32. } JPEG_TypeDef;
复制代码
# H8 L% n  d7 N! V/ v
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:) a' Y7 \1 f: z6 D
' j7 n2 {3 m9 w6 c7 r+ J
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */1 \( S1 A# {- z" l, c- R" s3 N
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

) r) {3 ]" e* q' p; p下面我们再看JPEG的定义,在stm32h743xx.h文件。2 R" i: D. L3 X. z, }- S
$ j& n. M' D) ]
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)
    : X- {: w/ _+ G
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)& u1 V- F* r* x
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)
    8 n4 h/ l9 N! G1 D
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码
# j2 Y8 T, {: @5 y
我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。/ |7 ^# M4 I4 k; i& l$ V3 I, i. S

, C' ~; n& u$ a- {/ L57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef8 E6 I! N. S  `& s% O
此结构体用于JPEG的编解码参数,具体定义如下:, G4 t) P* ^) T

1 A$ V+ B) G5 a4 a/ ?: i1 c
  1. typedef struct
    8 S9 G! a/ J2 r% e3 i9 @
  2. {5 y" p5 p' W9 j' f( \6 K1 l
  3.   uint8_t  ColorSpace;               2 r/ F- P: O5 J3 x/ _
  4.   uint8_t  ChromaSubsampling;        # c4 Y; G) r3 q* Y. a6 {( ^
  5.   uint32_t ImageHeight;              9 x8 m) U4 Q- p, }' \
  6.   uint32_t ImageWidth;            
    . x2 R) D+ P. C& J9 n* u
  7.   uint8_t  ImageQuality;               
    # @2 n# E3 ]! c: ~
  8. }JPEG_ConfTypeDef;
复制代码
: s- ~" [# k# L0 ~! s: P) [
下面将这几个参数逐一为大家做个说明:5 U/ P  f. j( p) w; f' t7 [( ~1 H2 O( u4 _
  uint8_t  ColorSpace8 N6 k" {# s) k0 K; I' J" l. L
# O! F7 g. u, ?5 F! D7 P' @

0 l) M5 G8 d2 ?) R* [5 a0 a此参数用于设置输出数据流中的量化表,具体支持的参数如下:
4 f9 ?& y* B2 j% m( |
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/5 `& Y0 s4 h4 Y2 |! F
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */5 ~" o% f* u9 `8 M3 e
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

1 V/ U, V) H: S' f  uint8_t  ChromaSubsampling7 D. K$ x4 k# D7 I& d& {
此参数用于色度子采样,具体支持的参数如下:, ]8 @, @% F1 r& e( {/ }# V. j6 h

# J  c3 b6 g0 c1 g7 R* ]
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    % g3 O# Q. f. `
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */3 P% G5 Q  O# \$ [1 x! B3 f
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

9 B  B. D, y) z7 s7 @: E  uint32_t  ImageHeight# e' j& n/ R8 r8 q) X, s2 O* y2 k
此参数用于图像高度。) t7 V  {: j* N3 z' V1 N

! H0 N/ R* u9 F  uint32_t ImageWidth
! X1 y# R& P4 g! C+ w2 m4 s3 r) s$ s; G' y此参数用于图像宽度。
; h+ i/ F/ j: [) G1 y* y5 L: B6 K, J  @
  uint8_t  ImageQuality
  K3 P) w: ~1 k) X此参数用于图像质量,参数范围1 – 100,1最差,100最好。
+ X6 x" g9 C( y. Q$ ~  m7 [; [! l: h3 d2 E+ k' g2 i' T* p
57.3.3 JPEG结构体句柄JPEG_HandleTypeDef2 Q% X* f0 g) b9 Z
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:# \: H. W  ^" v2 o
! t% h3 R9 t6 O2 w0 P* r' W9 Y( B- M
  1. typedef struct
    7 n0 I: j/ F2 j
  2. {
    0 J" @: f" g% {
  3.   JPEG_TypeDef             *Instance;        
    ) T  U% t* J+ `) n( Y
  4.   JPEG_ConfTypeDef         Conf;             - K6 s" y- l5 E
  5.   uint8_t                  *pJpegInBuffPtr;
    ( B6 r' Y) D& ~! P2 n2 `2 W
  6.   uint8_t                  *pJpegOutBuffPtr; 3 b* d4 [% z* N3 V" s
  7.   __IO uint32_t            JpegInCount;      7 @7 V8 D# S0 R! \# b# L: K7 E
  8.   __IO uint32_t            JpegOutCount;     
    + g+ t, o3 v  m: C
  9.   uint32_t                 InDataLength;       V) U. {$ E) _. L- H
  10.   uint32_t                 OutDataLength;     3 ^  }# i0 n7 ^: o8 a
  11.   MDMA_HandleTypeDef        *hdmain;         6 k3 c5 A6 L/ s6 q1 c
  12.   MDMA_HandleTypeDef        *hdmaout;        
    , w" ^6 H/ |0 }  E8 E; U
  13.   uint8_t                  CustomQuanTable;
    5 v7 A% l+ y' O
  14.   uint8_t                  *QuantTable0;   
    / G( }4 z5 {; v) Q& r6 K
  15.   uint8_t                  *QuantTable1;   
    ( f8 C* a, }3 M' y3 {% ]
  16.   uint8_t                  *QuantTable2;   
    # n6 r: Q( @/ W
  17.   uint8_t                  *QuantTable3;         
    5 r6 [6 r8 Q  i6 Q( L- p% r
  18.   HAL_LockTypeDef          Lock;            
    ( {. U& N; ^. X* j: ^' T1 J
  19.   __IO  HAL_JPEG_STATETypeDef State;         
    . Y6 |8 O6 O- O1 Q) A4 q
  20.   __IO  uint32_t           ErrorCode;      . E. D, I. y' x* v
  21.   __IO uint32_t Context;                    
    * [! S" j' O1 a
  22. }JPEG_HandleTypeDef;
复制代码
: D- f+ k. Q8 D1 Z$ y9 l* f
下面将这几个参数逐一做个说明。- S" L' R9 g& U6 q$ B, f4 M

5 m( [' }' \$ R4 y  JPEG_TypeDef   *Instance% o1 ]  K8 ?1 ~/ c7 }- @
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
6 Q. r: o& e- C+ H8 A$ t' v* q; N
( _0 {# g# N* L/ M& L0 D# R0 g  JPEG_ConfTypeDef   Conf! f; h4 H4 u- ^) w$ Q
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。
4 V2 z/ r; A3 g- G% L+ |* k/ m- L: l, B6 U
  uint8_t       *pJpegInBuffPtr% V: T$ J9 p: V+ N
JPEG编解码输入缓冲地址' {# s, `2 L  M1 ^. J6 u6 M8 b( ?

  c/ [: @: V. ]* w; x4 t  uint8_t       *pJpegOutBuffPtr, B6 x/ `. o. ~7 L2 P  Q
JPEG编解码输出缓冲地址. u* M. w3 O/ F

! ^8 A4 f# H3 \% i: f8 I4 v! M' T  O9 N  __IO uint32_t   JpegInCount
3 E4 Z, v$ `1 h, K$ F0 aJPEG内部输入计数。
( M& V4 [( o5 g- A* j+ z# }# b1 g. T0 Q9 t) J) g5 Q2 k) \) m( ~. U
  __IO uint32_t   JpegOutCount
5 Y: @2 `: s& mJPEG内部输出计数。7 I' P, v1 r( A. o9 }- o% Z

+ J+ r! T( }! U0 [- v# o  uint32_t        InDataLength
/ q* F0 S4 y- Y* j' X7 }+ YJPEG输入缓冲区长度,单位字节
' e; C4 @* A1 K9 \. f$ W" G! [' c/ ]% O8 L: k) r2 b
  uint32_t          OutDataLength
4 n3 P$ @+ ^) f! j2 bJPEG输出缓冲区长度,单位字节。
, k# U- T9 g* T4 O( u4 Q1 q: U
. M: x; }' ?/ }% H  MDMA_HandleTypeDef        *hdmain
: X/ f9 j( y) p; d6 y0 N+ {) E0 q  MDMA_HandleTypeDef        *hdmaout
; |* O, r: k. l/ x2 Y3 r+ U: y$ `: ~$ IMDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
8 i- U" \2 x# M* M0 A8 t8 i( q7 ~7 X: d, H% X' L# N3 {0 c
  uint8_t       CustomQuanTable
) H. c" ~. J6 ~1 l8 E如果此参数设置为1,将使用用户设置的量化表。# e. {# ^' A( t3 q; {

, m1 {  U8 B; C! j  uint8_t      *QuantTable0;   % R8 S8 f: @: M  V
  uint8_t      *QuantTable1;     + |4 m! z9 Q1 J
  uint8_t      *QuantTable2;   
3 M7 V  g' F7 Z! @  uint8_t      *QuantTable3;
4 _6 P; O2 A9 ?指定量化表地址。    5 z  [$ @/ p# e  [6 m+ G/ D) s
! {: e! `* S& K  K. P7 u- N
  HAL_LockTypeDef          Lock           
( U# ]4 L( s, @) H  __IO  HAL_JPEG_STATETypeDef State           " [' {3 \+ b5 E* f, T. J% g# m
  __IO  uint32_t           ErrorCode      
* E0 O0 h) D$ H: f+ B这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。
# w1 t4 ^; w7 s. @4 A' Q" ^7 I6 k; V" a
  __IO uint32_t Context$ F  o# F9 }% _$ o
JPEG上下文。
# ^" {- x8 Y% b% K) n& O( Z3 Q0 L
4 {; z; x4 V; z4 M% i; j# q  p. i57.3.4 JPEG初始化流程总结3 s4 g' ^' b% n: y' [
使用方法由HAL库提供:
" o( ?& n9 ^: x4 K' |1 [4 M! S! `# Y" x# V
  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。
! T( ?1 b( G& p7 @  D
1 W2 z( A& R) F( n4 E如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、
2 I7 f$ `5 A! r1 F8 o
: z& g6 H7 M5 G. Q  z  第2步:调用编解码函数
! Z8 c# N8 X/ ]. r
7 n! w% ]. u! G  查询式编解码函数
* S+ |; j2 M8 D  @* iHAL_JPEG_Encode. s4 p* l) f9 P. o8 h! ]9 `

& G$ k# R0 F2 v% Y8 f  }1 UHAL_JPEG_Decode
6 s) }, i3 I3 K/ [: j1 @+ g
  ~! D# l* Z2 X/ t: z# I+ |: Y8 j- _3 I1 L$ j) [* k

" n+ t7 T3 `  g' Z: g0 i4 j7 O  中断方式& I) z1 _0 w4 W* ^2 r, _1 \) ~
HAL_JPEG_Encode_IT
: ]% c' I! r. |% \0 X3 q1 N! F  e6 `: }9 p, d) \; z
HAL_JPEG_Decode_IT
& v) b4 V& ^6 w; a7 h: x2 w
+ z' v3 q9 R7 S: s+ D! n1 R/ C0 P
6 n( G" b! Y( X4 i' {: q9 D
, f/ E/ e3 T$ U( o. d8 m! F$ R" x4 P  DMA方式4 D: G) X3 ]/ E2 [4 V  a
HAL_JPEG_Encode_DMA$ F; [4 [8 s0 f

. R# z$ R7 T) V; gHAL_JPEG_Decode_DMA
8 z$ ], i, _% x& p" [8 m0 k: C8 R+ C
/ c' Q( [% x) k, C: L8 I  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback; R( b8 z, ~. {+ p
: A. V: Q: ?' _- h6 {; W8 r
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
! p, @  J3 |/ r
2 c4 K/ q4 u1 p  Y& |$ T如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。5 h% u/ A  X/ F/ L* s% H3 B
. J) h1 C4 g0 m

' d* p' t4 G5 y8 G' G" T, I(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
& D4 f, L: D# j* R; u
4 a& g8 o- `( D! K* |4 I( O5 S( J3 M1 }5 ^2 |6 |" i4 M/ n& |8 W
(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。8 U7 L! }- w' D. I
  ^: Q8 e* m7 o: v2 q- d7 y- i
2 v, B+ l" }' Z* S: _
  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback5 T" C; X; q) i
) m  a& _4 i# E4 R
(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
; f* n" |0 s  s/ H2 `0 G! L4 N) J$ P
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。
8 N- x6 y5 R! a% a
: g1 \9 U! ?; o(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。1 F0 q/ t9 t5 p: z

2 q& z4 e" ^8 |5 D; m! x6 s: V- R! O
  第6步:其它相关函数0 y1 j% k: Z5 l
6 I2 {- x0 l" {* E9 J) m6 j! h
  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。3 z3 C  m0 l+ L4 Z8 G+ m3 l# d
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。; Z. A( n5 a0 m6 |% _+ U) o
  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。$ S# r, m& N0 M4 j; A
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。9 _6 w3 J4 Q1 Z8 K% }' l5 S
  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
; k- U  z# h+ E$ d% Q  通过函数HAL_JPEG_GetState可以获取JPEG状态。
3 _' ?0 D" x' Y6 R/ \# [
& w* `9 x% c# d" U0 _& r8 g
: {6 V! _8 `9 y57.4 源文件stm32h7xx_hal_jpeg.c0 h, H3 K7 N. q* i
这里把我们把如下几个常用到的函数做个说明:
: R, d/ D3 d( \# ?. F% g  W4 f1 u" `( `9 P: h* M
  HAL_JPEG_Init
, K/ s/ J" A( b  HAL_JPEG_GetInfo, m0 i$ Z% _& j6 E
  HAL_JPEG_Decode_DMA. O2 {8 D, l0 R8 P4 J2 p& H) {" \5 I/ Q
  HAL_JPEG_ConfigInputBuffer, }0 k- y0 ~3 ]
  HAL_JPEG_ConfigOutputBuffer
+ z# Q7 k7 U$ P
; ~8 o; `7 U% \' @4 F% j8 o57.4.1 函数HAL_JPEG_Init& u7 K4 B) N7 h& M3 x+ Z
函数原型:
0 H1 O4 x) ]( e8 V* C' T# M( N7 B
0 ~" \$ j+ h, c+ u
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
    3 _' G5 c; w  q, y$ r+ M5 D2 t- u
  2. {
    ' @* P6 H( _/ @  a
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);
    . m, F0 W; r+ T# F3 f
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);
    $ B+ R, f- I3 ]2 d4 X, U( }
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);9 i( A9 E& p! ~+ H* t
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);6 a3 G7 H/ V% Y1 s+ W. z

  7. ( g& a  m0 B' ^6 [
  8.   /* 检测句柄是否有效 */
    4 T2 r; H* m3 m+ Y4 m9 o
  9.   if(hjpeg == NULL)
    6 l( R4 F9 r$ ~" j  r% q1 ]1 R9 y0 x
  10.   {
    0 O+ r* Q& ]9 \* J( u
  11.     return HAL_ERROR;& s4 O$ w# r$ p; R
  12.   }1 V: \% O- X& S9 G

  13. + c  |. {" |+ t* r3 W6 A; m2 u& I' e
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)- G# ?2 ?& F) v  q& a
  15.   {
    . A+ D3 e0 d) Y( H7 @* C$ h0 f  l
  16.     hjpeg->Lock = HAL_UNLOCKED;
    " ?  T2 l6 U" K: _- s% T
  17. 0 Y- x4 l; Q2 e
  18.      /* 初始化GPIO,NVIC等 */
    * `% e. a7 P4 \
  19.     HAL_JPEG_MspInit(hjpeg);( O  ]5 r+ \: c7 h$ L, x" l
  20.   }6 K9 M8 @2 a4 I! a0 n, L
  21. % g; C0 M* \0 X5 H2 V9 Y
  22.   /* 设置JPEG状态 */8 [, W$ ~, C3 W; A$ Q
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;. Z" g& p: @& G
  24. 6 y% X( _+ e" U: s
  25.   /* 使能JPEG  */) y; I5 F1 n. }( u
  26.   __HAL_JPEG_ENABLE(hjpeg);2 |; F5 P) T2 m; ]+ r2 Y

  27. 6 q6 _& E4 [" O8 \! V
  28.   /* 关闭JPEG编解码处理 */7 c& [( c5 t8 u' c) j  A# v- @
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;8 b) R' V5 X; U4 ~- X4 Y: Q: d
  30. & E) U7 ?* n3 U
  31.   /* 关闭JPEG所有中断 */
    . U" i* Y& a: L9 b# p1 y. u
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    . w$ Q5 ^( H9 q0 ^* w
  33. " h; Z; |, H( N! U& A- e. D
  34.   /* 清空输入输入FIFO缓冲 */% K7 H+ O( y+ ]% |2 f
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;
    / h( ~0 g  Y- l5 }$ k' C
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    7 _  @6 W. G, Z% _

  37. ) q  i1 Y3 R9 @9 T9 I4 M
  38.   /* 清除所有标志 */( w2 @' h% `; Y0 K; m3 w/ N2 c
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);9 T: [( f: g- l. k+ q4 l5 X4 w

  40. 1 b$ @0 G; @8 P' S# F" d2 }
  41.   /* 初始化默认的量化表 */
    / \9 p/ m: M8 o9 P* H
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);1 j6 E' M/ l9 B, ^! ^
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
    * Y) B5 }; }0 h' X
  44.   hjpeg->QuantTable2 = NULL;& m  _$ x3 \8 _% p
  45.   hjpeg->QuantTable3 = NULL;* d4 \- [7 o- T- W% |6 w
  46. % ~" D+ \- D4 p$ v+ `$ ^/ C
  47.   /* 初始化默认的霍夫曼表 */
    . X3 y) |" W+ I9 h7 d; W
  48.   if(JPEG_Set_HuffEnc_Mem(hjpeg, (JPEG_ACHuffTableTypeDef *)acLum_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcLum_huffmanTableAddr, (JPEG_ACHuffTableTypeDef *)acChrom_huffmanTableAddr, (JPEG_DCHuffTableTypeDef *)dcChrom_huffmanTableAddr) != HAL_OK)
    % B, \1 O7 [) W$ B$ a/ S' ~
  49.   {5 K" k# y4 b7 ^
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
    $ U  E" }# z8 `

  51. # C* s4 H. [6 Z  t0 u
  52.     return HAL_ERROR;' `2 E' Q; z  e% q
  53.   }
    8 T0 s, c; @" m) {
  54. % B) f# O- k- I3 L9 e7 S
  55.   /* 使能文件头处理 */
    $ s3 p) _4 w9 N( u0 @
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;
    9 }+ g+ S1 E, L7 h$ W& r0 o. q' P
  57. ; ^7 B3 w$ d4 a" o1 M6 k5 ~- C
  58.   /* 复位JPEG输入输出计数 */  u5 t) D7 }4 O# O4 y9 u7 u  I, A
  59.   hjpeg->JpegInCount = 0;
    ! v  Q' g9 i9 \5 M1 K1 t
  60.   hjpeg->JpegOutCount = 0;
    4 m, E2 t0 k( Z! j  Q# b
  61. # P- U0 v' C0 @! E% P0 [/ O- L; B9 f: }$ d
  62.   /* 设置JPEG就绪 */( W* r: O( j1 c1 B( B- u
  63.   hjpeg->State = HAL_JPEG_STATE_READY;2 J" X4 q. o( ~+ R  T0 V% m3 i

  64. ! M8 q: V" R: p1 V# V( [: n7 s
  65.   /* 设置无错误 Reset the JPEG ErrorCode */
    $ f3 C4 R. g5 i5 |/ {: d
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;8 ~& l1 Y0 }7 v# O
  67. # k) ?9 x2 K  K/ j8 e
  68.   /* 清除上下文 */
    ; A" ]4 L. H& S, {3 m% _
  69.   hjpeg->Context = 0;
    2 @4 n9 q2 D9 y; W
  70. 1 G( }$ Y; E- w# i5 J+ P9 y
  71.   /* 返回HAL_OK */8 d+ `7 h  \: _4 `; l
  72.   return HAL_OK;5 t* _/ P2 t- `# ]
  73. }& P% f8 B3 a$ }$ g' ^6 j2 Z+ G; @+ z

  74. - y5 N/ z( b& _  n( L
复制代码
2 j3 T9 b6 r6 v0 S! c! \
函数描述:
& c& y# e+ b( P/ b" F8 a9 V* t; P5 N4 e
此函数用于初始化JPEG。
4 i7 c9 B; Q- P6 K5 _
6 g- K: b: r+ b9 s1 v' a函数参数:: a% C1 m. I, [! G8 s: _6 i" E: X

8 e" J; a; d/ k# D  l8 x2 v+ l  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。! T/ i  F  D7 l3 v) a
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。% y5 Q, f2 L3 ]) F
注意事项:4 q) [5 m- W# A4 i6 A* M8 |

/ C- G. V& b- {函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
1 a; g! O/ Z' A2 S7 S& ]! ^8 B) u! N如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。
% v3 o# F7 f( N) y; b4 J: E对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。& t" P! R# |$ C9 a, b+ g
1 i  d* B0 F3 J. y7 T4 t
解决办法有三4 V  a- B2 m4 W$ v. j% n

; n5 L$ h9 |# F( l3 N$ i方法1:用户自己初始JPEG底层。
7 I% D6 F1 K; ]) Y4 O$ Z2 G# A) ~5 z; c& C0 E
方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。* u7 ?) i( H, Q, C5 t0 b/ V4 B

* }( ]5 p9 C1 t7 w方法3:下面的方法; F; c; {* R5 P* c0 K" _3 r% f
9 i- t$ y4 d% _6 l* D4 f
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
    , |" {/ J3 V/ z# ^. D3 e
  2. {  t" T+ T1 V" i! Z6 T
  3.     Error_Handler();9 y. @( P5 w) t# ?; i5 ~* i8 {$ ]
  4. }  
    * U7 T. k; m$ v; c% t' Z0 P
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    # r- u6 X+ Y) I. d% T
  6. {( L) i3 e- p7 O2 `" C
  7.     Error_Handler();
    * `* Q$ P; c' f0 s/ ?
  8. }
复制代码

' G7 M% ]7 |$ b: l* a( _使用举例:% t6 B2 L: A" n: ]- w+ N
  1. JPEG_HandleTypeDef    JPEG_Handle;' t6 z6 ~- [6 x: D7 T! S
  2. JPEG_Handle.Instance = JPEG;
    ' W* v; D: E* x  S# s; K  G! Y5 x
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码
' s2 t; K2 C0 E% [& x! K7 x
57.4.2 函数HAL_JPEG_GetInfo
; ?2 Q6 i2 T1 y/ o3 v3 v函数原型:7 H& F+ E- R) [* R) j
& K2 f) {' T: ]1 c
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
      t/ x) ?, t/ \$ r6 n- E
  2. {& X3 U& l% e" {
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    ' F2 b; n: K) a! m

  4. ; C: i) q1 D/ m" s
  5.   /* 检测句柄是否有效 */! T- v5 |2 v* M0 J( g7 O
  6.   if((hjpeg == NULL) || (pInfo == NULL))+ _4 P9 z, P- D3 W! a6 a# e+ E0 D
  7.   {) H7 d* Q/ M4 w/ q# U
  8.     return HAL_ERROR;1 d* b' g9 T5 P5 f" U# O" Q/ c. u2 G
  9.   }& Z! i$ w: `9 N
  10. 7 A- z' {* n8 n& E+ A3 U, e
  11.   /* 读取配置参数 */0 P( A0 s% |  t: s+ z  _) T2 k
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    - U8 }- z* D0 u+ L: j
  13.   {; n1 o8 s8 ?) Z9 W$ }) S0 {
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
    0 ], ?% O/ `+ j* }2 |
  15.   }   
      H4 O' B& a/ t/ }" f" N
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
    3 L  K0 Q+ E2 s
  17.   {
    $ F8 b6 Y0 d9 y
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;" k+ {( d1 D$ j, W: G
  19.   }
    2 B- C( ?2 D$ U9 L  Z, W9 T
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)8 r5 y# L  H; b9 g. ?; N
  21.   {% {- t6 g& Z( x% L* q* ?/ C
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
    & }1 S) h6 }7 H
  23.   }* ?+ Z! u" P: m7 N# e
  24. . X. N8 n6 Q0 ]8 k2 g3 ~: o
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
    + y1 S/ R$ x" S2 h
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
    5 i- r2 ?1 J' |! _/ }; K, t0 A

  27. 1 v6 n# @" I, r) ^, I& H7 T
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))/ V8 ^$ C* l" u: }3 w
  29.   {. J. D9 A6 r. ?0 W! d
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
    $ Z* q" r" ?: j+ {% X2 U
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;1 {" ]% ^0 y7 Z- p: G- b6 @/ m3 }
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;  C  t4 u0 ^% A5 _4 _& J( Q
  33. ' o! M6 _2 K* O! Y: w. x7 ?
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0)). t, o/ Y$ F( B
  35.     {
    4 S/ X* O+ V! b  B& {3 ]
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/: ]$ ]7 T9 J: ^1 R
  37.     }8 b9 a  b' b$ L/ e  ^( J
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))* X3 {6 w& n9 G" y! G
  39.     {
      @( ^$ R+ H. _( o8 D
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;0 E1 s% o5 N: A! b! A) n+ |
  41.     }# y/ D; g  u/ H6 h* G% g: y
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))( Z/ o6 o. [( _0 Y
  43.     {9 j3 I7 A! h- @# P- p% s
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
    1 _8 z- m* b' N) ]; g1 A
  45.     }' d- B2 j" o, Q5 F2 f0 R
  46.     else /* 默认是 4:4:4*/) j* n- n: Q( A& E3 |0 D
  47.     {
    / \2 L0 r" w; \" c% u3 k
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    # A0 Z8 V, x2 r' o2 P
  49.     }
    3 A" j5 x- g; q: s1 Z  ~; s8 r
  50.   }
    ; X! P* [7 b, ~' }9 p! X* b3 B
  51.   else
    0 V7 Z/ |& N* ?$ F8 C
  52.   {6 k8 O3 C$ j9 ~1 f
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    ; T( W/ R" f7 v. r4 }9 |9 D
  54.   }8 J$ F( v4 N/ y" s
  55. 2 a! [- J- U1 T4 @- S" E, o7 m
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);. E5 u& ^7 g8 i

  57. ' s4 G2 U' D' ]+ N- q- G
  58.   /* 返回HAL_OK */
    ) F( M0 k2 i$ Z% A
  59.   return HAL_OK;7 ~% g& ~, z4 Q8 x
  60. }" Y: }; h+ V" t; [
复制代码
( A0 H' R4 y% U$ b
函数描述:, g8 K7 W+ l5 n& y  s. h

( T5 ^$ L+ o1 q0 V此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。# T* Y2 |& t% }3 z

, c' P4 S8 _) l! b$ O2 ]函数参数:
! w; p: `  ^2 w. Y- m! f  z( M
; \  J( o1 @. c% S  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。  u( P$ `# [4 B6 G1 K9 ~
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小. y  E1 A# t, U$ R9 N3 `- k
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。  `4 {$ i+ I5 E9 Y  O9 q
1 Z4 B+ B! b% o# a2 ~+ `0 ]* X& H
  C8 W4 Z. P# W
使用举例:1 r3 ~, b8 x* O" u4 S! Z. I1 j
  1. JPEG_HandleTypeDef    JPEG_Handle;: M( _' t. l. i& V
  2. JPEG_ConfTypeDef      JPEG_Info;
    . H/ q6 O$ h% X5 s  j+ l: c5 F
  3. , K  y9 I( b9 w3 J; f* E3 x5 ~
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

6 L- L2 a7 o9 ^57.4.3 函数HAL_JPEG_Decode_DMA! P* L; r, C) d2 `* v7 ^
函数原型:
# ^8 h1 Z' `5 J# N7 T3 y6 o5 D/ f# H5 F0 E. Y- F  a
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)1 F# \7 I, x4 k2 u  X
  2. {
    9 i" u% D  ?8 M1 W
  3.   /* 检测参数 *// k/ Y2 }1 W" p0 l* a
  4.   assert_param((InDataLength >= 4));% V+ @9 B5 A3 n
  5.   assert_param((OutDataLength >= 4));7 k) L  P( J  `/ R- M

  6. ; j* P( _+ K+ C. o# c8 P
  7.   /* 检测参数 */! J. T5 Z0 A# f+ y% \7 I- a0 t* p9 P* K
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
    ) d8 c, I( ?- Y$ B9 |$ E; u/ ]8 _
  9.   {' z' A( |$ H8 i" V7 d
  10.     return HAL_ERROR;3 F( ?/ R) i) X2 v
  11.   }, \% Q8 _1 b8 n8 @

  12. ( M- M$ ^1 t3 a& Z  ^9 Z* k
  13.   /* 上锁 */
      b8 ]% Y, {  x' ]8 Q/ a3 b
  14.   __HAL_LOCK(hjpeg);
    5 i4 _6 ^* L* m  b! r9 {
  15. & P3 O6 T2 @/ X* O- U/ |
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    2 I' Z4 D0 A9 c& X  A! U5 W$ I
  17.   {
    - w6 H8 R+ ]& B5 g, L; l$ u
  18.     /* 设置JPEG忙 */
    5 G2 i8 d5 p* d& H; q
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;
    , p7 [' S2 s& d

  20. , V, {4 ]3 x- U; J0 H4 e* K
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */
    2 I: B- z/ Y, t; M; f
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);* k; P- B" k( l
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    ! q3 B! ^/ f- e& z+ _

  24. 2 j( m1 G$ z4 ^; u! R) I& V- y
  25.     /* 设置输入输出缓冲地址和大小 */
    8 g" }- Q2 ]% ~$ a$ Y7 j5 s- Q7 ]
  26.     hjpeg->pJpegInBuffPtr = pDataIn;
    ; J- i3 [3 N& Y6 k* E3 b
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    6 w# ~1 M+ F6 H& L0 w
  28.     hjpeg->InDataLength = InDataLength;, W- l% J9 s) S: N' T2 e. e
  29.     hjpeg->OutDataLength = OutDataLength;) _2 x" B+ s! X" G9 A

  30. 7 ~/ q: `/ e$ K/ q' _. l; v
  31.     /* 复位输入输出缓冲计数 *// ?. K3 x; D; H1 k, o
  32.     hjpeg->JpegInCount = 0;    , ^$ x$ Q7 V7 U
  33.     hjpeg->JpegOutCount = 0;   
    " N  ?5 q1 J: N5 q$ G# D" c
  34. . E6 l; C' d' \' |$ U0 [6 W5 q, a2 h# x
  35.     /* 初始化解码处理 */+ l2 Y' ~" n; Z
  36.     JPEG_Init_Process(hjpeg);
    # u1 G* r3 p% j3 @' z% S: l4 Q

  37. . X6 _' k" i8 X( K* _
  38.     /* 启动JPEG解码处理,使用DMA方式 */, Q4 V- a/ c; Z9 N9 _
  39.     JPEG_DMA_StartProcess(hjpeg);
    . i6 Y. d4 X* b" C4 H3 f( M

  40. 6 k- X6 k4 G" i0 {* M: Q, a
  41.   }0 Y$ j) `3 K% f$ `- Q4 D0 R+ N
  42.   else
    7 O$ m  {7 @* Q) V+ [  y' V; e
  43.   {0 ^0 }. q# D) T" `
  44.     /* 解锁 */
    ) r) n0 _8 j- o- U  g# h
  45.     __HAL_UNLOCK(hjpeg);/ ~- J. q( u% F. H4 _
  46. + D& H; F0 a* d' I
  47.     return HAL_BUSY;% R  o/ I% M4 ]( k) p
  48.   }
    . i/ d* C  t! K- E

  49. $ `- M7 h; R5 U; W; y
  50.   /* 返回HAL_OK */3 D  L1 v/ l% w& \( p' K5 g
  51.   return HAL_OK;) G5 H: q9 h/ s, {6 ~' s" m
  52. }( G& O1 t5 R% v" A1 D/ x
复制代码

, m5 b0 k# ~% w$ a. G* Z
# ^! f: h- i4 d. v函数描述:9 o) ^: ~0 i( V2 ]% T0 O% B) L8 e

4 ^3 c  g  c. T, D' r5 e3 `5 ?7 I6 }此函数用于启动JPEG的DMA方式解码。
; F% I4 O/ c0 D, c& \  @: P$ ]
* {* v, p- e: F函数参数:% B& _- v, i$ S: x

4 O. {/ D, x1 W# h7 K% {+ e  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。2 _: C2 \" p( C9 n% l
  第2个参数是输入数据缓冲地址。
1 `; j" g- `/ }& ?  第3个参数输入数据大小,单位字节。
5 u0 A* p7 V" U- I  第4个参数是输出缓冲地址。. c4 ^" ]% x0 O
  第5个参数是输出缓冲大小,单位字节。4 ]2 I! C2 Z4 _+ `
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
4 [: V2 s8 A/ F' B% }! K+ W! Q% x4 g; ~  X% l" Y+ |
使用举例:( x) N8 K. J0 \; o! }1 f

) C8 d2 v' x& s
  1. /*! l4 x$ D# F' M  e% U% J  ?; g
  2. *********************************************************************************************************
    4 u5 \) c3 E3 D
  3. *    函 数 名: JPEG_Decode_DMA
    ) S0 H: ?9 N+ N" c1 P+ P! c
  4. *    功能说明: JPEG解码5 i5 C9 j2 a+ P; n; T: W
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    % O! T' H1 y7 V" U* R
  6. *             FrameSourceAddress  数据地址6 t- H. b! V$ u. N! X2 Z
  7. *             FrameSize           数据大小( p, ^; D* I) q$ _+ }5 L
  8. *             DestAddress         目的数据地址' O1 ~( [/ s1 s0 ]4 x/ T4 r. t! {
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功
    " k8 O0 l. M% i& W# W
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    * T' S7 C$ P- b; J3 d
  11. *********************************************************************************************************/ R, {3 q8 g2 h1 b+ i1 n3 S
  12. */
    6 K* c, T8 z& @- l# K$ X4 d0 W! J
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)) [# k$ J% j- b) ^6 u( _, m
  14. {
    ; D3 s6 w3 @# s0 d8 L
  15.     JPEGSourceAddress =  FrameSourceAddress ;; @! H' U' y  n
  16.     FrameBufferAddress = DestAddress;/ T' U. _$ m( I- V2 r
  17.     Input_frameIndex = 0;! C) K5 k: Y+ M' A' B6 A9 \' t* d
  18.     Input_frameSize = FrameSize;$ Y3 z5 P* a9 K- a4 _
  19. : I0 A- n1 _" ~+ i8 W* t/ C
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */: X3 S+ u3 h* H" X5 @
  21.     Jpeg_HWDecodingEnd = 0;
    7 u! i! P+ `+ F  ]% ~# D

  22. ; N1 ]' C% p3 L  w
  23.     /* 启动JPEG解码 */
    ' g1 m$ `" k  u. a. Q, N% v6 D  x
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
    " `) J$ i; N4 t4 z0 }% F" m
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
    9 s0 ~9 I/ u6 n( @$ Z7 S% s
  26. 5 x+ D7 z7 c2 e: l3 O
  27.     return HAL_OK;
      }1 _% d9 ]( N3 X( q1 r1 W
  28. }
复制代码

, R8 R8 I+ u# F/ M5 d57.4.4 函数HAL_JPEG_ConfigInputBuffer0 H7 Q5 l( J8 i  a
函数原型:2 p* ^- |, I7 e" E% O

8 v" A8 K9 {' ^+ m
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)
    9 F( J8 P" g# q6 D4 ~+ a$ U
  2. {
    " ~$ g* r; d" y, x3 N4 `$ Z
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;
    : p* H4 p3 ]# @" Y* ~
  4.   hjpeg->InDataLength = InDataLength;
    3 @2 {7 D) t" l) v$ v# u
  5. }
复制代码
5 r( q3 U, k- O3 V
函数描述:+ ~0 \6 [8 s* a& K8 l7 T. A* R
8 P* K  H( S5 f6 N7 A0 {
此函数用于配置编解码输入缓冲地址和数据大小。
! l6 z! X. `+ k; _2 F* N$ z# }/ D, U0 T) t1 U( D3 R* F
函数参数:
! ?% b" X9 k" n1 R$ ]4 X2 R( z  [% U
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。& U+ @- ]8 r% J1 F" u/ Q
  第2个参数是输入缓冲地址。
' |' R. M. a$ a, ~' K. p  R) @5 g+ E+ ~  第3个参数是输入缓冲大小,单位字节。
( c6 d  W1 R  Q: z* H& ]  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
* L2 e+ J9 ~! \9 E使用举例:
2 W) I+ U) m  ?" `) b6 ^  S. M5 Z9 H' @
  1. /*& y: `: f) H- u$ [/ n& y
  2. *********************************************************************************************************: E( `0 F1 o2 I* }4 f+ b
  3. *    函 数 名: HAL_JPEG_GetDataCallback7 V& ?5 U0 s3 H: h+ W
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    + T' ^5 \. D4 h
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针$ ^+ @7 a7 [8 _
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  ) O( {- h0 i5 c4 H6 m- A
  7. *    返 回 值: 无$ F1 L4 n% g: }0 P' U$ [
  8. *********************************************************************************************************
    : c% N# R) b* V8 L4 L6 _
  9. */. H5 p  }: ^+ B
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
    ' N( x( T, B# H& O+ {$ M# f
  11. {8 K  f& c3 ^( X( {4 b  [) U+ x
  12.     uint32_t inDataLength; % |) o) B( ^; |8 F) `

  13. 4 |" q0 C0 y0 @, l* R( E
  14.     /* 更新已经解码的数据大小 */. y# O7 p' V: z0 w
  15.     Input_frameIndex += NbDecodedData;
    : E2 A: V! C+ ~

  16. 9 g/ E: S+ r- h' Q* p) u6 N) V5 N
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
    ' D/ D+ ?) V+ U* o
  18.     if( Input_frameIndex < Input_frameSize)
    + M9 \2 N& Q% _& T/ P
  19.     {& k4 D, x  W+ Q# x( N
  20.         /* 更新解码数据位置 */
    1 ^9 o' g) f" x2 P) W: P
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    # D+ o4 [9 V2 z. O% R: r1 E
  22. 2 R( W! U" _! U+ X5 I: N5 s/ f' s
  23.         /* 更新下一轮要解码的数据大小 *// M7 t) d3 I8 L  Q7 b- R: v
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
    ( o, s% w  i: ~* A0 T: B
  25.         {
    + U' z4 m6 a  W0 n1 d6 E: V- @
  26.             inDataLength = CHUNK_SIZE_IN;
    0 r8 {5 K2 Z4 i2 S
  27.         }" h1 c; x- W1 [; B/ [* x+ G* f4 Z
  28.         else. S/ b! n! N; j, m; x
  29.         {9 L9 J6 I& v  U* J. j0 \
  30.             inDataLength = Input_frameSize - Input_frameIndex;8 F, g% C) ^5 Z7 k6 o+ m0 w
  31.         }      n2 d7 B1 j5 W& p
  32.     }
    8 }% `) M% |7 K
  33.     else
    + W5 c  \( @. J! I8 X3 s1 @
  34.     {6 O! g! f" m; K1 Y0 `
  35.         inDataLength = 0;
    " I2 W2 N7 E. I% A- x% Z
  36.     }
    , J: C8 I; o9 L* r1 L# i- E
  37. 0 E- X7 C+ Q( F! {( P
  38.     /* 更新输入缓冲 */7 T8 e( F4 E' ]1 M
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);      [3 g" {" J; Z8 M. |8 O
  40. }
复制代码
# ~/ G0 K: J8 S
- S; n/ }5 `# L( o. _, g" u
57.4.5 函数HAL_JPEG_ConfigOutputBuffer
$ ^, ^, l' x; v9 \' Z! ^函数原型:  a8 ~+ ?/ M/ l8 ^8 ~6 e8 o7 [

1 G2 O( m! i) }2 S
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
    2 f4 W  ?2 z% ^) a$ ^, o
  2. {
    8 [( a8 w0 C* M2 M0 t1 L: O
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;! [- N' |. j! s( G
  4.   hjpeg->OutDataLength = OutDataLength;  
    7 l1 V" z$ O5 g2 M- t
  5. }
复制代码

) _; m( B/ b( w+ H  ^1 w& U8 B5 i. d* V# `: B4 H
函数描述:6 p& ]- {8 d3 l8 {9 v) i6 W
( h/ ~9 }, _/ o  ?% p, ]& k
此函数用于配置编解码输出缓冲地址和数据大小。2 x! [+ o& @9 x% M7 N+ B

$ U) O$ d9 I- i. M8 _1 ?) P函数参数:
/ C2 v( Y! q0 P( `9 e" b% a* @! a% X& W8 d
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。% Y6 m( `# ^; e4 h9 O5 A
  第2个参数是输出缓冲地址。
. Z& z" Q: \& g' }5 D% @& l, w  第3个参数是输出缓冲大小,单位字节。1 M) m0 H2 }2 ]+ B2 e& A; E
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& F% W8 w9 t/ x, }, s: r使用举例:
8 g9 k4 X3 W4 c9 E% W
. [' V# A, d5 c$ H
  1. /*, M! d& [  X; x# ~
  2. *********************************************************************************************************  d" ~" P3 `+ t5 U! a1 Q" W
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
    % m% q. V$ T* `# e/ F0 o
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新5 w4 E  k" |& y
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针
    / t+ C2 v' z/ L; s  H
  6. *             pDataOut      输出数据缓冲# V% i$ W) }, Y" j# l  M" x
  7. *             OutDataLength 输出数据大小,单位字节
    4 T4 b0 K# R3 P
  8. *    返 回 值: 无5 y9 m1 W- w5 u* K. g
  9. *********************************************************************************************************
    # j0 j5 m, B' N% H: [+ o5 Y
  10. */
    - x+ T9 F- s7 r# Q  g
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)( s' {1 o+ L7 T+ D
  12. {
    # Y: w1 ^  Y9 J
  13.     /* 更新JPEG输出地址 */    Z/ s) ^! ~" i6 n7 S* M, i5 R
  14.     FrameBufferAddress += OutDataLength;8 b) v" p) ], D, W
  15. + i5 G: {% k" s$ C/ |9 H
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT); 2 F% x6 q4 j: G' d
  17. }
复制代码
, X) P. x) t" k( c
57.5 总结" i! I+ {8 G4 B0 T
本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。& z6 o: p; I* g- Y

8 \: T3 v1 G0 k1 M
1 ?; H( T  z+ B5 T# i; X3 C* P, H* a% _9 d6 [
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版