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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示
2 a( ]0 V2 @% ]( u! d2 ~0 s  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
% z$ P3 J9 V4 F- m6 @  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。
% y5 ]( X* m, _  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。5 {1 Z/ k8 ?8 o) B- w) k$ Y" C6 l/ P! k
  本章JPEG相关概念的介绍参考了wiki百科和百度百科。
+ {% J7 x+ ]$ D- `  y57.2 硬件JPEG基础知识

) Z+ B4 {1 P3 H/ g0 q7 F对于STM32H7的硬件JPEG了解到以下几点即可:
* X2 K, c9 E+ s, C: Y! Y: e) B) |: Q2 @4 T( J$ }- ?/ ~! K) I
  支持JPEG解码和编码。! [4 h& }9 ~8 \3 S/ _, p# S
  对每个像素数据进行编解码只需一个时钟周期。# z. p1 T, V1 L$ A
  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。
/ n/ x) @  }6 [3 P  编解码时每图像分量8位深度。5 |9 X4 f' S$ m8 v

. |: s  B$ T2 z1 s57.2.1 JPEG硬件框图
% f0 t# L4 \" M认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
& L: `% W7 t$ x0 I" v  I9 B7 k7 S3 U* O/ l9 x9 P2 W2 f" D
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

" s0 {) Y% r) C" b$ k3 y) }
9 T/ ^' D! i) E$ {通过这个框图,我们可以得到如下信息:6 E4 m0 |; e; [( z, W. @
7 k+ W- F6 X$ U$ M
  JPEG硬件外设支持编码和解码
: o& r$ O6 y# v- z并且对于输入数据和输出数据都有FIFO支持。( [! N( {- T, d& |, R0 ^; |2 R

! R3 S) W* J  ]2 c5 h: R  jpeg_hclk
' x* x8 ?( |/ c' b为JPEG内核和寄存器提供时钟。
3 |$ g9 d# w: g: o0 u6 B$ @5 R% F' o
6 m2 ]6 G. M% N3 |% Z7 y  jpeg_it
. g$ \2 y& Q6 N9 f( R+ F  bJPEG全局中断输出。
) A- ^5 T& L5 d5 Z) _5 Q8 E- {0 z" [% P
  jpeg_ift_trg- l- V3 \% J2 C
JPEG输入FIFO阈值信号,可触发MDMA。: u8 E+ I. t' A6 }' ]$ o  C

' ?8 `- y  u9 d) Y! ?+ r+ ^  jpeg_ifnf_trg
- a5 d$ d# \2 n2 _. IJPEG输入FIFO未满信号,可触发MDMA。
! s' D1 E$ E+ J7 n" D1 K5 d! m4 x- ]% |' y0 W" p; E' A/ e
  jpeg_oft_trg
" a7 M" H$ Y4 d2 _$ ^$ X2 U" dJPEG输出FIFO阀值信号,可触发MDMA。
; U% x7 O& L- c: g3 O! k- P' O6 i; i7 Y" \' T# l8 u
  jpeg_ofne_trg
; E0 q  Q4 C# h( a, A8 ^4 VJPEG输出FIFO非空信号,可触发MDMA。5 s: D  {% ^2 W
) s: f% R' b# j+ C9 C! y
  jpeg_oec_trg" m. k, w1 O1 ?8 s
JPEG转换结束信号,可触发MDMA。
. H; v0 u5 _( H- S4 ]7 [$ m. z+ W) t; f' N2 d
57.2.2 YCbCr颜色格式' j3 }1 p2 ?1 X' Z2 b4 X* P0 q
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)
1 _3 O5 \2 ?3 l9 W  b3 W3 F
1 Y9 w# U0 U6 x# H9 K5 n" N正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
1 F1 ?6 O) H& k. ?
9 b4 U" Q$ y5 o1 @" x- R8 V7 tYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
8 Y! v) B2 J8 d0 E) ?1 n( K8 a# ^. j# b6 f. S  C8 l
在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
& Y7 f- z# G7 y* D2 }
: \. U9 h: t% R, i: a) w7 {6 c57.2.3 YCbCr采样格式& l2 i: Q$ T4 b- z- T3 ?, ]) s2 ?8 Z0 W
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。' z/ g' D6 T2 n% c( _9 Q

9 |' T- k' |- f; n# w  4:2:07 j5 M. g9 V, V* p* L. |
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。1 U2 F% l1 q( u, U2 O$ K
' c. \( i1 o4 A' i5 D" i
  4:2:2) Q1 W% [: W7 I* M3 r8 Q
表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
5 H: x6 e: Y! i4 {( \: n/ ~: ]' _6 n$ ~  Y6 C3 _: c8 q/ Z
  4:4:4
; |: E: Y, b( y$ k" X. |3 z" Z表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。
$ l$ O& m& s' L5 L; o2 I1 ]( X) X* H( s$ m
具体的采样方式如下图所示,以8个像素为一个单元进行采样:
; t+ e; J3 x2 M0 w0 N
5 _5 l. q: {3 e( R4 c3 l( |
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
% b5 Y0 z. \5 J7 i) J. G

6 ?# ]5 [+ l8 y8 t由上面的截图可以了解到:4 p; @5 p( J) y: D/ K( \/ d
- b3 h  S: Q  Y
4:4:4表示Y通道,Cb+Cr通道全部采样。; X3 _9 |2 M0 o" o

& ?2 C/ ^# a9 r" t' Z: L5 f4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。9 F' J: g& F4 t0 o4 V. B: R
+ c; X5 G8 G- R! c% {
4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。9 g. b" n/ X9 l( e8 \
3 Q6 z/ y: S: z( x4 T9 j
下面是整体效果,方便大家更好的理解:
) n: t9 t; c9 u; @7 u  t
0 D0 c4 R) l) n' m$ X
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
. s  ?" j, V! c& W- N1 }$ ~: e
1 \1 g2 u" Z/ [# `
0 B+ w4 Y+ x# j6 o0 D% g
' R6 P0 @  J/ P
57.2.4 YCbCr的优势
4 l0 r' ?9 J5 S3 vRGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。$ G6 {4 R: X/ J

3 ?" Y' t4 i* \! y$ F8 @  T% H* w57.2.5 YCbCr和RGB互转
2 A8 x; P, O" T8 g4 |
为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。' W4 O7 H* u2 c- [# Y

7 U) B. ?: p! v+ F; \
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

$ X' D- ^7 X8 S6 E. x  E' L
* p, ~3 x2 p, ?+ h" S5 m/ d2 N0 v下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
+ ~4 ?) F6 d- i  ^7 D
! \  ~! n8 g0 ]/ ?, R8 z2 X
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

1 Z7 g: L$ g6 F
1 Z2 ~7 n4 J7 X& D57.2.6 JPEG编解码知识2 H4 R$ w- n- }" g/ A
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)" d8 j! G$ A5 u. X" |3 G) l
, i# A: T% W" x7 O- e$ I/ U
57.3 硬件JPEG的HAL库用法; d! i7 C  i! t; }- X  B9 _  y/ j
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。7 v8 G! t, z% M$ e. h

