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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示5 O1 a, y3 C, S6 j1 k8 ]
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
# A# L; ]; q; M" h1 v. z3 _  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。$ I; `# }( v3 D# i. D
  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
$ E' L4 l" R1 X1 x: k# y  本章JPEG相关概念的介绍参考了wiki百科和百度百科。
3 t- ^7 k5 s- v0 w4 _$ Z57.2 硬件JPEG基础知识
* l, h0 c1 p9 m
对于STM32H7的硬件JPEG了解到以下几点即可:
# o2 C+ T  T" G  k2 ~
6 n9 g4 y# x# N, M) W  支持JPEG解码和编码。" e# d! i& N5 w3 r. f" K
  对每个像素数据进行编解码只需一个时钟周期。! }$ d! m: p3 V& j+ {; H6 Y. C
  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。; P5 ^1 y1 J7 i7 d6 b' b7 {
  编解码时每图像分量8位深度。
( e! W: ?4 \9 D% M) @9 O5 |
7 [7 H, [! P3 j2 r; ~; H57.2.1 JPEG硬件框图' y; G) `# Q! }* t
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
1 E% |- r7 p! C3 M# _
4 t: T, l- y& M- J" V3 I* L; U
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
$ i3 R  }6 b: ~/ o- J7 b
2 A' |: t4 h+ v* a9 W% l3 d
通过这个框图,我们可以得到如下信息:6 k& k5 s, i4 L7 h# g
3 s  S2 K- N$ E; A  |+ j
  JPEG硬件外设支持编码和解码- i6 n# g3 s7 f
并且对于输入数据和输出数据都有FIFO支持。, Y2 R7 g: M. s( p" x
- X) ]/ M' A5 M
  jpeg_hclk- {* {( K+ @+ m
为JPEG内核和寄存器提供时钟。% X8 z; W6 o* a7 m
- s3 u* G" Q$ a7 o2 K0 h
  jpeg_it
8 Y, s3 x' Z; e8 M( \5 h2 Z6 H/ K2 IJPEG全局中断输出。9 I( N; V  |5 L: U; y5 ?
# B7 w, c: c' F
  jpeg_ift_trg
4 n9 ]* R- ^! FJPEG输入FIFO阈值信号,可触发MDMA。
, d6 S  p$ T. _- s  M4 d& U' j
/ _# H7 Z' E; S; K  jpeg_ifnf_trg
/ b  x  W! y$ U9 cJPEG输入FIFO未满信号,可触发MDMA。& y& e% a6 S( @9 _6 H+ d
* }7 _: |/ ?6 v6 F2 I( s% J
  jpeg_oft_trg
3 g0 M2 [; Q) s5 ]& w6 AJPEG输出FIFO阀值信号,可触发MDMA。
- a4 g+ ~6 W: ~1 k1 L- i% g$ |8 H. n0 W4 N( f$ D
  jpeg_ofne_trg9 \" @! q3 T2 N4 q! B
JPEG输出FIFO非空信号,可触发MDMA。
) J; ]! J7 U% p& G! ?% e% ^3 }# g) N& T( T- p
  jpeg_oec_trg
/ r6 Z: [( k7 O4 P  L9 oJPEG转换结束信号,可触发MDMA。
# d% q7 u2 j2 G
1 G4 [0 k# _5 \% _57.2.2 YCbCr颜色格式! h, r0 L! I: ^% `9 i. i
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下); f% ^) T+ e& Y3 s/ _

7 H" q' l! Q5 h正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。) g7 V% A8 e% T

) J+ j- g! Q: k, n+ z( mYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。3 r8 c6 D4 |$ Y% A

% [  @9 b' Z% h: ^2 X6 r在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
6 E0 I" R+ Z  I5 j2 A8 J* }2 j) x: P1 x: S
57.2.3 YCbCr采样格式
4 y% s4 Y. \! k4 J+ v6 ~YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。
; v/ R0 x' ^  W. i6 S2 u# z9 ?( w  \  O6 a
  4:2:0. _2 a+ {) u+ A
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
) a% _6 m% U, m$ ]- V. y: s; {1 B1 z( I4 {0 F8 `
  4:2:2
5 y) S; G( q# K: V$ U表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
2 f# W9 s# P' ~6 C4 [$ w4 ]& [! B: g4 j6 W: @
  4:4:4
  k% s' O0 M6 R* Q0 x表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。
' P; {: x: `/ \1 J0 L9 Y; T# e, P5 i! }1 H1 m* O- ~5 Q
具体的采样方式如下图所示,以8个像素为一个单元进行采样:- _' }0 f4 S) t7 O" R' r
  e& h& A4 I  Q: |9 R3 \  U3 T: f" A' i
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

" h$ X3 T: z# G0 l& u4 q6 i  ]' h$ o0 {# I: b* J3 N( ?
由上面的截图可以了解到:8 }% p: |! A) X$ @
" l0 }7 ]7 a6 k/ i+ x$ f" n
4:4:4表示Y通道,Cb+Cr通道全部采样。1 D2 S- ~$ ?, d" ~5 b; @9 E
: U- m% T) Z' |
4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。
6 w" O) s5 x4 Y1 \& L! }, ~
1 S' t# l+ i( X4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。
$ @$ L& J- ?" Z/ i  h! S3 C
0 N. p$ L2 L4 G! C$ v3 R下面是整体效果,方便大家更好的理解:' G  H  J& a3 n9 P
0 K2 U; t- q1 N% q' d! l
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

) x8 B$ m  b: k" ?5 ~( @0 J) B6 r" n$ s7 v9 m  M/ T
* p1 s1 C( w) b6 G

