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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示
- `" Z& E7 a1 e$ o  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。4 G4 I5 H( U/ {9 X6 B7 w! S
  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。
0 \& e, ?7 v6 b$ d5 }2 V  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。5 k6 E6 [! Q* S* n6 v/ J& K
  本章JPEG相关概念的介绍参考了wiki百科和百度百科。' F  ?9 i/ q# p0 k
57.2 硬件JPEG基础知识
) B& j3 q/ A- N  V. q1 m9 D
对于STM32H7的硬件JPEG了解到以下几点即可:
$ U( e5 ~$ _. x- h. S0 C( M
7 E7 \" Q1 S# L# t. {& c- ~) @  支持JPEG解码和编码。
) T6 A; q; \7 S/ _6 I4 N  对每个像素数据进行编解码只需一个时钟周期。
+ e* I& V: g/ C( j) a  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。" e; P/ T% t# E- s! P5 {: e+ T. @
  编解码时每图像分量8位深度。, g: e; Q: e2 S8 o, R' N

* E6 U6 r0 L8 s$ X' M* K57.2.1 JPEG硬件框图
1 g; d/ O: H) o认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:9 H. c) n5 A1 Y8 v, [
+ x5 x. u+ R2 `- D4 ~2 M1 W( n: s
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

# {: c" p8 E8 v) J$ p0 Y6 W
; M$ b2 i4 U+ u$ S5 d7 j; Q通过这个框图,我们可以得到如下信息:& ~/ G4 ^! G  a2 v7 P) i) p4 G9 X

