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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示$ l; a" u6 @0 l) U: D. {' P' W9 \
  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。
2 H3 X. b; @! C0 E" |8 K  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。
- F. T, V8 y% r& I( }, @4 ]6 j  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
5 k: u2 l9 _5 T4 W2 F  A  本章JPEG相关概念的介绍参考了wiki百科和百度百科。6 B* M1 e& O! I* w4 [6 p2 Q& H
57.2 硬件JPEG基础知识
+ _5 e, s; u; p. r6 f
对于STM32H7的硬件JPEG了解到以下几点即可:
' Z# n( T- l: L# M3 a; m6 N# [6 ~
; ]3 X) d6 X! S3 w$ x' {$ w  支持JPEG解码和编码。
8 i: U1 @9 S$ P  对每个像素数据进行编解码只需一个时钟周期。
4 W. ?* u6 m* K: Y& _- a7 Q) o: R9 T! T  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。
8 |/ p' D. q0 e' y  编解码时每图像分量8位深度。' f* k0 v2 Z, E; |8 N2 V- |( ^" k
$ R2 [  B& O7 }* d  N& t. A8 t
57.2.1 JPEG硬件框图$ F: a/ X  ?: O) ?+ k
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:  J! i5 w, L. V& R+ J$ |

5 G7 J: G" Z' g  G
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

7 U, d" \/ g( C# P
# l% t' _3 c; T8 F3 s. I通过这个框图,我们可以得到如下信息:6 `6 i/ d; N! x% o7 F. H) l1 ]
/ F" s4 T# [0 C$ }: o# D! P
  JPEG硬件外设支持编码和解码8 @; y- `' K* z! w4 J3 Z
并且对于输入数据和输出数据都有FIFO支持。0 e; y3 Z! N- f* a
1 r0 _, }+ n) i+ }) E
  jpeg_hclk
) ]; ~8 y7 r) n* O; i) V1 @为JPEG内核和寄存器提供时钟。6 ^' ?* p% N3 S  `" ]- J7 ?
% b8 g! r9 c- x# m) f8 `
  jpeg_it2 o0 \/ z! D% [- H
JPEG全局中断输出。- v( _3 s6 O9 K5 l4 m6 a: Q; H

' \9 u" q0 O/ z+ I2 V  jpeg_ift_trg
1 s0 Q( o( Z8 k. |$ E9 Y# bJPEG输入FIFO阈值信号,可触发MDMA。" p( r/ l8 m# Y; E; M* z& G( H4 `

! ?3 O' {9 i- z, M. A+ c  jpeg_ifnf_trg6 ?2 Z% C) w2 l
JPEG输入FIFO未满信号,可触发MDMA。
, f7 n/ ], l8 s- Z* n( R& e/ {; K- s7 W
  jpeg_oft_trg# F/ z) @: s% }( t) P# f% v9 a
JPEG输出FIFO阀值信号,可触发MDMA。  c& v: I; e; p9 q* z

$ d' `' O$ L8 D/ E( s5 P: O  jpeg_ofne_trg
( H9 U# i3 K0 u; M  A& \9 T' b7 {JPEG输出FIFO非空信号,可触发MDMA。
& Y5 A# ^; X& R* a" d1 l9 _; f8 \7 r& D5 U# O1 f8 k% O2 _
  jpeg_oec_trg! f, l. u7 c$ f& R& r. Y/ P
JPEG转换结束信号,可触发MDMA。9 b! |2 z7 t2 `% R

. V& X* z' U- f: e3 I57.2.2 YCbCr颜色格式
$ c, K' z! v* V% g  L(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)
- o3 M) p' Q$ |
- D( t+ m  t8 C. o* a! g+ U, `正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
1 H1 t: w3 m3 k: w5 W
  }* W% C! m* ?. u  K' c& MYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
6 P: P% u; A" C# |& ?* X( U
2 L+ L: ?4 Q% U4 ?在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。- P+ T& U- g) \: }9 j

% u) W  T6 m  |7 U  E7 s57.2.3 YCbCr采样格式/ Z% ^, q7 z0 h7 x% [+ I
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。2 g. O+ F6 D6 d9 U# g

! `' J5 h* k5 p5 S  4:2:03 T5 j4 X8 A8 t6 c; G
表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
7 e, W8 D6 R, U" ~+ H1 |9 W& _9 u. p8 n7 A; x+ X# p& b4 E% ?
  4:2:2
# t' V4 N  H9 C# z表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
' ^2 N' V2 k0 ?- p1 J" T* b0 h
  4:4:4* r/ ^, G5 ~3 Q2 J# g
表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。: [+ i" H% {, d- u* H+ h

* P4 F& b, a- b$ B具体的采样方式如下图所示,以8个像素为一个单元进行采样:- o" Y  R# c3 B8 ^
5 e( R4 R2 ^. D' o5 B$ T0 b6 ?$ O, H# b
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

/ O% Z: E1 i: J. g3 w
4 N; ?& [$ o# s" r* u" }# f由上面的截图可以了解到:: X; Z7 V+ q% W+ l7 L

! c3 B/ {  V1 Q. |0 L4:4:4表示Y通道,Cb+Cr通道全部采样。
5 e3 M$ z% o$ D9 H3 e( V. N: ]/ _1 F( V1 q4 l6 Y  E- b
4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。
0 o5 [$ b6 e7 s
) L, z" t- H, M) n! [( `1 q! G4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。1 k% I. [' C+ M) ~. C+ A
. b. e- Z. O$ W8 }0 y
下面是整体效果,方便大家更好的理解:
3 }1 a* b/ p( \% h
+ f* \; K0 m0 Q; x" b. X/ W
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

6 e  m5 b0 J& P8 e& z2 A, N% o
* y3 y: U& v# @: [5 e. K* q
5 d6 @. _& R$ a6 j/ S/ X8 O2 d8 ^! e: q5 D
57.2.4 YCbCr的优势: h' Y, Z, I3 z! g
RGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
( g1 a; \+ R, ~- F, V7 H" ~: h. ]; K- W" c" D0 [) [; l
57.2.5 YCbCr和RGB互转

) }) C- t& `5 u6 ]3 `& o为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。
9 [: @) @  U+ n- Z8 j$ _5 @2 n. B, r, ?0 g9 C
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
0 }! y! b, r) m! w9 V3 p
8 P( a6 d3 w! J6 c7 N
下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
& V0 ]: r5 D7 D+ j7 s; g8 V% \+ j, d" x- j9 T
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
5 F: t0 e& z/ Q. t
2 Q* D- Y, _( x# x6 `" l' ~
57.2.6 JPEG编解码知识+ D4 Q! f1 c7 I  t! m$ O
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)
7 A/ K. X( ]# ?- `( F5 c
: l' }% s; `- C. C( [57.3 硬件JPEG的HAL库用法
0 ?# j  s# z/ N7 D% `: ZJPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。
  S0 I( u' l8 ?; t+ s+ V& A6 O* q4 l2 _$ r$ j
57.3.1 JPEG寄存器结构体JPEG_TypeDef
+ S9 X* B* h/ j2 g# pJPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:) s/ o* [2 q) M5 W! R" B

4 G1 V: y; h: N
  1. typedef struct
    ' x4 ?( X& U3 h% t: m- K' M
  2. {( h) z* o2 {* Q
  3.   __IO uint32_t CONFR0;         9 G$ G+ s, @) {9 k7 [% P& k' e
  4.   __IO uint32_t CONFR1;          ( W! P# }* Y  E2 Y; ~& ^
  5.   __IO uint32_t CONFR2;        
    % X2 k+ z+ N$ Z
  6.   __IO uint32_t CONFR3;        
    : p) ]5 r+ j8 v9 V+ ]
  7.   __IO uint32_t CONFR4;         
    1 }# L, `+ S2 ^/ r+ C$ J' X5 q
  8.   __IO uint32_t CONFR5;      
    $ }5 s( O( G: E! D6 R6 I" D: H
  9.   __IO uint32_t CONFR6;      
    3 |, K: r$ o- l" _+ t) b9 L
  10.   __IO uint32_t CONFR7;        
    7 T7 R7 Q5 V4 i) _
  11.   uint32_t  Reserved20[4];      + U' V( m% K) S& T" _& Y" L! B
  12.   __IO uint32_t CR;             5 E9 B6 \! {% N
  13.   __IO uint32_t SR;             . n. ]& l4 L2 v$ E; v. k
  14.   __IO uint32_t CFR;            + X, z  L1 K/ G) U
  15.   uint32_t  Reserved3c;        
    " G( b% y* |7 x; r0 M* g
  16.   __IO uint32_t DIR;         
    : O. e# Q3 y$ @) n- B; _- Q
  17.   __IO uint32_t DOR;            5 l; M4 i: X! x% F( g& K
  18.   uint32_t  Reserved48[2];      
    * e6 ^" o* q# S* S; Q5 w+ `3 i
  19.   __IO uint32_t QMEM0[16];     
    * s, B* R' D5 k7 j9 B, E
  20.   __IO uint32_t QMEM1[16];       " p3 \6 T$ e4 ~( l
  21.   __IO uint32_t QMEM2[16];      
    / E0 D: \" n* h) V4 u4 D
  22.   __IO uint32_t QMEM3[16];      
    - B" J; e- a0 e7 ~+ n; C+ u+ g
  23.   __IO uint32_t HUFFMIN[16];   
    " R+ \3 |7 b( d: C/ ]% J
  24.   __IO uint32_t HUFFBASE[32];   + y3 ^5 m9 X4 C9 e
  25.   __IO uint32_t HUFFSYMB[84];   $ p3 {( C8 i5 w: a0 q8 @" y
  26.   __IO uint32_t DHTMEM[103];   ( p& @! J4 u. f$ n2 R4 F
  27.   uint32_t  Reserved4FC;      $ H1 ~# _5 h) e! h  M2 ~: Q
  28.   __IO uint32_t HUFFENC_AC0[88]; ) U- A  o; s! W6 q% S) O4 M+ w
  29.   __IO uint32_t HUFFENC_AC1[88]; 4 p% @# e. i; d% A+ _  Z; A/ n
  30.   __IO uint32_t HUFFENC_DC0[8];  
    2 V% A* H2 ?% m! D+ n; ?1 U
  31.   __IO uint32_t HUFFENC_DC1[8];
    ' U+ o! r0 j: B# b) E
  32. } JPEG_TypeDef;
复制代码

% u6 T7 k$ |& y# s$ S5 Y__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:' f9 D+ @3 @( J3 t8 G& a& t+ D
+ S+ h8 R! e+ [: @7 U
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    8 a: F. o1 J+ a+ h
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

5 d- ~, |: B6 y9 s& j下面我们再看JPEG的定义,在stm32h743xx.h文件。) P' `4 B0 |$ M" ?

% Y! m$ M' g: N- ~3 Q
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)/ w  I+ G" N: M2 g, B* T6 H
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)* A1 x8 ^& x1 o: h5 p0 A
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)# A1 l  a+ K) N& g( y
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码