# t* @% f9 K; {; J8 S+ V' k57.2.4 YCbCr的优势
5 D/ |* S8 j6 l- @3 x8 pRGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
& a( I0 Z9 w7 M/ Q% ^# L: r& P, m0 v9 {6 v9 N% l4 N, D' l
57.2.5 YCbCr和RGB互转
: m# [, o9 M  U3 v+ ?& h0 p& m
为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。
" ^7 U; ^7 b& A; X6 ~0 d* ~) x, D: s& O
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
* c( h- b0 p) y
/ C/ D* B, j5 n, H& K% y
下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
9 o% c6 l6 N4 J5 J+ F% W
$ I8 V2 U& J9 f$ F7 a9 n6 r1 N% b
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
& W$ R" B, v, N8 N9 V

2 T1 y! _7 ]5 _: I4 D: U! Y8 |57.2.6 JPEG编解码知识, L: Z' t/ j; O5 \5 |  h' s3 d
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)
: i4 ]; ]# r4 S& T( R8 k0 i% G) g3 t% ^% t/ C/ ^" }
57.3 硬件JPEG的HAL库用法
2 S8 C3 B; D+ C6 q' J' k: k2 pJPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
0 a; ^& B- b5 c/ A: S/ m$ `$ p* I' k$ Z3 p" ~
57.3.1 JPEG寄存器结构体JPEG_TypeDef
0 U* l; m5 J0 [* v- E2 w2 y% c2 zJPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
6 c: |) v: Q1 Y! V5 r( _" k
: U) U7 T4 |" P0 x
  1. typedef struct# g) W: q& R$ o+ c
  2. {
    8 u& ?8 a5 {/ ^2 L' U) o
  3.   __IO uint32_t CONFR0;         
    * I. w3 T+ t+ e
  4.   __IO uint32_t CONFR1;          4 |0 t; w; v1 }0 _( D2 z
  5.   __IO uint32_t CONFR2;        2 |( D9 O* y8 x5 i: z, @
  6.   __IO uint32_t CONFR3;        $ h) w4 t/ z- g& m
  7.   __IO uint32_t CONFR4;           X3 ?* Z8 W) q) V* u
  8.   __IO uint32_t CONFR5;      
    - B- G2 E8 o) D0 |- ]
  9.   __IO uint32_t CONFR6;      
    7 e$ E( o5 A+ P$ I
  10.   __IO uint32_t CONFR7;        5 ^5 D3 r9 f9 g: G
  11.   uint32_t  Reserved20[4];      
    + O  b; L* M, v' ~7 s' {  Y
  12.   __IO uint32_t CR;            
    2 z& g, I/ j; J
  13.   __IO uint32_t SR;             - K7 n* s$ Q; u- `! q) \- _  U4 a
  14.   __IO uint32_t CFR;            ; U7 ^3 W+ F! r$ J% k8 G
  15.   uint32_t  Reserved3c;        
    % v( K0 ^& z& F* V5 }4 p+ d
  16.   __IO uint32_t DIR;          ' l8 p! a  Z3 S$ H2 o& h
  17.   __IO uint32_t DOR;            
    " {  }6 s5 H( s2 o2 S+ I
  18.   uint32_t  Reserved48[2];      8 o8 a. |! Q5 z9 P7 V# n0 y
  19.   __IO uint32_t QMEM0[16];     0 q! U3 |1 E9 L% S: h1 s1 ]; p# s
  20.   __IO uint32_t QMEM1[16];       * m3 H- k7 W6 l  X% V' G
  21.   __IO uint32_t QMEM2[16];      : \( a+ K. u9 m, J8 v$ x6 A
  22.   __IO uint32_t QMEM3[16];       7 J9 J( [! y3 K$ p! V" I$ _1 Z
  23.   __IO uint32_t HUFFMIN[16];   
    # n# _- h  j1 z! I# U2 b3 _& J
  24.   __IO uint32_t HUFFBASE[32];   
    $ ~! U. ]9 G2 N: k/ y7 V
  25.   __IO uint32_t HUFFSYMB[84];   
    $ a9 _) A" i- {! ^1 P- x& }1 a
  26.   __IO uint32_t DHTMEM[103];   
    3 Q, G& p, y0 c0 t5 ^6 N+ c1 T
  27.   uint32_t  Reserved4FC;      
    $ M8 L( u5 [5 D9 A! t3 v" r
  28.   __IO uint32_t HUFFENC_AC0[88]; 2 ^1 h( m# ?9 |7 r* O9 ~0 b
  29.   __IO uint32_t HUFFENC_AC1[88];
    + A9 K0 Q" O: q; ]# T3 p" d2 \
  30.   __IO uint32_t HUFFENC_DC0[8];    D. K4 [2 s$ l; I2 o
  31.   __IO uint32_t HUFFENC_DC1[8]; ' o, b  x; @% \
  32. } JPEG_TypeDef;
复制代码

4 b' ^! U! `7 w__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:& M! f2 l) h" a7 l

7 Y4 u/ X1 V3 n& h0 E
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */; h. M: j5 c  o# g) a3 ]/ L6 d
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
  V5 @2 X% r+ U  i% ]4 J
下面我们再看JPEG的定义,在stm32h743xx.h文件。6 V& c& `3 O) j: }6 `
2 d+ G$ R1 V6 O6 S* S9 a2 h
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)8 Q; I* E2 R8 A" x6 l
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)
    1 O0 d! q4 V( u2 c; d
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)5 {; r9 C6 m3 \" h
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码

" p& y' o4 O% Y- {4 z+ O我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。) \( o; J% V8 I% @
1 |, a  O. x3 N. j- T
57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef4 V* s3 y5 J, i' Q
此结构体用于JPEG的编解码参数,具体定义如下:
. N" l5 V8 D. y9 i2 M# a1 B$ O  ^9 X) j
  1. typedef struct4 g+ e3 s) K, _
  2. {
    5 X" y& [+ u% N8 m
  3.   uint8_t  ColorSpace;               - v$ ]# m3 X; q! x
  4.   uint8_t  ChromaSubsampling;        
    ! f9 k5 t6 O" O' b) V1 `
  5.   uint32_t ImageHeight;                }- }8 o+ c% s- T. t
  6.   uint32_t ImageWidth;             ; g6 o" S( C) C+ t" N* k0 u+ @. u8 j8 C
  7.   uint8_t  ImageQuality;               ! [' d& Z3 ^; O; S; ~6 ]
  8. }JPEG_ConfTypeDef;
复制代码