1 J; C, b/ r) j6 K( A  JPEG硬件外设支持编码和解码: p# z8 d# [1 T/ K2 l; g
并且对于输入数据和输出数据都有FIFO支持。
2 h* {1 |- b- [9 ?: W  Y# E6 H/ P+ U
# z% n/ M! o, @& R6 R$ S8 o  jpeg_hclk
( u" o+ S# x& R1 V( J& x( r为JPEG内核和寄存器提供时钟。  P2 t/ U  ~0 W# S+ P; y

1 F) N. v( q: Q  jpeg_it
0 A/ i$ S3 z" o0 z/ L- P4 QJPEG全局中断输出。! v# B8 i) i1 w3 g: _

% m# g: V$ `2 v* d  jpeg_ift_trg
1 ^( X8 Q; l  VJPEG输入FIFO阈值信号,可触发MDMA。. X* L1 x" ^  U7 W) c5 @

( W4 F) E' r# H6 ^  jpeg_ifnf_trg+ H' b- p; u& H( O  \% y, q0 a' S1 _0 ~9 f
JPEG输入FIFO未满信号,可触发MDMA。$ O! R6 J  {# @
; z' \# N% z5 a4 e5 K8 a6 `. K: a" F
  jpeg_oft_trg
; O& R3 B, c- {! CJPEG输出FIFO阀值信号,可触发MDMA。# }1 g! O  R! _- T

( A1 w: M% o, H4 f  jpeg_ofne_trg( \. }* j5 w# |5 T* E+ C
JPEG输出FIFO非空信号,可触发MDMA。; k' Y( U1 s. X8 L
# ]- p% i0 i; b9 A" l0 \4 u( H/ w/ M
  jpeg_oec_trg& ^8 I( G7 M( F7 d* ]) v
JPEG转换结束信号,可触发MDMA。
; S7 x+ M3 A5 S2 {. L
* J8 W# ~  H9 S' @" p& Y57.2.2 YCbCr颜色格式  ]8 ]  X, G! w# p6 o
(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)* H! p- @7 I) b- ^& K: @6 u3 w

; ^+ b. ]) B2 {' p$ H$ {正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
9 }$ F; \6 i+ r4 ~$ f* L+ U" d6 g, e
YCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
) R: |; v( Y+ N9 l( j- A6 I# }6 @$ }& w# ]; r4 i* h. Z. {" I
在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
' e* T% P  N& }2 }. H( x% Z; s! p1 A2 n) d6 T
57.2.3 YCbCr采样格式+ G- B, I0 V4 B* @/ y
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。
1 |+ x. }2 n8 D8 ~1 n* U" @! _  C; q2 v/ e  n
  4:2:0# V  R) J2 _9 A* X" ]3 L
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。& `! `# M3 G& q4 z. `) F5 N$ P
; ?4 Z% L, \5 z; L
  4:2:2
( _5 j. K  y6 P. v- @表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
6 l- m9 i% ~1 p  E9 u$ m; i
* |' n# j3 j- W& u/ C  4:4:4# F5 J" d7 B1 e4 P; J% ?$ c
表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。  `* ?2 H' G4 O+ R- g

9 v) t5 b! [# t* Q/ \具体的采样方式如下图所示,以8个像素为一个单元进行采样:; _3 ]- h- \4 s; R

% N  Z1 {/ O4 B; l
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

  h. m+ X: m5 t- d. n; Z4 j$ I8 N) z- ^, T  l) Q, H
由上面的截图可以了解到:
( @9 O7 E' S; A6 \% E1 ~9 a: l; z1 z
4:4:4表示Y通道,Cb+Cr通道全部采样。% |7 ^! W9 h+ K' i! Q+ ^% j% `

( q* G$ _' j: u% p; i5 B4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。) \3 U( d' x0 `. a. s

- c8 N4 N! H; S+ W5 D* |5 ~4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。
2 m7 p3 H0 v3 \$ J
7 Q# z1 L% Y5 M8 P; M0 n) K下面是整体效果,方便大家更好的理解:
; f- c% P# o. m% M  G& w
# X* b% n- ~" _+ }
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

3 r: \0 b- B; N* c  X7 i0 V
0 M) k% [; ?! I5 s7 p
7 W* O7 t, c8 P7 h4 V0 o. G- t' u; R1 m  H4 o
57.2.4 YCbCr的优势
7 w$ L, z& a6 U2 O) J" TRGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
2 |0 c# L* [% h1 S: t" k
5 X1 E' h; E6 w- f3 d57.2.5 YCbCr和RGB互转

. t; M$ F3 \3 X5 z0 T: {' C, p1 u为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。/ O. r0 P1 d0 [8 q

4 b  e5 {8 F  R- ]# Q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
% p1 [/ v" e. T2 a9 c/ }! Q
3 ~/ p7 f6 a) {  q3 N' e
下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:2 D/ o2 h" y' _1 G
2 h( \1 e. t3 ~" L( v7 W5 Y( m
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

8 y) ?8 i/ O( }# c  D  }
6 T" v+ M* @4 L3 k57.2.6 JPEG编解码知识
$ I  v# g9 I& j5 Z& lJPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)
) o2 `, N6 W4 f1 [: [' p4 O  T* i! P7 p$ I- U  t' L8 x. ]6 f
57.3 硬件JPEG的HAL库用法5 J% L( [' W7 F) E3 E* F& ]% A) V
JPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。0 M! K5 i3 B" I

" X: T0 \5 ?% r. O57.3.1 JPEG寄存器结构体JPEG_TypeDef
& D" Y1 y) f1 j% e) B" l. RJPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:/ e- S" u: m7 P8 m

/ @: M, y: d7 M/ |
  1. typedef struct. s1 W9 T7 v2 @- n' m. k
  2. {/ _1 g) v& d7 R( a" w8 W( p; ~: N
  3.   __IO uint32_t CONFR0;         ! a" D% g( s* n9 ?9 p
  4.   __IO uint32_t CONFR1;          7 P% `! _. u/ J* F/ g: \% _1 d
  5.   __IO uint32_t CONFR2;        
      j, t8 q7 k% k( `' n' Z6 y. O4 c
  6.   __IO uint32_t CONFR3;        4 f5 |, J* e9 q% t+ P& s
  7.   __IO uint32_t CONFR4;         
    ) [4 ?1 g3 @" H; l
  8.   __IO uint32_t CONFR5;      
    / I0 k: x" ~" x: B4 a0 A0 a  o2 m
  9.   __IO uint32_t CONFR6;      
    ! G! Y( K1 `$ _; d
  10.   __IO uint32_t CONFR7;        5 I8 R* w2 O3 B9 |2 O
  11.   uint32_t  Reserved20[4];      ; ^/ x2 U8 \: H2 o) ]2 l; g
  12.   __IO uint32_t CR;            
    ! m6 L7 Q% a4 u
  13.   __IO uint32_t SR;             0 m  z7 ^/ p: \9 b) O2 i
  14.   __IO uint32_t CFR;            
    ) \* _1 U* g! ]; i& A* x
  15.   uint32_t  Reserved3c;          R/ p. k6 W$ ~7 T4 N
  16.   __IO uint32_t DIR;          : ~' D9 W3 r1 @. e) c% I2 \
  17.   __IO uint32_t DOR;            
      U- J3 n2 G. B' h) r; A: I6 G
  18.   uint32_t  Reserved48[2];      
    1 p# t8 g* [! P( r  ^$ X
  19.   __IO uint32_t QMEM0[16];     ) f$ Q+ U% [8 s6 j- e: F$ j
  20.   __IO uint32_t QMEM1[16];      
    2 a* X* }! {9 J9 {5 k
  21.   __IO uint32_t QMEM2[16];      5 X7 z  c. x6 q2 e- h& l
  22.   __IO uint32_t QMEM3[16];      
    ) q0 e& `  c- N, n5 j0 X% Q
  23.   __IO uint32_t HUFFMIN[16];   
      ]4 y* |% y- B" r
  24.   __IO uint32_t HUFFBASE[32];   7 ?4 d& w% h) `5 M- x- z6 B
  25.   __IO uint32_t HUFFSYMB[84];   
    5 j/ I+ Y, Q7 ?' m2 f
  26.   __IO uint32_t DHTMEM[103];   
      |# e' {( n8 _, D. n. R3 {3 n  T8 d
  27.   uint32_t  Reserved4FC;      
    7 W0 x0 o; n, ~; [
  28.   __IO uint32_t HUFFENC_AC0[88];
    * V: o: }3 g8 p6 [; B
  29.   __IO uint32_t HUFFENC_AC1[88];
    . V1 B5 W& W! [7 m) V3 s5 W
  30.   __IO uint32_t HUFFENC_DC0[8];  
    * b" O, E8 I' W2 w0 ?
  31.   __IO uint32_t HUFFENC_DC1[8];
    * l/ |: ^/ B1 m. O) D
  32. } JPEG_TypeDef;
复制代码
" l  u0 J! ?/ `! I7 V. a
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:* d. Y0 A" x+ P

4 I. E6 E5 x, o+ Q3 q/ a
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */! z) L; `* z0 x& J) `* p
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

" g0 z) W2 _' B; X下面我们再看JPEG的定义,在stm32h743xx.h文件。
  ?. z; j5 P% X- G+ r
% N& Y0 e3 G4 N9 |$ g) a
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)/ C$ S' b' [: k1 B4 Y. T" V' i
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)8 h3 }* Y4 x+ ~: G) t8 I! M- C8 S$ n
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)8 ~' {2 a  D+ U' [
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码
/ Z, h* m, ]4 h2 v% X% |1 z
我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。) C8 D: J2 K6 O$ h

; o. V' u7 \6 ^4 ^57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef- E3 g* Q/ z7 H3 k# \+ A4 R
此结构体用于JPEG的编解码参数,具体定义如下:
0 f- G& p7 }  z: O! U. A- i* W+ `4 |7 c6 D9 E, F1 ?  }
  1. typedef struct
    9 X/ w% c# j' s
  2. {
      t5 q  y% g9 k# M) R" u' C
  3.   uint8_t  ColorSpace;               ) _0 j' G  d0 `4 V# }# F  d1 ^
  4.   uint8_t  ChromaSubsampling;        
    % S0 O. J5 c0 w2 H' K! u
  5.   uint32_t ImageHeight;              
    ) S* E* y, `1 h' g/ v5 b
  6.   uint32_t ImageWidth;            
    : Z$ ^% r7 Z3 J; u1 C9 G8 |9 i1 V
  7.   uint8_t  ImageQuality;               : H: F4 a6 o7 p5 g4 i4 M: }( {
  8. }JPEG_ConfTypeDef;
复制代码

1 @' Q; f6 {5 O& h3 C4 [" `下面将这几个参数逐一为大家做个说明:
8 b- S7 k/ R; ~$ v1 I4 h  uint8_t  ColorSpace7 F! M" K! Y3 G
; N; X# [9 Q7 P. A- E3 F

2 g$ }! U0 |& R此参数用于设置输出数据流中的量化表,具体支持的参数如下:
; ]% M  x- j/ C  p
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/1 V9 p) \- n- z
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */1 F% D# I, K" R9 v- h& d# Z6 Z
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