( `; x3 [+ G( F0 o& e0 ~我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。
; A, g  p& A# M* e( p, H7 `- ^0 B5 l, D  x, k
57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
/ \0 k/ q7 c+ k$ A/ L- x5 b$ y此结构体用于JPEG的编解码参数,具体定义如下:* m- l" g  L" R; w4 i
6 e5 Z$ b& Q3 i! F' y6 L
  1. typedef struct4 S& Y8 @0 h+ v4 u
  2. {2 P) @) T( `. f2 P% Z
  3.   uint8_t  ColorSpace;               8 J( O9 N  s9 P1 ]/ H# b
  4.   uint8_t  ChromaSubsampling;        ( I! W; ?, l4 O- k% f
  5.   uint32_t ImageHeight;              
    , `2 u. Q' ?( \# U5 t
  6.   uint32_t ImageWidth;            
    $ {& n! N$ I9 E0 L/ F& r2 H
  7.   uint8_t  ImageQuality;                 `/ ^( t, K! h) I( g: ^4 j9 T- I* R
  8. }JPEG_ConfTypeDef;
复制代码
8 m- F( ~; y" P- A
下面将这几个参数逐一为大家做个说明:
: d! @1 ^; S/ x  uint8_t  ColorSpace
0 d* W8 X' y7 d: T- |
9 T% L. J( t& {) v6 b) i% p) p" [$ b/ d; ]9 `2 h: z
此参数用于设置输出数据流中的量化表,具体支持的参数如下:
# n  K9 n- v. y, J
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/
    ; @# ]: m" E. ]' D: K7 T9 [. X- {. f
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */# H/ d$ X& E  |8 @8 R
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码

8 a: F0 ^: D; c7 Y2 r  uint8_t  ChromaSubsampling# \4 Q# L* T" F' P: g
此参数用于色度子采样,具体支持的参数如下:- N# F+ d1 P( O
, c$ O: o% ]% q- {; h; q: m
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    6 C0 t$ Z6 n! U7 c' H6 j0 R
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 *// u1 F. b# Z2 d+ E! }' ^+ B
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码

3 z9 F4 l1 Z  d  uint32_t  ImageHeight) @! ~, P0 h0 `- I
此参数用于图像高度。4 n- l' }2 h( l  Y3 ~' T1 J0 i

) E' U7 C: ]8 ^. O/ Z- Y  uint32_t ImageWidth& a( V; Y; H4 A2 D
此参数用于图像宽度。
6 J6 L, r4 G9 f9 c) B& x# k# C9 ~/ U7 @* n( T( ~) t
  uint8_t  ImageQuality, u9 }/ r/ ?0 h# G' n+ j
此参数用于图像质量,参数范围1 – 100,1最差,100最好。3 t$ V/ u5 C: ]5 R& V

$ j$ o2 z4 Y  j% o& D' }$ ~57.3.3 JPEG结构体句柄JPEG_HandleTypeDef1 a+ i8 d0 `4 B, p9 q0 d: T; N
HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:6 \2 g4 [# U0 H6 S6 \

" R$ p/ \! ^4 {2 I
  1. typedef struct
    * P; W7 Y; p# }# d- I
  2. {2 c) N" E" S  x+ X3 j/ m, ?! e
  3.   JPEG_TypeDef             *Instance;        - K- ~5 S/ C/ ]6 V9 l
  4.   JPEG_ConfTypeDef         Conf;             ' ?  p% E% A- d2 U! T) U+ C
  5.   uint8_t                  *pJpegInBuffPtr; 9 `6 y- F7 s' q. m
  6.   uint8_t                  *pJpegOutBuffPtr;
      S7 F2 p$ g- B- D( p6 p
  7.   __IO uint32_t            JpegInCount;      
    $ g4 L$ `  c  w( m5 _
  8.   __IO uint32_t            JpegOutCount;     ! c" c# T, D* {8 w; i) N7 \
  9.   uint32_t                 InDataLength;     * E' V$ `" K9 i+ ]8 T2 v
  10.   uint32_t                 OutDataLength;     
    % Q2 S0 `2 y1 B+ N' K
  11.   MDMA_HandleTypeDef        *hdmain;         
    , _! s1 D9 V* ]8 g5 W
  12.   MDMA_HandleTypeDef        *hdmaout;        ! ^" u6 t( N* d! x3 d) N9 P2 v9 n" D
  13.   uint8_t                  CustomQuanTable; 7 {5 p2 O% l" B( ?3 s: S5 p' |
  14.   uint8_t                  *QuantTable0;   1 X3 \' j% d" ^% H9 |# {
  15.   uint8_t                  *QuantTable1;      T& \! O# }3 q! @$ V
  16.   uint8_t                  *QuantTable2;   
    : i) ?$ W, V) y, K
  17.   uint8_t                  *QuantTable3;          . z0 M+ L9 G& o& u/ ~
  18.   HAL_LockTypeDef          Lock;            % Y% |$ o( W3 N% V3 X
  19.   __IO  HAL_JPEG_STATETypeDef State;         
    1 P; Z7 X7 N2 C5 ^5 z7 n. V
  20.   __IO  uint32_t           ErrorCode;      $ Y( x( y; ]/ T5 `) \
  21.   __IO uint32_t Context;                    2 i* F% o3 ^+ Z! g- s
  22. }JPEG_HandleTypeDef;
