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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示4 |- `! F  ^; k/ F5 n: Y
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
4 \) Z* y3 S# F/ g9 x$ [+ `  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。8 v- d7 |* v4 ]: w8 Y
  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
. H. N. z( c9 O3 ^  本章JPEG相关概念的介绍参考了wiki百科和百度百科。
7 h& h2 r* L/ t& q' u- q% N57.2 硬件JPEG基础知识

7 |3 F9 z+ a: O) u- Y, X) j; {对于STM32H7的硬件JPEG了解到以下几点即可:0 B: b& f$ \: ]) g" c

6 c0 o5 S$ t% O9 b3 O2 s. {; ~2 y  支持JPEG解码和编码。
7 q% F3 J, o1 d6 W- y1 B2 F  对每个像素数据进行编解码只需一个时钟周期。
) Z) y% R; E0 B4 t* N  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。* G5 E, ~5 O+ a# D: ?
  编解码时每图像分量8位深度。
& U" m. L0 S/ v0 i* U
/ Q! `3 }; s0 W0 ^' j- i& p57.2.1 JPEG硬件框图2 J' A2 @) g: }- l9 t
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
5 x! {  j) z$ M- W5 y
; g2 \, A' Q8 i& X4 @+ q( j4 V
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

( F5 ~) ~* u- ~/ z3 H' e$ A8 Y. C- N6 j) f0 O% X% t! J
通过这个框图,我们可以得到如下信息:
9 h/ g/ p7 E- }( u5 u7 e2 ]3 T) t, \  F2 U
  JPEG硬件外设支持编码和解码
8 z8 q1 N. b4 c) Z* H并且对于输入数据和输出数据都有FIFO支持。! _# v0 q  ?4 V8 t( l! K! i
, L# P" w# V0 n5 p) q2 r8 `
  jpeg_hclk