: _2 m! _* i9 k' T; _3 [: o  uint8_t  ChromaSubsampling
) X9 _& ?5 r8 w& l$ n此参数用于色度子采样,具体支持的参数如下:
0 B3 n& `0 B; ]9 T
! Y7 w) j/ Q) ~7 p! Z9 Q( j8 [
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    5 [4 {. j/ s& c* {6 j) R; A
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */7 ]4 _2 H4 ^) G4 z, l2 W
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

9 H; q& b0 L: n7 F' T' I, @2 e* Q  uint32_t  ImageHeight
; }) t) L* O/ A+ J9 l此参数用于图像高度。% G9 J* f' f2 p" h' v6 G

0 I4 [& ^2 g" R0 V' O  uint32_t ImageWidth
" O- M! D5 o: |( t此参数用于图像宽度。
5 J7 U. K, r- I7 S* s4 r9 t, I% o+ k- m4 R0 c  l7 S! ^
  uint8_t  ImageQuality$ ]+ P* a& d0 _1 Q3 o
此参数用于图像质量,参数范围1 – 100,1最差,100最好。2 @5 e, j: |* j/ b

. U9 @% F- k: r3 z; z( _* r57.3.3 JPEG结构体句柄JPEG_HandleTypeDef% ?# z7 P8 i9 C. V! M* R+ o
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:
6 D1 J- |3 z$ x6 H3 R6 Q% M% ~- N3 e' n6 R! G" j+ J/ o
  1. typedef struct& V8 y! a; W2 I$ \) i
  2. {
    " s3 @1 T6 O' [; z
  3.   JPEG_TypeDef             *Instance;        . ^3 [/ e  C  I$ B
  4.   JPEG_ConfTypeDef         Conf;             , [" H: s% G3 v' V: ?( a0 v
  5.   uint8_t                  *pJpegInBuffPtr; $ e% N7 {( D8 C9 v% ~8 V' ?
  6.   uint8_t                  *pJpegOutBuffPtr; 3 v7 g2 r2 y6 I# H- V# X' W
  7.   __IO uint32_t            JpegInCount;      
    ' ^/ ]$ Z/ n7 r
  8.   __IO uint32_t            JpegOutCount;     
    8 T5 [. ]6 A: n6 A( ^! X: B
  9.   uint32_t                 InDataLength;     
    , L' \& u7 s. k7 p( Z) F/ d: ^! h
  10.   uint32_t                 OutDataLength;     # [2 j7 u* k# n, W* S, ]8 G; d
  11.   MDMA_HandleTypeDef        *hdmain;         
    4 I! `3 Q" l- x9 o3 L* R
  12.   MDMA_HandleTypeDef        *hdmaout;        
    3 d8 o$ B) i; E4 I; Z
  13.   uint8_t                  CustomQuanTable;
    5 ?0 H7 |8 ]2 @0 W
  14.   uint8_t                  *QuantTable0;   
    * w( \. Y6 j) W8 W% c* [
  15.   uint8_t                  *QuantTable1;    # Y2 ~/ A( m3 U6 {; m( |: s
  16.   uint8_t                  *QuantTable2;    - j  H" [3 O0 ~3 E5 N
  17.   uint8_t                  *QuantTable3;          , \% b8 ], \2 q2 Q. L/ C0 {
  18.   HAL_LockTypeDef          Lock;            
    + B3 s# P) U+ Q* U8 O6 Z9 q% {
  19.   __IO  HAL_JPEG_STATETypeDef State;         " w( v6 p6 ?, ^0 N9 [
  20.   __IO  uint32_t           ErrorCode;      
    ' V8 i9 @! [1 K
  21.   __IO uint32_t Context;                    
    9 A- f- n6 x" ~$ _/ r
  22. }JPEG_HandleTypeDef;
复制代码

) [9 J: Q% ~/ Q1 Z' V下面将这几个参数逐一做个说明。
3 B6 z2 Q% ]  e+ E% c
( @7 D/ P% S7 F" o6 y  JPEG_TypeDef   *Instance+ a4 \* [9 Q5 J. Y+ P
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
4 H# i8 P( Z) g& W' d
3 L6 W% B4 I! R8 I: u9 ^  JPEG_ConfTypeDef   Conf
" H/ f: f0 o3 O! W9 d: }; E& r这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。- l6 g: h7 Q- q7 ~( m' Y2 g9 G

; R% h; Z; U. `5 R5 z  uint8_t       *pJpegInBuffPtr
2 D# n/ p9 [2 e) yJPEG编解码输入缓冲地址
! X/ z# t4 z8 o7 b5 Y/ ~$ `5 \4 E& K+ i( f* M
  uint8_t       *pJpegOutBuffPtr$ y3 E4 a1 K3 Z# f: }
JPEG编解码输出缓冲地址- v$ n0 W8 F* }' w' {
; q8 n2 `) I, h# W  m! q
  __IO uint32_t   JpegInCount
% C6 Y  m) t- L0 O0 A7 C* J4 \JPEG内部输入计数。
# R" |) L+ w* |2 R
/ E# J) f" x* l. z( q, D  __IO uint32_t   JpegOutCount
; k! l2 q; |: RJPEG内部输出计数。
- _- a9 ^1 g) v$ _6 ]4 Z, |
& W. Z5 s) `' B/ X. q5 r: {% e  uint32_t        InDataLength
& w9 g: D5 t/ ]- t& N2 U; _JPEG输入缓冲区长度,单位字节$ \! Q3 S7 |% v9 A! ^9 ^% B
7 b/ T3 d/ T% m; C
  uint32_t          OutDataLength+ ?7 ]9 b( M. B
JPEG输出缓冲区长度,单位字节。
8 O% f0 v- h( T: }- H0 O9 x/ r" [+ |# d' K$ I1 d! R3 m
  MDMA_HandleTypeDef        *hdmain- z7 V5 {+ {- z% K
  MDMA_HandleTypeDef        *hdmaout
6 ~3 z" K, Q/ w0 ^4 l8 N2 c1 k) y4 ]MDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
1 C1 d  L, i1 Y% |: Q$ \! ], O7 Q# z0 Z* |$ T, z8 M! `5 N
  uint8_t       CustomQuanTable: f5 k6 G' `  i- B
如果此参数设置为1,将使用用户设置的量化表。- O1 z3 T& D7 ?  T' I: l. m
1 ~0 }3 Q) S( p# M7 q  u
  uint8_t      *QuantTable0;   
# l  s% X$ s  @8 H  uint8_t      *QuantTable1;     & a5 T8 R% M7 H) A: b5 o
  uint8_t      *QuantTable2;    & r/ o: m. Z* u0 r
  uint8_t      *QuantTable3;3 R" c6 O# }. B0 v% v! i! U2 W4 ]
指定量化表地址。   
2 l; E% U8 J4 q7 S- C3 H- \, J1 b0 F, B0 f1 |# t4 I
  HAL_LockTypeDef          Lock           4 c& N+ I$ N2 U) l1 M
  __IO  HAL_JPEG_STATETypeDef State             K4 z0 ?/ I$ i) K$ h) j  x7 s# J
  __IO  uint32_t           ErrorCode      
