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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示! B0 K$ q8 N; O# b8 V$ j8 R( G5 c
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
% h: V- D2 K1 C# t4 G  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。
: Q0 v/ K' A9 ?1 ]( A3 R2 B  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。% t3 f9 f7 r' s3 Z1 n0 Y4 q. k. s7 z
  本章JPEG相关概念的介绍参考了wiki百科和百度百科。( O0 i, j/ P9 z+ `9 m: w
57.2 硬件JPEG基础知识
8 h$ w, B. z% H/ y; `
对于STM32H7的硬件JPEG了解到以下几点即可:
# B9 s" e. ~4 k4 q* z  V% v( Q& R& i% R! _) d# S7 k) N2 \, w: Y
  支持JPEG解码和编码。
1 _5 x+ v  Q' a* @0 A  对每个像素数据进行编解码只需一个时钟周期。( P+ r" A3 D1 \8 a* h1 e: Q& R
  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。
: D5 T5 }) ^& y1 H  Q  编解码时每图像分量8位深度。  M; p) i0 Y) G; G! D! ^5 ~7 [6 ~
/ |! v, D! f! U$ T
57.2.1 JPEG硬件框图4 W; D* U. K0 n8 W. l) X
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:" W' A* R: }3 i- S. B+ J; Y0 Q8 k& `
  q, P% E: p/ i" j2 K
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
% D. J' C1 g! ^- ~( Q4 m

1 D# A& P% }; q7 g7 T6 F* G通过这个框图,我们可以得到如下信息:" w; Y& X0 P8 i) `# g* j

/ ?' X" f. G% Y! [6 ]  JPEG硬件外设支持编码和解码
2 @# M6 ]* \6 m9 i! i$ O  s- E并且对于输入数据和输出数据都有FIFO支持。% X/ Q6 C0 a4 K; M8 S

/ b" z% Z" v5 z7 u4 D9 E! u9 W* Y% S  jpeg_hclk
7 a- U. b3 [. }: G: y7 `7 p为JPEG内核和寄存器提供时钟。9 w1 n5 u- G- `: Y- Y) x; k
7 h" t- c& s* q1 J  ?+ ~
  jpeg_it" t0 o" r/ Y0 b! ?$ Z