复制代码

, b* ?+ H8 O2 C: ?5 ^2 Y. M) H下面将这几个参数逐一做个说明。+ c# G% `4 K3 Y
5 g$ [& \3 V0 n7 O
  JPEG_TypeDef   *Instance% L- a. X) e- l4 M5 }; l
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。9 f3 ^& _1 L- R, S  S2 q

( F& Y6 |6 v- w2 F) J  JPEG_ConfTypeDef   Conf( N7 y* G) M& Q* C8 `- s
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。
9 y; S7 Y2 S% o% L7 u7 \; w
' _' k% b% S1 U& X  uint8_t       *pJpegInBuffPtr
1 @6 d, C/ k6 u: U7 {; i* e, UJPEG编解码输入缓冲地址5 I4 a* @: j$ S  s

: ^6 R2 {! z1 B' C4 K  uint8_t       *pJpegOutBuffPtr& j: o$ @3 e: S: w
JPEG编解码输出缓冲地址
7 D( `( k7 j% Q2 x' i
# }% y0 g; [7 Z" a" \  __IO uint32_t   JpegInCount4 l& ]2 [1 l! @5 m6 V. i
JPEG内部输入计数。
% y# c9 T7 M2 g. A/ s5 H+ `: k5 ^8 B  Z
  __IO uint32_t   JpegOutCount, B! U+ M/ Y( P1 W5 A3 \( G
JPEG内部输出计数。
# y$ X0 e' E; ^
3 q- H1 {/ x# ^  uint32_t        InDataLength0 s! U8 v  @6 P$ e" X
JPEG输入缓冲区长度,单位字节
. X2 T8 h9 P5 e
% y0 x& C5 @/ _& m2 o( D9 q) \  uint32_t          OutDataLength1 x4 u3 U% U6 |$ D9 _9 ]
JPEG输出缓冲区长度,单位字节。! j4 n$ g0 h6 L% c

, m+ v/ R6 L3 Q1 E0 f' f) m  MDMA_HandleTypeDef        *hdmain
, g3 i* L$ O2 u- P% _  MDMA_HandleTypeDef        *hdmaout
7 g) t4 i. C7 x) ?; I3 Y! c5 cMDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。  k% D8 U. R: p' h2 u
( k9 d( ^8 n+ z6 L* ?: o3 _
  uint8_t       CustomQuanTable
5 L% n8 [( H$ x5 q# M如果此参数设置为1,将使用用户设置的量化表。
7 ]$ Q; S* ?& Y2 }' H3 a8 x8 ^- h
  uint8_t      *QuantTable0;   
5 h2 ]" {; ?; J: |6 G' v  uint8_t      *QuantTable1;       A( A6 Q) p* z( Z9 W7 T
  uint8_t      *QuantTable2;   
/ s3 D. u5 a. L& i- p  uint8_t      *QuantTable3;  t7 ^4 w6 ~( d) g# J; u
指定量化表地址。    . d5 ~6 i0 u- X" a; y

- r" }0 w+ S" F- K4 g  HAL_LockTypeDef          Lock           0 f3 G1 J$ z) @  T( G8 `$ R; \
  __IO  HAL_JPEG_STATETypeDef State           7 s9 t. t' n+ P
  __IO  uint32_t           ErrorCode      
0 t9 b! x2 ^# v' u- y( H8 j这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。9 s# q; N9 |1 U
4 d( |& o4 Y1 d3 Z& C
  __IO uint32_t Context# i1 }, Z& _3 L& D( z
JPEG上下文。
8 M, r3 L- e' \* a6 h! D$ `6 \
: a% I* k6 j3 k6 V( t/ X57.3.4 JPEG初始化流程总结/ J( K' G( ]% n
使用方法由HAL库提供:8 J% [' M, V( w* ]- ^4 S
! U; T- y5 O7 S: J( ?' L- `
  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。, ~4 Q' q/ B6 k1 C0 G( V- t
1 D5 W& {* j; c
如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、* e4 V2 q3 |) J$ i7 T. F
7 s' X2 z# d! [" j& ?* a2 t. F( f  ~
  第2步:调用编解码函数8 W; V# _( r1 C( k9 R, T
  f% v) W& a% ^3 t( c2 m3 c* [
  查询式编解码函数( T- M, s( J) t; F- I% u8 m
HAL_JPEG_Encode6 N! ]' a! w3 v$ x- w. n
, g& o  g( z0 I4 w$ |* W
HAL_JPEG_Decode. y! s4 ^5 y: @( e' X5 g
3 [4 _' G' M" W! a0 A& p

: T) k) M. K5 K6 [3 G/ f" H/ u( s% C
  中断方式* N- P. d. c. [: f& `/ n; r
HAL_JPEG_Encode_IT
9 Q6 R' r- P! _8 s1 A& U
3 e% m0 B% M+ B% OHAL_JPEG_Decode_IT# }1 i6 [- ]0 X& l& M5 @

6 Q. t& ?* u& H& [" F2 ~
) I3 E( J5 `1 R& ^+ j3 k0 U" C% r
# \* I" ~5 h4 a7 s  DMA方式3 g8 O' g3 [/ `) g
HAL_JPEG_Encode_DMA+ X1 Z) q$ K7 o

2 h8 T9 d" R. e% h! z  GHAL_JPEG_Decode_DMA
7 Q; b9 h3 F1 a1 q' L! ]) A* a1 g: h. L$ T: N
  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback% v) D4 L( f2 Q# j) b* |
9 t5 f! u$ r2 Z# {. [4 B' X
(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
. A4 m- {9 u$ Q1 r1 f: b/ _
$ K- v1 r0 @; i如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。: B) b" D: ?( K; o7 ^, @
& T9 `% z5 \9 `! @5 S

- D' H' z: m. w5 Q' j- P9 \" L(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。' L6 X4 ?. |: \1 Q
' n/ v# y: {  H
8 F1 E5 [+ f) O9 ]6 f
(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。: T4 p; k, I) x$ v1 q* H3 H0 \

. M) J" ?  V6 v( U" c% n4 b& t" }9 a) x" U* B- Q: a- l1 h! `: h
  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback
" G" m( P, g4 Q! J
8 Y2 ~1 W3 b+ A  y(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
# b* B2 c& v& y5 d' w( e, g6 `! p& h. f5 r5 I' Y3 S
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。1 a- g' X$ r" e% W% J* r/ b
. Q. K+ d6 p% D  B1 e9 f; K) G  g
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。
2 B( x" j5 H/ Q! g9 a2 p( W; O: ^, m; Q  L& x3 ?

& t' E# U' B: e2 Z8 G& j4 S  第6步:其它相关函数! I" c, K/ |5 V
( C7 {6 U4 Q/ i0 z2 D$ q  o* L
  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。, ]5 }, K$ `" e" M
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。
. Y/ G( J. B3 [* Z( U  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。5 [( m& [% g; D& F' G
  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。
& s% W! \6 V! W, O  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。% h3 E! m0 A. z* B
  通过函数HAL_JPEG_GetState可以获取JPEG状态。
( f% ?/ N: x2 O, l
( e+ v( E+ I6 b4 E5 {) q" @7 @+ s5 y/ n" l' H- R
57.4 源文件stm32h7xx_hal_jpeg.c
. B3 o  f# L$ A2 @6 x/ a这里把我们把如下几个常用到的函数做个说明:
. W, B+ u9 {' h/ o( T+ _5 ^  J+ _- B4 }$ c, a
  HAL_JPEG_Init, z  P% L, k: v2 Q
  HAL_JPEG_GetInfo
7 c/ Z" A1 c2 z* b% A4 P8 X4 F' L  HAL_JPEG_Decode_DMA  T$ n" l. n- k- V, ?/ @
  HAL_JPEG_ConfigInputBuffer# k2 O- Y; ]3 q
  HAL_JPEG_ConfigOutputBuffer  [6 @$ ~1 z2 v% l

% V+ z; B# }8 \# H8 F  M57.4.1 函数HAL_JPEG_Init* w7 I- ~3 S1 o3 [5 _* T4 p
函数原型:" B, `$ m9 ]$ b& q
3 Z9 M1 W; O0 s; m3 Y6 O; Z* w
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)* u; c+ ~" y+ t
  2. {2 T8 [, e4 e# A# t
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);. u5 n' F& P- ~9 f0 N
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);. y8 }: _& d& T. r
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);9 ]5 x- T5 o7 ?
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);
    ' }2 Y% m4 Y0 i  K

  7. 6 O% T! o& Z& z* @
  8.   /* 检测句柄是否有效 */
    5 Z' C. [, h8 S# ]3 X
  9.   if(hjpeg == NULL)/ O2 L/ k. ?) ?+ S5 J- ^  r) a
  10.   {: R0 {2 [3 Z. G& h9 Z9 @
  11.     return HAL_ERROR;
    ) m9 l; a6 W$ i4 r* y* d5 D
  12.   }9 F) Z* x% Q- v6 x# Y- H
  13. 6 v5 S* U0 w. N7 b# Z
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)) K# U  r4 d& f) A: ^5 a# [, \& O3 X  W
  15.   {
      C, ~- x9 X3 N- c5 a# s
  16.     hjpeg->Lock = HAL_UNLOCKED;
    8 K8 d7 k7 z8 D6 Q/ }4 E9 U
  17. 6 a8 \% D. S& @3 h. X  M2 @
  18.      /* 初始化GPIO,NVIC等 */, [, D1 A, g; b6 Z. O
  19.     HAL_JPEG_MspInit(hjpeg);& A  g- k: T5 q5 K; ~
  20.   }' J1 n1 a2 K/ ^

  21. . d# u& K5 b5 M8 f; e
  22.   /* 设置JPEG状态 */& W  b. |0 i% F+ P; e5 I$ q
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;
    ' ]5 ~& w  _: E  j' _2 g. l6 y& R

  24. ; ~9 |8 }- v8 u8 D' v4 V2 D! ^9 C
  25.   /* 使能JPEG  */4 l$ h! c# `; J% T
  26.   __HAL_JPEG_ENABLE(hjpeg);$ M( @4 G& H' _( e) ^0 R0 @

  27. % s% K' s$ p1 i
  28.   /* 关闭JPEG编解码处理 */
    " i) f2 f& Y* K8 u0 @8 ]" k) M
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;3 A! k/ O. o) ~2 D& a

  30. 7 Q+ d: I$ T9 _* W
  31.   /* 关闭JPEG所有中断 */- S- b# j5 T" i+ s$ k" V; s% d
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);
    4 r( f" t+ y+ i8 D  j! U

  33. 7 s6 J% D4 t. [7 s. i' ~
  34.   /* 清空输入输入FIFO缓冲 */* @8 `9 a5 G- ]% `0 {/ |
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;9 p! s; V- ~' W0 Z/ M, ?1 Z
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    & ?% ~, @& y! {- j$ `

  37. 9 p% w% J( ]; o' R. f
  38.   /* 清除所有标志 */  ^# _' k- ^( G7 t
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);
    5 m  h- p9 w2 k4 j: c' l# F* ~

  40. ( Y  b, R% k1 k8 f9 j9 ]+ Y
  41.   /* 初始化默认的量化表 */9 Y0 ]! @! k' T6 n7 r
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);
    1 M6 n& _8 a  E1 M
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);
    ( ~9 U$ |, e  G; q8 B4 [- r0 J+ u/ R' q
  44.   hjpeg->QuantTable2 = NULL;
    + S4 I5 p5 \: h. s
  45.   hjpeg->QuantTable3 = NULL;$ d( s4 S  U# j/ x* L

  46. . G& y5 a* L5 L6 G* @! E
  47.   /* 初始化默认的霍夫曼表 */
    ' p! v; P# D0 O" N1 H4 X# U+ r
  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)8 S  e1 V+ M1 U6 v+ O2 w
  49.   {8 d' B3 T, S* C. P! s4 @2 x3 B* d
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;; J0 N1 _6 a8 p6 w* C- u
  51. / K6 L% J( i& t2 T
  52.     return HAL_ERROR;
    ) B+ w8 t5 Q9 Y% `! i# @
  53.   }4 x/ A) k1 ?/ {5 y1 v* W

  54. ' F8 i& W( F9 o5 v8 ]- S& g/ l
  55.   /* 使能文件头处理 */3 l! i: k# C7 V" E8 g: C4 `
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;8 q. s; k( m. m5 w# q

  57. 7 N3 S: k% C6 c  a
  58.   /* 复位JPEG输入输出计数 */
    # Q1 G2 S' q1 c2 z5 w/ P+ z* }/ x. q
  59.   hjpeg->JpegInCount = 0;& V+ p3 n+ f, m( c
  60.   hjpeg->JpegOutCount = 0;
    $ I5 |' D, O: d' A( B* g

  61. 1 @' B- ~# c1 k+ |; y1 y; @
  62.   /* 设置JPEG就绪 */+ m" E* h; j& t6 k9 G' |8 K* |8 Z. j
  63.   hjpeg->State = HAL_JPEG_STATE_READY;" M7 c& S% k( [7 V
  64. : L/ b7 M& o' o
  65.   /* 设置无错误 Reset the JPEG ErrorCode */# `( {7 r& i9 X2 C) m$ E
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;
    4 S" ]$ c: F" L' C  G/ D7 c
  67. ; X+ q9 c% k8 j4 n' C4 o3 ~
  68.   /* 清除上下文 */
    7 n- u+ j9 h; y1 l
  69.   hjpeg->Context = 0;4 K. G( }5 o9 k5 y: ~! K# x

  70. 1 \1 F; f9 e! B2 T8 Y( h' C
  71.   /* 返回HAL_OK */
    7 Z9 I# }' c5 Q4 n7 K- F/ V5 _: M/ R
  72.   return HAL_OK;
    5 _/ v- B( F# \6 F
  73. }+ Z. t8 Z9 J5 B) }2 J% y2 j/ \+ h

  74. 5 O2 w8 k/ `5 v/ m3 E- a
复制代码
! k- S! j. o7 T6 b) v7 _/ r: c
函数描述:
' x& n6 c' R% {9 Z$ n( ~/ x" ]/ g
: r1 e/ s2 X" m此函数用于初始化JPEG。
$ q; u8 X2 V2 C4 N
" `" x' o: A) d: n/ Z9 V函数参数:
5 }' c+ h! @* S1 d4 W+ Q
4 Q9 l+ p, ^5 T2 y  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。" W2 d* b, k8 C  z
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
: y( l1 l9 ^* i; P! b# y注意事项:6 I) Y# [6 U7 T5 {& \% O
* ^6 R" I  v) d# T
函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
# e2 d) \1 \$ {# @! [如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。& A' l: t6 C% j) A5 |& Z* L# M
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。) j: u+ _( p" _. f" |7 _1 |

5 r0 Q+ F, p4 ]# q( P3 `解决办法有三1 ^6 M2 ]7 a- S- N
8 y7 H7 F" E- o3 Y3 Z' A
方法1:用户自己初始JPEG底层。
: S8 B; [2 i$ }  b4 e4 o
9 B$ {6 e5 r8 Z% @方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。- w0 T$ O9 i* t% V' V

0 v' c( ^. }. \+ t3 A2 Q6 @方法3:下面的方法
2 o; G/ S3 I6 Q8 Y* T" t
* l# f; u. i2 U
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
    # r" \4 E7 f3 K  F+ j
  2. {
    1 `$ g: d1 P* m7 K
  3.     Error_Handler();
    4 [1 u  y! S  }5 P+ B$ v! }
  4. }  + F- u7 @+ i$ z* F2 `! p
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK)
    % o- L# V& z8 T" w
  6. {( }8 j' M* [+ u- W1 y
  7.     Error_Handler();
    7 Z  w- J4 G# i! \+ g' l' I, ^& ?" L
  8. }
复制代码

- k+ G/ a  D" g  C4 T# z7 v使用举例:
9 {) N9 V2 T: K; J1 [& ]0 X" @
  1. JPEG_HandleTypeDef    JPEG_Handle;& a% ]( T% v% t4 R0 j
  2. JPEG_Handle.Instance = JPEG;
    ' n3 W/ k& U9 D* e( |
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码

- A* z2 v/ d: h$ s. L% ~57.4.2 函数HAL_JPEG_GetInfo3 p+ o% K1 S  p( h$ X
函数原型:: w6 ]& `  y& j/ o5 r; [/ r: ~/ U4 t

! C+ P; M7 i7 \2 O/ w
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)# p* Q; b- B( J7 a9 \  n& a* o
  2. {
    ; p& M/ M5 p1 o5 ?- I
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    , Y" J+ T0 D' K5 L" F6 `- }7 A
  4. " j3 B# Z- A: n) N  h8 A5 u# u9 L$ @
  5.   /* 检测句柄是否有效 */
    : @' R$ \! U) i, {
  6.   if((hjpeg == NULL) || (pInfo == NULL))9 Z$ D1 W! A, N3 C2 B, C/ n
  7.   {9 x& o% K' T" V' j+ S* K+ X! b
  8.     return HAL_ERROR;
    3 W" j0 s: V' f( j
  9.   }' ~% F! L$ Z' Y+ d7 D8 |9 i

  10. + @2 o( |+ f" b) b0 R/ V: ^6 @$ O8 f" [
  11.   /* 读取配置参数 */
    4 n7 u$ P/ O- u
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    : o" \0 {+ @3 N0 c
  13.   {' Y% X  h7 s1 Z: B3 `
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
    & j* S& s1 t, o1 z3 h
  15.   }    9 S6 ]+ U1 d1 n
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)  M: m4 H- B' E( g( w% T) _
  17.   {: M* o/ m" h2 J- [( ]/ r
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;* q/ v) U' G- @
  19.   }
    , }+ b+ M" W! B/ O7 L9 Y% _
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)* t& B5 x6 _% w3 o
  21.   {$ X/ X' p$ K* u3 Y$ U3 E% X; Z" f- e1 V
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;    ' t+ o, d- D8 P0 r) j7 w" T6 ]& J0 W0 e
  23.   }
      u4 L9 q* q2 u; ]  Y  O

  24. ! c6 D% M6 Z. b) m+ ^$ A' n: H
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
    / z# M3 p4 p  {1 f0 e" ?! Z# m) c
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
    , D6 e3 f* |) B1 q

  27. $ V6 ~9 i& B$ F, A
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))
    - x  o* e2 t+ J
  29.   {5 I7 [8 L  [) g$ x: P3 w
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;! z1 e# ~+ n+ Q) `- m( m8 M
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;
    7 o4 o# R+ {  |/ Z( B
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;& ^; R: I4 R/ d1 u
  33. 2 c* ^; W; S) i8 c/ U& p% G/ m
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))! q1 P- N; a  n
  35.     {( ~5 x5 T" r. A! a. M
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/) m* i+ B* u, T" h, g
  37.     }
    7 b- S: Y( V6 t$ F) N- ~  ^
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
    9 z7 \; Z6 h6 n$ A7 n
  39.     {7 _" a, r% N2 @( s4 D
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;5 @, Y  t. N& z
  41.     }
    % w4 o/ l  t' m$ w" B% g8 H
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))
    3 J' J1 K+ V3 q1 H* z4 U
  43.     {, S6 ]4 k$ _8 k
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;# z1 f9 h3 S2 d5 N
  45.     }
    ' }: \3 d9 N8 Q& K( x1 d# n4 z
  46.     else /* 默认是 4:4:4*/
    + @$ T- X+ S$ O
  47.     {
    / m, t, \' a5 C, m& M$ I; n
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;5 s+ W) ]; y* ?- U* n+ _& g
  49.     }
    ; D* H! h! Z5 P+ ?1 L4 f# Q
  50.   }
    $ Y% a8 H( Q+ W7 o
  51.   else
    6 x* Y4 E, M$ O3 e  }* u+ i) T; c7 ~
  52.   {' v: _- A' e7 Z" ?  g
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;/ h- o- j* E) ^" w+ M% }
  54.   }
    - B" v* [6 Y1 b' u/ f7 P9 I

  55. $ V0 K4 Z) w2 i4 k: E% l
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
    1 b$ f$ L1 R. H$ n+ U/ y3 Q

  57. 3 G# |, c4 O* z3 W9 F
  58.   /* 返回HAL_OK */( o  \0 D! O$ Z3 a# g) R( E
  59.   return HAL_OK;
    * }" q; k  U" Z$ ~- V2 r% w
  60. }  l8 {  u, W5 W
复制代码

+ ^' r4 w: G9 O函数描述:
2 N& S& g6 w0 u: \6 i# r
+ N' Q% O* ^8 V3 f此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。2 ?: D/ E9 a9 s. D8 |& @/ M  e) b

# z# ^6 u5 z+ }: p/ F5 F函数参数:
6 B# \" y4 T* ?# A8 [( y
$ T( k9 F' f! S: k8 U6 K+ q7 ^' @  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。% E' O3 H# g6 @0 m. R; [# ]: h
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小
1 o$ o- V$ z6 |) Q; v; ?1 V  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
# z  q3 \9 \; M% E! Q; G( y+ P% \( j+ q- _/ z$ f
/ Q/ {/ M/ _* |) G
使用举例:- H! f8 f( m# c, O3 c4 |4 Q$ n# l
  1. JPEG_HandleTypeDef    JPEG_Handle;% T: p5 X9 F4 K7 _. X6 A
  2. JPEG_ConfTypeDef      JPEG_Info;
    + ]3 U6 e* j! r7 j3 C

  3. : F; K0 Y5 K4 t* P# H! I
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

7 ^% r* O- U3 \- T- ]( _9 L57.4.3 函数HAL_JPEG_Decode_DMA
  ]+ L9 k6 d+ M) N2 _9 R# R函数原型:
, O, }( b( ^7 ]% \$ u( K# v6 x- M, X/ `4 o# T# ^! _, E. [0 D
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)/ f, v( G0 ~% A7 I
  2. {
    . |4 W0 x4 |) s% ]% }( j5 T7 D& W
  3.   /* 检测参数 */
    % T5 l  @& ~3 u$ P  S, |: \
  4.   assert_param((InDataLength >= 4));
    , _$ I6 F% @4 G! F
  5.   assert_param((OutDataLength >= 4));
      D# \: q# C) X- C4 S1 s

  6. 7 _! O% [2 o2 o* C- S* Y
  7.   /* 检测参数 */
    8 Y8 ~% x6 r1 W9 m" [# W
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))( x9 ]% P. b' A8 Q
  9.   {
    * Z; E+ t% n! v+ u5 W! s
  10.     return HAL_ERROR;; k2 y) S9 H& n' h- F
  11.   }
    $ y; {0 O7 E' [3 G/ A. {
  12. % D- A( B9 C- B/ g0 W) y+ l7 @
  13.   /* 上锁 */' j' ~/ z9 ~" T- q3 Y/ O
  14.   __HAL_LOCK(hjpeg);
    : L; c2 d1 F# v& O6 N
  15. # [, ~. ~* L3 Q6 {
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)
    : d' ^- F2 T) c
  17.   {
    % ~" [) C9 F" |! c& Q- [+ y  Q
  18.     /* 设置JPEG忙 *// k6 T) D1 `0 C0 d4 r" C9 k! z
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;) R  `& U" N- L* t! z: w- r9 Q8 K
  20. * n, R8 Z7 U, S  v2 h0 g
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */$ _' E7 L4 P5 S2 ]4 r
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    3 j* h9 M, Q7 P: N! _; L' n
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
      O6 B5 M2 c( |2 J

  24. - s' m2 s7 u! W! ~  v
  25.     /* 设置输入输出缓冲地址和大小 */
    ) f% {5 ]6 h% g! o# l  I; J
  26.     hjpeg->pJpegInBuffPtr = pDataIn;. q$ n, S/ u! b% B) K2 j6 v
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;* w  M& d' e/ i# [
  28.     hjpeg->InDataLength = InDataLength;
    $ W) f3 t5 N& C4 m7 F9 Q- y" i
  29.     hjpeg->OutDataLength = OutDataLength;
    ( _( c# L7 `0 I' \
  30. 4 d/ P3 K2 ^. ]
  31.     /* 复位输入输出缓冲计数 */
    $ M# O! {- l' ]$ F+ B) p) w% b3 |
  32.     hjpeg->JpegInCount = 0;   
    / e5 C6 z- l- Y& l
  33.     hjpeg->JpegOutCount = 0;    1 [& [" M* P# U) B1 v' }. q

  34. : [$ O+ v% |6 W. w0 b
  35.     /* 初始化解码处理 */
    1 {8 r$ e+ f$ x. y
  36.     JPEG_Init_Process(hjpeg);
    $ P6 t8 P& K$ S# t$ N

  37. - k/ t8 s( S' O5 L  T; C
  38.     /* 启动JPEG解码处理,使用DMA方式 */
    * m/ _8 k' x5 T+ W
  39.     JPEG_DMA_StartProcess(hjpeg);. j( W( U% _* q2 ^

  40. & H7 D% X( b1 N- Z' {
  41.   }* D" n! z9 G) u) \& T3 t' D
  42.   else
    : f3 q" \4 v7 Q5 w! {
  43.   {1 ~' ]& X& |$ R+ L% {
  44.     /* 解锁 */
    6 m0 |  Z2 B% `; [3 g; y
  45.     __HAL_UNLOCK(hjpeg);
    ; ~+ |  \. H- g# V" K' i( S

  46. ! C# G. U' z$ l* h
  47.     return HAL_BUSY;# F' ]) H, h5 ~  A: l! Y9 g$ ?
  48.   }
    ) F# K* N* ?' s! n+ a$ \% A5 `3 g( [
  49. , ]' Z2 j4 s! N$ t' U  t2 J8 k
  50.   /* 返回HAL_OK *// z- V8 P+ s) w; ?" S
  51.   return HAL_OK;
    " U9 z2 j+ B* J
  52. }# \5 Z% T6 j1 J* N! t  c0 A/ m
复制代码
2 I6 V- `4 @; t) e$ r

, E1 f- E% S3 D6 u函数描述:% v# T- {7 s3 K& h
% I. f* x# [  ^0 f
此函数用于启动JPEG的DMA方式解码。
, c( l8 L) H) T. M. V, W! q6 v+ ?4 q; h! [2 t3 `$ s: J' u3 W' l
函数参数:( V0 S0 r; W/ e; h$ p; Z9 `7 d
/ Z4 t* B/ M7 g! O0 L) \9 k
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。; h5 K6 I4 m2 D7 m
  第2个参数是输入数据缓冲地址。
$ i2 ~7 F& \! s1 v% n: C% O/ v! m3 C2 x  第3个参数输入数据大小,单位字节。4 z3 a6 B3 _% i
  第4个参数是输出缓冲地址。
+ B8 X; ]8 ?( R" x  第5个参数是输出缓冲大小,单位字节。
0 W  F/ q* c$ @5 Q$ I" J  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
: D9 ]5 s$ h& u
9 a" w) A- O( a4 H7 s1 Q) `( r3 I使用举例:
% X  Q8 ?( `+ Z% T5 ^7 f' k6 \# U0 |( H3 x! e- ^
  1. /*
    - r& O2 ^' q( E- U) U) @
  2. *********************************************************************************************************$ c4 @' B* @7 F0 v' U+ _7 X
  3. *    函 数 名: JPEG_Decode_DMA% @) H4 N$ `0 f) A" X( e# H  ]$ @
  4. *    功能说明: JPEG解码
    ) k; S3 A! J; r# ?+ [. l7 `5 N
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针, i! z* K) i' T
  6. *             FrameSourceAddress  数据地址
    - K1 l% c7 [- o' @, n" x
  7. *             FrameSize           数据大小
    0 D( p3 ~( _5 Y8 F( j7 b5 I
  8. *             DestAddress         目的数据地址
    4 c4 w8 ~1 O2 h2 Q  T
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功9 _0 k  m7 b9 c3 C7 J
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    ) E# x! ]; b7 R) N* \4 H
  11. *********************************************************************************************************
    2 u7 V. s4 G3 P+ }% Y0 M# r
  12. */
    ! b5 n( K- U7 w- f0 q/ |
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress). M/ e, L* s; g# E' L
  14. {: r$ B+ y/ G. H$ i6 k5 N! j) y& Q
  15.     JPEGSourceAddress =  FrameSourceAddress ;! t1 S4 X5 Q" S* E/ ]: L, N. g
  16.     FrameBufferAddress = DestAddress;
    + r( ^0 _1 M4 H! D+ ^1 w
  17.     Input_frameIndex = 0;
    9 m2 |; o! Z, N8 ?
  18.     Input_frameSize = FrameSize;
    9 V- f' I  ]8 Z7 @
  19. # |  m8 @; m) i5 A4 m, ?0 V. G
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */
    5 n# }) e/ F! H
  21.     Jpeg_HWDecodingEnd = 0;
      n5 Y9 t. P9 p" L: e5 V2 @
  22. ; X- L4 b  n( E' x
  23.     /* 启动JPEG解码 */
    - d- r! F4 F# y3 X1 t( j
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,& \8 q2 N2 c' h* w% E
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);5 z3 _5 Q& P( }( u) R

  26. % N; b' d! U/ H( c& F2 Z
  27.     return HAL_OK;
    " D+ N- c( i4 Y: l3 s8 Y9 p
  28. }
复制代码

2 L& |7 H, @4 h% M4 b! h* V& c57.4.4 函数HAL_JPEG_ConfigInputBuffer
: q6 `; q1 d% G函数原型:
! x4 g! C. y* s# m+ b0 P* V" L; ?6 ?1 s' H1 H
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)& h0 Y4 y5 R3 {$ P
  2. {
    " L4 r# k+ A( I6 a$ U8 |
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;, }) ^5 k+ V7 {! k: [
  4.   hjpeg->InDataLength = InDataLength;1 \) X) t  {3 a) T* j' T, |- r5 O. e4 S
  5. }
复制代码
6 R& M" z( q* Y0 N
函数描述:/ f7 H. k; x3 N' P7 L$ z

' D- j2 u, n8 x( i4 c- R此函数用于配置编解码输入缓冲地址和数据大小。! l% h; R/ \! F9 z# e
! K& `' d6 a8 T7 y1 L
函数参数:
) @: o3 G; T6 s& V  ?$ l$ M
! w7 x1 n# b" g1 F/ C  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。+ {, s5 b7 |4 c: b! U
  第2个参数是输入缓冲地址。8 A0 v6 J2 Z+ P8 {$ d
  第3个参数是输入缓冲大小,单位字节。
/ g7 S# a2 _1 n# @% V' I9 k  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
9 y) Y2 d3 ~7 i/ B0 M使用举例:, Y+ t2 W2 W! y% i4 f5 E) x
3 U1 o/ E% _. m9 v9 G$ i  v7 x
  1. /*
    " Z: c, U& `/ N3 h
  2. *********************************************************************************************************
    3 C2 k5 k9 F6 a8 W$ e; D+ G0 r
  3. *    函 数 名: HAL_JPEG_GetDataCallback
    + C9 Q3 E7 D5 z
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码
    " P" n! d3 C! ?" t
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
    3 j9 r/ g- b& |5 t4 C9 q6 V
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  3 i% O9 u$ |+ I8 v. `
  7. *    返 回 值: 无& o/ r* ^+ B( C: M* f
  8. *********************************************************************************************************7 e- ]) \9 g# [5 p# X8 s7 `
  9. */0 w% D$ F: \6 G0 Y2 m( w
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)1 B* E8 y) _/ R" f4 @
  11. {9 U1 T) H8 s% X5 `/ _' m& ?" U% p$ y
  12.     uint32_t inDataLength;
    # y6 O6 Y; H* c$ S8 r
  13. * l& l7 o, H) y- h* c5 d0 N2 Z
  14.     /* 更新已经解码的数据大小 */
    ' b& g& K; U7 {
  15.     Input_frameIndex += NbDecodedData;; ?6 r8 D5 t- n

  16. 6 _3 j* Q$ _" }: s
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */
    7 E0 G$ ]1 [3 W" O8 v* q
  18.     if( Input_frameIndex < Input_frameSize)* f; x) ~% k5 J$ h
  19.     {
    ; r) m% N! r, n5 H" Y
  20.         /* 更新解码数据位置 */" _7 C8 [' n5 E' @1 U: f: m1 x! L
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    * x0 v# Z- a+ p" j0 [
  22. ; r! G: w" F$ @$ A
  23.         /* 更新下一轮要解码的数据大小 */
    0 Y& x$ b) s: n, K/ Z
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
    4 Z8 @5 e. b/ Q6 R7 {
  25.         {* K  a+ H" x, _  v* f/ [
  26.             inDataLength = CHUNK_SIZE_IN;0 }& v$ [- z- n9 B3 f* y7 Q
  27.         }
    6 _5 k/ ^  ]3 {! ^
  28.         else
    . y; q2 J1 d. Q' {! i% P( M
  29.         {3 N1 @3 t6 l$ P4 K
  30.             inDataLength = Input_frameSize - Input_frameIndex;
    2 ?7 O0 l) L6 [" R5 J: Y
  31.         }    & o# h+ [0 L4 C  ^1 M
  32.     }
    $ ]6 Y/ h' O4 A
  33.     else+ v; g" S* y, U6 c5 i. p9 D/ X
  34.     {
    / N( I- k3 m, P. P; X
  35.         inDataLength = 0;
    2 {! B3 b7 L+ X5 i! x) Q
  36.     }/ |$ |9 X2 Q: x0 i0 x: T) l

  37. , g* z! Z& h, J) W; z8 Y: d
  38.     /* 更新输入缓冲 */
    * @9 y" N& Y1 l- z3 P3 {4 S
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);    6 F) q+ a( ^3 l
  40. }
复制代码

+ ]4 E" O5 F* L0 u& e
' P/ p6 F/ d% N4 D  p57.4.5 函数HAL_JPEG_ConfigOutputBuffer  R) j9 h6 C# T5 |/ _1 o& @4 d
函数原型:7 L7 B( b1 s* ~3 Y# _
3 B/ [4 \- I6 u: v
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)
    + {# x9 e% i# q. k) P7 \2 p
  2. {# h0 Z1 u. J5 W
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;
    * E2 y/ p0 G. O  z
  4.   hjpeg->OutDataLength = OutDataLength;  * D2 k9 k* `! T' j) |  _
  5. }
复制代码
8 W8 T, H0 V. N

! @. d& N6 D8 b/ R6 X函数描述:( T& m: h. f( ?: q
0 D# {1 g( U4 Z0 W  F
此函数用于配置编解码输出缓冲地址和数据大小。( m0 ^. t- A* T  F$ Q

5 n, ~( S1 b, w, c6 ~" m函数参数:4 H& @1 ]; X7 V: A* m& S

- x1 D) k2 W/ o9 I( \! t( v. u  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
# m1 f* }& ?" L& C9 k; m) S  第2个参数是输出缓冲地址。
5 p$ `* S" w# h& V$ D1 {; T  第3个参数是输出缓冲大小,单位字节。
3 T, t, D3 d7 U. i) O. k, c  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
3 ]5 ~8 ~0 _- U: l使用举例:
1 |' ~4 |+ k: n+ T
, U" f9 G$ O$ f# g4 g
  1. /*
    - _$ A- k% I0 A' E7 T, S
  2. *********************************************************************************************************; D4 y6 z9 C1 M& G9 [& q; S, c& a
  3. *    函 数 名: HAL_JPEG_DataReadyCallback9 h4 N( D: O  \' u; Z& |
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新, h9 B, D& R0 a/ S; p
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针
    8 w) B' C4 L& n; n
  6. *             pDataOut      输出数据缓冲9 @% G7 s7 B# w+ K! {  w' J; z
  7. *             OutDataLength 输出数据大小,单位字节
    # k" V& a8 E5 |' Q; [; R
  8. *    返 回 值: 无
    - c- o! L: \7 S
  9. *********************************************************************************************************, D. i2 ?" t% @& F1 B7 l' j; e
  10. */$ a1 o- f9 ^; V$ G7 N3 p$ K
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
    8 J% Y- G; D* C$ p: ?' G( W
  12. {
    3 J5 S+ W/ c. K0 a! s. \- Y
  13.     /* 更新JPEG输出地址 */  : @0 b, D; F7 Y
  14.     FrameBufferAddress += OutDataLength;
    5 [( ~+ t. ~) U2 w

  15. : N; l0 b' D) `" z  ]
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
    0 V2 q. {" {+ X3 A1 g, T
  17. }
复制代码

; l/ H- E5 a& s# d$ H57.5 总结0 N2 W8 D) K+ M: U7 `3 g; J
本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。
$ y- w' B9 P7 T/ ^3 s& g
8 K; w" ]8 d. G; R5 C5 S" N5 J% E
5 U4 Z! G/ g& x8 y) w/ l0 {
; Q; j3 _; |9 \  F! U* h
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似技术帖

官网相关资源

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