; W  _. H5 B2 V& Y" k这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。
; x, T, H9 T. G# Z; C4 n
, V9 C% U' A* v$ ^' |0 x! P8 z  __IO uint32_t Context. F( {  q$ E, J* n3 s1 u6 f
JPEG上下文。# ~- r; ]% r9 ?9 E
: Z* F5 S) e2 ^, l0 y% p# _$ b
57.3.4 JPEG初始化流程总结
( e% Q1 I' e8 b) r; N使用方法由HAL库提供:" ]) R; T  P, z; \! x1 Y

8 m, g6 @" S3 s3 F# Z  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。
' h: i6 w% G+ q$ `7 k% q8 i, q0 x, i3 y2 b6 ^. n' j) G/ U: U- p7 J
如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、. P4 T! o+ \7 R* b9 W" i

1 W6 \- u& q  N6 x) L( Q- i  第2步:调用编解码函数% J- }5 o7 K( R* x" o

9 C( o+ h, {* m1 H1 }$ [  i  查询式编解码函数# |, H/ W+ I4 V* X
HAL_JPEG_Encode- c) u4 l' m5 b8 c
  i* o6 P+ [" ?
HAL_JPEG_Decode7 D5 d. D$ |" L- J2 B7 S' x! J

5 F% Z  I6 i1 ^! }# @% G  c# ~! u; H

' j' w& V( t4 {( ?( h4 l) Y  中断方式
# [7 x5 b" h; M1 y* }+ t- nHAL_JPEG_Encode_IT/ |3 g  y9 ?. H2 \  I& t

8 c! X4 M5 G) wHAL_JPEG_Decode_IT
: V" }5 u" c. ]  h* a  |
- P( f4 c# l. Z& ^
, L7 Y, B- T2 g* C. g0 q
$ E- r# n# }) N  DMA方式
2 p# @6 f# E  i- [" k; OHAL_JPEG_Encode_DMA' K+ m; }. J! A; d+ r
0 V, v# `! x# d) H* S( r
HAL_JPEG_Decode_DMA
2 h2 M9 P9 `; j* w4 B4 J& D  a
3 o% O# t% C, C# g  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback9 q+ r. Z2 A& R9 q
6 R" U0 d; D6 f6 E7 t
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
( j2 b$ Q) i7 _0 `! v  E: w/ `1 {* d" ~. ~! M8 X& I2 f, f7 \3 b
如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。# U( E( t3 ?$ l. l( \6 T6 v3 ?( y
. ~& }( Z' F4 Q
/ P& e0 a  g% ?8 o" y; P0 v# ?
(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。" }5 S2 k: z' }, ~, j" ~6 i. K& T
" w( q& K/ K/ g: O8 V4 x! ~
, g% B( k( s/ B' x6 \5 |; f: I
(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。
+ Q6 S/ x0 ^3 U+ X0 a) L' I# N
' q7 c* }- D; Y! }3 I' d$ |3 u* |& J" D/ x
  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback
: z! C* V6 ]& r- e% X  t  p; _0 P2 b! l  N" }) W3 B/ H7 W
(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。1 s, P3 u! U: s; B0 v2 `6 r& s+ C
( o9 L7 b& }, j) Q$ _
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。
: w! Y) q( Z2 z1 K/ i) h4 E% y, Z3 R; g
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。0 B& P( l5 K+ j+ a+ q% Y, s
7 b* y" q% E$ O6 H1 D- y" ^3 G

6 @" E! d7 @/ d3 A, S) ^  第6步:其它相关函数4 j( }' ?  D8 e2 m8 n' M6 l* x
" c+ R  E+ d# H% x2 B
  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。$ i# o4 B% U8 e' Y! Y) {  A. ?8 @
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
% a$ z! ^' D. f  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。2 w/ Q+ a6 @1 H. q' f/ m7 z! q7 r
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。, S6 Z, x: B, B2 |- b& ^
  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。: J& C$ H" u6 K7 L7 L$ p8 u
  通过函数HAL_JPEG_GetState可以获取JPEG状态。( {5 ]* B8 `% U
; q* j- m2 T- O# W  G. t
- W. [6 b7 I) p' e
57.4 源文件stm32h7xx_hal_jpeg.c
/ s! s# l9 Z% I) k( ?这里把我们把如下几个常用到的函数做个说明:
1 K# z: P$ [! ^% z/ b! x& T  x
) u; N0 J: h0 G3 U  HAL_JPEG_Init& U3 b# `: i% b
  HAL_JPEG_GetInfo
: z: d) R" _9 F  g, r3 u$ h* N  HAL_JPEG_Decode_DMA: J- T* b" s9 r6 p
  HAL_JPEG_ConfigInputBuffer
, _2 y5 I0 x4 e6 \: D) a5 d1 z6 j  HAL_JPEG_ConfigOutputBuffer
# e( c+ p  d. {! R# u
9 r2 F$ \' g5 F( R7 H: ^- i7 C57.4.1 函数HAL_JPEG_Init- c9 ?6 p* Y6 P) I" m* ~* c
函数原型:
* {% [7 u: s+ k0 K
4 K) A/ w" K$ r# e" c8 ~
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)
    ( z& _' w$ V0 n5 s! I- ?
  2. {
    1 d, x6 X' Y1 \+ h
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);
    " ~8 K! \8 v% y# E) e
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);
    : F/ Y# |' w+ _% I) I# z( \  H
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
    1 n% `3 |% N" h) X; W) _0 ^
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);
    6 m* [; I7 c  a" J, w9 |) i
  7. 9 g. _( }5 {4 r/ U( l
  8.   /* 检测句柄是否有效 */6 C* ]. i+ N+ F
  9.   if(hjpeg == NULL)7 }" L) m/ P" R" z$ s
  10.   {- z! a! @$ \5 _2 q, D+ ^# `
  11.     return HAL_ERROR;
    3 f, z6 {2 S* s( B0 Q
  12.   }
    ) Y( l& a/ q  X% o* n
  13. * h# ~' o7 T% h6 x( U# P' c# N
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
      k/ c1 U* d$ \( {0 o5 N% Q
  15.   {
    9 J5 C  F/ ~% A) A; g, k2 V
  16.     hjpeg->Lock = HAL_UNLOCKED;
    9 \( T6 s$ e  m- R! U
  17. $ {2 R/ {, o- M) ~) _5 i
  18.      /* 初始化GPIO,NVIC等 */- A$ B) _" M2 z/ b: m# S
  19.     HAL_JPEG_MspInit(hjpeg);
    ' A9 a4 S: @& V  i4 f4 `% s
  20.   }
    : z3 r1 \6 C0 {' T0 y
  21. 5 P: W! [! A5 K, l0 @& C  x! T
  22.   /* 设置JPEG状态 */7 ?8 U3 @% d$ D$ f0 g3 H( f7 y
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;8 q% n1 E, c- S; K( e/ P% l3 x
  24. ' t3 n) m! s9 I* i& L6 Y2 o
  25.   /* 使能JPEG  */$ h6 s9 c" P1 e' }; J5 }: n3 k) c+ R
  26.   __HAL_JPEG_ENABLE(hjpeg);
    9 D: s1 b! h2 K. w% g0 v7 S0 f) c
  27. 6 f- H! ?; E7 K2 ~5 K$ ^# L$ Z
  28.   /* 关闭JPEG编解码处理 */6 a1 \9 i# `$ ^1 N9 t
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;0 {1 N! M! ^6 |: }6 I5 N; }. ?8 v
  30. ( F0 g! m. ]# h! O! ~" Q
  31.   /* 关闭JPEG所有中断 */
    % F. a9 k! D% O+ B: B& j8 n
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);; `$ r( U) {* U: [. n

  33. 7 B: q% U+ Y( g$ H; \5 u
  34.   /* 清空输入输入FIFO缓冲 */
    3 U: O: C  V5 A6 h+ s
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;
    / \$ G0 J9 [. E3 U7 K. P3 H
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    / W7 h# k- Y7 o, M2 L; b$ {

  37. % B* K( N3 ~- @/ g
  38.   /* 清除所有标志 */% K, ?# m" ^" c5 \( ~
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);% |3 B$ E5 V; v1 T3 G  k1 a7 G

  40. ' p" w0 h. }- C' P- c
  41.   /* 初始化默认的量化表 */" f; I0 P, a0 z4 M% a. j% f
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);8 {. X) G  v* N5 k; @( L% M4 C
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);" z6 H6 y, c0 U5 `7 I
  44.   hjpeg->QuantTable2 = NULL;: ^6 B4 h+ r6 `. n( j
  45.   hjpeg->QuantTable3 = NULL;
    + ]' W4 p8 q, y  Q7 E; n
  46. 7 d; f- y) y1 C
  47.   /* 初始化默认的霍夫曼表 */
    , z) P! r% F; S" x( ~$ v" y
  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)+ u  o- g) T& k9 j# P( b. X: B2 C& Q
  49.   {# }( n/ f# v# F, k( r
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
    ( c; d3 Y3 ^& N( I
  51. / c4 E9 w- ]# o5 E
  52.     return HAL_ERROR;) D. D* A3 s" I) E% `
  53.   }9 l# ?7 Z/ ]4 T/ s. a" @4 H

  54. 2 @2 Q5 z, v* J  F6 A) ?* q7 n
  55.   /* 使能文件头处理 */  h7 C( W7 j- ?
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;
    & b8 D! d+ o5 W- b. a5 o) X; g- f% h

  57.   e; n9 B7 ]1 x, m- c; Z. L3 J
  58.   /* 复位JPEG输入输出计数 */
    4 G) Z# w- U2 O5 a7 o- e6 c6 a
  59.   hjpeg->JpegInCount = 0;& s9 M  T7 X* Z1 [
  60.   hjpeg->JpegOutCount = 0;: }8 m; ~7 s' _* G, H- p
  61. 0 ?" C3 h4 B' o
  62.   /* 设置JPEG就绪 */, x' ?6 U" W& E, ~/ F1 l
  63.   hjpeg->State = HAL_JPEG_STATE_READY;
    ( x* c5 ]( Z3 r% D! v

  64. , W) m: Y: |$ J4 s, {
  65.   /* 设置无错误 Reset the JPEG ErrorCode */" Q$ K7 Y" D9 @: K
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;4 P$ t- {5 Q+ K& i2 ]7 L
  67. 8 [9 x3 w4 C* R+ K& c; S
  68.   /* 清除上下文 */
    : B2 J! l- O% E' d& Q8 I: f
  69.   hjpeg->Context = 0;
    9 n8 H" ~3 ], Y$ d- Q5 M: j5 M

  70. ( V: }7 u" [' L! e. ^, \- D  _
  71.   /* 返回HAL_OK */: y8 o. q3 z! ?$ y5 y
  72.   return HAL_OK;
    ( Z, M( A4 L6 }, X
  73. }1 N8 ]7 ?( S: o, S

  74. 2 {% T3 f1 }' F1 \8 w  f
复制代码
; ]2 |; x* [% g" i3 q& B; D% h# c
函数描述:$ G# S1 |: `( p2 E8 `

) a( M% {. ?/ |# C2 R此函数用于初始化JPEG。4 N0 t2 b9 s; v+ C/ d2 N$ h8 q

3 t9 z3 Z* U! b# `2 |函数参数:! T" b& `2 H/ [7 k# v$ v# A% j
! r, w3 b6 `& J
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。' E% V* K0 c! ]6 \) Y
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
  ?% i! O+ o+ N" q注意事项:" X* ~3 u% @( d5 k8 j+ K8 H* ^# N; u

( x0 P) H( T" s7 n% l/ [; c6 \函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。4 n- c! p7 F% `! {/ h# n
如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。
6 ]  t% O1 `& }! f对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。) R/ |1 x6 V+ `# E: u; F
# [6 r  M; g0 l: @6 m+ G
解决办法有三
% E! L! g. w- H* |. P$ `7 I% ^  q1 v( ^( P
方法1:用户自己初始JPEG底层。1 t1 s' O/ r8 Z9 _1 x5 \

9 g/ f& j& G+ L  e# @方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。! Y& S, Z  Z2 Q  ^6 S( K  I

, M6 B* D8 h: k4 U( k6 d方法3:下面的方法2 c: r4 e2 D9 ?1 A( A5 L

( Q2 j: }& p4 l$ u1 z
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
      C) h& p; J. a0 ~' C
  2. {
    + W2 b/ Y! u6 Z9 X( v
  3.     Error_Handler();# G: A' j0 o  O2 ]  r
  4. }  
    ( w/ `$ s% f5 d/ T  ?
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)2 F# v- v- K2 R- g
  6. {( [) \5 ^" P# m* H3 @
  7.     Error_Handler();) V; C# f7 N' t/ f5 {: u8 q# \4 N9 a% e% |
  8. }
复制代码

* c" B( w1 X' I& [使用举例:' f0 O1 S- s5 N8 f
  1. JPEG_HandleTypeDef    JPEG_Handle;
    % g# Y7 R/ ]- E8 i! @: B- q5 i
  2. JPEG_Handle.Instance = JPEG;
    + ^& x" P7 m1 T; r
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

" i, B8 f  m( L5 E7 I57.4.2 函数HAL_JPEG_GetInfo. h8 N( h# u3 A" x4 @
函数原型:  Y5 E7 @  _+ p  R

2 H/ [$ h5 t0 }# M. n
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
    / G  w* L! v8 g3 q9 ~6 ]1 D! S
  2. {# ^0 {& C4 e- ~- k. |$ E4 D
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    2 q+ i# ^2 K# e; h

  4. , M: T; }7 z3 U8 I1 A1 P3 @3 o$ l
  5.   /* 检测句柄是否有效 */
    ) Y" D+ \1 R0 H% n0 s' ^
  6.   if((hjpeg == NULL) || (pInfo == NULL))
    & P/ e9 p9 W/ m! g) u$ M
  7.   {
    ( o# N! G) p6 }5 M. G0 q& D) ~; U
  8.     return HAL_ERROR;
    7 ]! N. |9 H3 @/ k: O. P# G
  9.   }. k/ a7 l8 p- }% a- |

  10. * m+ O+ E3 f2 c3 L" v
  11.   /* 读取配置参数 */
    ; W0 [, d" X0 {
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
      z# J* ~+ B- P1 W
  13.   {7 ?: Q4 x8 W2 o+ C# ~4 }' m
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
    $ W, O) G9 N/ B; ]8 }
  15.   }   
    0 a9 [! w9 w0 D8 f( O5 M" O
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)6 I1 K( {0 G  J( @; w
  17.   {9 |: I3 o/ h+ W0 m+ K
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;7 B( k* f+ a2 z0 r
  19.   }
    ( v6 s7 ?/ R% t9 M- H/ h
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)1 R9 h+ s6 }' Z
  21.   {, y" B, e& e2 H9 f; S6 |: X
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;    # t4 T5 O& Y- c) _5 H0 X
  23.   }' A+ R. z; p! G5 ~
  24. ' z# w+ u' s+ E% M9 K* U2 z
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;/ e4 X2 b: R$ |, `! j
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
    5 ?7 d9 g% b- e4 Y4 I
  27. ; \6 s* H1 Q3 {. V' \/ Z8 b
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))9 N2 {/ A  K# b
  29.   {' L9 R4 z6 ?7 Z9 L6 ?
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;3 O! ?; }9 e8 s8 O  U
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
    : i2 f! m  w! p: h0 A% Z  y* d5 q
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;. |- \' }8 l$ c* ?

  33. 5 q3 W  |# V- w. z- _, O, \
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
    + @# d7 Q+ t2 q3 a6 ]
  35.     {6 C) ]3 t& ^$ {
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/, r* _  z+ m" s
  37.     }
    $ ]2 R; J) Z* H' R
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))" N+ c1 k. v8 i: [$ ]
  39.     {& ~2 g+ Z" I/ M" w
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    6 {; P; z- ^/ ~. M6 @7 \
  41.     }
    6 F- ~5 c$ G, ~! U
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))
    8 U9 _! O5 [. J, Y
  43.     {0 B0 R' ~! F; w9 y0 `7 r9 n
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;# E4 h/ p( D  C# P: B. \
  45.     }3 y7 c8 e0 d1 Z9 L9 Z4 z
  46.     else /* 默认是 4:4:4*/
    & N- ], q% n9 B
  47.     {$ I( z% S6 a; M
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    ; i( E4 A$ e) W6 L& f4 n" I2 N
  49.     }   C* F5 g" f0 d$ J
  50.   }4 s7 `6 V- b8 A7 r; W
  51.   else
    * l8 y. c0 e: b' q# @( N0 f* Y
  52.   {5 `& D6 G$ M' V( i3 D% l1 U3 U$ H
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;' ?& X- E: M$ @0 ~& P  u
  54.   }3 C7 _% a* U$ A. m
  55. 1 p* _3 _* @7 R" ?& i
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
    7 W2 {( q6 _8 y1 x' G
  57. " V. L7 @5 {. m- b. U' {% F9 t
  58.   /* 返回HAL_OK */% M* g& I/ C* C) [; k+ q
  59.   return HAL_OK;
    ' W5 R! X( o0 q  @2 m! Z3 b
  60. }
    , z( L) D# V: r% S
复制代码
0 E, k& e, d0 c# ?, E6 i
函数描述:
2 O% f5 ~" @1 h( e1 c" w! r
, f& s7 T! e: y7 r+ h. [此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
0 R8 h) f4 ]1 Y; Z/ n5 B9 ?9 B0 H+ J' }4 s, |
函数参数:* C$ }; P% X& @6 q& \- M' S
6 P. K& h' h; M# q5 ^( w
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。2 R* a' {8 \6 I( H( W+ S
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小  p3 i' @& {5 [- v! }8 }# H
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
$ {0 m0 t4 G  m- T* }' |0 Q
* n( V) f$ T+ Y5 @/ f
' h9 @4 Y( q- s+ w# F使用举例:
' v* T' Q) W4 G" `) }3 T/ S
  1. JPEG_HandleTypeDef    JPEG_Handle;
    * i" A4 l' \* i- b7 }9 X$ @
  2. JPEG_ConfTypeDef      JPEG_Info;) q/ o. q. E/ ]9 o8 e
  3. . J6 r8 W- B& w8 m8 f8 h: L/ N& |
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