JPEG全局中断输出。3 a/ i9 _3 a4 U8 I  s4 V- p
9 c2 D# P; O) R, j# _2 A
  jpeg_ift_trg, l, O9 h$ k( G
JPEG输入FIFO阈值信号,可触发MDMA。+ [4 n; E7 q, r8 L, Q  W. r

+ W! U9 s) d  [3 p# r" e3 i1 F0 e  jpeg_ifnf_trg
* K" J* B, h" m6 C  b5 U, KJPEG输入FIFO未满信号,可触发MDMA。
3 ?& w. B0 p' `5 S% o, p1 f. u
/ y. U! T1 u+ A  y4 A7 `) J  jpeg_oft_trg
) ]* t0 B$ C; G4 n5 jJPEG输出FIFO阀值信号,可触发MDMA。1 m) v+ \& f- J7 V0 K9 f5 D

8 Z6 o% A5 \, d# F2 z  jpeg_ofne_trg
: b' i) X! O+ |JPEG输出FIFO非空信号,可触发MDMA。2 Y6 J0 M/ O$ Q: O
0 M' n* i+ G* i. F* l+ D9 m0 R
  jpeg_oec_trg
9 Z  m  C$ L. e4 \* wJPEG转换结束信号,可触发MDMA。
: b& f9 M* u6 @2 V* W3 }" |$ F% g* t9 k- V+ `7 N
57.2.2 YCbCr颜色格式
1 h: l; G6 h! t' t9 i% Q1 q(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)1 U/ ^% J0 j8 J2 r; ~5 T

: ~6 `- f3 e/ R' R0 v. f: x正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
, C& A; A6 q( C2 k- P2 H: e
* f- Y+ K0 q+ D  w1 AYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。! |! n7 f9 W5 _: L$ P0 |% J% a: X
/ F& i# ?; D6 k$ r* {3 i& O, A$ W
在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。/ G; u. T' Q. k. f' @: Q# F

/ z) e2 F( {( z( @8 J) n57.2.3 YCbCr采样格式( N) M, Y% U' }0 `" e# Y
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。1 c) c" q& K& W# A6 @. S

3 c* o. j5 p( D. d6 V. e0 t" {6 h( F  4:2:09 [, l( x: D6 f& M6 n4 e" X1 K
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
3 l7 `/ F" t" s' M4 C+ O, u- k5 p) W# m8 o
  4:2:2
( o0 H' F- V" v* M' t/ ?) B# R表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。) ~7 J& [; h4 c

) o/ W0 L1 E( R0 j, f8 h: A1 u  4:4:4
6 b3 m! l: h; n. e: q" a( Q( [" j表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。" A: \; L0 m( s" d
& G, [8 M) B4 k9 C/ Z% k
具体的采样方式如下图所示,以8个像素为一个单元进行采样:& S' Y0 k  v4 i6 j) ^, }3 Z
1 @* R! @+ l- @% H
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
$ z4 R8 A2 L4 M
4 D. J: T/ J& R" ^+ x/ N
由上面的截图可以了解到:& U0 f- M4 {. r& a- H. p2 e' z
+ z7 m# n% X1 a# U- u: D, E
4:4:4表示Y通道,Cb+Cr通道全部采样。/ q! [" F- X4 N' C' \! j+ H8 Z

# g, E" }- c! ^, @5 G" z4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。
+ ?- S( ^! ?" c( M3 F! b) b
  R3 }* A- h1 T4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。6 x" Y2 D! Y" J6 l7 t
) w* N. N$ }- e$ W
下面是整体效果,方便大家更好的理解:% \! d5 y' }3 y! m( \' v+ E8 ?

3 w2 {9 Y1 W* J: A/ t: q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

* s, `$ ?6 v& V6 u, t. u  a. s6 G" _' B+ {

6 G. w+ |/ c. i
7 ]3 s7 O) i9 @$ f) B0 V' `8 U' o57.2.4 YCbCr的优势
7 ~1 t# H& b$ Q  G4 GRGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。9 ~8 ~- q( F8 a& {- R$ `; h
) p! H& [. W( S* k5 m% T
57.2.5 YCbCr和RGB互转
% [& j8 e" e0 I
为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。7 k) |/ d# K- d9 N4 X3 z

) `4 ~) A) k& ]6 k9 @4 X
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
, e9 s4 @8 E: Q$ \" C$ C# N
/ m: N! W( K* h: {9 b/ r
下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
. i# n% P' j% _5 N4 f4 T5 q/ q& b
" a6 x5 g2 p5 |( l+ c4 l; x
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

3 x' ]4 s* G; b8 O! `
/ T- U: \# O9 z57.2.6 JPEG编解码知识# Q" N' X! h1 C
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)9 x  W8 l' D) ]
2 m) h+ l. M6 P4 B) L8 D
57.3 硬件JPEG的HAL库用法
) f  y4 V' R4 Y5 V' ?# PJPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
2 j4 m) @7 ], l! w- T! m/ d9 z& ^' _9 v* b
57.3.1 JPEG寄存器结构体JPEG_TypeDef5 ^8 @- ~' c( c# h  X" `* Z" h/ ?
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:4 V. q) J1 T, f& N% z+ y

) f) G) @0 S- Y% b
  1. typedef struct5 b! ]* `+ z5 T4 v# b9 a& |% T+ h
  2. {7 k: B1 `5 `- f) L5 M" H. j
  3.   __IO uint32_t CONFR0;         
    . f& w/ X. w9 _% _8 l
  4.   __IO uint32_t CONFR1;          : f& I8 B2 t4 i+ w  F9 {9 O7 f
  5.   __IO uint32_t CONFR2;        
    ! {: e7 y% @$ W0 a1 f- y% B( v
  6.   __IO uint32_t CONFR3;        2 z. w1 b$ S7 r! j" i9 T& F
  7.   __IO uint32_t CONFR4;         * {, B' m) y4 [- E. c; s# a! e
  8.   __IO uint32_t CONFR5;      
    ; k# T6 v5 j; a' g! w6 ?
  9.   __IO uint32_t CONFR6;       ( ]- A! U. b4 M& z1 D. U; h
  10.   __IO uint32_t CONFR7;        $ k, D6 X2 p& a# U* m3 {
  11.   uint32_t  Reserved20[4];      1 r& n# v5 h1 H
  12.   __IO uint32_t CR;             - n$ G* h- C- F) U+ }. j- y( y/ G
  13.   __IO uint32_t SR;            
    % D" R2 |' q7 S  v- G1 C/ w
  14.   __IO uint32_t CFR;            . H6 ?/ ?5 n! O4 R" t
  15.   uint32_t  Reserved3c;        
    ( ^4 V8 r4 P! @+ q) a0 V6 v9 A
  16.   __IO uint32_t DIR;          9 I# [2 y% a$ @6 C
  17.   __IO uint32_t DOR;            % w% t% o; e8 f
  18.   uint32_t  Reserved48[2];      
    / p: w, c6 _$ [3 Y! x( E: C0 |
  19.   __IO uint32_t QMEM0[16];     
    8 H  {$ l& O( w2 E
  20.   __IO uint32_t QMEM1[16];      
    6 o$ I7 e& H- w5 x- Y" Z# S  r
  21.   __IO uint32_t QMEM2[16];      
    * Q0 V& x, O5 Z9 [$ Q
  22.   __IO uint32_t QMEM3[16];      
    5 V8 I; X5 x' y! w4 \8 q
  23.   __IO uint32_t HUFFMIN[16];   
    5 s. n9 Z/ V' X% O/ h) F
  24.   __IO uint32_t HUFFBASE[32];   
    7 |% Q3 M/ x, E
  25.   __IO uint32_t HUFFSYMB[84];   
    & H8 B' m- M! V3 z/ Y4 ^1 N
  26.   __IO uint32_t DHTMEM[103];   
    9 n# t; a# W) [2 z9 T
  27.   uint32_t  Reserved4FC;      
    $ ]1 Q8 O6 V# ]. [; _' [/ w; D" l
  28.   __IO uint32_t HUFFENC_AC0[88];
    / O' e) a) g9 Y, o, N
  29.   __IO uint32_t HUFFENC_AC1[88];
    8 B4 t( p6 p5 h8 J7 j  y: _
  30.   __IO uint32_t HUFFENC_DC0[8];  2 c; T2 I* G. Z+ n5 }6 X& S# F+ {4 n" R
  31.   __IO uint32_t HUFFENC_DC1[8]; ' W+ x2 c" E& U  \% Z% m1 Z" \
  32. } JPEG_TypeDef;
复制代码

% l- J8 }) n( U5 E( p0 J" O__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:. J, p* b5 C: A+ W. P8 P  }

3 l; @( ^  a$ O# g/ Z1 K
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
      U3 Z9 z! b( ~; ?( o4 L9 p
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
9 L" }6 h% x6 e
下面我们再看JPEG的定义,在stm32h743xx.h文件。* M" o/ Z/ W5 H# a; t! Q

6 L/ d7 _0 a+ r7 t6 `- D$ ?5 m" `
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)) l3 M- o6 ]7 K* t
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)/ M( e; s5 M* h- n  c% [) G9 r
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)
    1 p0 X  ^; u7 `' J9 K7 S8 \9 `
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码

8 Y, `0 V; Z  S, b  k( B. [3 B" w我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。# Q& T0 E  q* x) h. l% k
) \9 H+ O. C: R$ r+ G
57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
& b0 w" a5 t; a4 h2 e此结构体用于JPEG的编解码参数,具体定义如下:
2 \4 F+ J3 e' c2 a' ^1 E5 L! K
, i' }9 v: W$ f& L2 G8 Z
  1. typedef struct
    ' s) t) E* A5 w/ W% _) S
  2. {
      M5 \$ V2 T$ l! Y- x8 E
  3.   uint8_t  ColorSpace;               / I8 Y$ D5 Z) ?6 ?9 S
  4.   uint8_t  ChromaSubsampling;        
    # Q) E0 N# \8 `. X3 [8 j- c
  5.   uint32_t ImageHeight;                D* s8 @& A# ?" X& ^4 A+ L
  6.   uint32_t ImageWidth;            
    ( i2 k) C1 o$ N' ]/ M: G* @
  7.   uint8_t  ImageQuality;               3 P/ t, u/ v* \! |3 _
  8. }JPEG_ConfTypeDef;
复制代码

3 d: M; W* O& h& ^; l' A$ _下面将这几个参数逐一为大家做个说明:& p& j6 t3 `8 F" @
  uint8_t  ColorSpace' ?$ i1 }, t: x3 X

8 G* t! \5 D. e1 I$ c, g6 ]) e
" l$ I9 q% {8 \8 s6 W. h- T此参数用于设置输出数据流中的量化表,具体支持的参数如下:
( n& \& Q, }2 S$ z
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/0 L* R' A& n" ?8 n
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */
    + B9 ~; T, o7 {( I
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码
" _, S  l' B* g( B; z. a- I% s+ q7 `" h
  uint8_t  ChromaSubsampling) [7 @! Q$ w9 A
此参数用于色度子采样,具体支持的参数如下:
$ j% l) s. n! n, [; a
8 w( R6 |* f' j1 o, ]! o: Q! V
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    - h7 Q2 G' ~+ [3 s" _, M
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */6 n$ T/ p* D2 ^$ c; n
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

; s) r& s0 v" c1 Y6 s8 s& ]  uint32_t  ImageHeight- b# O/ T9 _7 Z7 V
此参数用于图像高度。
8 U: M1 t5 V5 }' i+ ]- e6 x
6 O) p5 L# B2 c) O( z- H5 F  uint32_t ImageWidth4 M3 T" u% F: ^' a# j: z1 Z
此参数用于图像宽度。$ [! Q. q8 d1 N; H0 ?, _
* d. u7 T& ?* \' R
  uint8_t  ImageQuality* D8 g! r3 h! P0 R. @
此参数用于图像质量,参数范围1 – 100,1最差,100最好。& ?$ ]8 g) S/ ^% ?2 D2 M