" z/ _' f6 I  L  y为JPEG内核和寄存器提供时钟。* a2 b  u! y) P" y
1 m: N/ M+ E6 O0 `9 S
  jpeg_it
) T. i9 ~5 p* R; p3 C* WJPEG全局中断输出。% A' l4 v) c" _2 \: M
; y  u" z  [( I: m! w, p# ~
  jpeg_ift_trg/ ?, f% m  e7 C9 ]
JPEG输入FIFO阈值信号,可触发MDMA。
1 ~2 Z& v/ q: L8 h& W4 ~' h8 a0 y6 k; q) b" B
  jpeg_ifnf_trg
/ f1 M$ N( x: ]JPEG输入FIFO未满信号,可触发MDMA。
5 [2 j8 W, ~& s* w& _, e; Z
( i' M$ C, `* ?( ~5 q  jpeg_oft_trg! x, w. Y. p7 g0 w$ [
JPEG输出FIFO阀值信号,可触发MDMA。9 O' Q9 l3 L% K" I  h$ e

/ [* I' O( D4 g  jpeg_ofne_trg
6 |( d, J# W! d6 zJPEG输出FIFO非空信号,可触发MDMA。( X- C, a1 Y3 _, f

# w  J) A+ Y" N2 @- ^9 k  jpeg_oec_trg) R/ H- [# G% o
JPEG转换结束信号,可触发MDMA。
' ?0 P! J9 K$ V! i- C$ g% i- ^
4 a; [2 ^8 E$ u* B2 R% _- c( Y3 `57.2.2 YCbCr颜色格式
' y9 M! ?3 p! F! D/ U2 t$ a2 S# q(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下), N6 p3 ?4 }& x+ J; i9 ?) m2 |/ v
5 W- z: H% c3 a# [# W& ]$ b
正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
; i$ J9 d& H# F4 z- T8 S  Y3 t( t
0 ]1 H! }: y. ]7 L% v7 h  r, mYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。% ?; M4 B! }; ?3 _! O3 W
' E1 O0 h0 [9 n0 b! [1 x9 d/ R) w$ z
在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
- Y5 e+ l) V! O7 Q2 k" v8 @' Q* O
7 Z2 |5 L1 O, V. ~- a5 |0 _57.2.3 YCbCr采样格式* z5 S! D8 R) u
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。5 u: i# r# E; r+ _) w
6 U. n+ D7 u7 z
  4:2:09 S7 u$ c- ]0 @, P% P# M+ A8 y* e. u5 L
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
7 z& z; j5 B7 F8 \4 e% z0 j9 D, i# Z) y; _4 o
  4:2:2$ X  h! p, i5 t+ m" k4 ]
表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。$ e' v5 F5 x/ s3 k
8 [; u8 |. W$ |4 X6 T  |
  4:4:4
* X2 ^4 r: r" p& [8 f3 w# B# l/ v表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。
- N# U2 c* O8 U* e. W5 Q5 ~9 Y* `1 D  a" `; E
具体的采样方式如下图所示,以8个像素为一个单元进行采样:
/ G7 j% a! ?2 @/ C& |( E6 F
+ V  `% M% X) P% t2 [
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
- a  z/ J8 }6 L% l

7 v+ i% _5 K' J. y; t6 j由上面的截图可以了解到:0 a% E6 B9 k) Z  }

* x1 ?9 m8 W  ]7 v& J4:4:4表示Y通道,Cb+Cr通道全部采样。
% N! z" y. L* b2 Z. q8 R2 b3 p5 c6 C7 p1 d% C, \% ~
4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。6 z' i/ Y9 n0 s

' o9 A0 H; h( Z9 B4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。6 `  ?* F; |8 E0 ]6 J6 \& W

0 }& g/ e) m& b! v; i下面是整体效果,方便大家更好的理解:
/ g4 L! o7 U" M* C9 [: N' A
$ ~* v2 N& }; L2 S  U6 g- P/ s
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
$ S1 ]" c1 y+ A
; i7 j  o5 x" _

# l+ I, Q6 X- _# g2 E2 O) ~4 a' `  F9 Z
57.2.4 YCbCr的优势2 q+ |0 B4 V. w& y% i
RGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
# e6 o2 d% m/ v  i% e1 W+ i% T  N. m$ H) s7 L. |  n! H  b5 z$ [
57.2.5 YCbCr和RGB互转
! W% V; O, C+ L
为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。$ F% b$ L9 `1 ?! M9 z) C5 d
& J3 m2 Y2 n; w
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

0 P. M! `4 Z$ d5 x8 A
9 H  f. @4 c+ h9 I. J. ^下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
. j/ Y) c) K: ]! Q* i* _* ]" e: C4 M! G1 U- c, T, N$ W
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
3 s; ]7 i% V" ?. ~" J: Z" A7 @
$ l* i8 T: O: s: T- n! S- m
57.2.6 JPEG编解码知识
' }2 q9 R& [7 N8 U8 J2 fJPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)6 o  [  g" h* m% C. r4 C
2 H0 ^+ V' l: Q
57.3 硬件JPEG的HAL库用法5 f( z8 ~! r, L, S
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
/ [4 \4 a! Z1 w* n) A: O0 j6 f4 A6 X5 {9 d! {& F/ n
57.3.1 JPEG寄存器结构体JPEG_TypeDef; Z9 ?. u, L3 ]& C6 C  k8 {
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
& _  \) ?) x, g4 ~! }
5 f5 e4 P4 m/ a# }& V# Q2 u
  1. typedef struct
    7 T5 U7 J$ y, g, h& b+ a0 g9 S
  2. {
    * N" p# _! o1 C0 o" b' b% P& X7 [
  3.   __IO uint32_t CONFR0;         
    ) M) G0 i8 y+ D' H  j$ y) |
  4.   __IO uint32_t CONFR1;          ( Z( d. N: p7 M7 `* ?
  5.   __IO uint32_t CONFR2;        3 V$ t8 u' f/ ~: h  }9 k4 L, F8 ]
  6.   __IO uint32_t CONFR3;        
    9 F1 P' r: s1 z1 z- ?! n' ?
  7.   __IO uint32_t CONFR4;         
    2 ~/ z8 `' h0 A1 b2 f2 {9 t! N
  8.   __IO uint32_t CONFR5;      
    & a- J. W9 B2 X0 I/ G4 D
  9.   __IO uint32_t CONFR6;      
    8 h8 Q' X% Q7 D% G3 m5 Y! z, H4 b
  10.   __IO uint32_t CONFR7;        & n+ ~4 k0 i0 B* h' g; |/ t
  11.   uint32_t  Reserved20[4];      
    % o6 O! q' B2 W7 Z" y, u
  12.   __IO uint32_t CR;               E. B# P5 E( t4 z+ }
  13.   __IO uint32_t SR;             - Y$ a% g0 {$ N  v9 G0 n
  14.   __IO uint32_t CFR;            
    / i0 {6 V$ z1 r" ^' R' w
  15.   uint32_t  Reserved3c;        + ^  b' w" n- I1 R3 }
  16.   __IO uint32_t DIR;          * R+ `8 c/ m! T% O4 e9 X
  17.   __IO uint32_t DOR;            
      g" T5 d8 C. v7 L0 d) V/ I$ a+ Y
  18.   uint32_t  Reserved48[2];      
    7 E" L% n& R* s4 j/ F2 o; ^2 [
  19.   __IO uint32_t QMEM0[16];     7 a+ ?# d7 b: o: i
  20.   __IO uint32_t QMEM1[16];      
    + x$ V: o3 d1 t
  21.   __IO uint32_t QMEM2[16];      6 ^/ @" r2 Y. s
  22.   __IO uint32_t QMEM3[16];      
    8 }5 ~+ n: Y+ r- f
  23.   __IO uint32_t HUFFMIN[16];    : I+ O4 C. a8 f9 r. ^0 S% N
  24.   __IO uint32_t HUFFBASE[32];   
    , t- |- V! ~( m* p$ h2 ~/ b5 F2 ^
  25.   __IO uint32_t HUFFSYMB[84];   2 ]" C, s! H8 y5 d; n8 X3 f+ z9 R
  26.   __IO uint32_t DHTMEM[103];   + p$ W2 w" Y/ i9 w" m# @" }
  27.   uint32_t  Reserved4FC;      0 C+ u2 s4 B) `5 q! r  K6 T
  28.   __IO uint32_t HUFFENC_AC0[88]; % m6 _! Q4 k: v7 j' m
  29.   __IO uint32_t HUFFENC_AC1[88]; $ H. ?& f) t0 c& `
  30.   __IO uint32_t HUFFENC_DC0[8];    O1 r) ^# J7 q  w" V+ I3 ]1 E$ f
  31.   __IO uint32_t HUFFENC_DC1[8]; ) h- W3 q& ~0 E: e+ b1 j
  32. } JPEG_TypeDef;
复制代码
; s* q! F) D1 L  }+ N
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
/ Z0 `( N8 r; S! C. {7 x7 L6 r( L2 g* F9 P$ {! r7 O4 i) `: E$ D( A& c
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */& B$ r+ o3 ~7 W$ p& k; L+ t
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
8 L; ?! m6 f/ L" v0 N
下面我们再看JPEG的定义,在stm32h743xx.h文件。) ]) I! K2 i) x: g! R

( C8 C4 y7 h5 x# ?7 v
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)
    6 D0 Q7 T7 |/ P' x/ Z, C% j
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)- E: z5 ~6 z9 \
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)# s$ \. c' d. E* a7 y( q$ I! M
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码
7 G( [5 `& c, Z( j* W
我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。! j) c( w7 t7 H. \

+ {1 M! C- b4 y# ^# ]- o" P57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef; M4 T" \) o4 g
此结构体用于JPEG的编解码参数,具体定义如下:9 O: n& G" H' Q8 w

9 R$ [$ L6 z; g# p6 F" q+ f
  1. typedef struct
    . p+ ~& U- x4 s6 v- s. i9 B
  2. {$ d8 ?' _! h- Y' O9 n
  3.   uint8_t  ColorSpace;               
    6 C. S" K  q( n! C3 w8 d+ }7 Q0 w
  4.   uint8_t  ChromaSubsampling;        
    0 l) c4 d, W7 \  m3 V6 z5 ^5 ]2 ~. m
  5.   uint32_t ImageHeight;              
    ! C% I. F) f3 g0 L) l
  6.   uint32_t ImageWidth;            
    - X7 J) \3 O2 \0 L, n) w
  7.   uint8_t  ImageQuality;               9 K4 I, `$ T& N9 @
  8. }JPEG_ConfTypeDef;
复制代码
: r. V, W0 V. D
下面将这几个参数逐一为大家做个说明:
9 q+ C2 a; c& K  uint8_t  ColorSpace
. ]+ J1 f" V4 _& D. f$ G1 D0 ^8 _1 `( w  H' `6 K2 U9 U& f) ^* Y
% I6 w: I! r2 ]% ^. W- C9 q* ^
此参数用于设置输出数据流中的量化表,具体支持的参数如下:5 z: \! j/ h% |) i7 o3 d1 V$ G# o
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/( L6 C: C" o, p9 S5 f; T) W% ?
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */1 e0 S1 W( C0 e: S- r& h+ Q) N+ p
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

9 m4 a3 K3 W$ I( r  S  uint8_t  ChromaSubsampling
2 Y5 r1 Q. `7 f' F  @- \7 U此参数用于色度子采样,具体支持的参数如下:
) s+ A) ~" C7 w( L2 G  L/ |& }. t, T
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */6 @7 g- f$ E, d" w% M
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */
    : w. b& K% ?1 R" G' `5 o/ |
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码
- e% ^0 h1 E6 g4 ?% x
  uint32_t  ImageHeight3 {$ j; Y7 ^7 q
此参数用于图像高度。6 C' p1 y2 U; j; X% p. W. X6 s
3 A2 R' l# J6 c4 H2 y) Q; E
  uint32_t ImageWidth  S5 E5 W4 r9 L, h' p- ?$ s
此参数用于图像宽度。  |$ j# M9 M: ~$ s! R

3 e# Q% E6 D8 f  uint8_t  ImageQuality
( }* @9 u* i; X+ J: x$ t此参数用于图像质量,参数范围1 – 100,1最差,100最好。
1 [/ x! ~4 I* S& y$ [- w4 k8 }! `9 B7 S! h
57.3.3 JPEG结构体句柄JPEG_HandleTypeDef
- b! e  p) m/ }! m, P+ |5 I, |HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:- r3 h8 X+ ~! u3 D' d) i/ w

" N* l% d3 ]# Q4 F* s* J7 a
  1. typedef struct
    # z! ]1 ?  v& ^( r8 P' k
  2. {
    & O2 \8 X9 v. ]4 H& |
  3.   JPEG_TypeDef             *Instance;        
    % m# b& c) K2 o5 `/ b
  4.   JPEG_ConfTypeDef         Conf;             ! v$ e9 u! z9 ?  o
  5.   uint8_t                  *pJpegInBuffPtr;
    8 F' b  a  T2 R- x0 V  _$ M
  6.   uint8_t                  *pJpegOutBuffPtr;
    , L: G# k/ i% K0 t* o: U
  7.   __IO uint32_t            JpegInCount;      0 T7 T8 O6 U" \- l
  8.   __IO uint32_t            JpegOutCount;     
    . K/ y* o, M% o8 H9 @# _' a
  9.   uint32_t                 InDataLength;     $ w% d( [1 r; u! ]
  10.   uint32_t                 OutDataLength;     1 G- w: x/ [+ S  d
  11.   MDMA_HandleTypeDef        *hdmain;         " d# w8 D* R. Q& ?2 @
  12.   MDMA_HandleTypeDef        *hdmaout;        . }" F* x9 s$ k4 A0 `
  13.   uint8_t                  CustomQuanTable; % d" ~* e$ _$ X& f+ W; h1 x8 l
  14.   uint8_t                  *QuantTable0;   + [0 n" I  o; h3 u5 ]9 s
  15.   uint8_t                  *QuantTable1;      W- d  g' a3 F& T4 w
  16.   uint8_t                  *QuantTable2;    : _0 _# o0 x, r5 v0 \
  17.   uint8_t                  *QuantTable3;          # n0 }% l* b; U, q. Q6 f9 o
  18.   HAL_LockTypeDef          Lock;            
    $ Q2 Y6 K" g" C( X) O% R4 d
  19.   __IO  HAL_JPEG_STATETypeDef State;         
    : c) n  a( G1 h3 G. b7 R
  20.   __IO  uint32_t           ErrorCode;      5 \/ @" s5 w; V4 E# u
  21.   __IO uint32_t Context;                    
    + H) D' t, w6 X3 r
  22. }JPEG_HandleTypeDef;
复制代码

- G/ e) K# D3 l  d5 ~. e下面将这几个参数逐一做个说明。
. n# J7 _9 \5 t) R* e! T
% Q: k4 s5 F1 L* I, L  JPEG_TypeDef   *Instance) i" ]% W/ V& l% c
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。3 y# @; t  f' @6 w1 T1 u
4 ~. C  c) G: t. Y- i) c
  JPEG_ConfTypeDef   Conf
5 I7 }- b. \8 O- t0 y这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。( @) c' D( @" |2 f) L

) C3 V# n6 z  R' H( K  uint8_t       *pJpegInBuffPtr
+ Y6 C+ u4 v; g( FJPEG编解码输入缓冲地址
+ V6 q* z  D3 w+ \" U) n, a) [
' Y' N0 l7 I; O, ]  i  uint8_t       *pJpegOutBuffPtr* i0 u6 r% B8 c0 W* ?
JPEG编解码输出缓冲地址
$ d! g) \( d6 L; a/ C5 E$ Y# y5 q' N- `6 F# v- \
  __IO uint32_t   JpegInCount
/ }" Y# [6 w/ m- c: m. LJPEG内部输入计数。8 z7 q9 w0 m5 [, y, E2 G4 ~" s
1 Q- K: s, z  n/ h8 h2 w+ ]
  __IO uint32_t   JpegOutCount6 K5 w6 S7 `5 M
JPEG内部输出计数。
5 Y3 m" d) G1 P8 X  I
7 \7 d& M6 h: C4 X7 @: p7 g, ^0 d  uint32_t        InDataLength
" R7 S- w/ E5 O; h! o, {" LJPEG输入缓冲区长度,单位字节: {% R& q' X5 }

; z- p- b0 G- [& v  uint32_t          OutDataLength! U) l( m- h3 w. @
JPEG输出缓冲区长度,单位字节。- W0 j- E  T+ b, Q

( s- a5 E2 w. E  MDMA_HandleTypeDef        *hdmain0 Q9 }" h' d6 G# w
  MDMA_HandleTypeDef        *hdmaout
; g& p- \1 A( v6 d% H0 a! u- x% J( AMDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
6 `0 I- w: P( M. f. N! a
3 ]0 G* F2 O6 H  uint8_t       CustomQuanTable
) x, t) U8 a, n8 ]+ j如果此参数设置为1,将使用用户设置的量化表。
8 c+ J% Z% O( Z" b6 ^7 C1 T# U( Y2 N' i, x2 r
  uint8_t      *QuantTable0;   
* c; K; D9 R+ g+ u  uint8_t      *QuantTable1;     : v$ f; A6 p  m& }+ q' j4 n
  uint8_t      *QuantTable2;    3 q/ z& U7 Y: `: G
  uint8_t      *QuantTable3;# W4 q) x' ]# O9 I
指定量化表地址。   
# @! T" T& a7 |/ Z& _6 x% q: W7 W7 d& R" U6 V$ f$ x; `
  HAL_LockTypeDef          Lock           
  ]' q' o3 d2 M' I9 V) O/ w7 R  __IO  HAL_JPEG_STATETypeDef State           