8 H( I% G" Y( c8 c) p2 R+ ^0 G57.3.1 JPEG寄存器结构体JPEG_TypeDef  `4 F7 t0 L9 n6 w/ L! ^# i; _6 E/ m
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:9 k& }1 p0 L5 w0 [1 p! c& f

) S7 C4 S7 W4 N$ S6 L1 L
  1. typedef struct, R+ D# L, B2 n9 t
  2. {; b. O- p: M1 H6 d
  3.   __IO uint32_t CONFR0;         
      }6 P, Q6 ^) f2 [7 |: }) j
  4.   __IO uint32_t CONFR1;         
    # X& p% l) ?9 A8 k7 t
  5.   __IO uint32_t CONFR2;        
      i9 B. M9 x7 ?( s! f& ^
  6.   __IO uint32_t CONFR3;        
    : e! |6 X' f  @5 }
  7.   __IO uint32_t CONFR4;         
    5 y  @: O  d+ T# t1 J2 \+ V
  8.   __IO uint32_t CONFR5;       / c# e0 Z: Y" k- W& a- n
  9.   __IO uint32_t CONFR6;      
    $ _, ^* x# W& e, K0 d2 k$ ]# x' s
  10.   __IO uint32_t CONFR7;        / G1 p+ q+ j0 e% E6 k  Z4 b
  11.   uint32_t  Reserved20[4];      
    2 [8 \$ [- U% |8 i4 N( K* b
  12.   __IO uint32_t CR;             + C" _6 X/ l3 u$ `" E9 N% m
  13.   __IO uint32_t SR;            
    * W0 g+ \$ C% i/ D( B2 E; S
  14.   __IO uint32_t CFR;            5 @) I; {! F' ?2 ]. l2 u5 a
  15.   uint32_t  Reserved3c;        0 j4 t& y9 ?8 s- B: Y7 u
  16.   __IO uint32_t DIR;          $ f! u0 e) x, x1 t! a8 r) U
  17.   __IO uint32_t DOR;            
    ' k8 m" @# J$ A
  18.   uint32_t  Reserved48[2];      
    # O# K% z) d6 ?3 ]
  19.   __IO uint32_t QMEM0[16];     : ^9 I/ }6 m. Z% L# n
  20.   __IO uint32_t QMEM1[16];       4 H  M6 d8 I3 p; i% y9 E
  21.   __IO uint32_t QMEM2[16];      
    ( X7 `# j# S  X6 N; y/ h% ?
  22.   __IO uint32_t QMEM3[16];      
    $ e9 r  |0 x! m; ^3 ^$ t2 ?( ]8 B3 Q
  23.   __IO uint32_t HUFFMIN[16];    4 z1 A) n( f; X, y
  24.   __IO uint32_t HUFFBASE[32];   
    5 n5 l% S- O# D* @
  25.   __IO uint32_t HUFFSYMB[84];   0 m* M8 l9 x  a$ R8 n" z, U
  26.   __IO uint32_t DHTMEM[103];   
    0 [$ t' G# Y" M: r2 {% z
  27.   uint32_t  Reserved4FC;      
    7 S5 E$ i; G9 f% ~0 d  ~3 r. m
  28.   __IO uint32_t HUFFENC_AC0[88]; # v2 ]. X% m# A9 N- ?& {
  29.   __IO uint32_t HUFFENC_AC1[88];
    7 u( l, p; m  h% o
  30.   __IO uint32_t HUFFENC_DC0[8];  
    : P& S# t1 q; ]" H# P
  31.   __IO uint32_t HUFFENC_DC1[8];
    5 ?' y: V$ |3 i: Z
  32. } JPEG_TypeDef;
复制代码
' [: ~' z6 J. k, H# _
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
0 i/ K& ?& d9 F) h! U$ d) c9 l& h) _. R; A
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */$ g1 E* D# i$ ?. S  e( i
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
4 z) Y0 v! t# P% M$ e# }
下面我们再看JPEG的定义,在stm32h743xx.h文件。
  ]0 Q) R: [! v, B1 T& `! Y
9 W- w4 x* ?. |7 S4 u
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)
    . u, V0 D* a9 W
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)4 B8 y9 i5 e4 H4 S- Z
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)
    : g' T& n6 E5 j- Q! B
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码
! }1 D3 N0 [# X+ z  o9 }
我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。
4 ]/ f$ f1 v7 ^, S% E8 ~% X' p/ C" p% [0 Q/ w: a
57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
) j8 U2 i; [5 B! A! |此结构体用于JPEG的编解码参数,具体定义如下:
7 ?) ]3 B% z" }& H. ^; a( Y$ a1 y  ?1 t
  1. typedef struct: h& u. N/ V8 n3 M4 U
  2. {
    4 a* @2 I2 _& w( L
  3.   uint8_t  ColorSpace;               2 q; o% k) i/ B) M) i
  4.   uint8_t  ChromaSubsampling;        
    0 ?) p- {( y  F4 ?
  5.   uint32_t ImageHeight;              
    6 `! J% E9 k5 U0 C2 n
  6.   uint32_t ImageWidth;            
    * M' E+ m) D1 h1 \
  7.   uint8_t  ImageQuality;               
    + z# _$ s7 E7 h
  8. }JPEG_ConfTypeDef;
复制代码

& v/ N5 A/ Y: r! X下面将这几个参数逐一为大家做个说明:
2 k2 x7 V" E! G" @2 b  uint8_t  ColorSpace# P/ N$ s. _- f, Q8 L2 a6 E
' Z$ {* N, |8 A

  q: t# [9 X4 I9 o% V' m此参数用于设置输出数据流中的量化表,具体支持的参数如下:# n+ Y. H9 Y" h7 {( P9 ]& i7 h, ]
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/
    3 S% M3 o8 J/ l% _% b
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */
    ; \9 s, H& u0 J8 G
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

# L# _. I: t. t  uint8_t  ChromaSubsampling, l2 m: S  O5 x& e
此参数用于色度子采样,具体支持的参数如下:
! E1 w* u6 v8 j: m% M# X& C9 v  l" Y: r
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */2 c& V3 }( H- h$ y$ A
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */
    9 S) x& N. {" |$ @; |
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

7 M; c# b4 S. v* j9 Q; C  uint32_t  ImageHeight
, F+ b0 G( r6 D7 M5 Z* t$ ?6 k此参数用于图像高度。' F( ?5 K3 k/ _; ]# m

& ]$ v; K! a5 W1 _- S  uint32_t ImageWidth, `# Q0 b/ L" w% P) I2 N, n
此参数用于图像宽度。
  ]2 v3 e3 v; o0 S
* Q; j1 Q# j( g( Z  ]% [% w  uint8_t  ImageQuality
! }( l; s: w5 Q4 U: K( v此参数用于图像质量,参数范围1 – 100,1最差,100最好。" h' n$ r2 W( f2 A4 g

6 s& U" H% C: x- U$ S. B. x57.3.3 JPEG结构体句柄JPEG_HandleTypeDef
2 N8 E* ], x- KHAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:0 w! [, [  f4 h. {6 t8 \& t/ z
7 G5 ]% _  \4 T/ k8 Y6 g" f
  1. typedef struct
    2 k- y5 q1 Z9 y: g5 Y; V$ J) B
  2. {
    2 ]8 f0 B; ?6 X9 s
  3.   JPEG_TypeDef             *Instance;        
    ' I" e. n0 ]0 s6 A! d  U9 ?6 o4 m
  4.   JPEG_ConfTypeDef         Conf;            
    * M& k! y% Y5 |; B. t
  5.   uint8_t                  *pJpegInBuffPtr; 3 G6 @9 D$ N+ ?2 i
  6.   uint8_t                  *pJpegOutBuffPtr; 3 J* N. s0 d1 _% ^3 E- W9 B. z
  7.   __IO uint32_t            JpegInCount;      
    / Y8 U! T3 V! u' z# N8 S
  8.   __IO uint32_t            JpegOutCount;     
    . N9 k7 a* @- ^7 ~: _% z
  9.   uint32_t                 InDataLength;     % y6 Z$ p% m' [: |
  10.   uint32_t                 OutDataLength;       \# _- z" b6 X  o
  11.   MDMA_HandleTypeDef        *hdmain;         
    * G* K! r1 u$ W1 ^
  12.   MDMA_HandleTypeDef        *hdmaout;        $ i3 H9 v6 l6 ~  t0 y: v3 y
  13.   uint8_t                  CustomQuanTable; ) Q% {3 F7 s% a' O
  14.   uint8_t                  *QuantTable0;   
    & z+ f: D( Y. {* y# A) G: m
  15.   uint8_t                  *QuantTable1;   
    / i/ U8 a# B$ A; i- }1 ^
  16.   uint8_t                  *QuantTable2;    5 O* P: O' B6 Z* c9 x- d
  17.   uint8_t                  *QuantTable3;         
    - B2 L+ f' e; k! [
  18.   HAL_LockTypeDef          Lock;            7 }; S  Z# S" t
  19.   __IO  HAL_JPEG_STATETypeDef State;         ) l$ g& t; U8 T% K4 l
  20.   __IO  uint32_t           ErrorCode;      
    6 S# A8 w7 G: j' q7 L
  21.   __IO uint32_t Context;                    
    6 w6 }: r+ H* n) L, e
  22. }JPEG_HandleTypeDef;