' Y2 o) J8 f7 {  V+ j57.3.3 JPEG结构体句柄JPEG_HandleTypeDef( @1 k9 r2 v/ j+ q
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:- P9 ^4 ]- {9 N  o: a
4 W; ]' ?5 m% D3 L( ?" Z
  1. typedef struct; m  N7 v# U4 o# q7 h- F( N
  2. {
    . z$ n( C1 p& ?- h" t
  3.   JPEG_TypeDef             *Instance;        
    ) J* }  a+ Y, Y0 A1 J
  4.   JPEG_ConfTypeDef         Conf;             0 s: M" o7 J+ P
  5.   uint8_t                  *pJpegInBuffPtr;
    / o! v& S8 [" l/ A) h
  6.   uint8_t                  *pJpegOutBuffPtr;
    5 Q) O7 C3 o8 F( W5 f
  7.   __IO uint32_t            JpegInCount;      
    ( {& n/ m$ O8 `' _9 i% U; l0 W
  8.   __IO uint32_t            JpegOutCount;     ; {+ ]3 ]7 G6 J6 m. `
  9.   uint32_t                 InDataLength;     2 x$ `) Q7 x' d2 n) `
  10.   uint32_t                 OutDataLength;     $ V$ f: U" w& Y  V
  11.   MDMA_HandleTypeDef        *hdmain;         
    $ ]5 T2 j2 m" W
  12.   MDMA_HandleTypeDef        *hdmaout;        
    3 N0 H" G# j% }5 `; }; r% Y0 c3 j
  13.   uint8_t                  CustomQuanTable; ' O3 [' `# T+ C8 O3 U  A
  14.   uint8_t                  *QuantTable0;   
    + w, _/ c+ J  c$ W; I. {
  15.   uint8_t                  *QuantTable1;    8 X: c: f' M! g" d" `
  16.   uint8_t                  *QuantTable2;    + {' G, @1 k) x/ B1 }: ?
  17.   uint8_t                  *QuantTable3;          3 y* @* N: L/ ^# L/ A$ p
  18.   HAL_LockTypeDef          Lock;            
    + A  N& z4 E& f& }5 V
  19.   __IO  HAL_JPEG_STATETypeDef State;         
    ( J+ P/ h+ v8 E! j4 _6 B
  20.   __IO  uint32_t           ErrorCode;      
    0 p- k$ C0 T+ `0 F. D0 c3 z7 X
  21.   __IO uint32_t Context;                    
    , p: T5 H$ E) p) K6 j( Q( a2 {
  22. }JPEG_HandleTypeDef;
复制代码

! j8 V. a; t( o0 ~2 H下面将这几个参数逐一做个说明。
" H; x+ d. Y8 P  b5 d2 [8 U( h
, r' c& i3 s5 `+ v2 w! G  JPEG_TypeDef   *Instance
: N+ M* l+ L! v. ?这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
5 _; K. k/ ]9 n; l# O7 @
( E" W9 B1 E) ?: }  JPEG_ConfTypeDef   Conf. I$ k) _: T" G+ Y
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。5 K6 Z  ~4 ^- E9 \# p
6 O, ?3 J" o1 ]0 [4 t
  uint8_t       *pJpegInBuffPtr
3 {* y; t, f1 v. u2 R# M# mJPEG编解码输入缓冲地址6 m7 ?" S/ u, N( L; G9 Q7 q# e1 e4 e

+ Q$ C. u& q* o  uint8_t       *pJpegOutBuffPtr
" D  _6 `8 I8 d& y$ _( x6 A2 @JPEG编解码输出缓冲地址
  ~. G! n/ U8 R2 C; j' M8 [: v5 q
$ r( t/ X+ m0 b: K! O# I- X! {  __IO uint32_t   JpegInCount
$ S% s7 y8 R* d1 B" p) k) @JPEG内部输入计数。/ y6 Y& D* w7 h' r0 _3 t
( W/ p- N: g; `1 k
  __IO uint32_t   JpegOutCount
: v- J) d: B$ d9 NJPEG内部输出计数。
4 }, s. M5 p' W" G6 E3 D% q
8 f! v; ?+ `! B3 @  k  uint32_t        InDataLength
% r7 E7 b5 M2 t9 f/ e3 o7 G( eJPEG输入缓冲区长度,单位字节8 E8 d) B; L. @2 |2 U
' C9 U1 Q% D2 Q. K) K
  uint32_t          OutDataLength
7 ~0 P: j1 b# J; N( E) XJPEG输出缓冲区长度,单位字节。
: F% ~" P( Y6 m/ A+ B  P
, q* |7 ]/ P4 L$ s2 I$ w6 H8 u  MDMA_HandleTypeDef        *hdmain
3 g( p$ E  j* S7 B/ P7 X% K9 G1 A7 e% }  MDMA_HandleTypeDef        *hdmaout
2 ?$ B/ e# b& l' _0 T* EMDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
& `5 `0 _% u4 o7 G$ [+ x
3 x# X. ^0 S0 C' N6 q: O3 f  uint8_t       CustomQuanTable# m6 v& y7 _4 t) A; J" p
如果此参数设置为1,将使用用户设置的量化表。+ R; R7 D# Z, V' n6 F; n
" @  V6 O! b0 v
  uint8_t      *QuantTable0;   
3 I- n" U: X/ q" O  uint8_t      *QuantTable1;     3 j' Z+ d9 Z. j* A6 W
  uint8_t      *QuantTable2;   
- k, u; Y, l8 ~  uint8_t      *QuantTable3;
) ^5 s5 v6 s! U1 C) G0 k指定量化表地址。    % A3 O: q  c. s
! C; m* `# A& }) N; F: c* k
  HAL_LockTypeDef          Lock           
0 _; R! K$ ~; K/ A- [  __IO  HAL_JPEG_STATETypeDef State           & Q/ W1 V% Y! {% k3 d" H. v# A+ t
  __IO  uint32_t           ErrorCode      : D5 H6 t+ |: f& ]
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。2 ?1 i' l: V" e6 n: Z7 M

1 L( ?8 {) C5 @& C  __IO uint32_t Context9 }$ U4 ]2 x) u# s( y/ V* P
JPEG上下文。, ^# F  T+ t8 @
$ P8 W2 Z& J4 I4 K
57.3.4 JPEG初始化流程总结
# ?1 `& f+ v+ R" c( d9 U使用方法由HAL库提供:) \# V5 x* k4 s* d6 f- C
: B8 q$ K/ X! c: c1 a
  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。
# O  s: a6 V8 n' X7 V/ X
! F9 w+ g6 x0 K+ y, \7 M如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、( x; b% c4 @% ]

1 n0 O0 f( H5 `0 Y: a  第2步:调用编解码函数
! W+ A1 C! c' Q& ?0 |( a  v
' w8 g/ C5 c! R1 z$ S$ r7 ?6 h$ D) E( S' d  查询式编解码函数  F; {& |5 c5 \2 _$ b
HAL_JPEG_Encode- n, B3 N: t* T6 e7 x2 d' i- ^
6 d% J- J' @9 b
HAL_JPEG_Decode4 c- m4 Q6 ]% r+ Z
% [  p2 g# {7 A' z6 d2 V  c

; B3 Y' g2 c; s( g9 K! C' O& U) A$ c" i5 _- z3 t, M( \+ Y7 J7 M
  中断方式
4 \2 v, \8 M! s# ^6 }HAL_JPEG_Encode_IT
8 Q( S8 I1 s3 O
) }- ^1 B4 u6 _3 u- r  G1 NHAL_JPEG_Decode_IT
" A; m5 K/ O/ p# H
, @, u5 P& m$ m1 n
) @$ ^! Y: x$ y, Z$ k) j
4 {! b9 Q4 P# P  DMA方式: R; J* s# t# n1 G& X
HAL_JPEG_Encode_DMA
$ A% ~2 h* h& j( L# v
* x+ u3 ~7 W  oHAL_JPEG_Decode_DMA
& c- w$ ?; [! o  e( ?2 |( J4 r# W& v, ]9 _9 h# w7 v7 w, q
  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback
6 ]4 Q; V! g7 d* }
3 X7 l) K. c5 x( O" @& E(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。: L( E! V  @8 ^/ i/ ~
# m/ o; I' G5 ^& L/ V
如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
9 l6 f# K' q+ D$ r
" @8 f6 U1 Z( v/ Z! U- Q6 ]
3 s5 ?1 Z0 y# m  w, P! l(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
$ Q* _- ?7 }  @* G- S2 a  M1 v: d: X! D) B0 {9 N' A' u

- A* A- [, @# R8 C(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。
; B, D' v7 T4 q) j( ~* _5 @8 R+ v
8 S6 b8 }& \) I* E; _/ \: p2 u) d" Z: {2 T* `1 l& m
  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback
  n1 }: G2 L; A0 G$ p7 c9 _+ T9 ^; z; j7 d3 b/ p
(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
+ L" D% u) t  S% f! I2 X! p% L- y  ]7 p( o. V% I" N4 Z
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。) A2 H0 L3 |; V% @3 ^
( f% m/ z  N. q, h
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。
0 l& _, Q  S  k9 x8 Z/ u3 J3 h
, ]/ Z0 M; `6 e$ E3 ~7 [
/ W  {$ R% L7 X3 Q& `  第6步:其它相关函数. ^% d2 |9 [, e1 Y3 z5 I, m% V

& h, P" u+ Q! o6 |! |  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。
% k  e5 `/ z  C1 T3 G9 u  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
7 ?5 a' o  E' s1 Z4 v  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。
0 q( c! u+ W  b- x/ E# R  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
- D' Q  M- }7 X$ S. j( a  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
; C5 e9 C' \! Y/ {0 X  通过函数HAL_JPEG_GetState可以获取JPEG状态。6 p3 Q! s# P- h
. m1 T1 {! m& X' \) w- X; c

, g( R9 t2 ?( j& U1 ^57.4 源文件stm32h7xx_hal_jpeg.c6 q) R! x' @7 N. z+ ^  x3 M2 O% M6 {
这里把我们把如下几个常用到的函数做个说明:
7 d6 i8 [- Z7 U& j; T% l
0 F  A3 f9 T, }$ _8 R5 W( u. y  HAL_JPEG_Init, k! ^9 J& E4 o6 g1 c
  HAL_JPEG_GetInfo
& A0 F) z; ~  T: Z4 c' }+ L7 m  HAL_JPEG_Decode_DMA6 r6 E) Z4 `- U' k% n) k8 e2 N( Y
  HAL_JPEG_ConfigInputBuffer+ m5 r3 v2 _0 ~, Y; N  `
  HAL_JPEG_ConfigOutputBuffer
% J  m- c" B) M
/ o1 c0 z! s$ q! _) v57.4.1 函数HAL_JPEG_Init4 M: X! G; y3 t' N2 O( n
函数原型:/ x2 U. M0 d" m% s' E
* k, K% s" Y4 m0 F+ C( j3 ]3 I  T
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)$ ~6 X) p' I# ]( f
  2. {- y6 R6 _8 j+ m
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);1 j* v) _6 m( J  a
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);
    ; u9 H2 v% w5 Z9 {
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
    % O+ V/ a6 ?. L& s
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);
    ; b" i+ d+ i5 m6 l8 p8 E
  7. 2 P. J- t# E* F2 o
  8.   /* 检测句柄是否有效 */
    8 k2 @+ {$ E4 q# h
  9.   if(hjpeg == NULL)- q" w1 F, P6 B7 Y* A
  10.   {
    2 R# W: _1 D/ N: r. G  i
  11.     return HAL_ERROR;6 w0 Y+ Y: ]0 u1 L3 r; e  t
  12.   }: L7 a; ?  N' x" d3 [8 U! [

  13. . W+ \+ v. ?1 Q9 n' y/ U
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET), B8 |% W/ r9 C; }* R" w
  15.   {
    9 }4 R, x8 G* D6 h4 U2 M. M; Y8 X
  16.     hjpeg->Lock = HAL_UNLOCKED;
    2 ]! o  x) a3 x. I

  17. ( N$ I% a- h3 Q0 w
  18.      /* 初始化GPIO,NVIC等 */
    & K" j9 V/ x$ o: F3 r5 v" q
  19.     HAL_JPEG_MspInit(hjpeg);" m3 W: a3 P3 t5 T3 A0 f
  20.   }
    ' }) S0 ~0 X7 t2 [
  21. 5 i  A4 S( d- F
  22.   /* 设置JPEG状态 */) Y% q7 q* X: c
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;
    , g; c5 l% l7 P. p( }# V1 e

  24. 9 j; _0 U( W1 I+ `9 I8 P
  25.   /* 使能JPEG  */9 {" ^% |- k( z% A- u& c& v
  26.   __HAL_JPEG_ENABLE(hjpeg);- [& k4 `& a* b8 u5 @+ y2 R! ~8 _) |
  27. 7 w6 ]) ?, ]) N6 x7 n
  28.   /* 关闭JPEG编解码处理 */7 I& F% Y$ V4 t6 [
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;+ ~; x) |- _$ x; ?) A

  30.   N, @( t( N1 ?9 r9 l  y' V
  31.   /* 关闭JPEG所有中断 */
    & {4 n. \3 Q8 {' I
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    # _1 Q! m$ @: \' D( k

  33.   R% w" {0 o* k! _
  34.   /* 清空输入输入FIFO缓冲 */1 d% k, o# }2 v! F- z' D* l$ ~! `8 t% h
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;
    ; A7 X: e5 n; G! L% Q/ x+ K+ Q
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    / X' O6 k1 |* L, g2 _4 B4 W1 f. x* v
  37. ) L! _0 K1 p3 L) P$ v
  38.   /* 清除所有标志 */
    8 G/ }$ p( z0 y" v( M: i3 g" ?
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);
    ! q  |5 F' B3 x# C
  40. / E! O7 m/ ?, C" c. k
  41.   /* 初始化默认的量化表 */6 C; v/ c0 p1 ^
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
    8 O: T2 V. `. O! h) W0 o* p  ?3 n" i
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);2 O+ v* o1 L$ z. v$ d9 T7 W
  44.   hjpeg->QuantTable2 = NULL;
    / w7 c8 g- A( D) L+ Y% x, L( {, t
  45.   hjpeg->QuantTable3 = NULL;& @/ @, `4 \( Y$ ]% l0 Z/ f
  46. 4 k' k! }+ c9 A, P7 v* J# x) C
  47.   /* 初始化默认的霍夫曼表 */  z9 g# F  W3 c2 ?) }
  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)! d: W, d7 ^2 ^& P* |
  49.   {
    & Z6 r: _/ q4 P6 v
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
    " L) G! E9 L3 o
  51. : f; L/ C7 M% [& z
  52.     return HAL_ERROR;( K/ D4 R* F6 O) B
  53.   }# ^  Z+ c" r& M2 L& g! ^
  54. & S5 |( y! T" r' A& m
  55.   /* 使能文件头处理 */
    ; V$ [2 U- `( [9 p. Y
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;- A& Y# Y9 q; @' R

  57. ; ^7 b9 F; p: w8 k) h& t. Y8 q, J
  58.   /* 复位JPEG输入输出计数 */# m% ?# a) m6 S2 f' a
  59.   hjpeg->JpegInCount = 0;' N+ I9 D" S, w, r
  60.   hjpeg->JpegOutCount = 0;
    3 n& V8 l8 l* x  B% }
  61. 7 \' a9 K; v4 d1 O. p
  62.   /* 设置JPEG就绪 */
    ; S# t4 X0 o9 B: r5 o
  63.   hjpeg->State = HAL_JPEG_STATE_READY;
    3 \( v* U0 k+ l4 t' U6 @
  64. 2 s+ Q  {' d. Z/ C" s
  65.   /* 设置无错误 Reset the JPEG ErrorCode */
    0 M* ^, @3 m% X* ~0 B: t, J" m
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;
    ) g" m( W7 x8 B
  67. 6 a# K8 m' v2 x* A3 b
  68.   /* 清除上下文 */' i1 Z; V  o+ Y0 j9 T/ c8 h5 g3 A1 [1 ?
  69.   hjpeg->Context = 0;7 s2 z4 x9 ?" V' `1 L

  70. " L# \2 }& K+ L& b) \' [3 m
  71.   /* 返回HAL_OK */& l7 K$ j) k9 Y# e7 [0 N
  72.   return HAL_OK;, s8 t5 ]2 J: Z2 {9 N
  73. }# M  O5 n& U' C6 N" P" r& C# n, b

  74. / ?, X$ P# S( j2 r' p! w
复制代码

7 I# I! A' g; U函数描述:
# J, l8 ?' \  W2 n& P6 d2 f/ |5 ]) R
此函数用于初始化JPEG。
/ s* }' Q- {) H
6 r: N9 O' b5 K$ a' M5 z. i2 p函数参数:
2 F5 r9 E3 L7 c2 T# Z" y' L
) A) O: e( B6 b4 z* B) j& \  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
7 F+ R3 q6 h# j) w) @+ y  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
+ D8 R! g) ?, {" f注意事项:
! d- w& d! y. ?' p$ U* ^& m; x
, |6 J* ~4 n4 D4 d- j2 V函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
- M/ S, X# q- ^# m. o9 A0 t; P如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。1 ^4 w  u8 F2 t- k# R
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。  R1 U( E8 G+ P

# }: ~0 N* y1 Z% J  r解决办法有三0 Y% j) Q$ M( W- z3 I$ ]

/ H0 u# z$ ?* m+ C方法1:用户自己初始JPEG底层。7 o* I' I  z. u. @! T
4 x/ y8 y' b! X4 o
方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。% Y+ u! ?" x* o, N; \; K+ L
+ _5 d& B6 J- I% S, ?  t" Q' q
方法3:下面的方法( Y7 D+ l% e6 G+ s9 I
/ N" Z3 c9 _* I. a
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)0 j& G' P3 _. M4 e# V6 W
  2. {! O& {: k6 c( e
  3.     Error_Handler();
    9 m# ]" v1 X: P8 Z( r
  4. }  
    7 x, _2 ~' t! I# l
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    # B( k! s; r: z( G' b$ l- i
  6. {* c) h' \' ]5 ?
  7.     Error_Handler();
    " ?4 v  Z  r: }
  8. }
复制代码
* j9 N7 L! b1 ]3 z- q7 ^: O
使用举例:! J- ^4 ?) h3 I8 E) y* O* j
  1. JPEG_HandleTypeDef    JPEG_Handle;
    6 g8 r7 P' \0 [2 F, O& H2 d9 b  e
  2. JPEG_Handle.Instance = JPEG;8 Z& C/ `  W3 V5 F/ W
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

2 V) G1 x- b: E  _  ^57.4.2 函数HAL_JPEG_GetInfo0 T1 v  `# \6 g2 O$ Z
函数原型:
, O0 S) G! |5 G, {9 n+ v2 _! P0 k( B) Y
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)4 d3 s& z6 e* ?
  2. {
    + G! T$ Q: t& w* R! }( r
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;" H2 }" J( ?7 s7 }1 ]; r& q

  4. * Y% e# f3 x7 O( u# O" ^
  5.   /* 检测句柄是否有效 */
    ! d& L5 y0 {& p: C# {
  6.   if((hjpeg == NULL) || (pInfo == NULL))
    / y- W! i  B% D; c
  7.   {5 R7 b  e* p4 ?0 }5 N( G
  8.     return HAL_ERROR;# }3 u* `7 s" }
  9.   }
    . F# v' N: ~, [5 E- l

  10. & E9 P9 R+ D( s* t% F
  11.   /* 读取配置参数 */
    . i* A1 M. ^8 t# P9 {2 ?1 U
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    4 c. \# h" F# R5 H" q* E. H
  13.   {
    . f$ I# i2 v, l
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;    $ T$ A  Q, z1 d7 R# I4 m
  15.   }   
    + Q$ E% E: M. l+ V; ]. T& p; f
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
    : w- I9 V2 l; Q! p9 ]( v8 P8 ~
  17.   {
    + ~6 |' o' j0 p, \" a6 B) ]$ l
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;9 e6 c7 ^; T$ U
  19.   }! Y  }4 J2 K3 o$ N8 S& j2 Q2 S( w  ^
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)2 Y3 Z' ^+ L9 \# l
  21.   {5 |1 w9 m  V& X
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;    5 F# I  J" M, [+ r4 o; Z' e$ i- Z
  23.   }" i* G5 T7 i  S; k

  24. ! i1 Z- }8 S) n  P
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
      I$ ^! A, L4 M
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
    - |, ]2 j! b/ w; U( K

  27. ! M7 m8 j% x  U0 B. n* x% i9 ?
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
    3 }/ p- o% y- _1 L8 `
  29.   {
    * i; y- V* v* ]
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
    ( p8 g. Q$ E5 t. c+ T% k7 G
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
    2 q7 j7 p& u8 o# z  q8 x/ \
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;, X' b0 L5 y/ [. z# X

  33. + D1 l/ U; L- [- k4 V0 {" G
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
    0 T) r: W( n" A7 n3 a( i2 Q2 h
  35.     {" Q& [: [: c6 r; \6 D$ U
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    + E& j8 p$ }, z6 l+ ?# H! h# a) j
  37.     }5 A# ?" L7 ^7 |& [8 ~0 _" N$ t# @# z
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))2 W: M! }9 o' d" ~0 h2 a
  39.     {' A5 H8 `. m6 B$ O0 Q5 |2 u
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    6 X0 ?" A+ V1 h: `3 [, h0 t1 \# ?/ i
  41.     }
    0 |# B8 O. Q* a* }$ f! S; @9 o/ L. r
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))
    ' q* a* K2 r3 x% a# m9 H0 q) E
  43.     {- {" E5 h* ^% e1 a
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;5 T2 `' `5 l! x, U8 q3 n
  45.     }' P! k6 J) N; p- {( U
  46.     else /* 默认是 4:4:4*/4 G8 j& c! Q. \7 g
  47.     {" u. t' d4 F6 H
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;) [6 T# }9 G% Y+ }0 m0 ^
  49.     } * P$ g6 I/ v& y' X0 O( v
  50.   }
    9 [9 \/ c( G; }6 X
  51.   else
    0 C1 O# p4 }! Q: q
  52.   {
    & J( d4 x8 K. b. S
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;! D0 b$ Z- m, Z. p
  54.   }
    ( a3 R3 R- a. Z" g' S

  55. ) g6 i3 F9 J" Z- o
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);3 _! c$ }+ s' {; `7 ^$ |% K8 G
  57. * t5 I" C' g* V( h7 k. @
  58.   /* 返回HAL_OK */
    7 A, b0 f% M9 ~/ Y# f
  59.   return HAL_OK;
    6 L- X5 R  m7 X
  60. }
    5 L& S; j8 c) G" Q1 R9 w