, X: J" o0 t4 n  __IO  uint32_t           ErrorCode      
$ J+ B3 o. `( ^- Y0 [+ b. A8 t这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。: e; S! r1 B7 q7 |6 ]
, D* Z3 m$ p, Z
  __IO uint32_t Context
7 w# p" e& S2 @# s4 X6 zJPEG上下文。& I# Z6 f) a$ E% B

* w$ v/ O4 e7 ^8 R6 ^* ?3 b8 V& G57.3.4 JPEG初始化流程总结
# S" }4 h/ _3 M& P/ o使用方法由HAL库提供:# G0 P+ f7 I) s
3 H4 Z% a7 ^) z! ^) O6 W0 E
  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。0 N4 Y% ?8 P# W! D$ t

: s$ ]5 C8 y, o9 i6 D& H如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、3 z0 [6 U5 ?3 J, S/ b

* \5 B7 _# {5 p! C  第2步:调用编解码函数
& q) r8 z, ~/ S% M: L! |/ ?. x- W' F( t. Z- z( B8 |
  查询式编解码函数9 O& C& E% J3 c* k; K% y
HAL_JPEG_Encode  I/ ~" A+ y2 Z1 O' b
" E& w4 F0 ?/ i# i4 h: K
HAL_JPEG_Decode
" e/ E, f& S1 ?) K, Y/ l
4 g- b1 V& ^8 x( r' G9 v
7 n1 f) n. ~1 z$ }  N1 i3 s- y, z3 N& G! Y6 B5 n& J* s. W4 {# {
  中断方式" X8 k. f& r# Z' p8 n
HAL_JPEG_Encode_IT
' M, O+ |" f- H# U' |1 {4 G2 O. M8 g& {% ^7 k; k, u8 U7 D: [
HAL_JPEG_Decode_IT  ?6 K0 ]9 _8 u9 [4 ]' t

, T: F7 W# ?( H: U3 L3 e* b! c8 O' M
; l& n7 j( c/ l7 A  w
  DMA方式- T' Z9 N0 [8 O$ K( f
HAL_JPEG_Encode_DMA
  X% v% F- U7 Q+ \7 d  _% ?  @) D* L' z6 S
HAL_JPEG_Decode_DMA
9 b0 a8 u! c* J: O# d( B6 `1 S# x
  I( y; J0 d" n/ n  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback
" n7 s$ z) M0 v+ D; X/ |+ W- a% f% [/ u) g3 ?) j/ U* C
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。/ p  ?1 K+ D% h! w1 [

8 J4 {# `! [7 k7 J( j2 q: {如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
, G% g7 e0 w* q# v
" I9 d3 X) Y3 R. N
  K! s2 D' C" o% g2 D(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
' y, N: T# w5 t7 V# n  D' [) C& @7 t3 r: h

2 i$ k) K7 W8 q% [(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。& E2 e8 E, e' E0 n

- a5 [9 _; q! f5 f5 R
' s" r: M2 l7 ?  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback& b8 n1 ~) e( m; e0 h

& R2 Q7 m) |( O" h6 B4 \(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
& b6 r- P* o6 ]- z0 m2 ~* b. u% I/ x7 X* f; D1 a5 M; X
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。
- _; K7 D2 P* Y: @# ?
+ P4 ~' I( p" i: f3 H: _(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。7 O, v, G5 V6 Q" a! |) X

2 w7 Q- t; u3 _. q. ?; @# i
) m: W% ^9 u3 Q: t1 l  第6步:其它相关函数) v- h! u! f( T- b: [: j( c
* b) c7 }0 r$ Q% _5 h
  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。
! w9 A1 n" l4 P! F& m4 d+ q. A  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
4 P& G! x- ^) U9 o  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。$ S. b  ~8 q& ~& X9 J" j' A+ k
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
8 g. _% D7 ?& D& L' e- m) U  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
( U* A  e* w* v+ j' b7 r. _  通过函数HAL_JPEG_GetState可以获取JPEG状态。
' L  n6 L" z3 a
6 Q5 d5 c% s( P& W
3 Z& g7 r( A' g% K57.4 源文件stm32h7xx_hal_jpeg.c
& ]8 g5 r' Z6 {1 m这里把我们把如下几个常用到的函数做个说明:8 J8 `/ r0 c9 @9 ?! h# r3 n
3 K/ K0 Z" _( F8 o6 X/ }; ~3 P  T7 q6 @
  HAL_JPEG_Init3 `- J5 e8 B- v2 r" |/ X- V) \
  HAL_JPEG_GetInfo, f2 P7 V" x( s4 y. U
  HAL_JPEG_Decode_DMA
; H0 c5 s) i& R' y+ t0 ?9 Z  HAL_JPEG_ConfigInputBuffer
' c# H; o  F+ M4 F8 f# O  HAL_JPEG_ConfigOutputBuffer
9 ^# X5 N( `" n" |+ S0 [8 e' d# X- |. Q* m, R
57.4.1 函数HAL_JPEG_Init/ T: ^+ }3 o( T7 F
函数原型:: |( j" `& k5 ?0 P
% L+ @8 p4 i" ]( g: w
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)4 `# U: F1 u/ Z5 j' b; X5 t
  2. {/ W8 U, n5 K- h# Y
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);6 I5 R# O7 Q- q  K$ u! {  E) C
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);; a5 N3 Y; O1 y
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);* h' O3 P8 w: S' ~
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);$ E8 P! F8 |6 W; H0 e  c
  7. # K$ o$ N' b& g! h8 G% b
  8.   /* 检测句柄是否有效 */% z6 |5 g, n) W8 n% }6 S8 ?/ k
  9.   if(hjpeg == NULL)' t6 A5 K  }4 j) x& C/ ^1 |! |- C0 _; W
  10.   {9 ]% I- P, Y; x+ m( u+ k
  11.     return HAL_ERROR;- V  s" n6 [) E% z, K* \
  12.   }
    3 A3 ]- C; s: W, n% o; N

  13. % @5 d, [$ C3 D6 N2 T
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
    / M$ q4 y$ V! l. G
  15.   {
    . I+ C7 a" z% T; y; \: ^, q
  16.     hjpeg->Lock = HAL_UNLOCKED;0 m, Y! k- }3 M& Z5 z% g7 E! k

  17. 4 u: H) X$ d( n
  18.      /* 初始化GPIO,NVIC等 */
    9 J0 n  w4 Q( S% n+ _
  19.     HAL_JPEG_MspInit(hjpeg);# I( X3 z( w2 [* g0 S3 ~
  20.   }
    % c: M* J+ x5 T$ {2 T% G0 Q
  21. , D% k/ x" Y8 b! r! J& W
  22.   /* 设置JPEG状态 */
    ; ~% X7 T4 Q$ ?* ?
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;( K3 X5 d4 R$ p2 p

  24. / }# [" n1 q+ i2 C) [: H& o7 k) k
  25.   /* 使能JPEG  */* Z( x( `4 w; y" A: ^; r
  26.   __HAL_JPEG_ENABLE(hjpeg);: |' i( n9 c9 C6 L+ K0 ~
  27. / G& Y5 [) R7 ~! h, e8 j; P& \
  28.   /* 关闭JPEG编解码处理 */
    * A  O% ^, [- R% q8 y9 {+ ]
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;) Z; j: c% k; c, n( O, V/ L, ^4 Z7 l
  30. 2 M; g4 L( P0 j
  31.   /* 关闭JPEG所有中断 */
    - v0 a9 b, ?: t& S( O& G0 Q
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    $ M, _# g, @3 {8 y; o, G  G% k

  33. # n4 I4 E6 w8 T/ ~2 [9 P4 S6 e5 Z
  34.   /* 清空输入输入FIFO缓冲 */
    - l, K- n: y$ j/ @* U" X
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;1 R: ?- z# O: k3 P% I1 f
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    ; y% K0 `! Z1 u

  37. * G8 r& K- {# @9 v2 E1 K! Z
  38.   /* 清除所有标志 */! |7 y# Q6 p: u% Z. R
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);
    6 l1 M; {) p, e' T

  40. 2 S  I& I9 c) W& B4 s7 Y0 k. Y
  41.   /* 初始化默认的量化表 */( Z2 j6 U  g8 `: c( ~( h  x
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);" w- q: p) t. m3 i7 Q2 s% X6 k- |
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);5 q* M+ ]# G7 U1 [% J6 e' E
  44.   hjpeg->QuantTable2 = NULL;
    . m7 h! O4 v0 A- A7 u7 S' l! C
  45.   hjpeg->QuantTable3 = NULL;" C8 l% I- r) D
  46. ( z( T' m  T+ ^! r- d
  47.   /* 初始化默认的霍夫曼表 */
    9 J9 V0 P6 r& {' s, 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)& h# b% o$ F+ }
  49.   {
    3 B7 L( g5 S, }: d/ H
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;9 Q4 {! |+ U" P9 F
  51. ( t/ e% ?3 O3 n0 _( B$ j) `
  52.     return HAL_ERROR;! y9 N& B' M/ G6 u; d
  53.   }
    7 ?1 \+ u; _, U' ]9 \- G* d8 S8 s
  54. " E; p7 s: r( i& A4 O) m, r
  55.   /* 使能文件头处理 *// W6 \6 R7 n6 a5 C0 p! G" ^
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;! G8 u6 _8 _. I# d% j# S

  57. & Y* H& h1 a6 Z( I4 {; u( U
  58.   /* 复位JPEG输入输出计数 */
    ' x5 |; Z; M) V( P7 l
  59.   hjpeg->JpegInCount = 0;
    + h% M+ J+ U& e3 Z
  60.   hjpeg->JpegOutCount = 0;
    5 g& E6 N9 M8 p( J; P6 ?( i' z' r
  61. $ n2 X8 E7 _, m; x7 f1 w
  62.   /* 设置JPEG就绪 */
    ( Q7 R5 H6 G  r( W' Y- l: l$ Z
  63.   hjpeg->State = HAL_JPEG_STATE_READY;6 L. L6 O* f- R+ @9 H5 E
  64. % s! |# g7 @; T# I
  65.   /* 设置无错误 Reset the JPEG ErrorCode */' v$ h4 J5 n; J; U
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;" }: b6 O; ~3 T1 ~0 _

  67. 7 u4 |8 q3 R4 G! q/ N
  68.   /* 清除上下文 */2 n: a! c& D" }. k% y
  69.   hjpeg->Context = 0;4 u) G1 {2 v% P) |
  70. 8 p0 i7 ]" p2 M& g, D. b
  71.   /* 返回HAL_OK */6 C9 P, x# ^# h# A/ R
  72.   return HAL_OK;
    " `& y5 C, ^0 c: k+ C
  73. }) C! ]0 }6 q  L5 J0 Y% B- {
  74. # j8 L1 _* `+ O; f$ h# n* w
复制代码

+ M/ U4 U: t1 S" h; g函数描述:8 Y5 h  z- @  J" H. N/ |) x4 p7 k1 i

+ u1 V3 N7 _% T& E% Q* w8 H. x此函数用于初始化JPEG。- w: e. r7 [. P5 M3 M
! ~& K3 w: Y) v9 |/ z" o
函数参数:
0 g7 D4 i: b6 Q. [7 K( I  a" M1 y( B! r
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。" Z8 E5 F: h5 S1 q
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。& D) x3 p& E* T# V  f
注意事项:7 u& K3 v8 b' a4 H
) a, }. {* `4 v- O+ W4 n$ [
函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。7 h- m7 S% E8 a5 d0 M0 G/ [
如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。
& F" q( c2 @; Z# |- t: {7 D5 x; ]对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。
8 L) T! O7 f9 i+ L3 D" o  c
$ |1 f, v1 [& G6 t3 H( {# M解决办法有三+ h# l/ Z, f3 v5 ]$ }' v

7 J0 l! N0 p8 y, _0 V  A! n方法1:用户自己初始JPEG底层。8 Q+ K0 W3 I6 w  h0 k
: \8 L1 o- ~+ K* U0 @* X# t
方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。
; L8 J3 x8 x+ F- o* e" v' M
- h) ?- c1 a8 g" f方法3:下面的方法- W  d+ o  y6 |0 Y  S+ h: i+ S. o

0 D3 [0 K1 o; G) n- O
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
    " q1 h2 q# y: B9 x1 ^; q% Q' c8 a
  2. {
    8 c/ t. y" `& e3 y: \  X# u& Z2 J
  3.     Error_Handler();
    " g; \' d7 [+ m
  4. }  7 u) e6 r7 ^, b& h' G
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    . `1 ~! a4 Y5 d8 I1 y5 N
  6. {5 Z; ^6 X- V+ ^3 J
  7.     Error_Handler();  O: W2 E! B5 y
  8. }
复制代码
" M4 d" X7 F( M) F1 k
使用举例:0 z8 g8 Y/ d4 z2 p: |, o
  1. JPEG_HandleTypeDef    JPEG_Handle;8 p$ u/ [; h2 M# V( N; q; R( u' `  @+ n
  2. JPEG_Handle.Instance = JPEG;
    / j: B0 E6 Z/ [; d' K% j7 S5 u0 e1 A
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

  e; `. A# i7 o+ ~57.4.2 函数HAL_JPEG_GetInfo+ u* i/ Z8 {. p/ r, Y2 p1 \7 P- j4 y
函数原型:
( V: P+ C! S6 h! M1 |% Z% j8 K0 Z3 {0 U/ e4 N( l! D
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
    " T7 B6 p- `% M9 Y
  2. {
    ! u+ O  C5 K, K5 f( S, y2 N
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    8 M8 `' c' W4 K  |5 l; d
  4. 3 C! v& a2 M  ~
  5.   /* 检测句柄是否有效 */
    4 J8 [& a  T0 j) s3 B
  6.   if((hjpeg == NULL) || (pInfo == NULL))
    ; g$ z) B' e0 z! O
  7.   {
    # Q+ k8 L; B1 U" {' `& \
  8.     return HAL_ERROR;7 Y6 R% r: P% `  C
  9.   }
    # b9 v7 V8 \8 g% \) F. z
  10. $ R3 }, ^0 Z4 l2 {0 D. v( H5 |
  11.   /* 读取配置参数 */
    3 _# s& f* R; l4 @
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    # b" s3 p2 _$ a  y; V5 q: ]* C" I' D
  13.   {, k" H6 v8 _: Q+ g: n
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
    " e( d0 a6 ]; V: e* r
  15.   }    6 X* w! J/ ?5 H1 N! \- e
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)! d# P( I/ l9 W, N5 p
  17.   {' x$ N5 t( n1 c, G7 ^, U, \
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;7 j8 c& `8 z) b$ c: E7 f
  19.   }
    ' Y8 a# O% d7 x) s: i9 C" I
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
    ! {( m) U2 C* u5 l- z! Q
  21.   {! O" i7 x* R4 E& O" i! b
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
    . _) N- i  b$ L9 q  S- F  y: T
  23.   }5 @* A% i+ h9 z! s0 Q

  24. $ q. S# o5 x4 a  _0 Q
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;9 G3 z! g' ~1 ^! j# E
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;5 Q9 k7 `4 V" m2 E; M
  27. 0 ^4 k0 F! f$ k: E9 g
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))1 y' h! m) C9 R
  29.   {! F5 @" Q5 L" U$ f/ Y
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;
      u, O9 o, r# N' I: V( }
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;  a! w5 j' K( c$ T/ N
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
    3 h$ E7 D+ i/ Y7 e9 N3 X# R& z
  33. 0 s/ z5 d  \2 I
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
      ~5 t0 J4 F$ U& r, p2 d
  35.     {3 b6 Z! u$ f. t
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    . c& m- d' a- K3 w. t" E3 V
  37.     }
    ; n3 }  J) ]% Y' w
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
    ' I, X. Q' W7 q$ X& L2 j- ?5 R
  39.     {5 C! W4 ^5 l0 b1 t
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;& y7 ^+ O  p9 v$ P/ T
  41.     }
    + Z; q( ^1 n) K4 P
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))
    5 s1 |; Y# \$ m, V. S
  43.     {
    1 w$ l2 T$ w; j
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;
    $ z2 h( E  b/ D8 K
  45.     }' i; ]% ^" m4 ^; J% _* M
  46.     else /* 默认是 4:4:4*/
    , K- }. q% c4 t+ n! a* X* s
  47.     {
    9 P( H* E5 j7 e* f  R
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;; u: `* H$ t6 ?3 J" O
  49.     } 8 H  M$ ^  d- ]) j& R# r3 o4 w
  50.   }
    2 o' ^7 L8 v* E" M
  51.   else - W+ V; Z+ I% `! n4 Z, N
  52.   {4 ?0 e" e1 q4 T1 S, [+ F3 {
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;( v4 m% W' C- M$ f
  54.   }
    ; Q( e5 a) ^) O+ j# g& C4 a. j

  55. # E% V5 ?; s! B: |9 f8 N# D* ~7 n
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);+ ?* T5 t; E: O6 b
  57. 5 b- r: n2 s4 q/ R& `
  58.   /* 返回HAL_OK */
    % I+ P6 q1 J0 a! X3 m, R( @6 s6 [
  59.   return HAL_OK;
    ) J  J/ _- w8 {3 G6 s, i6 S
  60. }
    6 P/ p% _* X& v5 [/ b  x% t
复制代码

1 h' N" J2 A! q函数描述:
; U% T7 j0 f5 v8 N1 a
# e+ m' i) _- L  T0 b, E% |此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
- `& F+ V8 ]) ^7 F" W# r
& r6 M5 {; P3 t1 j函数参数:
5 `% r( H  |8 ~1 U- R4 t- k" C9 T8 @# f9 ~5 N
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。5 o0 b2 X9 h& _0 k; z3 K3 m
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小
  h( V" d( A) F& S- E  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
/ g: L+ C" Y) ]; c: k0 z& }
3 j9 C6 n' b# `; |3 [9 Z9 v6 q8 M3 X5 z9 e" M3 p, [( s1 L6 z) B, q
使用举例:9 s* w! }# E9 j- V* V+ m% @& ^
  1. JPEG_HandleTypeDef    JPEG_Handle;- c- |$ E8 g" ?- d: a1 u" x8 z
  2. JPEG_ConfTypeDef      JPEG_Info;- g+ v3 S; H- }  q2 R

  3. 6 t1 a% H. s5 @5 D% i2 F+ X# a( }
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

/ [! [$ t' d7 O0 w! C  O- C57.4.3 函数HAL_JPEG_Decode_DMA
+ {) I+ o8 S9 [# q' W- o函数原型:
& [2 m# A) C  k# N4 b  O: f; o) a
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)% |( I$ z% u, z( d$ J( G* b
  2. {( }* }* a3 H3 V7 M4 f: G
  3.   /* 检测参数 */! R) S: C" j9 k. b: X$ w% _
  4.   assert_param((InDataLength >= 4));5 w5 u) x; G& }
  5.   assert_param((OutDataLength >= 4));9 t2 T3 K8 |3 x" _

  6. " r& u$ W$ j  V
  7.   /* 检测参数 */
    # X% f, F  \* L! Y
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
    1 u/ S! k% e1 T8 e$ y$ D4 v
  9.   {- A- T. x, E: @; E; y
  10.     return HAL_ERROR;; ?2 M  `# ^; c, j( u1 Q6 ~6 v! e1 E  e' e
  11.   }
    9 @, t$ q" \/ \
  12. ( v7 i; g) b* v" ~/ `( S! d
  13.   /* 上锁 */
    ; [- w" ^" O  L* z, A7 @7 `5 R
  14.   __HAL_LOCK(hjpeg);3 F$ h- O( k+ o- e  z- I

  15. 3 n+ F) }1 w, l9 O! W! v
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)& E; o( X5 x( D" \  K
  17.   {3 u- H2 @- d/ [& F; h" @" s
  18.     /* 设置JPEG忙 */; [; r) F7 K4 L( f6 _- ]
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;( v6 ^; [/ b+ \" ^/ w! ~, @" S
  20. 7 q: U( e, q" U; t* X& V
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */
    * C" K9 [, ^  w. n! v1 U' ?
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);7 l# n  a/ L2 y, b
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    # f5 e5 J2 m; J
  24. * w6 ]! m, E+ e% v% r8 G
  25.     /* 设置输入输出缓冲地址和大小 */
    # `9 M$ |+ j# O5 z) l) z
  26.     hjpeg->pJpegInBuffPtr = pDataIn;& _) x: C( s1 }9 W
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    % c! q# ~) e6 D; K! x
  28.     hjpeg->InDataLength = InDataLength;( p6 g1 U* A2 ^8 I& N0 w( _
  29.     hjpeg->OutDataLength = OutDataLength;. t$ O4 N+ v& \7 M% V+ |
  30. # ~( `# J6 q- f+ C) I$ e  C
  31.     /* 复位输入输出缓冲计数 */
    # c7 t* J4 E- ]$ C; x* ]3 f
  32.     hjpeg->JpegInCount = 0;   
    9 v% ]5 _9 O; H9 @! j9 k. v
  33.     hjpeg->JpegOutCount = 0;   
    $ Q5 D6 u) ]& x5 h9 }3 ~+ X# R' O
  34. 7 }! Q0 t0 l/ \8 w
  35.     /* 初始化解码处理 */
    4 h. e' j5 O# x% u1 R+ N
  36.     JPEG_Init_Process(hjpeg);
    . E8 a' F6 |# A5 T
  37. 5 Z, G. H7 o4 h
  38.     /* 启动JPEG解码处理,使用DMA方式 */8 f  z" _3 x0 W6 Q
  39.     JPEG_DMA_StartProcess(hjpeg);
    7 C9 M0 l$ o! v* n- n& s
  40. . V: P5 y/ r3 d
  41.   }
    6 q7 L! P1 `# z. I. y
  42.   else
    ! x- ]! @9 |( r( c* S& [
  43.   {5 N2 U+ S" U4 G  `0 u1 A0 T. ]/ |
  44.     /* 解锁 */: q9 m/ j" I8 T6 C1 r! [4 c8 H4 A% T
  45.     __HAL_UNLOCK(hjpeg);$ B" N2 V* X1 }
  46. & M# P! E0 y% B$ R8 G, O" u
  47.     return HAL_BUSY;
    & }& E) t. w! c' `6 {* `
  48.   }+ f6 x2 @; ]1 k, K2 v- a
  49. . z2 y; T8 G8 s; H! C
  50.   /* 返回HAL_OK */
    , ^) o% C  y. @9 P: {" n
  51.   return HAL_OK;# E: R1 q+ f* L  S  I
  52. }
    5 q* C# q# r- r3 Y# O
复制代码
, G1 L+ D! ]+ D9 z; X" v( \
7 [- b! B3 `7 P* I& V+ X
函数描述:
7 S9 \% t% i' c( S* P2 S) F/ ^1 I3 W, W: N7 c
此函数用于启动JPEG的DMA方式解码。
" O( f! J  u' z9 h  n% G! m$ @6 i: N' C( |, `
函数参数:3 G# o4 ^6 s" r& H! S
1 r- j- U3 B, o; @
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。" q! x: _0 E8 a7 \; F+ t
  第2个参数是输入数据缓冲地址。  M4 o# O7 ~9 P7 V
  第3个参数输入数据大小,单位字节。