复制代码

1 G0 {: B0 \! @) B. S# `7 S! H下面将这几个参数逐一做个说明。
9 J9 [  o6 ]% S7 k; B) g! n2 t- @1 q0 J9 A, {6 F
  JPEG_TypeDef   *Instance9 A% b" n# X+ w6 B. k  ]* ~1 x1 l6 a! ~
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
( V) Q* @% P3 G0 j9 @2 b: ?1 u6 W! r7 K1 _& w% C
  JPEG_ConfTypeDef   Conf
1 Q1 B2 f$ K, j) X9 d这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。
6 m: ]7 l7 k9 n. [- C1 N( p1 n4 |2 h8 D
  uint8_t       *pJpegInBuffPtr
4 Y  S7 u2 }% \$ CJPEG编解码输入缓冲地址' M* C( y6 G% i5 o
3 q( s( T" T$ L$ P3 F- p2 {
  uint8_t       *pJpegOutBuffPtr9 a; r4 p3 A, v+ W5 ~
JPEG编解码输出缓冲地址( I" {; @; Y6 m) A/ s- P6 `0 H  f# Y
- [; E4 @/ M1 f9 k
  __IO uint32_t   JpegInCount
9 A1 m, K% W: N1 S$ Z- a" GJPEG内部输入计数。
2 b% Z' B% m6 m) e; r
1 C! D+ Z, {4 W" ?# z  __IO uint32_t   JpegOutCount
0 G/ _# J7 x! y! DJPEG内部输出计数。& N$ ?3 t3 }4 t) O3 ^' I
7 i! X; n3 ~/ w% y
  uint32_t        InDataLength& M3 ^2 z8 ~1 x5 A
JPEG输入缓冲区长度,单位字节
9 L1 F& Y3 w* ^6 q" p1 e* J
# \2 `% E! y0 H" l  uint32_t          OutDataLength
, w* w1 V% L4 W6 rJPEG输出缓冲区长度,单位字节。9 Y- h- ^8 M6 V" S  c
: \+ N6 F* r* S. L, V1 {
  MDMA_HandleTypeDef        *hdmain
. L$ T: y6 g2 \: ?$ ]  MDMA_HandleTypeDef        *hdmaout  U7 W! C4 [, |; }
MDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
0 z7 e* h4 \* s. O3 X) Q0 f7 I
7 o# N$ u! W/ n+ ?' h9 U" r" H  uint8_t       CustomQuanTable
0 [0 B5 j- B! z5 Z, X0 n* a如果此参数设置为1,将使用用户设置的量化表。
- D* ^) p) c5 f7 Y! Z0 n* t
$ f6 V! j; U. E  uint8_t      *QuantTable0;   / P- d, w3 F% J. B8 D* \1 C
  uint8_t      *QuantTable1;     ' b* r( T& B8 c+ P8 l
  uint8_t      *QuantTable2;    : }( P# a' @5 W" \& F7 v
  uint8_t      *QuantTable3;
+ H% N6 h5 L4 l: Y' Z* O指定量化表地址。    4 _* ]2 N5 A3 l6 {2 s

' o7 `: e9 X% C$ y+ ]& G  HAL_LockTypeDef          Lock           : d$ S2 n0 x: {" p$ j* n: Z: \
  __IO  HAL_JPEG_STATETypeDef State           
1 E0 A( P+ t( Q4 r6 O  __IO  uint32_t           ErrorCode      : @' i* K- Q4 @6 A) G8 a
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。; V% [7 B4 U9 N
0 n# P- t  C- |+ x+ L3 w
  __IO uint32_t Context
8 L$ g; v+ V9 BJPEG上下文。  J7 B+ p9 l5 M8 [3 \, u% G

7 ]* y; k" f: q* y57.3.4 JPEG初始化流程总结: [) V1 ?9 \0 t) r* u$ B" o
使用方法由HAL库提供:
7 Y" M9 n# }' U
" c" t. c4 D5 J: q  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。+ n  Z# Q8 }% a$ C

1 i, R& H2 y1 i4 ~如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、
, L0 C+ L8 D4 \  u7 U, \) R% n5 e1 q. G7 {3 w
  第2步:调用编解码函数1 {& w0 D: E, S( ~& d

& ?; n! I  s8 }) U  T( k  查询式编解码函数! n7 I( ^. y2 B# d, }
HAL_JPEG_Encode
8 t7 q/ w% ]$ A' j5 g# h3 p
+ Z% B4 a' ?; |' Z2 d7 \HAL_JPEG_Decode
( c. l$ M- G9 D  C
3 l2 }, s, n- I5 t' W6 U2 A6 q# ^4 b- A3 p8 j# g* B/ [

  J6 }+ H* P, n& n  中断方式
, ]/ R  N  R4 H( J0 Z" v" LHAL_JPEG_Encode_IT9 [. R' @9 N) Q9 t; ^2 w. ^
; @% Q: d) t9 f. g4 T
HAL_JPEG_Decode_IT' }) Z/ l9 ]6 l8 [
% v! b: @* [3 [8 z! |

0 B" k& K9 q* B' R2 [2 k( v
/ X# R  u( M+ w9 o  DMA方式  p/ H: n  _4 f) r
HAL_JPEG_Encode_DMA
0 t, i3 j1 W8 n( Z' M8 m) D
7 I6 w5 I( n2 L" B& FHAL_JPEG_Decode_DMA# {% j" p' K; r& ~5 O+ G5 t
8 M! r+ J" ^# y; Z$ G* \
  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback
2 {8 f, J0 g* g' c6 J# E0 c" y5 {( R: a6 j
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。+ v. l. h# P/ L, p% q6 ^4 u
) {# y9 f% q4 v# J" i
如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
# f6 F: \; H- }9 l& i0 i
4 ?0 N2 w* l! f
5 W) e3 R) Z& o3 m7 H1 O(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
! K, Q6 L4 _  z4 d7 f9 N% u9 ]8 a& p9 }1 ?% N+ W) U
! s5 G5 M' S/ G) \
(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。/ ]; a( q3 L3 h) x$ N- |

" H: s; e9 A. n1 H) e, d' m- k. x: N
  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback
$ v& i' G7 w& {' v2 j: q6 [3 B9 @+ F9 I1 \
(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。( _+ _) B8 Z( c# c) B! h8 m/ v/ ?
! K) V7 e% P# u* ]- d( J
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。" w0 s9 y9 ~- C
0 |- g$ ]% v* o2 Z* m7 U
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。
5 z' Y3 T* c' C& {, Q
; L; r' l' m, T. N$ a8 P3 j* _
* q2 ~; T* Z$ w  g  第6步:其它相关函数
/ b, J: x/ q$ [5 u- o
* E1 r( A& F( \% ]5 ~8 ]  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。* t6 q( ~0 v9 f8 \, |* }& \
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。7 q# u4 L0 e0 H/ }8 [5 r2 Y
  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。- O$ B4 S" G: @8 K
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
% J1 \- F) ^8 [* v0 Q- X% m  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。4 u2 [0 h4 o; I) |5 K5 |
  通过函数HAL_JPEG_GetState可以获取JPEG状态。8 t* N0 J# p4 z
0 U9 [7 s9 j3 z. b. I% e: V% t

+ n5 g& z$ x+ Y5 Y' S57.4 源文件stm32h7xx_hal_jpeg.c, L9 Y+ U! }' ]1 Q1 O8 y! h1 a
这里把我们把如下几个常用到的函数做个说明:/ {9 T6 U: X- W, {1 I7 g
* }2 x6 h: s4 n; R8 V+ R
  HAL_JPEG_Init
$ ?# s- g' b: `/ V" `) ]  HAL_JPEG_GetInfo4 P! y1 W. T1 P' G+ O8 D9 Z- Z
  HAL_JPEG_Decode_DMA: d8 q6 z2 U$ a/ K& D6 W7 r: \' W
  HAL_JPEG_ConfigInputBuffer: ?* t. o6 W9 P
  HAL_JPEG_ConfigOutputBuffer
9 |4 Y9 ?$ T3 N7 O3 q- a# u  z& X! u, X" c( a2 W
57.4.1 函数HAL_JPEG_Init
: a2 X2 }% @" O8 |函数原型:. [5 {( i' {8 U1 H% e
5 K$ Y6 f$ x- }
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
    * ?- k# L" p: e3 B) U. z% R1 X
  2. {" L% r; d1 y2 ^& [
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);' }6 r" j! W; e& v8 L! Q; v
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);( p% W, }0 z( n& x6 V. c: @# z
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
    / b0 ]3 Z# @' s) ?  j0 b: y$ R; `
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);
    8 R2 N: k& P" x# y  q4 v! [* s9 x+ L

  7. 4 Z: s% _1 d6 r4 q
  8.   /* 检测句柄是否有效 */
    * F+ h) M/ s8 R5 ?( a- Y
  9.   if(hjpeg == NULL)2 z6 F9 y6 G! ^
  10.   {: ?8 m8 \+ f5 F% b) A* i- ~9 `
  11.     return HAL_ERROR;
    + ~8 W: B: E- S- H
  12.   }
    & q; i6 s  Q( g
  13. 4 Z/ X2 _5 D* u* I- ~# x
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
    6 U2 h; D- ~3 N) H# i& V
  15.   {8 l* `( M) @; o5 [( q
  16.     hjpeg->Lock = HAL_UNLOCKED;0 o( l. T) Z/ Y. a8 y

  17. & f+ A' P2 k/ e. G$ q! k
  18.      /* 初始化GPIO,NVIC等 */% D( f3 r3 f; D. V
  19.     HAL_JPEG_MspInit(hjpeg);; ]+ Z$ S: F2 _) G& ]
  20.   }
    5 S' [' T& G  A) V8 B. k2 F, L8 \
  21. , e8 }' F( `1 M" M% Y$ d  Q! A
  22.   /* 设置JPEG状态 */- g" C# L: M: i& Z
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;
    0 M6 d  F; R/ F  k

  24. - G; K/ {9 k# ?
  25.   /* 使能JPEG  */, W* i# H' U0 d) W. v6 ]0 E# \: x
  26.   __HAL_JPEG_ENABLE(hjpeg);
    3 ]$ Z  C: d$ N
  27. & z  u, f" N0 I* f/ w) B; o& U7 G
  28.   /* 关闭JPEG编解码处理 */
    / {# N- Z6 f4 {) B
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;
    $ ~0 u5 ^3 g+ H" j0 U: s. ^$ r
  30. 7 `9 B9 U( @$ L& f/ B* Y; J
  31.   /* 关闭JPEG所有中断 */4 K% f8 i# j; z3 Z/ m. o5 \- ^
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    6 Q6 a1 e2 `- `4 ~* M$ N, r% k/ p

  33. : d' P0 E/ t& w4 A, U4 \+ p
  34.   /* 清空输入输入FIFO缓冲 */
    , r/ Q$ V. ]: b5 ~  z( x. G
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;, U8 W% i0 }5 p" K* k3 n/ Z
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  ) h( U+ d5 ^3 z& z4 r

  37. & V' x6 [& Y1 y- ?, r1 p
  38.   /* 清除所有标志 */* D' t5 c- V+ U! C, R; g
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);
    , N0 O0 V3 {5 A* k0 l2 j
  40. / @- ]* x1 A) B. {% c
  41.   /* 初始化默认的量化表 */& U. J8 N7 ]  I  v# ^: i/ n/ U
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);2 S. @0 u* Z5 c( Z2 J
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
    - W  `$ T0 X, c0 n& F
  44.   hjpeg->QuantTable2 = NULL;
    7 M1 s7 k& [/ ^% v0 r
  45.   hjpeg->QuantTable3 = NULL;
    , S$ T5 o+ o# E* p/ @

  46. & D, r1 m. I6 k/ B& j$ W" Y
  47.   /* 初始化默认的霍夫曼表 */+ c2 u9 y7 z# k+ ]; C" v
  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)9 k- J: z2 K+ I3 @$ A- o; |% Z
  49.   {3 g5 c. j6 C1 z1 y/ f9 Y
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;$ a8 p' y5 ^/ x6 O* X
  51. " R; r( Z& h' e: D
  52.     return HAL_ERROR;
    2 n+ t7 d4 ?, S
  53.   }
    7 s. G( o& J7 C! a
  54. " v) I# b/ W" |  [
  55.   /* 使能文件头处理 */2 }5 f( b4 M% q" V3 A* V
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;" _7 M8 T0 h; T( i$ y) T6 c

  57. + D' ^0 ^; l& Y! D0 ]
  58.   /* 复位JPEG输入输出计数 */* A: Q6 u" p, E& Y  f
  59.   hjpeg->JpegInCount = 0;' e+ M& e' Q$ c% F4 C
  60.   hjpeg->JpegOutCount = 0;$ f3 }( Y: ~9 `" L+ h9 J

  61.   A$ J" ~" C9 u) S& p0 S1 z
  62.   /* 设置JPEG就绪 */% g/ @5 C, B5 {. S4 p& s& @
  63.   hjpeg->State = HAL_JPEG_STATE_READY;
    - j9 e& ~) D% }( f2 o- Z

  64. " f# m  y! q! ]* w3 }
  65.   /* 设置无错误 Reset the JPEG ErrorCode */8 r4 M& R! @2 G2 }7 O8 L
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;1 }0 M) K. F  {% K( A
  67. % n8 b! d$ E0 F7 I6 f9 u
  68.   /* 清除上下文 *// A) x6 v2 `# ]6 x! M3 y
  69.   hjpeg->Context = 0;# o# g# L: J* [+ V3 r) Z  r
  70. 6 j- t) P/ d4 h, p
  71.   /* 返回HAL_OK */6 j. f) G5 |7 h: x: r
  72.   return HAL_OK;
    $ c. G" I0 M( M) {/ X7 f# `* m
  73. }
    9 B, x9 u( C: L; v+ J" x! y

  74. : i, E# R" M! W0 D  D9 \( f: p' S- N2 N
复制代码
9 q& i- }& k, W# l* E0 K
函数描述:
5 U9 B: N8 X7 C9 G" e/ T3 Q9 i9 Y3 X2 V9 a
此函数用于初始化JPEG。" v6 u# a) Q/ r* V$ w

) J: Y1 {1 M. F函数参数:
  \5 d5 {+ W6 p( {; m( y. P; Q' ~
4 @( `! z/ ]: s4 Q1 L3 P  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
/ ^; z9 G" A6 g# B8 k" X) F& w  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。3 a5 z( ^/ A4 c4 V2 I' b* G
注意事项:1 ~: x) x1 S: i5 W0 e' V/ o

9 N7 A. s5 z) V3 l4 a函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。5 s( M+ p" G8 l' x
如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。/ {8 L6 |7 R0 `& l8 ^
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。6 Q, F( X+ [. U3 g5 ~% C- p7 {
/ g6 c4 Q9 F6 s0 k5 w8 y7 y
解决办法有三
/ s$ K; V5 v( U. v* h/ A
7 M! X, v6 u, Z$ I7 r* }1 Q' G3 w方法1:用户自己初始JPEG底层。7 G- ~6 T$ R3 j, u6 s
( \0 z- |- g1 O' O# ^
方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。
- p, c" r# m4 y# T: K. r0 D+ t
) ]7 I4 U0 m  T; Z* X方法3:下面的方法
* l+ U6 O9 D5 x0 S& l
- Y8 k4 I! q7 F
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)2 A; B) H* [4 U# W' t# e+ u
  2. {
    4 E9 R! Y; Y# `
  3.     Error_Handler();( B  k, a9 u/ v
  4. }  ( ?4 C/ ~( E% [
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    1 y/ p+ i8 \$ G: P& P; _& L
  6. {7 _8 q$ T3 x: o& O$ k  Q
  7.     Error_Handler();
    # i* k9 y2 g/ f( ^; ^/ D4 J& L
  8. }
复制代码
1 |1 D, r+ n. j
使用举例:- ?8 X2 p" _( y: A4 a( L  n
  1. JPEG_HandleTypeDef    JPEG_Handle;) a, g6 j0 g. j4 j
  2. JPEG_Handle.Instance = JPEG;! g# e$ c& w* |4 O
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

" e" e5 G5 p* j/ a9 g7 `* l57.4.2 函数HAL_JPEG_GetInfo
, o- C  `4 K8 O% o9 [, l. T函数原型:
2 e; g' F6 G; M2 r- C! k" a, ?7 b6 K; F* b$ j" E
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
    0 G' |8 q( D/ ~6 @7 ]
  2. {
    . ]3 C; M% M& e' m6 \( e: D
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    3 P! n, }1 A+ l  y. _

  4. 1 A# k7 W; x0 c+ [2 J, F
  5.   /* 检测句柄是否有效 */8 T7 Q4 {- O& w: A
  6.   if((hjpeg == NULL) || (pInfo == NULL))1 [8 p! b6 u' B8 ~; |) E( B
  7.   {
    # \+ e  w& F+ b- x. ]
  8.     return HAL_ERROR;% \! _& K- q8 b9 y
  9.   }
    % M' R' d) |0 a- X& R6 z# v
  10. / l9 l* R7 q# E3 F2 z
  11.   /* 读取配置参数 */
    $ L3 @' W+ J1 V
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    / u6 N" K1 ~# X. U, u
  13.   {% |) x+ ~6 d- _1 |# Q9 n
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;    : o( i: s& d! K( W: D
  15.   }   
    - D4 u% \' a9 f5 X' M$ b
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)) }* F$ T& T2 d/ l6 U* |; p' Q
  17.   {
    $ b0 w# _: |! K: H' S* v9 u1 i* Q
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;7 p; |9 t# G9 b' p9 w/ [
  19.   }, N! }2 X8 j9 m+ D$ \
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)9 a' p, {0 y& M; n# [4 o4 L5 X# N
  21.   {
    4 |5 W  q0 |  @  w( l8 [9 w1 X
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
    7 H; X" ~/ h$ z* O3 z3 I
  23.   }
    + ?/ |3 t" r) P/ E9 }1 s
  24. 8 M( S8 s% I0 M3 y7 ~5 t7 y  g
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;0 t! l1 W/ k8 J# m' @* u3 r
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;* {4 k- R2 z8 O0 W# P; U# h) D% j, E5 T

  27. 6 B3 k$ K4 O, j/ R! Y
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))- V" `( s1 w- u
  29.   {) V* h* r+ p; s( Q; _
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;! g5 ^0 k' R' Z, p
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;3 u. l$ P' ]  Q0 v0 b
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
    2 N! G8 M+ m) E& Z# h

  33. 3 i4 S5 H1 k: z+ `2 Q; [: y
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))& D  \! H6 \) @- V
  35.     {. [7 A" {& ~9 f" w1 |; P8 P- ?
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    ; T, W- W4 i9 t( C4 E
  37.     }
    ) G& }* u6 f+ l" l8 {8 i
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
    ) g8 ^3 D, p! I7 E; Q4 C) _
  39.     {
    " N4 l- [2 v# [/ D
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    9 D" J6 H+ w$ y7 P  \* X( m* t1 }
  41.     }
    % z# [/ v6 f$ j3 x
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))0 g  }% t+ z& k% P
  43.     {
    6 @1 H* D6 t  ]/ H
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;. Z) l% H. i( U  [# A7 Y* V
  45.     }
    $ n+ q7 t8 Z& V
  46.     else /* 默认是 4:4:4*/0 x. i1 ^& `) K* ~
  47.     {/ n0 @  T, l) ^1 H+ o% p; h0 w8 {, Z
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    & X4 ~7 ^5 E& j/ X- b
  49.     }
    ; _8 i7 X/ o5 P6 T- T- o& f& A
  50.   }2 c# E+ H1 c# Q
  51.   else # h7 A) ]% ]; M( \
  52.   {
    1 t9 v- A, m" E+ r& j7 ~5 K% E
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    1 O  }; Y) |' R. n8 n/ O
  54.   }& r3 R; G% P5 A+ A" S9 N; y

  55. ' E% o- g! v% N" i9 W, Y
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);2 e; j4 b8 D& v& x8 F- i3 I

  57. / M6 S) \2 ?% @3 k8 u
  58.   /* 返回HAL_OK */
    ! A3 Z  S+ D- U: h# V: J
  59.   return HAL_OK;$ D3 {2 p, {; ^' n7 U6 s& H1 z0 F
  60. }0 _% X/ o% f) o  E0 p- c4 y3 Y
复制代码

0 h9 k6 j, a- {0 j7 K4 c& j函数描述:
1 `0 Q+ _8 [" v" r
7 |4 g  V3 r* `) K% Z此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
/ ]: k3 N! U' \3 b; \' O: x# X4 b7 h5 Q. a4 h8 r3 s
函数参数:
2 p5 Y( v+ H& S  ^2 T" P' R5 A
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
: x1 Q1 f9 n6 @  h* N  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小1 k5 B8 n: X' @/ ]0 r
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。) Q2 d: v: N2 H+ C. H  Y
4 t7 X' K$ j! R, G
- h0 |/ w5 C9 A. v3 m4 {
使用举例:. d  ?1 L. d. z  Z* z+ q
  1. JPEG_HandleTypeDef    JPEG_Handle;" ?0 C* ]7 u+ q8 S: F1 g, R
  2. JPEG_ConfTypeDef      JPEG_Info;) ?6 f. u+ t3 o. h' s' Z& z
  3. ; U* b  @: e/ g! h# l
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

5 ]3 Y9 O) q  F8 U/ s  D57.4.3 函数HAL_JPEG_Decode_DMA7 c5 Z3 v0 h  J0 m
函数原型:6 g' W+ v) @2 f' t7 w

5 z( a1 c- c7 ~( N# p
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)
      E& x3 I. V$ X6 `4 v* R% N4 @! j2 S
  2. {) W; h; L  S6 l7 E( e6 E; Y
  3.   /* 检测参数 */0 `+ C) B) v! O& o$ C% i# A& s6 q
  4.   assert_param((InDataLength >= 4));
    , |* x4 ?' l* @+ j2 |; K: p; @" q
  5.   assert_param((OutDataLength >= 4));% X& e1 m& L3 p9 }1 |  f
  6. 1 i) F* Z: b& M/ \
  7.   /* 检测参数 */
    0 Y+ I) A$ x+ h, B( v
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))- O2 ~/ y  h+ I+ ]$ U0 w
  9.   {
    1 C( l5 Q- R/ g+ ]: ~, ^+ N
  10.     return HAL_ERROR;
    7 L- @. h) M) b/ D
  11.   }
    ( @$ X: q. P  [* |1 _$ s
  12. $ O& O1 l9 ~1 s
  13.   /* 上锁 *// M1 z4 N  e9 K9 `+ B% X
  14.   __HAL_LOCK(hjpeg);
    ) P, {7 l- O4 E0 C+ E7 N2 y
  15. , [" Q& o; v( Y
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    ! x) i3 v6 j! {3 K. f6 ~
  17.   {
    % x" \4 \- {& A* w& k6 b  P# P
  18.     /* 设置JPEG忙 */
    . D: {9 g% {# d8 }! r
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;
    " F0 T4 y2 i4 G+ g% |
  20. - W- z3 _; y5 k% Z) y
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */
    ) `' `- f! g* }
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);* l/ j; B- }( J8 [
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    8 A, n- D1 a+ |5 k4 \" X  z

  24. # R; m2 r; ?3 Z+ d7 q! R
  25.     /* 设置输入输出缓冲地址和大小 */! `+ h1 h- x1 L& i  y( V- ]4 q  I
  26.     hjpeg->pJpegInBuffPtr = pDataIn;
    ' f6 [& A' Z/ q& S. ?+ Z
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    3 T9 x9 v& I. \# N
  28.     hjpeg->InDataLength = InDataLength;
    0 \$ Q9 l2 D, i( J# w
  29.     hjpeg->OutDataLength = OutDataLength;0 Y% L. ^2 i" _6 @& h
  30. . g2 o8 }3 ^2 a# [
  31.     /* 复位输入输出缓冲计数 */
    ' h6 p: D9 S4 c5 l( X* q0 b+ U
  32.     hjpeg->JpegInCount = 0;    1 H# O9 [4 J' V, w- Q1 W. @
  33.     hjpeg->JpegOutCount = 0;    , H  i; N- d! g/ D  T9 Q) P/ E

  34. , J  R8 n. _" W
  35.     /* 初始化解码处理 */
    / [% t0 A  |3 H  \( w0 l( T+ X
  36.     JPEG_Init_Process(hjpeg);3 t$ |  p: x' V5 n# J
  37. 3 U' t; v7 }) ^; F3 L9 j, Z
  38.     /* 启动JPEG解码处理,使用DMA方式 */5 C8 g- U: N  u+ _0 G3 D
  39.     JPEG_DMA_StartProcess(hjpeg);8 U' c2 k! c$ o! i1 Q1 F' z

  40. * x  p, m- ?6 L2 [, h" O) n1 e. {- r
  41.   }
    1 f, e# J- y& l5 [$ d1 T6 ~. ]2 }4 D5 H
  42.   else
    5 O' Y+ ~, [0 }2 Z6 R5 U. V2 ]6 U/ l
  43.   {2 c, C, M+ K$ h/ ?: d
  44.     /* 解锁 */
    # d0 ~4 [1 R" A  G. V1 c1 |
  45.     __HAL_UNLOCK(hjpeg);
    8 E3 w6 S! g1 w9 }* ~1 ?
  46. - W9 G1 \& O4 l- x& Z& ^" ?
  47.     return HAL_BUSY;
    ! s/ i" l/ C: j' [( H- |3 c/ g
  48.   }6 @& k5 s) J+ Y2 ?- B7 W$ n
  49. 1 S) Z0 Q$ ^$ H* _# R9 R  N
  50.   /* 返回HAL_OK */# M6 Y, B: p' U* F4 [/ T, k
  51.   return HAL_OK;+ n0 j0 t. F% e; v+ T! o. l( b
  52. }+ I; e  F! D) O3 k2 K/ t
复制代码
" |  ^% ^! A, B, Y; j& m4 ]' `6 G7 L6 I) y
8 X& C- S* P5 x* z2 B/ a; B9 h
函数描述:
5 x. |# G; `) _
( M4 _. |( @* Z4 r: |+ u+ o8 _  w此函数用于启动JPEG的DMA方式解码。
- U( [* `2 t$ s. C# x4 _5 K! K1 a, h
函数参数:8 K6 R. e. U0 \/ @! l; z- Y

  f0 _1 X' g' v) k5 B  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。" j0 W3 b" P) L4 b0 Z" v
  第2个参数是输入数据缓冲地址。! G* j% v( g. d* \
  第3个参数输入数据大小,单位字节。
  w! z  p$ ?7 P5 X4 R- q  第4个参数是输出缓冲地址。/ A/ D1 h& H2 Z' N% {
  第5个参数是输出缓冲大小,单位字节。
% E4 }3 ~1 I* t; m* b  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。$ [7 \  D  k% `! b$ q" f

) x$ o7 c( U2 M# V. y使用举例:: i/ Q8 d9 K2 ~* V

7 M  V, g2 O) t1 \
  1. /*
    3 L- B& g& A1 D
  2. *********************************************************************************************************7 [/ e) Z1 S0 L2 B3 m) \) r
  3. *    函 数 名: JPEG_Decode_DMA
    5 p" i- c, s( h  Q
  4. *    功能说明: JPEG解码
    / Q% Y' q& B8 I. {; I; V0 D
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    ) O: m) h/ b0 A
  6. *             FrameSourceAddress  数据地址" @  e, _1 L- |6 k# m' i* Q
  7. *             FrameSize           数据大小  h. D7 [/ k2 k+ y: E& c! h
  8. *             DestAddress         目的数据地址4 B' J! r( ~! C
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功, D" a4 G1 r6 j
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    * J, t; W2 @! s6 Y4 K3 @/ d
  11. *********************************************************************************************************% v) {% j) S5 D3 _4 |
  12. */( z: S1 W: V: ]
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
    7 r8 E  {3 b9 B; x- @, R0 K
  14. {6 n/ x" B+ l8 d2 U7 M- k2 s, R) R
  15.     JPEGSourceAddress =  FrameSourceAddress ;
    + ^) O2 w. i% q- n0 a, |- J
  16.     FrameBufferAddress = DestAddress;8 N9 g: ~# v( F1 G; u5 `
  17.     Input_frameIndex = 0;
    5 W5 ~+ J6 w* D2 S
  18.     Input_frameSize = FrameSize;6 Q' B, d/ m' f
  19. 7 p0 G, p3 P6 P$ C9 y
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */" Y6 ~3 z; T# \2 Y; S1 D
  21.     Jpeg_HWDecodingEnd = 0;
    0 ~9 \8 s4 O: b) H

  22. 8 [  x" ~4 ?' M" r! M9 B
  23.     /* 启动JPEG解码 */
    ) J( Z9 y+ F' D0 ]) Z' j, c1 W9 G4 n
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,/ q5 p, C. P3 G. \8 G2 g0 y4 A& O
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);6 N+ N0 K$ {, }! x, u' _" \! z8 |
  26. . G- Z7 ^% d) I+ W: `" B: c
  27.     return HAL_OK;: i4 y! c1 k2 D* d% c
  28. }
复制代码
- o6 H  k* o+ r7 B+ z
57.4.4 函数HAL_JPEG_ConfigInputBuffer( c2 u* l( H2 A# G
函数原型:5 J" X% |) @! r5 s, R
0 g+ u1 n' a. T  V3 R. D
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)7 ~7 y% e9 q3 b
  2. {, Z1 i2 @/ ~0 c* `- [. r
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;0 G4 G( ^3 c) Z' O
  4.   hjpeg->InDataLength = InDataLength;
      ^' C( v+ k* L; e
  5. }
复制代码

. [9 x  ~; @9 q1 g0 ~( k+ P9 u函数描述:9 }5 Z# L3 A" v4 x7 Z9 ~9 y; c2 C
8 ^+ P. H# s5 i" q8 [: u' d" l
此函数用于配置编解码输入缓冲地址和数据大小。' N( V/ N# t! T  L2 B4 f( _
5 ^! Z2 C5 Z. R. B; }' a
函数参数:
, E# C& p* j" j
. g# r3 k* K4 _' b  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。! E! p! ]3 Q! G( m9 U, O  D; L& ^
  第2个参数是输入缓冲地址。
- ~0 J6 Q" r9 i  第3个参数是输入缓冲大小,单位字节。
  t! g# ^3 m3 P8 M! P5 _6 P0 ]' C  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
2 \+ x4 T5 J4 j; X# S8 n  a使用举例:
+ f9 e3 @* |, n# ]
2 Y# w: B: ~4 J% }* M( \1 b
  1. /*
    7 P: Z& s$ M$ X
  2. *********************************************************************************************************# N# @( {" X$ q% a- N: O
  3. *    函 数 名: HAL_JPEG_GetDataCallback
    ' j* t4 ~' Y7 h, g
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    . v5 {/ ^/ G3 b. k. {. O
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
    ( ~. Z& z- o# K& V4 `9 k
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  3 \$ F+ c$ a/ m/ ]: y
  7. *    返 回 值: 无
    7 w4 r- ^" |; d. d1 |2 U  ]
  8. *********************************************************************************************************8 }* L/ [, |9 |& }8 v1 S. C
  9. */
    4 A9 s' k: ^$ F. K2 N% a: r3 ^* V
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
      U6 z  {) v) P9 w
  11. {
    0 K0 P1 M. ]6 O
  12.     uint32_t inDataLength;
      j! R0 D3 a+ ?/ r6 ]7 g
  13. 2 {6 E" c9 D9 Q9 G6 n9 s
  14.     /* 更新已经解码的数据大小 */
      {0 B6 S9 K. B4 K* T' _. l
  15.     Input_frameIndex += NbDecodedData;+ s* [) R/ Z0 F3 _1 C

  16.   h9 _" R- |! }& R
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */! }5 }6 i0 a: g2 I- T
  18.     if( Input_frameIndex < Input_frameSize)+ i' y# I. Z+ r# B# M
  19.     {
    % K% C* [% m% y' p1 W/ C/ Q
  20.         /* 更新解码数据位置 */4 H9 U. L* }/ x0 A1 N1 y3 O" c9 D
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    9 S* |$ }! t4 K3 D$ f. S" O

  22. - ]+ C: r4 Y" l# i
  23.         /* 更新下一轮要解码的数据大小 */2 j1 o7 F0 k; X) I
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)( ]3 r: E( c8 c# ], c6 b
  25.         {# {/ U! k5 P2 |) x; e
  26.             inDataLength = CHUNK_SIZE_IN;: K3 [* s! h4 g: C6 ^, F. Z
  27.         }
    1 s* H% |8 C7 {$ S% Q
  28.         else) v; H9 g, u0 O- {. G. p4 ]0 L- k
  29.         {
    % s# b- f: m& E3 s1 b
  30.             inDataLength = Input_frameSize - Input_frameIndex;
    4 W" |+ P, |  W- U1 T$ x
  31.         }    $ T  k7 W7 E# e8 ]; {) _2 }
  32.     }
    9 l% i* }5 ?0 C: m# C
  33.     else- N& E% |6 v/ S2 x0 J& c
  34.     {, P7 _5 d" i/ g9 ]$ L4 m1 L7 }
  35.         inDataLength = 0;
    $ P0 r* p/ `5 `; d/ m/ F
  36.     }
    0 `' N7 o) F& j

  37. . T2 [' u+ ~+ X
  38.     /* 更新输入缓冲 */
    % `4 g2 K- x( K% z3 R, b, Y
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);    5 r, X% ]* r" Y  W) g' k6 s7 G, v" V
  40. }