复制代码
: ]  ?* D2 J( u/ m& x
函数描述:6 A8 p4 G5 o6 `. w; a) g3 h

. _0 i" b3 u" b& y* A3 ]此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
: M3 `$ g5 f5 d4 b5 s8 s
/ S8 @; a1 r  R$ N函数参数:
' v0 ]: `$ ?  ~: Q- n3 \' Z3 l; Z4 R( `. R0 {) W7 ]) e3 O. L
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
3 V6 P) b2 v8 R; C* z# ]1 j% I  q  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小
% @: B+ u( R8 j% `/ t! S. r9 t  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 e; g) Y" ]1 S8 f. j& B. U5 v4 i# W% ]7 a# D
: H" q, R8 g4 j9 ~5 Y+ p9 S
使用举例:
6 u( d( n1 c5 [$ l; v) P5 c2 M, x
  1. JPEG_HandleTypeDef    JPEG_Handle;8 R6 g' u* D) a5 K% ~3 v) {$ R
  2. JPEG_ConfTypeDef      JPEG_Info;& X% _) \- j, V8 H# i7 ~
  3. 2 V0 N/ R. q/ A& b
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码
  E( L# r+ E( Y$ a! _% g
57.4.3 函数HAL_JPEG_Decode_DMA
7 f' Q8 c% S1 u2 C: y) x* c( s函数原型:$ ~2 e" A$ v2 z1 L
) r0 c( B- y1 Y2 P$ Y6 `7 Y3 r
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)
    / V+ l$ Z  G' i( b2 K. J& N' T+ `
  2. {! l0 i. ~2 P0 t2 V
  3.   /* 检测参数 */
    # z6 B, r. w8 t0 s8 w
  4.   assert_param((InDataLength >= 4));
    2 N# n' I8 ^+ K3 Y6 V" v7 P" q
  5.   assert_param((OutDataLength >= 4));% p! a9 h9 \4 S, t4 v" J

  6. 3 [3 U3 T0 }; }$ y: T
  7.   /* 检测参数 */% h9 i( {3 X  w; c" L! p' J+ b9 |
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
    ! ~7 R1 Y5 G" t. x. Z! |9 h6 ~
  9.   {
    7 b) M. h2 c* T# j% U' f
  10.     return HAL_ERROR;
    $ T5 {+ `8 e7 f& g- C
  11.   }
    8 X& t6 J" A& \) E; A( g: U
  12. ( l: S* A4 r  G9 o# S* V
  13.   /* 上锁 */
    8 Q6 |; i/ a* b* C3 D3 g) q/ Y0 m
  14.   __HAL_LOCK(hjpeg);" {. h5 {" n$ H1 \6 x2 r$ j
  15. % U7 O2 v. i% l3 b
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    & S1 Z% S4 j' v" G2 W, `
  17.   {* x3 }9 H" ~  I
  18.     /* 设置JPEG忙 */1 `2 j7 v( x5 k4 r: U9 w, l
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;6 O8 ^7 U& l$ |5 P: V0 ^

  20. " X2 I+ G+ n: ^& F1 v1 T
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */
    ( J+ i: Q" v: ^* R2 F5 Y( Q
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);  I; t' l. `. ]
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    ) w7 `1 E. K+ G/ f, J0 e9 t- F( P
  24. 5 m1 T  B& {$ z. u& W" U+ \
  25.     /* 设置输入输出缓冲地址和大小 */* \" h% Z' Y7 U$ f
  26.     hjpeg->pJpegInBuffPtr = pDataIn;
    + k+ J# [6 r0 m+ S& s
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;8 K- p* K9 J1 T5 y
  28.     hjpeg->InDataLength = InDataLength;
    ( t, X* e' e" p2 O' \
  29.     hjpeg->OutDataLength = OutDataLength;* d( |7 P! T& e8 z7 ^( S
  30. 6 r& r" e# c# T- [* b' a0 p
  31.     /* 复位输入输出缓冲计数 */
    + U8 n3 a6 V6 Q# m0 M
  32.     hjpeg->JpegInCount = 0;    " X3 n1 h( j' g
  33.     hjpeg->JpegOutCount = 0;   
    : c! ]( b2 f# ]

  34. + G6 Q- h: _( t( z2 d! q
  35.     /* 初始化解码处理 */
    ) T9 h  {  m$ J- A
  36.     JPEG_Init_Process(hjpeg);
    / x* C) ]# P  a& Y; |. P  o

  37. : h* b, W% ]+ j! f: Q8 _/ H
  38.     /* 启动JPEG解码处理,使用DMA方式 */
    4 z4 ?& m) E9 P
  39.     JPEG_DMA_StartProcess(hjpeg);/ `' L- w2 d" c- \- `
  40. - q) l, A( N* i& y0 P
  41.   }" r. a  g; h6 R7 _! h/ p2 [1 a
  42.   else
    & I/ @+ {4 U( F$ }9 s7 T2 g
  43.   {
    8 F8 m$ P  l( E
  44.     /* 解锁 */- Q7 M, Z) }2 Y, q( I2 S; L
  45.     __HAL_UNLOCK(hjpeg);8 U1 b3 Z7 M1 P. a" D

  46. 6 f% u: ]7 T" M8 n2 S$ S
  47.     return HAL_BUSY;
    # C0 E; B- {9 I# [* _5 Z
  48.   }6 C2 Y4 d& d, R% @
  49. ! U) ~/ A+ w+ x" `# x
  50.   /* 返回HAL_OK */
    * B: t8 E& ?2 S" ~
  51.   return HAL_OK;) n) O) P9 A) J/ `2 S6 H" d2 d
  52. }! l: B. h. ~. ~/ F+ O/ z2 s
复制代码
& o( q9 P* R+ S+ v3 k

6 L9 T& c; x9 k, q- `1 k函数描述:! U; |3 P4 f- D
1 M$ v) v2 c" K) ^1 i  I/ U
此函数用于启动JPEG的DMA方式解码。
! w3 h5 ^# [. F7 Q3 }& u. [5 M9 t7 s! T+ {% M6 x# V
函数参数:5 P# _2 s6 w% T3 m0 A