+ e* ?& E7 o0 m' v0 l  第4个参数是输出缓冲地址。
! V8 \0 L3 b6 Z9 O  第5个参数是输出缓冲大小,单位字节。
, }  P4 I# N5 w0 `  {4 k# C  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
, p% X. M+ h5 S9 \, |2 {6 _- {3 u0 t- C( p& R, ?
使用举例:
3 r" U" {  B, M6 P8 l3 f& s
, [+ e+ I$ M) S
  1. /*; C- Q* k% `. W7 O$ p* q( c, h+ ^
  2. *********************************************************************************************************) n2 I! n; T4 C( z3 k
  3. *    函 数 名: JPEG_Decode_DMA
    # [4 Q" K2 B1 M/ U
  4. *    功能说明: JPEG解码
    9 M5 R% m2 R7 m5 R$ X
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    " m6 \+ C& C. {3 o4 g
  6. *             FrameSourceAddress  数据地址
    5 l' p. g% i. R. M* Q
  7. *             FrameSize           数据大小4 n8 z4 J' k2 ?* W! t; O
  8. *             DestAddress         目的数据地址; a, P* a7 ]- ]6 o- J% A
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功) m/ ~9 k6 N: h  j
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出' M! ~% A9 P# |7 |3 j8 ]: w" q5 ~
  11. *********************************************************************************************************
    6 s. L# `* {/ j
  12. */
    - X& U( l- Y4 b! E. ?
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)- y3 h- X) [( F2 f1 o
  14. {" ]6 W, h0 X5 H9 }) Q
  15.     JPEGSourceAddress =  FrameSourceAddress ;
    , y  w9 A. R! A6 t# w! ^
  16.     FrameBufferAddress = DestAddress;
      {3 C( F' D+ k  h: M
  17.     Input_frameIndex = 0;
    ( s0 b% N1 k, j5 M: u
  18.     Input_frameSize = FrameSize;2 v# N' t$ E4 \: b# J

  19. 9 ~4 Z3 J9 j3 z' r; `
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */5 F  m, B. A6 p4 g
  21.     Jpeg_HWDecodingEnd = 0;. y' n4 A; {( K- z
  22. " S% O' X9 @5 z( o3 W8 ~
  23.     /* 启动JPEG解码 */* R8 S5 E, r* {6 k
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
    4 j6 n/ Y  }7 {+ n& E
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);
    5 n, F2 l* g% n: Q- Z5 F5 f
  26. , M- N1 E3 v8 f1 i, F# |
  27.     return HAL_OK;: o# I( P( ^( K9 }
  28. }
复制代码

* B$ n1 O* v, K0 ^* c" e57.4.4 函数HAL_JPEG_ConfigInputBuffer
2 M2 ^* _! i8 _( Y2 x! ^函数原型:# a8 P& P/ b- g5 v. u3 L. T
" g+ V9 o# r6 m& i: O$ _! C
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)2 G1 d# @# |9 X4 @2 }# F
  2. {
    4 a0 v7 B2 L0 t3 L, u6 \2 ^3 N
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;% {8 H  N# @: H0 }- |
  4.   hjpeg->InDataLength = InDataLength;
    1 F3 D# H' P; n3 A  H: M
  5. }
复制代码

9 U# R$ ?; n* y函数描述:
) g, D/ b. i* o) H: {- s- k- O, G$ ]4 W5 G* e
此函数用于配置编解码输入缓冲地址和数据大小。
- s) f$ l5 D# {/ \9 X& ?1 q% k7 a7 _2 [+ f6 o$ ]
函数参数:
- u# ]6 d6 o/ i' [( J4 a6 f; T  j2 R0 u8 G
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
  e" q$ n% d' p  第2个参数是输入缓冲地址。/ r4 P  ?0 z6 V
  第3个参数是输入缓冲大小,单位字节。# B0 I! {( `8 Q8 ?5 W$ n, W: y7 U: V
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& O( e4 x. m, Q使用举例:
2 V8 S0 z4 E0 H. u6 W: a, {. ~
$ s* E" J' O$ ^3 v
  1. /*
    - `" |3 p/ a0 M! t) F
  2. *********************************************************************************************************
    ' z0 e' Q0 J; U+ g8 S) z( f' a
  3. *    函 数 名: HAL_JPEG_GetDataCallback( W; I* M6 M# Q2 o$ @, x: N) {1 Y
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    4 i: V: E( ]  f6 y  X* I
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
    5 I, m2 S6 s9 l; f6 t6 E
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  5 e" y% s$ t3 D/ b
  7. *    返 回 值: 无
    - E; n1 l  U& k) }
  8. *********************************************************************************************************2 x( _* y, {6 c% M6 ~
  9. */
    0 D$ x! [6 a! e5 O9 X0 h
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)6 N/ V2 H, U/ F
  11. {
    ; B2 \: F. T( y/ G
  12.     uint32_t inDataLength; ' |& A3 m) \0 z( e( Z3 l

  13. & `/ l/ u: |; b9 J7 _
  14.     /* 更新已经解码的数据大小 */* ~/ ^- K( j: e- `, Z
  15.     Input_frameIndex += NbDecodedData;8 i0 U. c8 }! ]; I8 t

  16. % Y( q1 q+ e& G  V+ H$ X7 l
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
    ( `: m! G, S4 ~% h' c! }* d: b4 p
  18.     if( Input_frameIndex < Input_frameSize), x( u# {, {8 B* r
  19.     {
    0 O+ h* C" u6 H+ R& e0 A4 O
  20.         /* 更新解码数据位置 */
    ; \5 T6 t+ J  K+ `6 |
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    2 e4 Z' H% Z- P% x7 k

  22. 5 Z# U" F& |9 y- F
  23.         /* 更新下一轮要解码的数据大小 */
    ! h% h* W( a: H4 V- F; ~
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
    * N% N! f. c* ?* c- _- m$ Z/ Q
  25.         {
    7 H4 v! D: E8 Y7 f
  26.             inDataLength = CHUNK_SIZE_IN;- k& V& |  l3 K: R) N0 g( y
  27.         }  C& H+ K# i: L
  28.         else# G. ^5 M( k- o# _7 l* H! f
  29.         {
    5 Z% t! a- ~$ Q
  30.             inDataLength = Input_frameSize - Input_frameIndex;
      P1 t+ p5 ^! s, t7 H, ~
  31.         }   
    - {/ q/ X* h' Y0 B7 v
  32.     }
    - k* w; u# w' v/ o
  33.     else# V2 J4 H# [; J2 ~# X
  34.     {
    - m8 }; \4 j1 f: x. i/ H, r
  35.         inDataLength = 0; / E2 w! M' e- L2 W6 m
  36.     }! Q6 {# {2 l2 z0 i2 A5 b. _
  37. + `. V4 F" B( r5 A
  38.     /* 更新输入缓冲 */3 S4 ~9 r$ O) d) Z5 h5 b
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);   
    0 ^5 P2 a" l" B* R! [
  40. }
复制代码
+ p" ?; L. ~7 J$ t' I

# _+ ^  a: H% R$ z2 p57.4.5 函数HAL_JPEG_ConfigOutputBuffer
! B: p6 t; z+ W& X% \函数原型:
# [0 f& d! u( T2 [5 a( J( ]9 W7 p' |- [2 b: s# f# a
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
    + S7 I. P+ ~+ n+ u! T  F* T
  2. {
    1 r  u# Z, n/ X
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
    4 I8 C( d, v! y# ^
  4.   hjpeg->OutDataLength = OutDataLength;  0 Q  `" d7 r. {* l; n
  5. }
复制代码

/ j1 u" m& T/ t( @7 P3 ~6 Q  i  T, d: `+ |
函数描述:; F! r6 @$ Q( C& h( p, r2 |6 n

# s+ c2 y+ G, P2 P( ?此函数用于配置编解码输出缓冲地址和数据大小。, X: T- [4 [, ]4 e: I5 W: h+ z

" t- z! h  S0 A; h函数参数:* ^5 m% p6 A. X& ^( g  l1 n
$ s/ e$ x, D4 X: h
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
& M& t! h  N" Z) G  第2个参数是输出缓冲地址。
, f7 O' V0 T. b5 D1 a$ `  第3个参数是输出缓冲大小,单位字节。8 w( `& {$ ^( \% d- N
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
0 U& t7 V9 F" ^3 x8 _9 [5 Q# [5 ~使用举例:- t0 f- H6 ^3 o; z
' J- S1 `; n, X
  1. /*/ s/ T: }/ g; k! t- _& G
  2. *********************************************************************************************************' @8 R' U2 N* b4 C: r
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
    : V- {) |- _3 j) d, ^; Y
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新
    : C2 P  q7 U/ n2 Q
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针# U1 i8 ]- L# x; _( L& H
  6. *             pDataOut      输出数据缓冲/ B4 M# X) V3 B" o
  7. *             OutDataLength 输出数据大小,单位字节
    " k, b+ K2 x0 N/ @7 O2 a! R
  8. *    返 回 值: 无3 s$ y! ^" w# d3 v7 p& B1 N
  9. *********************************************************************************************************
    9 t& k! V: m& N
  10. */1 A9 z* m5 w6 d& B, t" l" y0 `1 }* W
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
    ; T+ ]' t- b, _
  12. {
    - u- F( s; R2 J8 ^/ \
  13.     /* 更新JPEG输出地址 */  
    2 L+ k( Z8 R) K7 y
  14.     FrameBufferAddress += OutDataLength;# M4 H1 U5 C1 J, O) U( U

  15. : w" U  y$ O% V7 O- f) @0 K: q& _
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT); % c2 q4 v3 `7 ~0 |  s# |' S: C/ c. }8 D
  17. }
复制代码

. O0 m& i7 S- Z' L2 l3 ~/ a57.5 总结
9 V  y1 ^( Z- E: @, w本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。4 P0 }+ g- ]0 Y3 A% P! }& V) U

7 F3 B# a& d9 y+ g
! ]9 P5 s) Z' C: E2 y3 ?
, J) R. D, F5 Y8 M& L- ^  c8 K
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似分享

官网相关资源

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