& j! B' Z& Y: u& n$ i57.4.3 函数HAL_JPEG_Decode_DMA5 v' u$ l2 S0 y
函数原型:' l: C6 F+ A5 h

0 q* R+ @6 q  t) g! M' U
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)
    $ |' P  T8 O! I5 E  A8 C
  2. {1 N0 H7 @8 b  c, R# B
  3.   /* 检测参数 *// m. E1 Z5 A( U
  4.   assert_param((InDataLength >= 4));
    % Q- d. N6 S- W7 u0 e6 }, X* c
  5.   assert_param((OutDataLength >= 4));# R$ G9 K2 E2 x, T+ A2 C
  6. 4 n% f: r+ A  c$ [4 I  I
  7.   /* 检测参数 */
    4 u/ J% b( h; @
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))9 C8 i5 v1 i3 S+ O4 P8 j
  9.   {
    # ^+ ]3 A& u& M" ?% G1 J, @
  10.     return HAL_ERROR;7 a0 T. s5 ~- {, f- _* m
  11.   }
    8 F; O: H  t8 n( T9 Y& z

  12. & V( c  l1 b. B9 P; l5 Y: ~4 ]- N9 A
  13.   /* 上锁 */
    ' {, p3 h% ?1 @2 k. E& m2 v, N
  14.   __HAL_LOCK(hjpeg);) g1 \+ B4 C+ G& a

  15. & M# _0 c, o# @4 a2 v1 d: E
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    3 Q7 c) Q- Z8 ?: B+ d
  17.   {. C" _2 y: s  {' F% v& M* j. f7 v
  18.     /* 设置JPEG忙 */, s6 x) U+ t; r$ ]- u
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;2 C1 {: t: f: l) o# [
  20. % z$ ~  L7 w. x; V* K5 b
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */; n, _6 W0 o  x+ t
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    # w1 K2 H6 E3 @5 C7 U' U6 K
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    & I+ x. w" ?/ G5 \8 M% j. \/ |% }
  24. 1 h  K! B: K/ r! B6 X8 ]
  25.     /* 设置输入输出缓冲地址和大小 */9 D) K% ^' a9 H2 E4 S
  26.     hjpeg->pJpegInBuffPtr = pDataIn;$ `7 n( Z7 R9 }* ^
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;
    0 x+ n+ v& R# `4 v
  28.     hjpeg->InDataLength = InDataLength;
      U5 R* I# e3 ^) `$ z, [8 d
  29.     hjpeg->OutDataLength = OutDataLength;
    8 n+ H; j) T% E# c8 C
  30. # Q" x9 _- O! a" ~0 Z
  31.     /* 复位输入输出缓冲计数 */
    % o! [7 d6 _# i5 s$ L
  32.     hjpeg->JpegInCount = 0;    & a8 ]; I! g9 O) t
  33.     hjpeg->JpegOutCount = 0;   
    $ g& H, w* ]% E" U" Y( n
  34. 7 ?8 e% r% f+ C* u
  35.     /* 初始化解码处理 */
    . _4 n4 ^; g* ?  k; W5 g1 \
  36.     JPEG_Init_Process(hjpeg);
    & ^( d* G# b% s8 P5 r6 v5 p
  37. $ \# ?. l' X, l9 Q; a) @4 j' Q) q
  38.     /* 启动JPEG解码处理,使用DMA方式 */. R  t% C! ~# j% n0 Y5 N, L
  39.     JPEG_DMA_StartProcess(hjpeg);
    1 B2 ^' n8 W4 V* g

  40. 5 J5 {4 Q  r2 U2 S" u! p  ^
  41.   }
    5 e' @5 Z! B0 a) r
  42.   else( B8 w( j4 ~" o' r2 z: f5 m
  43.   {
    6 E. l( d1 I$ j2 L2 n/ ~- B9 l
  44.     /* 解锁 */
    + H! |  V/ {/ C" w6 N/ _- B. p" ?
  45.     __HAL_UNLOCK(hjpeg);4 U/ F3 m* t# d% _  I
  46. # c" r9 A3 Y! o* Q) J
  47.     return HAL_BUSY;
    5 E4 r1 K; T6 u% g
  48.   }
    ( h: l/ }) V0 l' K1 ^! B2 c. r' @

  49. 4 G5 g( j' ]% G
  50.   /* 返回HAL_OK */
    9 K  E* M. F/ N# \; C7 k% `2 M
  51.   return HAL_OK;/ q  Q6 c- o9 N% z
  52. }, D' o) L/ I8 q3 v; q2 @) l
复制代码
. I4 A% x4 e+ |; ]/ B: u

, z& z$ Y' Y; H4 m2 ^8 ~8 D: Q函数描述:. P; D) E! N% |# I! Y# j* I$ A# M
" ~% [5 e+ C# _
此函数用于启动JPEG的DMA方式解码。
: p" ^" F$ x3 \! J0 _5 T$ Z
6 p9 X0 ~- b" d3 v; L9 J函数参数:1 H* o% c- Z( i1 p+ P" x4 r
7 c, Z8 x, n% b# C- n
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
5 m% E3 H  l0 z  第2个参数是输入数据缓冲地址。5 G0 s( I+ k, L: b
  第3个参数输入数据大小,单位字节。
: D! i2 b% L* u, m) w3 m& o  第4个参数是输出缓冲地址。
4 ], m+ R& h- n  第5个参数是输出缓冲大小,单位字节。' Q& A. A+ r/ E; ~& q3 g+ f5 a
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& T6 h- S9 k" L/ H3 ?) Y: i4 u8 U# ^' \' @' g1 ^( g1 v: V
使用举例:% u( H) d) R8 y9 k9 n! ]& W
& E( x# @4 \% M3 h3 J) E& ~( n
  1. /*
    5 k( [0 p4 Q; a4 Y
  2. *********************************************************************************************************7 Y. L5 h0 A& E' z& H1 Z. _; |
  3. *    函 数 名: JPEG_Decode_DMA
    4 i$ F" ^& k, S
  4. *    功能说明: JPEG解码
    & b) t; ~  U/ s$ l
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针
    , u5 \5 e" E& v8 H4 k2 p
  6. *             FrameSourceAddress  数据地址
    ( p% H( u6 C2 l
  7. *             FrameSize           数据大小
    " |6 V* R% ?2 Y# H: |& f
  8. *             DestAddress         目的数据地址. q9 G, L/ w* i/ R5 d
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功' Y8 O& P7 x7 Q* Q# c- Q; N
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出$ O4 X5 {0 j  o4 c) v$ ^
  11. *********************************************************************************************************
    ' c  ?. s3 W% \" _
  12. */2 M  t( L6 \4 L) w8 `8 z; L
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)9 i" F2 k+ B/ h3 ?
  14. {4 h( d) i! f) E
  15.     JPEGSourceAddress =  FrameSourceAddress ;
    3 l3 ]" c7 M0 E+ n) y7 ~
  16.     FrameBufferAddress = DestAddress;; J; A. A3 }& f8 F$ K- ^
  17.     Input_frameIndex = 0;) [# o0 g( u3 b% B: z
  18.     Input_frameSize = FrameSize;- x0 v1 j2 H+ e

  19. # y" @5 D4 r! R  ]0 c
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */1 Q& B: f% |( ?) o# x, E
  21.     Jpeg_HWDecodingEnd = 0;& V, M( W. p3 \* L5 x/ ~
  22. 8 `( P# A; T% K& D2 z
  23.     /* 启动JPEG解码 */
    : _* o+ Z8 A2 _0 K; c
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,
    ( J5 z  {0 i1 Q: n! g8 n& W
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);; e0 t5 U- G- p8 D- }: V, v6 J* [1 f: j
  26. 9 [" j* ?) T* S
  27.     return HAL_OK;% R6 H' k, i, D$ [. s. f4 U
  28. }
复制代码

/ A  D, O$ A- u" f! u57.4.4 函数HAL_JPEG_ConfigInputBuffer
# k) [& Z/ m# J函数原型:! M0 U( y8 T" W! o- W1 ^

5 b( ^8 p$ x$ S* H
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)
    , B5 `" y* F& m. m% z' t3 f
  2. {
    $ m6 G9 F  q3 H, A+ j- b
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;6 G9 e0 f1 X0 ~! \) f- ?
  4.   hjpeg->InDataLength = InDataLength;
    5 x5 A1 D+ C. U- T8 q
  5. }
复制代码
+ y& z* B2 Y" Z
函数描述:6 ?/ I8 m) R  e" ~) O
3 }) Z2 n' q8 K* J4 g
此函数用于配置编解码输入缓冲地址和数据大小。3 ~' k' ]# g  ?' h  t

- C/ s( J: g$ f- `4 z6 C. R函数参数:
+ u: j$ e8 F  P1 @2 T& j/ J
4 t1 ~( i. a. E+ l! \; `5 Q  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
+ P/ g4 Z2 d$ S  第2个参数是输入缓冲地址。& O  f3 J" l- [4 @9 r! w
  第3个参数是输入缓冲大小,单位字节。
6 ?3 r$ K4 s, }' H* ?- N  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
! z' i! W1 }% [7 h7 X) d. ~使用举例:0 @9 H  w; [0 ~3 b: ^
8 _  s+ C5 J) Y& w
  1. /*
    ) f; r3 _8 s) d- n7 {
  2. *********************************************************************************************************  [4 ^+ m% T- r  d6 ~* B; m
  3. *    函 数 名: HAL_JPEG_GetDataCallback1 r- t) o$ ]  b8 }9 n  i6 S; X
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    9 T7 `' D# }5 g* O) l
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
    5 _8 U4 r( q% I& J
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  
    ' d: T  q0 B& }! `# q$ n
  7. *    返 回 值: 无
    : {; z$ z, J, L3 \% i( p
  8. *********************************************************************************************************: w$ n2 C; `- u
  9. */
    ; Q' h; Y2 s- h, x0 M% n& x5 ~
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)
    1 M. a' D" P% ?( d# _/ A
  11. {: S9 l' Z% ~6 p) H9 s8 {
  12.     uint32_t inDataLength;
    2 m1 L- ]. p  i

  13. 4 f$ s, d, N+ x! H  J! s6 M: p
  14.     /* 更新已经解码的数据大小 */
    / |% p  R9 `  k  V7 d
  15.     Input_frameIndex += NbDecodedData;
    5 Q& [# V, Z" Z9 _6 C/ I; g- `
  16. 1 ^: y6 Q% h- k0 z% B" c$ s
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
    , K2 M8 G9 X% H) b# t
  18.     if( Input_frameIndex < Input_frameSize)- q" t( Q1 B  ^1 C! H
  19.     {. K- B# {; n- S! o
  20.         /* 更新解码数据位置 */, F7 W+ W5 @8 I* D0 J
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    8 Y' ?* M! f7 h) V. \
  22. , i2 d9 K7 _* S( V  @/ C# ]- _
  23.         /* 更新下一轮要解码的数据大小 */
    6 Z3 d0 k  E) n  W( \' f
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)% y5 U9 k, b* i1 B% q% `$ B! s
  25.         {
    ( t; c$ d7 F9 n6 a  {  ^. o6 i
  26.             inDataLength = CHUNK_SIZE_IN;
    3 y: _3 R2 r% N" }  i( Y: W
  27.         }
    9 d0 \: h" B7 R
  28.         else0 `8 R' K& ~. C2 s' P
  29.         {: n! L) o) P- ^. b$ e" [" @
  30.             inDataLength = Input_frameSize - Input_frameIndex;$ w/ B+ t4 I' j; U! k! H) d
  31.         }    5 D3 }+ v6 f9 d7 C9 S
  32.     }
    ; Y2 m$ x1 P1 P9 M" q
  33.     else
    5 i2 ^9 X# _6 X& H/ ?. I% b
  34.     {2 b( N' k( ?% v: _  ]
  35.         inDataLength = 0; 3 P5 ~+ K6 k/ b' [+ k
  36.     }  f  L' W6 d" J4 M5 W; C

  37. % r: ~. s; r/ S4 w5 x! T* G* _0 j- L
  38.     /* 更新输入缓冲 */
    4 f) o* S2 U* a$ C- p5 M2 j
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);   
    $ r+ |# C) g) e  h. x, Q
  40. }
复制代码

$ M9 k7 B' B" c8 ~4 C
& v) Y! q6 m$ P: {* _57.4.5 函数HAL_JPEG_ConfigOutputBuffer
% C+ i) K; M: T. @函数原型:6 d5 g8 V* Y( Q, Q

4 k( N8 C5 y2 c, u: i
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)- p8 t' _7 \( `- u* m
  2. {
    / [$ _$ y. p" e( j
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;7 l) t5 Q9 i1 M) ^4 S
  4.   hjpeg->OutDataLength = OutDataLength;  
    9 e; Y. E6 h; s/ O' `! s2 n
  5. }
复制代码
1 p$ O( |6 \# H) j( z6 `7 p6 W
5 I  Z+ h3 ~/ S( G( [+ a
函数描述:
& ?3 t& }1 z# ?, x, H0 @% t2 t: U% R
! w4 _! R3 U/ i; m& j7 m此函数用于配置编解码输出缓冲地址和数据大小。' p1 w/ W# [  D# {" P

; v6 G2 ?$ J& N" ?# o$ L% m函数参数:. D/ q1 N: A/ i$ ]2 r7 ?

1 |4 v: v! ~1 S! L) C  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。6 D; Q) D( B( I% E
  第2个参数是输出缓冲地址。
: y9 n+ j0 w0 G. E  第3个参数是输出缓冲大小,单位字节。8 g$ P" K3 W; I2 q8 f. B, v
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
& a% Y/ l8 R4 k* Q使用举例:* A& p3 r5 @; z; Y

; `1 s) y- |) U
  1. /*' Q% z$ C6 s* R8 B1 h# r3 P
  2. *********************************************************************************************************
    , D' O+ u0 E/ N# W! |- `& e
  3. *    函 数 名: HAL_JPEG_DataReadyCallback
    $ p6 w+ g. s' s3 r
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新
    # F, m- z0 d! H7 U
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针% H0 V% f1 E- t: Q8 B
  6. *             pDataOut      输出数据缓冲0 I& q/ f7 g) y3 l* k( c
  7. *             OutDataLength 输出数据大小,单位字节3 \2 L5 |! b' C! B' s8 a7 N
  8. *    返 回 值: 无: x& J: Y1 a5 d* [6 }. d# G0 d
  9. *********************************************************************************************************
    " ^- {7 L0 g) G
  10. */+ @9 ^1 y( X7 ~% T. o
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
    7 l. H, M. _3 }, s6 {6 _
  12. {" D% t/ O& m, B: B5 e  X- S$ n# @
  13.     /* 更新JPEG输出地址 */  / ?5 ]: ?5 ]/ M8 x0 O5 N& i
  14.     FrameBufferAddress += OutDataLength;+ l+ g; M6 X5 d- L( B! \, v
  15. : O5 e# \6 e- [' u, V
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT); & O9 z5 r  y: C! T7 v! C7 v3 Y5 e
  17. }
复制代码

7 F# }# m; }* i7 v  v! W1 J57.5 总结
( D) ^! @; D9 l/ ?9 b本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。% e  y- k, D& y% w5 s( R

) |% |/ K6 l& {1 [. H) I* b. Y( D: X  Y9 {5 Z; ]$ A

2 u2 ?# k8 ]# e3 u
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似分享

官网相关资源

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