, R  F/ l5 o- \  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
' k* M% m$ X- q9 r" a3 p% O4 s  第2个参数是输入数据缓冲地址。- {$ m0 q0 j* W2 p5 W
  第3个参数输入数据大小,单位字节。! ]7 W/ r3 F6 G+ u; n
  第4个参数是输出缓冲地址。- e: E+ i0 {2 K, f
  第5个参数是输出缓冲大小,单位字节。
8 d1 s" a3 d8 x8 I  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
3 r- T! Z* X  I! I* X$ V0 v6 V6 W$ D3 p! k" _7 Y
使用举例:5 m3 o- R6 u" Z: m# m
1 D9 q7 f' R& k( E
  1. /*
    : J6 |1 |2 z' Q+ c8 A9 K
  2. *********************************************************************************************************
    8 W" q7 J8 q) W. W8 \  j
  3. *    函 数 名: JPEG_Decode_DMA  X" L" G  e+ M  M! Q$ v0 M
  4. *    功能说明: JPEG解码
    7 N& L( `. Q, ?, G+ `
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    7 J8 }  D5 ~6 K' W3 {9 V! d5 H
  6. *             FrameSourceAddress  数据地址
    6 I* X0 Y9 L1 i% ?; a8 \, s
  7. *             FrameSize           数据大小
    7 O! \! L* Y9 u" g
  8. *             DestAddress         目的数据地址% a" O/ S: n. J  ~
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功! I& ^7 e- f* F6 e6 m4 q
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    * S. F6 e1 \4 ]2 h
  11. *********************************************************************************************************
    5 Y4 S$ W2 X  Y. M9 X
  12. */+ A2 x5 E  U7 d+ H! E1 l
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
    * m- s# r: j/ ?% E& k  C/ @# X* H) I
  14. {& E) ]" D" t- k  E$ p0 J
  15.     JPEGSourceAddress =  FrameSourceAddress ;6 w& p; g" W8 ~- G0 O
  16.     FrameBufferAddress = DestAddress;4 P9 v2 A0 U: H, l9 p! V
  17.     Input_frameIndex = 0;& F" F7 P' C* _" e* S
  18.     Input_frameSize = FrameSize;" g. g) @- d" C8 y6 e2 G
  19. & u  E: U4 o+ ?: b1 Q* e" ]0 u: j* n
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */
    ) `& \/ p  g9 C- g
  21.     Jpeg_HWDecodingEnd = 0;
    . o8 Z3 k0 o, v% y; X4 O

  22. $ t. i# y0 u7 r( q1 `/ l1 l
  23.     /* 启动JPEG解码 */
    - Y3 p) E( |" t* t/ ^% j# w
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
    : P2 i. l; E% \; V2 }$ j! `
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
    4 g$ n, h* C4 `2 ~! n

  26. ' |, [; N; t! `
  27.     return HAL_OK;
    / c) t( S; c9 C: W- R+ y8 M9 O8 q
  28. }