4 M1 H. x: ^0 L/ ~. t下面将这几个参数逐一为大家做个说明:3 j3 ~: f9 c4 `6 k
  uint8_t  ColorSpace
  @5 _9 c) ^# H/ E" |6 P9 x/ A7 b! W) W0 L- o- D
! V* j/ o# s8 B+ V7 c- C1 H
此参数用于设置输出数据流中的量化表,具体支持的参数如下:, D9 I' @: H0 ^5 ^
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/4 {+ x; S- f2 Q5 E) ?- L6 o, _( y
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */
    % [3 _' r* p3 n- k1 ]- P) v
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码
; [: G- B5 T* \. s( U: C
  uint8_t  ChromaSubsampling
9 T# C# ]) W& `- Q2 S) e/ P此参数用于色度子采样,具体支持的参数如下:
8 P) z- a0 S# @9 G& y) d5 u3 Q2 W  @9 y3 c1 F
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    5 w4 _  O  D3 G8 S4 ?6 a% }* w" L
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */5 v8 L( t: w, y
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

1 d$ [& W& \; V, \' t$ P& m  uint32_t  ImageHeight
. p" B3 G+ F3 S; [6 X* }' K3 N5 ?此参数用于图像高度。# Y9 D  V) X0 }( c
6 E& |/ T0 R5 g( A2 `9 ]
  uint32_t ImageWidth4 ~' ?" x5 ], B$ V% [" k0 B: B& r9 u
此参数用于图像宽度。
! F  }5 C* i9 G6 X% S2 Q
2 z6 H6 i! f5 }' J) ^: ?  uint8_t  ImageQuality
+ T# c: P% `% L( X" ]此参数用于图像质量,参数范围1 – 100,1最差,100最好。
2 s4 ?5 l5 x6 S; B6 H0 X- L; U" I; j3 M/ ?) W' S
57.3.3 JPEG结构体句柄JPEG_HandleTypeDef3 h- N7 a. ^7 {0 z% G! N
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:/ a" I9 U- |3 z# K9 n

# x- B* O& r6 j1 Y- y8 @
  1. typedef struct4 x) t* Y( O9 n. d
  2. {% V& n  w1 P/ _$ \* V4 I( H$ D
  3.   JPEG_TypeDef             *Instance;        
    9 j8 N( R5 z+ |( E4 }. o
  4.   JPEG_ConfTypeDef         Conf;             , E( f, O- v8 g
  5.   uint8_t                  *pJpegInBuffPtr; ( X  L7 a* ^9 A9 A9 [" b
  6.   uint8_t                  *pJpegOutBuffPtr; ) F& ?9 E' G2 t
  7.   __IO uint32_t            JpegInCount;      : n8 B; ~$ |9 M" g
  8.   __IO uint32_t            JpegOutCount;     
    7 t9 g1 y% B/ F
  9.   uint32_t                 InDataLength;     
    : M* f# T6 W! \0 Q4 c8 S
  10.   uint32_t                 OutDataLength;     2 H: n( D: H2 x$ ~
  11.   MDMA_HandleTypeDef        *hdmain;         8 Z( {: I4 ^! O: y8 Y" ~7 x
  12.   MDMA_HandleTypeDef        *hdmaout;        " u( C7 `1 @6 _2 O$ [- F8 `
  13.   uint8_t                  CustomQuanTable;
    - \* W6 f6 ]+ [; W+ ?" c# I
  14.   uint8_t                  *QuantTable0;   1 j% r% t4 y* ?2 x( ]* a
  15.   uint8_t                  *QuantTable1;   
    . Y' M4 ]" X5 y! {4 K/ D9 q
  16.   uint8_t                  *QuantTable2;    7 C2 S1 a3 r+ o  f( I2 t8 ^
  17.   uint8_t                  *QuantTable3;         
    % ?" }! S' K$ T6 r( J) r; `2 I
  18.   HAL_LockTypeDef          Lock;            
    2 F/ m' a/ v7 b; F7 }
  19.   __IO  HAL_JPEG_STATETypeDef State;         2 @* t: K( {0 {# `: {5 B- ^8 A; V
  20.   __IO  uint32_t           ErrorCode;      
    ' |- A+ S. Q# I8 K
  21.   __IO uint32_t Context;                    8 e0 w5 f, x* w2 G8 D# V$ w
  22. }JPEG_HandleTypeDef;
复制代码
& K6 Y6 X3 i: R5 A5 R1 o; Y
下面将这几个参数逐一做个说明。
4 u1 v% E/ b  b5 G" v8 w+ ]' ~, W; z
  JPEG_TypeDef   *Instance$ Y$ C0 p" s0 v2 X# y+ E" [
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
# e. ^( H/ z: W2 N3 H) ?( k) q3 T! @) f7 L$ m6 I
  JPEG_ConfTypeDef   Conf
" N; T) p* B4 `5 `  _% p. J这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。0 h- e7 Z0 B* c

  s3 s/ ?9 @4 t) X7 O- _  uint8_t       *pJpegInBuffPtr4 L! P5 X0 C5 I0 q
JPEG编解码输入缓冲地址" Z, {' l- Q( l) w
% D/ R4 A8 f3 J8 Q* R
  uint8_t       *pJpegOutBuffPtr
8 a9 |/ L7 x7 o( r) ^+ }' iJPEG编解码输出缓冲地址( W+ J% {4 B8 C' d; N0 B
0 t: m% j* Z7 T0 ]$ Z* @6 v
  __IO uint32_t   JpegInCount5 |" }7 E; l, q
JPEG内部输入计数。, X  i# i7 D/ F6 O

( A# r% K- B, ^  Y! m  __IO uint32_t   JpegOutCount! T) |6 ^: A/ D7 c' u- c% L
JPEG内部输出计数。
) R  s5 Q$ D) |' m. e$ L* N" X4 V4 V% d/ \9 I
  uint32_t        InDataLength& K8 z/ E8 [( X
JPEG输入缓冲区长度,单位字节" k! r5 p4 e& |9 g9 G

6 {8 V% Y! N/ m* j" z) B: m  uint32_t          OutDataLength8 u8 g! I+ R: T- q) d! N
JPEG输出缓冲区长度,单位字节。
  g5 ^4 b) D( I! u' U/ a- N
( J! [7 ]$ W) w2 ~2 j" K  MDMA_HandleTypeDef        *hdmain
2 _8 M( }9 {2 e* _4 P  T+ X, G5 t  MDMA_HandleTypeDef        *hdmaout6 R. R* u6 q. C, v
MDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
" v+ e1 Y2 K4 ~3 ]' m7 V5 I
4 B+ R: a$ r8 B  o+ ^  uint8_t       CustomQuanTable) j" l! a8 |1 S% b+ Z
如果此参数设置为1,将使用用户设置的量化表。, F, @+ P! S$ b0 A% @$ e
& H& e$ O4 P+ D1 N8 ?9 U% p  s9 ]. ]1 D
  uint8_t      *QuantTable0;   4 k' @* y, T; E  v
  uint8_t      *QuantTable1;     ! J5 U( }2 {2 l# P0 z. L
  uint8_t      *QuantTable2;   
, U4 \# W5 o4 l! p. h1 H5 X: x# m  uint8_t      *QuantTable3;; ~9 T% a4 A7 w/ P/ _
指定量化表地址。    % t, B4 y, x( G0 ?
" h% O2 J, R" @5 n
  HAL_LockTypeDef          Lock           
/ p# i; ?, K3 R  __IO  HAL_JPEG_STATETypeDef State           & J  C) \( M, c
  __IO  uint32_t           ErrorCode      
2 q' }) t* C0 N这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。1 _+ d* w  c# a3 R: z3 W, q4 F

1 u) r% E  i. a6 F  S9 ~  __IO uint32_t Context
* ^4 z) a3 a3 B! B" M$ r7 |, W5 qJPEG上下文。
* Y: H& R" k* [: H/ I: r0 O) h; h  @1 y* y$ j. B0 N
57.3.4 JPEG初始化流程总结) ]) a1 m; N& C0 S, Q
使用方法由HAL库提供:# j; K' Z/ f) w" D  W

$ u+ w+ q, U( l9 z1 f; ^  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。
# U+ T! r3 G) d8 D) U! ~8 |6 \4 s( k. Y
如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、
, m. ?' S# ~' \1 O3 k% e6 D* P( Y, g1 P' Y) h9 ~% [
  第2步:调用编解码函数$ R  h( N2 f/ c1 l
  \5 G+ G5 t2 |# V% i
  查询式编解码函数$ H  a, g) M0 Q* f9 k1 J$ r
HAL_JPEG_Encode  D  _6 s0 S$ @) Z0 k) J

3 z) R0 [$ a2 G6 e" \HAL_JPEG_Decode  y% L6 T" x* A% R% p% J

1 {; I* [# J" i# j& ~  ~: C
/ P6 s2 _/ o6 _) }, m/ R- ]9 Z$ _( T# A# }
  中断方式
- h1 ]) f- O& ^5 ]2 q! T" e8 l1 MHAL_JPEG_Encode_IT
2 {; U* E4 z1 y; C% C5 r
1 `& \; Y6 t9 h1 M- g5 J) i- kHAL_JPEG_Decode_IT8 t! N2 L! M  ?4 v9 G: G

. T( {2 r$ \$ d2 n, F; B
) m1 r+ U/ |4 l, ]: B9 b: X% i/ F$ D" J9 J/ ~6 T: h5 c" A& U. @
  DMA方式
$ v$ [0 c$ Q& S+ b0 Q  wHAL_JPEG_Encode_DMA
6 t2 G& b& v  [9 u: D4 I8 f
2 Q7 X# x) z4 b3 O2 X2 PHAL_JPEG_Decode_DMA
" o6 w/ Q( Y' p+ I
' U" S3 i* ?% X0 ]1 y; R) a  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback
3 A  U9 `$ I3 ]4 ?: n8 _
, c- L, O7 |- F(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。: J: e6 k' B. ~8 ?' b/ v% A1 @

1 q' K" Q6 Q  h/ A8 x如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
# M+ f& `  s; o" [# R0 R7 g7 u9 Z* c# U* ?6 A$ l1 ~" u

* d1 o" O5 i$ Z& C) @(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。4 r1 l+ e2 K3 n! W9 S' X
# Y. V, z# q8 s) n

6 b! V4 J1 _4 E0 V% m( s8 W# X(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。
7 r& @/ O* ?9 |6 C; k/ f5 ?
9 r! o  ?9 g: r
$ x/ _; M4 R4 f  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback$ ]* x+ K' j7 s; Y8 V" b: R+ \

4 R4 s* G- K, t, u1 L(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。" _- f/ R" p' a$ l3 t4 f2 y- a
# @2 j7 P' s  o1 u
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。# i0 a5 E5 E0 J; P) C

5 d9 n0 ?% Q- Q% D(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。$ L$ z& H% f% g" Y7 k

( e- m6 @" l9 J' h1 ]% r
/ s, ^( V2 M/ L" E  第6步:其它相关函数
) p/ A& }/ W/ s
* J) ?4 X' v1 u; U' z+ x& v  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。
5 V# `, l4 t0 d0 o  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。. R7 X& i' l- M. I7 ]
  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。
6 {2 I  H& o3 s  M; X" n2 D* ]3 d  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
  R0 A- G# s8 Y3 T/ r+ j  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
# _, M* {6 L. h2 s) W2 @2 U  通过函数HAL_JPEG_GetState可以获取JPEG状态。4 C5 P% G+ f7 T

! t" o+ L0 ], k  N# _
* i1 P8 p' ]" ~57.4 源文件stm32h7xx_hal_jpeg.c
0 B9 o' a7 k# a; X  J8 D2 G4 h* j这里把我们把如下几个常用到的函数做个说明:
( T( l8 O1 a2 D2 z# n, p% w( _% q" D
  HAL_JPEG_Init/ r) ?& K: d) d
  HAL_JPEG_GetInfo" i+ G: M% _+ A0 M3 @
  HAL_JPEG_Decode_DMA* f! ]$ n3 Z' `/ H
  HAL_JPEG_ConfigInputBuffer
6 r* i" {6 I4 `: C/ q  HAL_JPEG_ConfigOutputBuffer
; ?" R* d. r" d2 W1 s1 A& X
( U  o9 @8 z# U# T1 @' O7 ^4 x57.4.1 函数HAL_JPEG_Init* v+ w+ ]9 T/ h' K8 M
函数原型:
8 f1 F* U2 X& x2 q/ J& a; p
9 ^6 R2 c$ s1 p5 g" C' F
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)0 }8 d9 E. b- |
  2. {1 f/ @) K' d! B; p2 M, ~
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);
    , B1 I# G& H$ u
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);0 w8 Z. @$ g- }% b9 ^0 q
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);9 x5 `) q: T1 H7 G. g
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);
    8 ?) y3 |% @9 w  W4 Q: t

  7. ! u7 Y5 w" S# A1 B: \
  8.   /* 检测句柄是否有效 */
      U5 U, P0 ~% v; q2 o* M
  9.   if(hjpeg == NULL)" V" }  i3 n8 ~" h1 y
  10.   {
    3 A3 B* L3 O$ C  `9 j# n' ^% O
  11.     return HAL_ERROR;, I% e! d. r! |# h' ?# ~0 q2 P  z
  12.   }
    / O  U+ t% ^7 s2 D/ _: s
  13. - Z  O' I1 v4 t! q3 g
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
    ) R. ^! G( k2 z% G6 q9 D' h+ p; p0 }4 L4 r
  15.   {2 \: \9 B' n( p" p0 ?( z1 [! a
  16.     hjpeg->Lock = HAL_UNLOCKED;
    9 w5 J- H3 }; H6 q: `$ Z" B

  17. 4 _2 F5 X: T; L0 U7 i4 {! |. o
  18.      /* 初始化GPIO,NVIC等 */: s- Q' E7 Z: P- U1 d6 o
  19.     HAL_JPEG_MspInit(hjpeg);
    / A, k( Y; C9 {1 L0 q! U
  20.   }) o0 i0 ~5 j, A2 }3 ~  o4 V7 W5 c
  21. 2 q% i' [- f4 g( X6 S
  22.   /* 设置JPEG状态 */, Z# L8 |2 ^- D. `$ d
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;% K# z( [# a% `- ~& K
  24. # M8 O$ J0 M1 t. M; C/ K
  25.   /* 使能JPEG  */7 ^* K% O' y& B+ i$ S
  26.   __HAL_JPEG_ENABLE(hjpeg);
    5 r* n7 C, B/ y
  27. 3 a# V  n: M: M2 I* D+ P6 \
  28.   /* 关闭JPEG编解码处理 */' g) j/ u1 Y" ?. @( z
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;7 g& Q2 k4 G/ w6 u1 N

  30. / C' c) I5 n4 K
  31.   /* 关闭JPEG所有中断 */
    ) [8 k5 J% W3 z8 `& }5 P
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    / Q5 v4 g! _! v9 P- V# _
  33. * X( m  l/ \7 y9 {
  34.   /* 清空输入输入FIFO缓冲 */# d& w1 A: K- D0 f
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;0 f4 ]4 i$ W' {
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
      E7 p* O0 L/ G4 t

  37. / |/ o5 K' i; m* g, A) B" d
  38.   /* 清除所有标志 *// N5 u; M. O. p8 x3 b+ ~8 N; `
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);
    0 K, i7 v* D1 P' |5 q8 r! r
  40. 3 j8 f# ~7 R% O! B( Q+ m% ?- w
  41.   /* 初始化默认的量化表 */2 A# x1 K  R  m  @3 f7 S0 _) C
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);5 P$ T# e% |+ c. k
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);, [# r) U! z5 M) X9 _5 Z. X1 L
  44.   hjpeg->QuantTable2 = NULL;; D5 v0 |4 K. G1 e; }
  45.   hjpeg->QuantTable3 = NULL;
    1 {2 T2 l* ^+ t( [: @

  46. 6 e' O' O) w  ~& }8 }
  47.   /* 初始化默认的霍夫曼表 */
    , O% m4 N( p1 [$ u2 U
  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)$ i) G- K# h# L% ~
  49.   {
    - y$ a# k; h5 C2 T% Y
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
    6 H: O- ^  G0 I/ R2 @' M' E, g
  51. 7 P( z& _5 v) ~% j8 ^% F
  52.     return HAL_ERROR;
    7 M0 \$ N+ Z% H+ T
  53.   }$ J: ^) T7 ^% E( k3 h6 z

  54. " a4 G! F( m8 K0 V9 w  Y
  55.   /* 使能文件头处理 */. K% T, u( |8 E7 S0 ~/ M0 w
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;
    $ b. }+ J0 d' ?: B+ W/ R
  57. $ |4 j& a8 t! u0 t
  58.   /* 复位JPEG输入输出计数 */
    2 u. C( {- z9 a# ^  `
  59.   hjpeg->JpegInCount = 0;6 W$ I7 S) R, ?+ S3 N
  60.   hjpeg->JpegOutCount = 0;; [& o* w& |$ M9 P  ~

  61. ) X: @! x  `6 S3 ?" y% j' ^* w' e
  62.   /* 设置JPEG就绪 */
    $ m4 u" n" S1 `) V! ~* P
  63.   hjpeg->State = HAL_JPEG_STATE_READY;
    % l8 S; I6 ?; I. u
  64. 0 \2 D2 U8 U/ `" E2 ^+ J9 j* P
  65.   /* 设置无错误 Reset the JPEG ErrorCode */2 L) |: B3 a5 f- _
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;
    0 \  U2 @; o) e# c

  67. ( l' d3 a+ {8 r: k7 z' @
  68.   /* 清除上下文 */1 k$ J, B$ ~$ l1 y7 [; v
  69.   hjpeg->Context = 0;
    $ D$ J8 h0 M* C# u% G

  70. 1 ?0 u0 f' d# ]/ ^. K5 X! ~* A! e
  71.   /* 返回HAL_OK */- n' x$ \2 |) B8 }
  72.   return HAL_OK;
    3 ^4 P+ F1 r( t$ t( ?
  73. }
    - X8 Y/ L4 y. k  q' Q% b4 @

  74. % w8 [2 S2 X9 ?+ D. G: O( Q8 I. ]
复制代码

- v1 f# t" m- K. J9 C函数描述:7 L9 ]  {- s. |1 n9 Y6 g

' o7 q" ^% v& N, W4 y5 U, _' v此函数用于初始化JPEG。
/ ~$ b6 x) P+ F  |8 Y
2 F0 o% Q! I  N$ _: ~函数参数:
+ X. S/ j% g3 H' k" x! Z  T- `/ p8 l
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
+ e- ]% r9 E! A1 p# N8 s4 C  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
! g2 S- H$ T2 R2 m6 I5 m: Y注意事项:
6 U  X3 B' u: }, d
2 \: u, J: l! A; Z函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
3 R9 m" B( v1 W1 |2 W5 f  x; t7 A如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。/ E* c6 Z0 y6 }/ Z8 @6 C
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。
  ?* \+ X  \/ F8 Y* I3 ?% r; k