复制代码

4 F& B( O( T1 ], y9 A5 q& ]  y  Y( ]5 N) h
57.4.5 函数HAL_JPEG_ConfigOutputBuffer0 P) g0 r7 Z; D, Z8 y' }
函数原型:
9 i7 ]# p/ L2 e/ G$ O2 i
: H3 R6 l9 h5 [
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
    9 I- p. N; D5 j1 [
  2. {  o' k& t+ |. J9 R
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
    6 R) y9 T- o! ~, ^
  4.   hjpeg->OutDataLength = OutDataLength;  
    ; Y' m' j$ n  w' A! H! m
  5. }
复制代码

2 P5 W0 j. @6 j2 L, ?" J' u, ]: V8 ]& c5 _8 j0 P( h7 y2 z7 z" B
函数描述:
# ~+ F8 `1 u! y/ m0 e! q% w/ ~
9 S# O; Q8 U; s1 r9 q8 c0 `此函数用于配置编解码输出缓冲地址和数据大小。
3 n4 R$ x; P/ F) }7 k% I- Y6 s  g+ \" N. E) j
函数参数:# d4 K. f8 n. C( t# w) p( h$ j
# }2 M: c4 Q9 W& O& [
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。0 C- ?0 D6 l- C; t/ Z, }( V
  第2个参数是输出缓冲地址。' I/ d, H5 }( }
  第3个参数是输出缓冲大小,单位字节。
. X! J+ k1 a8 E; H0 ?4 [7 T% @  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。1 K/ U0 v6 x  Q
使用举例:
) L) N) x, @1 M  |% x4 i' x! C! |- P& F7 Q
  1. /*% n" N5 ^0 \9 F# Q1 a, q; k% W  L
  2. *********************************************************************************************************: m& ~+ |" z, l7 ?# v! l1 \
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
    6 ^; d  b" D$ [) S" V
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新
    ) @& f5 r: c2 w! _( Z8 J% j) Z
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针
    " o3 W$ n- {  I  j) |, |1 y8 s/ }
  6. *             pDataOut      输出数据缓冲' |4 r/ q. ?( r) l
  7. *             OutDataLength 输出数据大小,单位字节1 l  a2 r( I$ |$ M3 {! B6 L5 @
  8. *    返 回 值: 无
    5 u8 P* h# W' |5 `8 m+ S
  9. *********************************************************************************************************# d3 E; u5 I9 T/ B0 p  M' h9 x
  10. */
    * {! v/ s0 E" ~6 r  `' @
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)% h! ]# u, d# d( V
  12. {9 |& Q1 r+ ?: J" a; A' M$ {
  13.     /* 更新JPEG输出地址 */  
    0 G: f* ~3 K) c5 J
  14.     FrameBufferAddress += OutDataLength;
    $ G0 A: L, O. O  Y! S3 e4 E9 B

  15. 7 Z1 M( h& F/ [# T3 P
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT); # ~$ _- {4 B" X7 F/ ^
  17. }
复制代码

9 H. _( I. ~' q) ~6 X7 T57.5 总结
" O/ ~# D/ U7 o0 H* T本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。4 Q+ t% B- S) S; z; Z" g

, a% G, n+ O3 H3 x6 D6 q/ \9 b/ A  ]5 Y& f
! m. n  X0 _& N
收藏 评论0 发布时间:2021-12-21 21:46

举报

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