复制代码

0 `( O1 L: c- V0 b. K3 \: W57.4.4 函数HAL_JPEG_ConfigInputBuffer
) O7 ?7 ?* J1 M; Q+ w3 K, }0 {4 l函数原型:
9 P, m* ^& M; h" F8 B/ R% i- w) j/ G3 @3 o' a) Z" A
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)5 y, j$ W$ M0 U+ ]% N* L( i
  2. {3 k) B: N) P( B& Z/ y- z8 G
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;, y1 z" R1 W  J8 u+ f! }( h
  4.   hjpeg->InDataLength = InDataLength;
    ! t$ r3 N- I3 {) ]$ U& K- a
  5. }
复制代码

9 C8 e1 J% t# C/ O5 w7 y函数描述:
* k8 ^- _1 Z7 k
! d$ B4 l- y' d% ]( B) T- Q此函数用于配置编解码输入缓冲地址和数据大小。
* G, O) r8 k& s2 P% E  R- w
8 n2 q( g! V+ a! y; ~. D函数参数:  s7 w3 r) T: U* g1 A1 V
1 b+ f. a; _) I+ N3 S* e( T1 Y3 e! Y
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
$ F3 Y! J/ K& q6 B% |8 H  第2个参数是输入缓冲地址。& K; D* [9 Y- K( b& h  b8 q
  第3个参数是输入缓冲大小,单位字节。& O9 d2 D. [2 F' H
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- h) l) `' P7 a使用举例:
* t' d( K6 U: U$ t/ I2 g- t; V4 B$ Q) G
  1. /*% x0 v/ T5 k  B) z' k( r9 N8 D
  2. *********************************************************************************************************( z+ K+ m" \8 \4 b- D* {
  3. *    函 数 名: HAL_JPEG_GetDataCallback
    9 ~+ X" A8 S* D2 i) ^
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码+ d) \- j5 l( X3 y0 o
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针& S! a# z5 N! u) _
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  
    # n' g. _! V0 C* ~' ~
  7. *    返 回 值: 无
    * h( f( T8 z7 n& m
  8. *********************************************************************************************************$ c& ^  w+ y0 Y" Q. p9 w4 Q
  9. */, e% U, s, D9 ]" h) M; x
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
    # N- j& n/ l. c
  11. {1 P% L* F% k7 [; K% M
  12.     uint32_t inDataLength; % O+ K/ \! l) O1 |6 S- c8 y  V
  13. : [* j' G9 e: {5 _; j# i
  14.     /* 更新已经解码的数据大小 */
    7 d: k2 W& t0 H/ j, k; @- M7 |
  15.     Input_frameIndex += NbDecodedData;
    8 c' _: T3 {$ }- e% d7 o: N

  16. & U! u5 g) a; B! e0 M: G
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */2 B* ^0 s! q. z8 x+ Y5 _
  18.     if( Input_frameIndex < Input_frameSize)# d2 G8 {- C/ N1 ?9 Z- Y; s
  19.     {6 F  E% y, f* D" ^$ C
  20.         /* 更新解码数据位置 */
    1 M7 s, q% O  g6 w7 k4 W* J
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    # L* s3 I1 S. a+ q

  22. 9 D5 a- A+ J# s0 C& L
  23.         /* 更新下一轮要解码的数据大小 */
    * p9 g) t& Y, m6 X5 x' Z0 c! Q5 c
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
    8 i2 W  b% s* S
  25.         {
    ; x3 y. ~6 d- ~  }. ?4 ?% g
  26.             inDataLength = CHUNK_SIZE_IN;" s2 |. x' l( L# B* P( {3 Z
  27.         }
    8 Q9 w* w: t/ L" m- L
  28.         else( c7 R2 a2 e6 \7 G
  29.         {
    0 R" r: {5 c* a2 c6 g. K
  30.             inDataLength = Input_frameSize - Input_frameIndex;
    7 g  X" g8 p0 |% I$ r
  31.         }    : r. [+ R6 x+ D2 p$ w
  32.     }8 I1 ~$ Y' @. T" v; Z
  33.     else
    % S6 q9 m; k. t0 [) i: Z& s
  34.     {
    ( f. J* V6 O  t
  35.         inDataLength = 0;
    ; Z$ D# P( z2 g+ F5 U9 _
  36.     }6 ]$ O4 B7 V6 Q/ [+ {

  37. * ?7 b9 L" W; F( j
  38.     /* 更新输入缓冲 */3 i3 U/ T, q$ L
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);    , H+ o- y* p7 k: s
  40. }
复制代码

) o. }) D# U- h' ]/ `
( U% G. w5 E& s7 C% ]( G! h% W57.4.5 函数HAL_JPEG_ConfigOutputBuffer/ `4 l8 V1 s- U4 c% K1 B
函数原型:
$ w4 E+ T8 H# R- c3 R+ H4 H3 t, J" g0 W' L0 ?' S
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
    ; V. N9 Z7 U5 I2 z  M. N
  2. {
    $ y' _! p# Q2 i' ~" d6 d
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
    7 T8 R# m# b) w
  4.   hjpeg->OutDataLength = OutDataLength;  
    7 j7 m  ~& q! S- x4 P9 T
  5. }
复制代码

% [. @# Z% V$ L+ b% J7 m/ M" ?8 p3 S' r1 E. O- Y
函数描述:
! w% ~2 W! N5 W+ W! o1 ]8 J4 I) u& _. h, W% c* S1 M! N' T- j' B
此函数用于配置编解码输出缓冲地址和数据大小。
$ s2 O: \& r1 N! h- R$ p
' H( [7 e5 J4 E, I/ N  \0 @% s函数参数:
7 k7 ]) O4 c' ?1 V3 b; U9 ^' y# j+ c% H
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。& Q+ Y6 ^, K8 e- f3 e6 b# Q
  第2个参数是输出缓冲地址。6 h, J0 N: o5 A
  第3个参数是输出缓冲大小,单位字节。8 M+ c( c6 x$ d
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。) ~* R7 ]' H& }) G& L5 R5 z7 _
使用举例:
* I+ v0 T2 m2 V" Z* f$ e+ @# V( p* @
  1. /*
    - Y* I% U5 }& Z* r- U+ Z
  2. *********************************************************************************************************# D! n3 k! d7 t# `7 f$ {  O+ _
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
    % _% H, f1 g8 ^/ R  \% H& c. r8 _
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新  Q/ Y1 M3 V* ~4 w0 u: m( z7 ^# S
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针5 B9 ]4 f0 L% ~* P
  6. *             pDataOut      输出数据缓冲6 \% m1 s4 j8 K( e0 M
  7. *             OutDataLength 输出数据大小,单位字节! ~5 |: Q/ E* f% d, R
  8. *    返 回 值: 无5 l, q) Q0 @1 \1 ]# i  ~! i2 M
  9. *********************************************************************************************************
    - z/ z2 N2 A! S" L8 I
  10. */
    3 b8 Y0 k/ m. N( m) ^- Q5 H6 u
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
    ' q4 e5 e- |9 u( V8 M
  12. {. W" S; z& A' K5 x+ ~( q$ _
  13.     /* 更新JPEG输出地址 */  
    ! w$ a' w- G1 X
  14.     FrameBufferAddress += OutDataLength;
    . W% H& h( g7 s6 a0 P7 h2 x
  15. / Y% S$ ^# }0 L9 @* A% c
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
    % m  K+ J4 M7 H
  17. }
复制代码

# Y0 s& x2 G' M9 {4 ]- D57.5 总结
% l8 \' W) {3 p* J本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。
( A" M9 x5 @4 x0 a! C" ^0 \
" I" B2 b7 N# L; ^$ M0 k3 U) _) W  V& ~- t/ v6 K
1 B4 @) S! M* v3 M- @
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版