( B! Q1 h: E1 _- p* s7 y解决办法有三
1 k# m  i0 I+ H) w# u- {
, L$ u$ X' p- d% ?方法1:用户自己初始JPEG底层。& |. d' G* a8 m% j7 `
6 y+ c% I$ _* `' B: ~) w6 v/ H
方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。
1 T$ Z$ ]1 f$ }1 o. |, s
& R6 s5 u- v6 N2 W方法3:下面的方法
- c  N% D( L8 o4 e
% n# \! \. G4 z% c6 n% Q
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
    4 h! [* B0 e: D/ K0 u# ^: h, |
  2. {5 l! R/ {, H) _% q$ f! V$ L3 d4 U
  3.     Error_Handler();
    0 p( b. D6 ]% d/ {7 U
  4. }  
    1 k# m% e+ S4 f* W/ a
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    ( u! y+ f* r! n. y
  6. {  i: z# T2 l  A( f
  7.     Error_Handler();+ h8 e, d/ {* u
  8. }
复制代码

' C0 _6 m! n, s" f5 G使用举例:
) z$ ~+ ~9 P. _2 ^  Z- l5 J3 b
  1. JPEG_HandleTypeDef    JPEG_Handle;* I+ {/ V  U3 D* f2 o8 n. d
  2. JPEG_Handle.Instance = JPEG;
    ( b! ?  `! d0 r+ W) ?, m8 F/ Q
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

8 [, S& N* y" G3 Y57.4.2 函数HAL_JPEG_GetInfo1 n2 a0 `/ [, q+ h
函数原型:: _4 m& v. Y* J7 a, `7 V5 C/ O
( ]; q2 ~; o4 W! x
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)# H; o) R8 ?/ x' g
  2. {* r9 R6 ^' c# M* x/ G
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    4 ~! C4 ?( i) s, W

  4. 0 {, n( z; U6 t: b. I
  5.   /* 检测句柄是否有效 */. p# W2 }) Z9 _+ W; ], c
  6.   if((hjpeg == NULL) || (pInfo == NULL))9 f* m% {7 {+ n$ _( T
  7.   {
    1 A7 A1 {6 w3 ^- N
  8.     return HAL_ERROR;
    / b) e. C+ a8 g3 Z9 b. y: V% A5 I
  9.   }
    " o, h# D$ }2 n. x$ U/ F

  10. 8 T: ~6 `3 H: j, W: H
  11.   /* 读取配置参数 */9 |' _, J5 D) U
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)4 y+ y5 J2 P( U4 [. C! s0 x
  13.   {
    $ \$ v5 q9 \. g6 k
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;    ' E, q7 p7 Y+ H, r/ A# k2 i
  15.   }   
    4 L/ G1 O7 A: a2 E7 D9 k0 a& z8 i
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
    / c& K# ^$ c/ X8 Z6 U6 W5 ?7 j
  17.   {$ ~+ {1 {; u. n1 e& R& `! ?5 `; l* A
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;! r) P8 h" W) X  v3 U# j- ]9 `( t
  19.   }6 ~$ j' j! f5 h
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
    0 e  q- L$ g  \/ ?0 S% f; b
  21.   {, u& \: L) Y( }6 P6 c9 N; b3 J
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
    ! e+ r2 E* b7 m3 @% b* f- H" g
  23.   }3 k/ Y$ F" w. P/ h" ]3 \$ N8 w
  24. 1 t7 R" e  Z- i# d, [
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;+ f1 E' e7 O% O3 L: r" d
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;4 ~9 j6 e: S( J. t

  27. " ^. L9 ?/ r" c4 e
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
    " G/ b" q4 Q5 O, N
  29.   {
    2 z( S. ]" A3 v& }; m& h
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
    2 L8 }# `4 u3 R  g
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;$ c6 v7 M! R2 Z* z
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
    5 u( \% n" F$ Q

  33. ; T) R" L8 w* u+ K# }
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
    2 N* y# p! x: B0 J1 d
  35.     {
    ( ^  g' M+ J5 ]( K
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/( {5 i) d* z/ ?; s3 `
  37.     }9 O5 n% i; G) E
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
    . {! p) r" [# H2 n) j/ g( Q- {: k6 w
  39.     {
    4 d$ `+ ?% ]" L) I, m8 `
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;( A# Z: R, B  ]+ K1 C# Y& m7 c
  41.     }4 u* c/ y* p% W% e; q
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0)). b# H, c! m3 n: \3 p' W6 B
  43.     {8 g  |" ]. Q. D" [0 r8 v& ?; w* D: n+ _
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;7 i* C& b# @+ t( S  ~% i3 q
  45.     }
    + l" ^! e) |: o! B" m6 U3 _
  46.     else /* 默认是 4:4:4*/) J: ?4 |3 x5 T. i
  47.     {+ @4 s& h  g; {* M
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;3 A$ `& t# O& F, \. J# S1 v
  49.     } ! j1 n/ q9 R& b* w/ Y
  50.   }
    ' u' E9 \" n/ X& v" f& E1 Z
  51.   else 3 O9 J& |9 J# g$ `) c
  52.   {0 |, K2 D0 V  X! m. ]
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    3 U) {3 A4 i: L/ l1 l
  54.   }' F- g( r7 ~0 A6 l& T: `' [" U$ d
  55. 1 \- d. l/ m8 r# Q/ M2 K
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
    . d/ C2 Q/ i- M; v% g- c
  57. & [! ~4 W: Z: Z+ `
  58.   /* 返回HAL_OK */& ^7 y2 q! X) Y) Y2 v7 Q" P8 b, ]
  59.   return HAL_OK;7 v7 W2 ]/ ]. G
  60. }9 V+ b9 f- I9 g3 a7 Z
复制代码
8 M' O6 p7 H' Q+ E9 R0 M+ O/ ^
函数描述:# t: k( W) F3 h
% A1 E/ s0 h8 u' R4 H
此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。: f$ C! H: s& L/ B4 P. |

& f: j& d; @5 W3 I  M' U1 C% h# F函数参数:
# y5 C5 Q6 \/ I" @) f
) Z% C, Y0 U& a( T  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。3 u0 w) O+ p: Q; P" J1 H# Q# _
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小$ ~. i) J% O; Z! w& x/ V
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。2 g; U" S5 o) w1 N
- _+ S+ r- |4 u. ^3 c& x% U1 D

" [+ x5 @# |% w! l8 \8 I使用举例:, `  Z  u, u+ F4 A- A0 d$ I; ?
  1. JPEG_HandleTypeDef    JPEG_Handle;
    % w  l6 r9 w% ]9 |, J- t
  2. JPEG_ConfTypeDef      JPEG_Info;
    , f0 M3 a0 T+ @8 M

  3. : O- Z  [* e5 G4 F
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码
- W5 }+ C2 y, c" s/ J" `$ g
57.4.3 函数HAL_JPEG_Decode_DMA
* }9 K1 N9 }, P4 |* k1 u% R- ^函数原型:2 c- T4 M9 W0 h0 l% ^1 e

' Z- B4 {& F+ ]: l% I
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)
    2 v& ], y' G% j; Y: x0 X
  2. {! [  p3 k' }) y. Z
  3.   /* 检测参数 */
      U6 e, h+ j# x- ^8 D, O
  4.   assert_param((InDataLength >= 4));  H) \" `, D* E  I; K9 n" n
  5.   assert_param((OutDataLength >= 4));0 D) X& m0 u* \% L; ?
  6. 6 J: M! O5 T: E9 T
  7.   /* 检测参数 */1 Z- o6 s: M5 o! x2 h! W' V- A6 _1 E
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
    & N3 t' p, X  g3 C6 I9 i: W
  9.   {$ b, i" q# e; d- x" \0 h* I  T
  10.     return HAL_ERROR;  g! ]2 U. X) f$ p, J( X- r$ {, x
  11.   }
    1 m9 J4 V  T! x: a
  12. 4 Y* t6 }8 O) h& _$ e$ C# c
  13.   /* 上锁 */
    0 L" d9 P" A  E* O, o7 @( I; O
  14.   __HAL_LOCK(hjpeg);; ?+ a4 C" |: F9 f  g2 \

  15. ( P9 L! y4 s. b
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    ( C) N( T/ G( U$ Y$ ?+ \9 T7 a
  17.   {
      P/ X, `2 X, V$ d
  18.     /* 设置JPEG忙 */+ x# ]) }/ V  c6 u* m3 i7 f2 `% _
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;8 Z) P) }8 v, z$ }3 S& e0 O8 t+ `

  20. 9 N- R# z0 [% C$ D. y
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */& ~) x& t- A- F. ]
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    # c* ^" F% o2 h1 x- w
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    # O% J5 X0 A- J+ e& S

  24. ' N' C/ \4 J! L3 C% L9 W' t( c; g5 C: K; M7 B
  25.     /* 设置输入输出缓冲地址和大小 */
    % I: M- Y9 p5 @7 W* u1 s" B
  26.     hjpeg->pJpegInBuffPtr = pDataIn;% k# Z% N5 |) _- j
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    5 t4 }5 r5 Q0 N  W
  28.     hjpeg->InDataLength = InDataLength;
    ' M8 W' {$ k* @( x
  29.     hjpeg->OutDataLength = OutDataLength;
    6 L; _1 T( o4 l7 O

  30. % _) a: W2 _" t, u+ L6 H! L. `
  31.     /* 复位输入输出缓冲计数 */: @, B& c, l7 \3 q& u0 ^  j
  32.     hjpeg->JpegInCount = 0;   
    ( ]0 y  @( y& a+ b1 ?/ C8 A! k% R
  33.     hjpeg->JpegOutCount = 0;    ' N1 m7 f; N5 {2 R! C& H

  34. 8 \4 ?' f6 i) o. i
  35.     /* 初始化解码处理 */( g1 t8 b  }1 K0 x
  36.     JPEG_Init_Process(hjpeg);" Y6 j9 g7 x& x: U* `

  37. 7 X  c4 K# U& }$ p; w
  38.     /* 启动JPEG解码处理,使用DMA方式 */
    $ _. j7 j  C# }0 p8 I
  39.     JPEG_DMA_StartProcess(hjpeg);
    * N. @+ X" k; H; `9 M% ~
  40. ' P5 o& P4 B6 p* C# u5 w+ P' F* h
  41.   }
    6 K8 F( |6 X) f0 r% r( a
  42.   else
    " J! A4 N  }' z: a, E5 H& W6 [% v: A
  43.   {
    2 D/ e) b: z% E) [  n7 ^
  44.     /* 解锁 */
    ) D% @/ U8 L( n0 t* k& z
  45.     __HAL_UNLOCK(hjpeg);2 j8 F- K, C6 ^) J. i% R, ]

  46. ( G, c! I) g. X+ {$ @
  47.     return HAL_BUSY;
    7 w% Z) G5 T3 c  m. H/ o
  48.   }
    ( \5 p/ {* ?: g# V" r" P9 [. n: B
  49. $ p: t( i0 G0 G! Y0 n  T2 q2 q( s
  50.   /* 返回HAL_OK */$ z9 v7 D9 A& W8 D  ^+ S
  51.   return HAL_OK;# W$ _% [* ]- h
  52. }4 ^0 e/ p( b/ ^
复制代码
1 i) Z) d0 F! k8 B
  |! l2 E8 v, g% F5 A
函数描述:6 y' X+ p' X7 ~7 m3 |% ^- z- c

8 ]6 T1 b* A$ I1 h  ~1 u! c, k此函数用于启动JPEG的DMA方式解码。4 q; c, j5 [6 T
7 G: F. Y* e% M; |2 Y. z- V0 g
函数参数:6 }! ?$ @9 K5 z, i

1 b/ L, z. _6 j  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。' w- R0 B9 ?. x2 L! P
  第2个参数是输入数据缓冲地址。
" j! Q: S9 m0 t% K  第3个参数输入数据大小,单位字节。
0 K' w# H' Q( V  第4个参数是输出缓冲地址。2 P6 Q" f$ N# _" t0 G( J* W" u
  第5个参数是输出缓冲大小,单位字节。
. Y$ A6 S, f; Q7 f" R# p  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
- {3 X# w1 P2 W, h% c# f% m" d, v" q; ^/ C4 M
使用举例:% H* Y: {& i) |/ b! m. U# Z& A4 K
0 [' ]1 z! {/ e9 V  q
  1. /*; m/ ]) }! {) R0 I9 E, x0 L) Y  L
  2. *********************************************************************************************************
    0 u9 r* \4 K* W6 y: L
  3. *    函 数 名: JPEG_Decode_DMA6 }7 v$ [7 p  r- C
  4. *    功能说明: JPEG解码& t8 R# l6 s8 u  x' n7 p
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    8 E5 V6 A2 Q. d9 d
  6. *             FrameSourceAddress  数据地址
    ( H! V( A0 ]1 G; R; N6 L) g" a+ V2 c
  7. *             FrameSize           数据大小
    % g) ?* ~' z5 e1 `1 {( r. ~& q7 Y7 I
  8. *             DestAddress         目的数据地址; q( A% x. y5 p' H5 L
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功0 M4 A0 Y6 g) N% |4 E
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    2 D; B9 E& P* n+ E% j/ E
  11. *********************************************************************************************************
    3 |. t1 J3 _1 c. u: j* d* O
  12. */5 o  x( {+ P  |- ?* q% m+ v2 ?
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)
    7 U9 _( N, ]8 o& F* ]$ ^$ b0 r
  14. {
    $ R3 |# o5 N5 O! v& t  j" G; q
  15.     JPEGSourceAddress =  FrameSourceAddress ;
    6 s7 r8 R4 w9 y- J
  16.     FrameBufferAddress = DestAddress;( I. n" K; z, @0 t# L( X
  17.     Input_frameIndex = 0;/ t4 P4 m, K! |3 {9 v( S" T
  18.     Input_frameSize = FrameSize;) _/ g0 [- o8 U1 y3 m/ x8 W

  19. % ^3 t% U/ ]9 u) w& x
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */
    . f1 J% _: p$ k( I) U
  21.     Jpeg_HWDecodingEnd = 0;
    - A( y" }2 H7 f6 T6 ]8 X  v. u+ }+ v
  22. 3 |$ i  T( K7 S
  23.     /* 启动JPEG解码 */# F- s0 q; a! H4 N4 J
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,; L* q4 T2 C% k' l" R. x
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
    2 W" `0 v+ F  l& k5 u
  26. * {- }7 `% C5 W
  27.     return HAL_OK;, n1 }( w/ g6 ?6 V
  28. }
复制代码
9 a$ ?+ G- i% d4 V$ w: B
57.4.4 函数HAL_JPEG_ConfigInputBuffer
' p& y" y( T2 _% T" s/ S9 p  i- l函数原型:4 a) j% ?& B: j, N/ G

! U6 c6 [% y! ^8 T
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)' N% p! b8 h1 Z2 R; S  o9 V
  2. {: H- Y0 j7 k; {! z9 u1 _# M6 ^
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;
    7 K$ M! ]3 P: l9 X# v8 \
  4.   hjpeg->InDataLength = InDataLength;
    & Z% v7 J1 J0 F( o: K" _* Y# P
  5. }
复制代码

8 e" V: P. q. `2 X* d函数描述:. a2 p, F( x  B0 [9 W2 D" H+ o

- u3 F9 t, ]' `1 S此函数用于配置编解码输入缓冲地址和数据大小。
6 G/ v  {5 _! [- m8 F
: r; O# T+ u, O2 o; D函数参数:
) \$ L5 v6 g! K9 J
6 M( @/ A/ j! W5 Z# c; }- b" ?  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
% x' K( \1 j' r: C2 w  第2个参数是输入缓冲地址。
5 Q& ?" z2 V4 {. o8 q% A& O  第3个参数是输入缓冲大小,单位字节。4 v7 F1 n3 `* _
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
% o% x+ s$ A3 B! Q; H$ m9 v. e使用举例:
, n+ P( {6 b: Q: N# f+ @1 u" P. X
/ D- q( V$ S3 F& P
  1. /*3 R2 \9 @" M' D& W9 d1 @2 i: n8 \# L$ W
  2. *********************************************************************************************************
    / N; M/ d. p! x$ Q  Q& a; e
  3. *    函 数 名: HAL_JPEG_GetDataCallback
    5 o# l. q" ]6 J" M! i3 m. @/ C
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    & P3 x! W0 X+ g
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针; q7 v( G2 m' h* S# B& S. j* p
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  ) h1 C; ]3 q3 x4 ~( K! ]8 m4 o
  7. *    返 回 值: 无; ~+ Z' p& V- D' ]3 ^2 \5 M/ a0 Z
  8. *********************************************************************************************************1 y- e+ |: A+ U0 P: w
  9. */8 ^) _' K5 N6 z! d4 H, A
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)+ O; ?+ {7 V/ E' m
  11. {# U) ^' F. J! e6 _. ^. T
  12.     uint32_t inDataLength;
    : x$ Q% \! J+ [
  13. 9 R- M3 x  W: A/ e1 w! p+ ]. a
  14.     /* 更新已经解码的数据大小 */
    3 ~0 a( i! ~1 A! O2 ^# H- S* E2 T* S  a
  15.     Input_frameIndex += NbDecodedData;
    5 R& i- |4 C% O  s0 o9 t

  16. ' Z0 R* p* ^/ M3 a0 `/ Y
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
    $ o; E  `" S3 C  _9 K
  18.     if( Input_frameIndex < Input_frameSize)% x/ @7 L: M' q1 o0 e
  19.     {" k7 U7 @- G( \3 v4 p- e
  20.         /* 更新解码数据位置 */
    8 t4 W& ~' w5 @6 G
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;# J5 [: r$ e  g$ G7 D

  22. - ]$ \  L* A9 Q5 _  S2 F" y8 F3 Y
  23.         /* 更新下一轮要解码的数据大小 */6 _6 y$ @6 a$ I, w2 `
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN); Q( l$ F* C9 N# R2 g0 c- R
  25.         {
    9 u+ ?, v3 K3 F; f
  26.             inDataLength = CHUNK_SIZE_IN;
    + J5 g9 K1 m0 Y
  27.         }
    " {5 s+ q* j+ |( |, z1 q& W/ d' Q: G
  28.         else
    / h! P- c' l) U7 f3 i* }
  29.         {
    3 U6 R# Z6 }! F, r: i+ u
  30.             inDataLength = Input_frameSize - Input_frameIndex;
    , p; V# x4 c7 u- M
  31.         }   
    " F4 R/ ]1 j  ^; v
  32.     }
    - k) s7 ~2 u; ^; v4 j* Z3 I: M  ?
  33.     else3 L+ G3 b6 [% J  m# X
  34.     {" K( d1 X, ^  O' m
  35.         inDataLength = 0; " e2 _) t0 D, ?- @0 C+ _4 C( j
  36.     }
    ' f# q5 [" ^/ H0 b( {' p
  37. $ _  W# ^7 B' N' J: `2 ~! z
  38.     /* 更新输入缓冲 */% \0 N+ m9 I8 s9 x) B
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);   
    # s# i; Z# A9 s5 ^0 n
  40. }
复制代码

% g7 s8 g4 p" t! P) g
' j9 @+ S( `8 h8 J+ M3 z57.4.5 函数HAL_JPEG_ConfigOutputBuffer4 t0 M' o# m- x8 L
函数原型:: J3 I6 y7 O+ r. x, q( s" b( Q! ^

/ ~  z9 o. r+ A- P2 [5 h  M  z
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)" H, c) h" W: i0 ^8 F$ V
  2. {
    9 b0 x4 G0 s8 N1 o
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
    * Q/ }8 A5 w* q, P( U" @
  4.   hjpeg->OutDataLength = OutDataLength;  
    ; f' x3 Z0 ]% B4 j3 }
  5. }
复制代码

# p" s: [% C5 O, J1 e% `* U# e, M0 j9 ]. t9 Q& K3 F- }
函数描述:% ]5 A! E* p4 N) E+ N/ `
/ A; Y1 v, J% U3 W6 `/ k' o
此函数用于配置编解码输出缓冲地址和数据大小。+ b/ L0 Q1 ~! ~' _. R

0 t% B  b5 n1 v1 W5 X函数参数:& N) Z2 R6 Q6 c# e
$ ?  z! x3 G4 m3 z( K
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。" |1 c! h8 _% X- k1 d! I" y0 Z' E
  第2个参数是输出缓冲地址。) t& h/ a6 S/ O
  第3个参数是输出缓冲大小,单位字节。' B4 \( I) j' I; X$ ?) d" l: m
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
! N# b: i7 ?5 Z& p  U8 ~使用举例:4 R; k8 P( h( |

# x; j, S$ |1 Y3 G9 \, n5 k* ~
  1. /*6 A/ e( r. A6 o8 V: y
  2. *********************************************************************************************************
    8 E# A4 y5 Q3 m$ i2 N# c
  3. *    函 数 名: HAL_JPEG_DataReadyCallback  }; [# V6 i' @
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新0 A3 U% ?3 |$ f$ Q
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针7 Z2 R& X2 P$ ^2 T% t& G6 E$ u
  6. *             pDataOut      输出数据缓冲
    ) ~5 m/ s+ X/ s2 X9 `
  7. *             OutDataLength 输出数据大小,单位字节
    * \% \' P3 O' M2 o0 n8 w
  8. *    返 回 值: 无& v+ M% p6 i' [9 i, d4 V# Q3 c
  9. *********************************************************************************************************
      O/ j* t. I# A3 g0 t: u
  10. */, u1 H7 k6 m. h9 I3 P2 Y
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)5 `5 @" K& o( q( J+ ]4 |
  12. {
    5 j! w; q7 J3 |" M
  13.     /* 更新JPEG输出地址 */  
    + j# X# [0 Q# z, K% d8 A
  14.     FrameBufferAddress += OutDataLength;
    1 l! {  m9 y) F: ^% X

  15. # G8 }8 c- K; n3 ?4 h& G
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
    : q* z& w  w" p8 Z  ]
  17. }
复制代码

( ]* D+ D+ o" D0 q) \57.5 总结
6 S* j$ d$ D9 C" d1 ?本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。6 t  _: r: D9 t$ Q

' R* w7 \' G; a6 ]( W8 O
  b5 a2 D2 X: P# |  t# [% v
! a5 m2 r0 P2 d# H
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似技术帖

官网相关资源

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