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

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

[复制链接]
STMCU小助手 发布时间:2021-12-21 21:46
57.1 初学者重要提示
* i$ }& w0 o5 n  由于硬件JPEG解码后输出的图像格式是YCbCr,所以本章对YCbCr进行了重点介绍。' w2 p: s! Y/ q- Y8 B5 i! I
  测试STM32H7硬件JPEG解码800*480图片性能,全部通过SDRAM缓存数据,解码10ms,显示9ms。. T7 ^/ o0 N5 m( @" B. d5 v
  JPEG涉及到的知识点还是比较多的,如果想深入了解JPEG的话,可以看本章2.6小节给的参考资料。
4 t' `7 p0 i( M8 b  本章JPEG相关概念的介绍参考了wiki百科和百度百科。0 |* I, \+ o5 r) j8 l  z/ O3 _
57.2 硬件JPEG基础知识

, c6 b$ W3 P1 h: j% P: }! u' @0 ?对于STM32H7的硬件JPEG了解到以下几点即可:+ z& C  B5 v- k/ D
5 j% e- ?. L2 p& G& b
  支持JPEG解码和编码。
$ ]& U* `- Z7 P5 q. o7 W: L" B, @  对每个像素数据进行编解码只需一个时钟周期。! m( z& p: n) x, Y! c
  支持RGB、 YCbCr、YCMK和BW(灰度)图像色彩模型。$ r2 q; k7 ?) \2 x4 L5 [
  编解码时每图像分量8位深度。
# u( Y2 A: j0 d% ~1 g- f4 i9 V8 M4 n
57.2.1 JPEG硬件框图& M' _9 f+ x7 b/ G
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解JPEG的基本功能,然后再看手册了解细节。框图如下所示:
0 C1 O% P% r& ^5 M- d, P
9 X2 G! ^# z! ^' f; t, V- n$ _
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

! T- K" w* ?" ]! i& G6 m  V
, p4 ^" M  m& A0 G" o通过这个框图,我们可以得到如下信息:
9 n/ Q% I8 O6 E% ~5 c
# T/ W2 l$ X* h  JPEG硬件外设支持编码和解码. o6 }( c9 s2 V! f
并且对于输入数据和输出数据都有FIFO支持。8 r0 X( J# c1 j$ |

$ E. [! r5 ]1 O) u. ~' T: S  jpeg_hclk0 j/ S# l8 u0 z9 p
为JPEG内核和寄存器提供时钟。7 n/ {. P3 p8 `4 v, k* ?: b+ p

4 i5 a9 O- Y2 @8 A1 ?& Y  jpeg_it
9 f. K* W# U: L8 `: yJPEG全局中断输出。
9 z: R" p3 W# h3 b) N7 V2 ]' b; l9 r) H5 F" y! K0 I
  jpeg_ift_trg9 \& G5 y* W$ Z. v) C4 {
JPEG输入FIFO阈值信号,可触发MDMA。
' k4 I5 `9 x7 }! a+ [6 [( g- @- K- c6 P5 `/ w; t3 f7 d; y4 R# T1 G
  jpeg_ifnf_trg# Q: F2 M7 z- H  x+ d8 _9 |
JPEG输入FIFO未满信号,可触发MDMA。
. a+ W3 ?1 N9 |" q& \
4 Q. j5 w+ T+ M5 u8 T& d$ w  jpeg_oft_trg3 M" A! e) i* O: J
JPEG输出FIFO阀值信号,可触发MDMA。1 D1 J/ [7 q0 i. C, k+ c" B
. f7 M, Q2 \( M* u+ I! B5 W
  jpeg_ofne_trg
! U, ?- m+ h) O( }2 c9 G) s2 Z& [% [JPEG输出FIFO非空信号,可触发MDMA。
( q1 W8 e) @5 g# i1 {! P/ s8 p3 ~" a5 I
  jpeg_oec_trg
  k/ W5 R7 M" n8 tJPEG转换结束信号,可触发MDMA。
* Y4 x2 ?4 r* P, V! Z; P
2 {% N8 K0 `! n0 S) s57.2.2 YCbCr颜色格式
" \4 Y2 Z9 E4 H, t6 s+ e(注,硬件JPEG解码后输出的图像格式是YCbCr,所以有必要了解下)) o5 ~4 Y3 G/ G$ z* M8 K

1 ^: q, u" @; v' f: \' w正如几何上用坐标空间来描述坐标集,而色彩空间用数学方式来描述颜色集。常见的3种色彩模型是RGB,CMYK和YUV。
- T& S& |$ M: {4 h& Q! ]3 _3 m
: e5 U3 n' d4 k8 y/ TYCbCr是YUV经过缩放和修改的翻版,只是在表示方法上不同。其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,人眼察觉不到的图像质量的变化。
/ ?& Q; N2 y# b$ v& a
! f' K- f% M* h9 B在YUV 家族中,YCbCr 是在计算机系统中应用最多的成员,其应用领域广泛,JPEG、MPEG均采用此格式。一般人们所讲的YUV大多是指YCbCr。
2 c" N* X) s  H6 [1 G/ p
9 a+ }5 B2 {8 S3 l0 h& B1 w5 u* i57.2.3 YCbCr采样格式3 c4 V- X+ d- ?2 L
YCbCr有许多取样格式,如YCbCr 4:4:4,YCbCr 4:2:2,YCbCr 4:1:1 和YCbCr 4:2:0。
; R+ s' Y4 F" d% w. [
3 y, h2 b3 N8 X; j8 P& u  4:2:0
2 Y) ~0 N2 u( a- P7 I+ W9 ^" O& A' S表示每4个像素有4个亮度分量,2个色度分量 (YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式。
# Q  V  Y$ s& j9 A$ L! h+ I% g
9 X6 Z+ h7 X9 u* N  4:2:2
1 d7 y% P5 w/ G, E表示每4个像素有4个亮度分量,4个色度分量(YYYYCbCrCbCr),是DVD、数字电视、HDTV以及其它消费类视频设备的最常用格式。
* ?3 B% y2 ~+ R  d+ C3 h
2 l3 A5 b$ o* D  4:4:4
% D3 G& `, e5 B5 k) |- R8 o8 D表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。! f$ u% B7 [7 [. ]9 Z! L+ g
5 b5 w* N6 ]) n/ ?( A/ P& G
具体的采样方式如下图所示,以8个像素为一个单元进行采样:5 Z  n0 Y) ]  S7 @0 L1 E& T
! Q& x* i% H' n5 Y: e2 Z  l
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

1 b' _, L8 ]6 }$ G( Y# M
+ m# b( j2 H3 t! ]  u/ `5 q  z由上面的截图可以了解到:
7 i, [2 R; }4 y, `& P
0 h0 Y' w' o4 j& t( U& S0 R4:4:4表示Y通道,Cb+Cr通道全部采样。. w, X: ~( {( S* [8 m
, Y9 q" a4 O& E: I. @
4:2:2表示Y通道全部采样,而Cb+Cr通道两个像素为一组,统一采用第1个颜色值。' g/ `8 t8 y$ C  o2 @% l* j9 w

5 `+ z; {# S( O0 N' r4:2:0表示Y通道全部采样,而Cb+Cr通道四个像素为一组,统一采用第1个颜色值。
& ^: @/ g+ F) m6 a' G, ]. ~5 \: |1 W9 ~
下面是整体效果,方便大家更好的理解:
0 l: |! p; S1 l8 X& F; X$ Y1 h, O# A! y4 h; z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

( Z8 w$ K; r1 c) j1 Y. e: v1 M4 z4 z/ V+ x
1 L4 v1 U. v9 F8 c& J
7 n$ n7 k- S! U: G
57.2.4 YCbCr的优势
5 M' F9 R  _* e" `& g* E: ORGB信号作为存储和传输的效率不高,因为它们具有大量冗余信息。而使用YCbCr可以丢弃一些信息以减少带宽,因为人的肉眼对视频的Y分量更敏感,因此通过对色度分量进行子采样来减少色度分量后,肉眼察觉不到的图像质量的变化。了解这种人为缺点,NTSC和PAL等标准大大降低了色度通道的带宽。
: ~3 b/ f9 \0 R2 b& |; [- v3 q, W( z6 o0 z
57.2.5 YCbCr和RGB互转

) E3 k' H% U1 u为了方便大家更好的了解YCbCr和RGB图像的实际效果,特此搜集整理了两个截图(来自WIKI百科)。下面是图像转YCBCR的效果:四个图,从上到下依次是原始图像,Y通道,Cb通道和Cr通道。
. y3 I& g0 C+ i8 M1 u0 ^/ @7 m' f
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

- x- l+ ^/ M5 f+ J- ]
: C9 P/ W% p" R6 F8 V下面是一幅图像分别以R,G,B通道和Y,CB,CR通道的方式展示:
6 ?  l( f0 C  ~" D4 I5 _4 c6 j
# |$ }! a8 b  H2 P5 L* ^
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

& j% k2 P) x1 f- X0 n) B
6 ?8 k0 n! B1 f& Y8 A! Q& o57.2.6 JPEG编解码知识6 W; @/ _  r! c
JPEG涉及到的知识点比较多,这里有之前整理的20多个专题知识点,大家有兴趣可以了解下(不了解也没有关系,不影响使用硬件JPEG外设)( y) N4 x1 A, ~. S' K
4 \8 {1 T+ l9 c. d/ [
57.3 硬件JPEG的HAL库用法
6 M. Q. k; P' E) ]- c5 B, ^8 G1 w# fJPEG的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和MDMA。下面我们逐一展开为大家做个说明。% ^; m3 s. X) ?/ B  U+ S, V; z8 z$ y

+ b7 o% G' R8 e) h( P1 U6 B/ [57.3.1 JPEG寄存器结构体JPEG_TypeDef! t6 X* L$ P6 P4 B/ k/ q' l
JPEG相关的寄存器是通过HAL库中的结构体JPEG_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
% L. `6 s6 J5 r4 d. V6 U; G' I- {* A/ q" w0 E1 l& l# l
  1. typedef struct+ m/ a  p6 q2 ^# A$ C9 H
  2. {! g, y$ Q6 s2 u
  3.   __IO uint32_t CONFR0;         ' E" h* `: j* F, A/ p
  4.   __IO uint32_t CONFR1;          & j5 {7 u- B3 B1 q
  5.   __IO uint32_t CONFR2;        
    * M8 n7 H5 U( j/ Z+ O
  6.   __IO uint32_t CONFR3;        
    3 J$ j$ f9 M  e& t! c
  7.   __IO uint32_t CONFR4;         
    / K" M- q- N. o1 o- U
  8.   __IO uint32_t CONFR5;       $ n# V5 G% z+ T* F
  9.   __IO uint32_t CONFR6;       ; h0 s9 g. ^! c  n
  10.   __IO uint32_t CONFR7;        9 r) i* ~: v& |/ d1 _' v* Q
  11.   uint32_t  Reserved20[4];      0 q7 M3 H: {/ v" }
  12.   __IO uint32_t CR;             ! b0 t) J7 c' b
  13.   __IO uint32_t SR;             ) S% F5 j1 @8 ?: U1 `0 K' H. l
  14.   __IO uint32_t CFR;            
    ( o; g. {/ B3 I+ V  K
  15.   uint32_t  Reserved3c;        & A/ d# I& `% m  E1 C* a$ t
  16.   __IO uint32_t DIR;         
    $ S! w  K- n4 U5 P2 p) C3 I4 E3 k- U
  17.   __IO uint32_t DOR;            " G7 Z7 S2 W. S- C
  18.   uint32_t  Reserved48[2];      # l  W, f+ _3 N5 D2 j8 J  t
  19.   __IO uint32_t QMEM0[16];     ' _7 ?' n+ D( h# l8 \
  20.   __IO uint32_t QMEM1[16];      
    $ ~+ N' b1 F2 q# ]+ E+ v
  21.   __IO uint32_t QMEM2[16];      ! H1 l7 d! @) r* P% y
  22.   __IO uint32_t QMEM3[16];       ! C% _9 k5 v2 i2 ?' y; e& }- U9 y
  23.   __IO uint32_t HUFFMIN[16];   
    . E" \5 B; Q  @2 i
  24.   __IO uint32_t HUFFBASE[32];   8 i7 |" }& Y# y! }
  25.   __IO uint32_t HUFFSYMB[84];   
    3 j. B& h" C( R' [
  26.   __IO uint32_t DHTMEM[103];   6 `& a+ @( v, K  j1 F0 Z
  27.   uint32_t  Reserved4FC;      4 r( ~; M  @' s8 v
  28.   __IO uint32_t HUFFENC_AC0[88]; 9 F8 h" j2 A! N& S, e  U& w% |
  29.   __IO uint32_t HUFFENC_AC1[88]; 2 m0 w4 {' Q8 [7 u6 C5 V# ~, Y
  30.   __IO uint32_t HUFFENC_DC0[8];  4 F. \. Z7 S9 f
  31.   __IO uint32_t HUFFENC_DC1[8]; # u" N7 m/ g. Q+ p
  32. } JPEG_TypeDef;
复制代码

+ {8 i1 o2 |4 m# i__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:- b% a; g+ S; h3 y6 s! c, e" Z6 V
. A: j; l- {3 \. O6 ^
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    3 d1 d! d; i- t, V' R. B
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
% v, B0 q4 f. D- A
下面我们再看JPEG的定义,在stm32h743xx.h文件。/ ]7 x1 _+ \2 d; ?, f( _* z
/ ]5 ^9 u5 o& m! ^5 n
  1. #define PERIPH_BASE           ((uint32_t)0x40000000)
    3 q& u- T  Y+ K% b1 p' b
  2. #define D1_AHB1PERIPH_BASE    (PERIPH_BASE + 0x12000000)5 F. A  I5 R# R
  3. #define JPEG                  ((JPEG_TypeDef *) JPGDEC_BASE)$ L' C7 \* \1 t$ I; c* y
  4. #define JPGDEC_BASE           (D1_AHB1PERIPH_BASE + 0x3000) <----- 展开这个宏,(JPEG_TypeDef *) 0x52003000
复制代码

$ L/ o7 I+ [3 A我们访问JPEG的CR寄存器可以采用这种形式:JPEG->CR = 0。2 e- ?% A) I8 w# F, S: x$ H4 N
: b& F( O' {4 i3 ~$ a6 V
57.3.2 JPEG的编解码参数结构体JPEG_ConfTypeDef
0 A! c6 Z! X2 d此结构体用于JPEG的编解码参数,具体定义如下:6 o* ~, k, Z' G

7 l) a2 q" n5 I; I0 C1 W* t, ?
  1. typedef struct
    9 U7 C8 M! e2 K* U7 S! I6 B( q
  2. {6 J! J) U) W; a, h' `
  3.   uint8_t  ColorSpace;               
    / S  L# f" D/ c* [. y
  4.   uint8_t  ChromaSubsampling;        
    3 C" ~& L" f3 G' Z1 R" u/ ]+ P
  5.   uint32_t ImageHeight;              
    ' p) J3 U+ N% ~$ T7 F2 q1 W
  6.   uint32_t ImageWidth;             5 ^4 e2 X7 @  g% _
  7.   uint8_t  ImageQuality;               / I6 A2 |0 y/ {# k4 Y! }
  8. }JPEG_ConfTypeDef;
复制代码
( @) @0 |6 Z. d5 y( {) P  F8 w3 I
下面将这几个参数逐一为大家做个说明:
, a- Y6 P2 {3 i2 ^  uint8_t  ColorSpace9 z0 G. ?  S0 j2 l

; x+ i6 F4 \9 x# _
$ `3 R1 g0 {$ ]5 x, L  U) l此参数用于设置输出数据流中的量化表,具体支持的参数如下:: Z' F$ g+ s( G* Q
  1. #define JPEG_GRAYSCALE_COLORSPACE     ((uint32_t)0x00000000U)    /* 灰度(1 个量化表)*/
    % ?5 t; }" _! Z& t' _) T
  2. #define JPEG_YCBCR_COLORSPACE         JPEG_CONFR1_COLORSPACE_0   /* YUV(2 个量化表) */
    4 R5 P4 @2 }4 }
  3. #define JPEG_CMYK_COLORSPACE          JPEG_CONFR1_COLORSPACE     /* CMYK(4 个量化表)*/
复制代码
, N. H6 s9 q. [- k) y
  uint8_t  ChromaSubsampling3 _/ \3 _% u2 h
此参数用于色度子采样,具体支持的参数如下:
3 o- d( Z3 K5 z6 ?  `( N( E: |9 ]: j2 H0 n9 R3 k! L8 x; {/ ~+ L  U
  1. #define JPEG_444_SUBSAMPLING     ((uint32_t)0x00000000U)   /* 4:4:4 */
    ' m9 g# A' {* _, ^! v5 B
  2. #define JPEG_420_SUBSAMPLING     ((uint32_t)0x00000001U)   /* 4:2:0 */% {8 L/ Q+ l  C$ \! \5 @) n
  3. #define JPEG_422_SUBSAMPLING     ((uint32_t)0x00000002U)   /* 4:2:2 */
复制代码
9 E7 K; M3 s  j2 R  L( p5 E$ P
  uint32_t  ImageHeight% P0 ]8 P7 g4 l- M6 ^; O2 I
此参数用于图像高度。4 r$ q: d9 l2 n$ u. F$ p1 e( o& F

  D5 e" g8 }* [2 q9 T& w  uint32_t ImageWidth  f. G# j% P- |& m
此参数用于图像宽度。
" Y  }* N) D* {5 Y2 X/ k1 T( u  P4 T
  uint8_t  ImageQuality6 }0 H- K' m8 ]. d8 M  e
此参数用于图像质量,参数范围1 – 100,1最差,100最好。
* Y/ q$ k7 c( {" L: t: @" B! z/ h+ n6 i0 s8 t
57.3.3 JPEG结构体句柄JPEG_HandleTypeDef
, F* x3 w4 i$ q; @# t# y' m  T5 y$ z+ E& ~HAL库在JPEG_TypeDef, JPEG_ConfTypeDef的基础上封装了一个结构体JPEG_HandleTypeDef,定义如下:
. E$ w2 U  ]* H/ f- J% g
# A' q5 ]& g; U( p9 t9 O0 F  W
  1. typedef struct# r/ |( G2 @# t& {/ V
  2. {
    - i4 W7 S, `+ i0 O2 z+ C* h0 Z. J2 F
  3.   JPEG_TypeDef             *Instance;        : H0 ]0 H! H8 Y+ T% j6 F
  4.   JPEG_ConfTypeDef         Conf;             ' _( B- V" B. c4 }5 |* f" L; ^
  5.   uint8_t                  *pJpegInBuffPtr;
    1 M2 `6 n  v2 `: {
  6.   uint8_t                  *pJpegOutBuffPtr;
    ! j. `' T0 N2 N3 ~) k
  7.   __IO uint32_t            JpegInCount;      3 k7 i! j; S" Z5 G" ~5 ?
  8.   __IO uint32_t            JpegOutCount;     
    * Z6 X9 A* W4 B8 u6 ]( Z
  9.   uint32_t                 InDataLength;     + a5 \' O; _4 E( H
  10.   uint32_t                 OutDataLength;     3 r. F: D! q; a% @) k" w) f
  11.   MDMA_HandleTypeDef        *hdmain;         $ E8 P: o5 P1 E. F% U$ J) u
  12.   MDMA_HandleTypeDef        *hdmaout;        
    ! S/ ~/ e: @6 p, D& a. w; E
  13.   uint8_t                  CustomQuanTable;
    & y: v; Y) c$ A9 l9 o- m0 A0 L
  14.   uint8_t                  *QuantTable0;   
    ' H0 |" W, i% L, c
  15.   uint8_t                  *QuantTable1;    9 @4 R5 r/ \9 Q7 V% B; h4 v
  16.   uint8_t                  *QuantTable2;    % }- W: T8 {, l
  17.   uint8_t                  *QuantTable3;         
    " G" [0 ?! i, ^' c1 Y7 X$ k( z4 g
  18.   HAL_LockTypeDef          Lock;            ! J1 c% W- A1 W' J# q. ?9 @* k
  19.   __IO  HAL_JPEG_STATETypeDef State;         
    / N" C9 N8 F. R* k) m; Y3 x5 L
  20.   __IO  uint32_t           ErrorCode;      , c2 n" Z2 s% U- t" l# x7 E0 ^9 W- x" [
  21.   __IO uint32_t Context;                    
    # _4 W% M! L7 t$ x0 w0 ?8 g1 j
  22. }JPEG_HandleTypeDef;
复制代码

, Q* c8 S% U- U1 N% a下面将这几个参数逐一做个说明。
4 ?: f/ u' A  B+ T: T2 q- ~. {6 @. H, a- r- |, \5 c
  JPEG_TypeDef   *Instance
( q7 F& l3 Q0 b; A+ Q这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。2 {: ?- D( D1 b. \3 k& p

# B; X- E$ T3 \+ g% H0 L! }/ b  JPEG_ConfTypeDef   Conf3 Y) u. K/ t; p
这个参数是用户接触较多的,用于JPEG的编解码参数,详见本章3.2小节。! V* s- {# O4 K5 {, W( {

# M  @; k; D6 K# ]/ [  uint8_t       *pJpegInBuffPtr
6 G! I, b3 z# L1 {$ SJPEG编解码输入缓冲地址
/ o) H1 a- Y  h
. q' N7 x( |" h9 A% `8 V1 e; W  uint8_t       *pJpegOutBuffPtr# w* Q. e0 t/ Y1 E" S2 r# s
JPEG编解码输出缓冲地址
! W, S7 W6 i3 B2 f
( o+ F# U! i5 }  Q7 e1 T  __IO uint32_t   JpegInCount6 S' V, g1 }) `
JPEG内部输入计数。
8 C; u) y. d3 a
, b0 a( U" x$ ]  __IO uint32_t   JpegOutCount. W* Q+ ^+ M. a5 V! A4 w! H5 j! S
JPEG内部输出计数。
6 D0 @5 w5 q: b. g% B+ u$ D' E" [- W) ]1 U4 X
  uint32_t        InDataLength" D4 L% x2 G7 D  v$ G$ {2 G
JPEG输入缓冲区长度,单位字节) A) }3 u" V/ l$ ]

* u( ~% N; N* D+ O% p( u8 A* R, B$ h6 U  uint32_t          OutDataLength' J- h4 z! R0 ~
JPEG输出缓冲区长度,单位字节。
' I! V2 z1 E0 |* r  p3 `1 z/ O- o$ P- a$ C' d) u+ P
  MDMA_HandleTypeDef        *hdmain
% L. x( Q, x: b8 U+ Y9 ?5 ^  MDMA_HandleTypeDef        *hdmaout
/ |* G$ H. W$ e1 FMDMA句柄结构体指针变量,用于关联JPEG句柄,方便调用。
  n+ H3 q5 a4 a) R" E) s; k& K+ B2 D" Q6 r" l0 w
  uint8_t       CustomQuanTable
5 M. ^3 F7 {( m7 G如果此参数设置为1,将使用用户设置的量化表。
4 R4 P- Y# F4 S8 T2 a  _1 x4 Z# i0 a8 x7 x  C. @" u/ F$ d
  uint8_t      *QuantTable0;   : p; |, S& \$ V; x7 [
  uint8_t      *QuantTable1;     . H! {3 v: E3 ?7 d8 h1 N$ P
  uint8_t      *QuantTable2;    + r0 m# P- J1 Z: g& y( x( }: \0 h
  uint8_t      *QuantTable3;7 }- p0 _$ V- ]( ^" \
指定量化表地址。   
3 r& u' Z! k+ ?! _1 F) U2 d! U# G8 H( L: j  n) k$ d; @
  HAL_LockTypeDef          Lock           ' C2 y0 o& t/ o- s7 |
  __IO  HAL_JPEG_STATETypeDef State           * N+ P) S- y3 g& k# [
  __IO  uint32_t           ErrorCode      % [, `2 s9 R; S2 t
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置JPEG状态,而ErrorCode用于配置代码错误。6 A9 o* e( b; q+ I% g2 l( Q3 O
, R/ H8 M. F& G" J& s
  __IO uint32_t Context
/ ^6 y3 Q1 n5 }9 \, \JPEG上下文。
9 L1 P0 f; @( F+ W  W! k1 f  j. z; ^% U8 D) Z
57.3.4 JPEG初始化流程总结
$ D0 Z+ N' t: r" ~' ]使用方法由HAL库提供:& `  A+ T  N, _" z8 N0 _
) p: C! \* e3 |
  第1步:调用函数HAL_JPEG_Init进行初始化,但这个函数不需要初始化参数。+ D! W0 v% V" a( K, x/ B3 R; Q
% a7 T$ i( u( i5 b5 r/ y! P
如果是JPEG编码,可以通过函数HAL_JPEG_ConfigEncoding设置JPEG图像的质量参数,质量越高,生成的JPEG文件越大、( |- q$ I) c, O9 ~" s5 {# [

+ G0 U7 {$ {* E3 k" s" K  第2步:调用编解码函数
, u% @* S- N/ }; w% ~: ^; X9 }
) F3 @1 d5 E3 G+ D3 ~' I- U  查询式编解码函数* L; E6 ]  Q% d( U1 B( @
HAL_JPEG_Encode
/ C; f  y5 G9 z" A3 [9 ?$ ~+ h; e  I* x
HAL_JPEG_Decode
1 ^, Z% c+ V$ v+ [* }1 k+ d2 \5 v- q  ]4 x; ~; @# U/ C' ~. d
! D1 K1 g# a+ V8 _* r2 x

3 W: s# B% m6 ]+ A4 h  中断方式
5 f9 O4 j6 X9 jHAL_JPEG_Encode_IT
8 d" z4 X- A5 D# Z% Q/ d5 o
. s7 z0 x, u. wHAL_JPEG_Decode_IT
- n/ S% j5 Y4 ]) {/ Y3 f5 r
6 m0 Y: [% K2 u& u% @! x- b, @- k% a' P2 X

4 l3 l) n0 N: ~$ P6 k' k4 s  DMA方式
( N- f! w- B/ v" |) f) S$ k( U+ BHAL_JPEG_Encode_DMA. }; l( o. C6 K: K% G# {7 P3 J
! g1 S% R9 c5 d
HAL_JPEG_Decode_DMA
+ V0 i) B3 H. j4 b: \! i+ a8 B5 F$ Q$ @* w3 Y' R
  第4步:如果用户之前的数据已经处理完毕,需要插入新数据,会调用函数HAL_JPEG_GetDataCallback
3 T5 e/ ~  ?6 K! [7 M
% |$ I- X  H3 C9 N" y(1)如果新的数据已经准备好,需要调用函数HAL_JPEG_ConfigInputBuffer。如果新的数据没有准备好,需要等待插入新数据时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。9 e8 e, b) \; r! c) x  e
  l+ C3 d$ L5 r; ~
如果编解码的数据已经处理完毕,可以调用函数HAL_JPEG_ConfigInputBuffer设置InDataLength参数为0(此函数是在回调函数HAL_JPEG_GetDataCallback里面被调用的)。
4 S* G$ y  }- Y3 t/ H6 I, _- B8 k6 n
8 I7 o4 l$ @& H$ a* m- @
(2)函数HAL_JPEG_ConfigInputBuffer/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位提供输入数据。如果新的数据块未准备好,可以调用函数HAL_JPEG_Pause暂停输入,待数据准备好后,可以调用HAL_JPEG_ConfigInputBuffer设置新的输入缓冲和大小,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。/ I$ q. f! ~1 T7 X) Q  X

, T8 W  S8 F2 F  k
$ O$ h* k0 Z1 h5 y, ^. `(3)新的数据块准备好后,可以在回调函数HAL_JPEG_GetDataCallback外面调用HAL_JPEG_ConfigInputBuffer 和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_GetDataCallback里面调用HAL_JPEG_Resume。
- e1 a* Q' E4 h% A4 p/ c
) B9 U+ u9 Y) C$ o1 a) F! ?/ T" }
7 ~  h9 J( L! h. v4 N) }7 [  第5步:输出缓冲区填充了给定大小的数据后,会调用回调函数HAL_JPEG_DataReadyCallback+ q2 s' s+ L% e" t' ]

; d* _; a  s% K- C  K(1)如果有数据空间存储新数据块,需要调用函数HAL_JPEG_ConfigOutputBuffer配置新存储位置。如果没有数据空间存储新数据块,需要等待有数据空间可用时,可以调用函数HAL_JPEG_Pause(参数XferSelection被设置为JPEG_PAUSE_RESUME_INPUT),待有数据空间可用时,可以调用HAL_JPEG_ConfigOutputBuffe设置新的输出缓冲,然后调用函数HAL_JPEG_Resume恢复JPEG编解码。
; `3 x0 x# B% i; C4 W% c2 R" _/ P( C5 y' o
(2)函数HAL_JPEG_ConfigOutputBuffe/HAL_JPEG_Pause/HAL_JPEG_Resume的工作机制允许应用程序以块为单位接收数据。当接收到数据块时,应用程序可以暂停JPEG输出来处理这些数据,比如解码时YCbCr转RGB或者编码时数据存储。
. {1 p# c, u  N; f& X/ o$ c3 ]8 C' ?" i# }2 z" m
(3)新的数据空间准备好后,可以在回调函数HAL_JPEG_DataReadyCallback外面调用HAL_JPEG_ConfigOutputBuffer和 HAL_JPEG_Resume,但是为了保持数据一致性问题,务必在回调函数HAL_JPEG_DataReadyCallback里面调用HAL_JPEG_Resume。6 P5 }  B0 K+ n% Q
$ E# H% H$ V7 t# n. H
% W1 }, [. m# G$ b0 G8 K* r1 M
  第6步:其它相关函数$ Q" m7 K  x. P
5 \' ^9 A# e. c' K4 O3 s3 |6 o& D
  JPEG解码时,如果解码成功,会调用回调函数HAL_JPEG_InfoReadyCallback。$ [$ v& X8 t# J0 m% V1 F! U! c9 M% H
  JPEG编码操作结束后会调用回调函数HAL_JPEG_EncodeCpltCallback。6 K0 `9 B9 t6 H
  JPEG解码操作结束后,会调用回调函数HAL_JPEG_DecodeCpltCallback。
+ B& @. i# j" m3 I8 b  操作过程中出现错误,会调用回调函数HAL_JPEG_ErrorCallback,用户可以调用函数HAL_JPEG_GetError获取错误类型。4 H% {  A  `$ l5 C
  HAL JPEG默认使用的是ISO/IEC 10918-1规格量化表,如果要修改,可以调用函数HAL_JPEG_SetUserQuantTables实现。
; e+ y$ O; W6 X; ~  通过函数HAL_JPEG_GetState可以获取JPEG状态。
3 e3 {3 M, ]/ G; v2 G3 Q8 Z# _* j1 z, S# s- H5 u7 j
: A! j$ ^, W! A% l/ O$ T
57.4 源文件stm32h7xx_hal_jpeg.c
$ p1 }/ l8 h/ r1 H$ `这里把我们把如下几个常用到的函数做个说明:1 r6 m: I  z: Z$ G& P# Y

* g! i4 o$ @% P, o& B! f4 C* p% b  HAL_JPEG_Init
3 l7 w! c  Z, F9 D5 M6 P8 a9 n  v  HAL_JPEG_GetInfo* b/ i/ y; _! w1 t" d
  HAL_JPEG_Decode_DMA
( `0 z% I. E8 U0 d  HAL_JPEG_ConfigInputBuffer0 G$ Z. n  k: d' S
  HAL_JPEG_ConfigOutputBuffer
- q' l- g* i/ S0 o2 U+ d3 G2 y
  X, L7 _  t( l' ]7 [57.4.1 函数HAL_JPEG_Init
4 o/ @( L0 ]( T) c" \函数原型:. @* D# S% U: v4 W; c  r& ^

4 ^% H# s0 d( ^8 d0 _9 U6 x
  1. HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)/ s# U- {1 w. f4 q  A; N: u
  2. {
    3 M* c+ e# G& I; T& x% h* i
  3.   uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);" V, @/ g2 R/ X9 m8 X( l
  4.   uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);9 m3 {' c7 U( F4 ^7 ^* t. M! O
  5.   uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
    , O" u! G6 W9 ~  P7 A
  6.   uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);5 D' x9 u8 k, w9 [% {9 X: l
  7. 8 j% T; T& x+ I6 P' |, T9 S# d' b
  8.   /* 检测句柄是否有效 */
    + V- e" V1 i( z0 B/ ~2 d" {
  9.   if(hjpeg == NULL)" D9 U6 ]$ j$ m& Q
  10.   {; y! D) G% a7 Y# l1 N
  11.     return HAL_ERROR;
    2 Y0 u- q* C  ^9 x) H9 ^* U
  12.   }
    + u8 D  w6 i+ B9 ], X" D
  13. / A1 q& @+ s( D2 D' @7 R% {
  14.   if(hjpeg->State == HAL_JPEG_STATE_RESET)
    5 c" k4 {. e; [+ a' w
  15.   {) a* P6 h1 i9 b  V; K0 z8 _
  16.     hjpeg->Lock = HAL_UNLOCKED;
    1 K/ [; ^5 V+ z2 `# B
  17. ) v( \  Z) y: c0 P5 T2 v9 h
  18.      /* 初始化GPIO,NVIC等 */- G( {( F1 M# S/ V+ m- _, D
  19.     HAL_JPEG_MspInit(hjpeg);
    ( Q& ^* g/ J8 z5 i8 [$ M9 ?
  20.   }
    * }3 q" q3 Y; y
  21. 0 r/ i' G$ f( [# V
  22.   /* 设置JPEG状态 */$ }$ |& d4 N- j/ f
  23.   hjpeg->State = HAL_JPEG_STATE_BUSY;
    : R; `5 |; u7 u8 _7 {% e) y' M
  24. 6 ]" D4 I% E7 D# |* }( j2 Z# I
  25.   /* 使能JPEG  */
    3 R1 a) v$ |% g6 X' a7 k
  26.   __HAL_JPEG_ENABLE(hjpeg);
    / M. w1 z; ^) q7 O0 Q" ?$ \+ s

  27. 3 J  c3 n  k7 D' Y
  28.   /* 关闭JPEG编解码处理 */' N5 J! Q. c) W
  29.   hjpeg->Instance->CONFR0 &=  ~JPEG_CONFR0_START;7 m, s* o5 c0 p
  30. ) R7 n* Q5 w2 f+ e4 U( F
  31.   /* 关闭JPEG所有中断 */
    " X, }! L( q9 S1 f8 _( l) I% b
  32.   __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);# ]& a) C- h5 z4 l

  33. 6 I8 ^8 S9 [$ W
  34.   /* 清空输入输入FIFO缓冲 */9 V4 }9 I$ q9 k8 q! |+ s
  35.   hjpeg->Instance->CR |= JPEG_CR_IFF;
    8 ^5 @( R  ]) u2 Q; \0 r
  36.   hjpeg->Instance->CR |= JPEG_CR_OFF;  
    9 V3 d1 O" n9 Z+ ?; N* ]6 A9 j

  37. ! r& E0 t- x1 f
  38.   /* 清除所有标志 */8 Q( w" \. u# b$ H
  39.   __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);. h" v3 B; P0 u" r$ w. B
  40. 3 I7 v9 U, \0 e; q6 Z" W& D6 f
  41.   /* 初始化默认的量化表 */
    5 Z  I% n! _$ _) B
  42.   hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);8 Y3 t' |  @3 a8 p( o. W7 V
  43.   hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);( q0 d; j& }( n
  44.   hjpeg->QuantTable2 = NULL;3 n5 a& t/ J5 v2 p2 t3 t& W+ Q
  45.   hjpeg->QuantTable3 = NULL;
    $ `! @  D3 l/ e8 i1 l# i# t4 D

  46. 9 {. Y. t' Z' d! D" Q  y
  47.   /* 初始化默认的霍夫曼表 */* X: m& Y, h7 S9 @2 m
  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)
    # M9 N4 |- V6 U) I4 Z
  49.   {
    ( u) ?( b) h2 B& H3 {5 E
  50.     hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
    4 a( m# @4 k3 ~' `

  51. ' `" K& @% q# w0 p+ w  k
  52.     return HAL_ERROR;  [! b. K7 e  _3 b! H  y& M
  53.   }0 }( P5 L* S- R9 t

  54. 2 y7 ^- w6 e* e+ s
  55.   /* 使能文件头处理 */
    & D2 Z6 t, U8 k8 o* ~
  56.   hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;9 e! _/ B/ x8 ?: [& v$ \, ?* r9 J7 ]

  57. % h9 E) k9 i  N) z9 f# c2 M/ j
  58.   /* 复位JPEG输入输出计数 */
    6 b' h% _. n; c: }# P
  59.   hjpeg->JpegInCount = 0;
    & o, T5 f  U$ G0 k2 `! z9 n0 @9 @
  60.   hjpeg->JpegOutCount = 0;3 _4 k8 {* [- y* L

  61. * ~& e% P$ s% Y3 N$ G
  62.   /* 设置JPEG就绪 */
    ' Z* N9 v2 x2 f9 @1 m3 {/ |
  63.   hjpeg->State = HAL_JPEG_STATE_READY;3 i- ]7 ~  N0 o6 c) Q( D

  64. * H7 R7 N# C- I6 f- i7 P. E# Q/ u2 U
  65.   /* 设置无错误 Reset the JPEG ErrorCode */2 i( u' u1 k$ ~& t* R5 _7 q
  66.   hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;2 P) }; Z2 B) }, O
  67. . S* `0 s( K* ^3 A, F/ V4 a
  68.   /* 清除上下文 */( A5 E2 _& p) F: }; W% p
  69.   hjpeg->Context = 0;; a: W) D6 s  U5 ~
  70. 3 [: v) O6 d/ t, q+ l+ Q
  71.   /* 返回HAL_OK */
    ; M% E+ W) T3 W, {( `9 [/ w
  72.   return HAL_OK;
    7 H. y/ p5 E/ u
  73. }. O8 }6 B" A5 z2 O+ y
  74. - C) d0 G- _" J+ Z/ T. r4 w+ F
复制代码
! p2 E  J% W7 i' Y  Z4 [
函数描述:' q1 B0 r: o4 D7 g/ z
3 R' d+ |# C- K9 p
此函数用于初始化JPEG。  q( Y3 d  r5 q

3 J% x; u. X3 V0 J1 Y" f函数参数:' ^& D  o6 u+ t6 X. i% h" }
; j9 c9 t5 b6 O& X7 p
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
1 @& n1 J5 U& K6 _& B9 G& {  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。, _  L9 a: A% u9 ^& |
注意事项:
- n) M$ u6 K! J9 n9 K1 D8 x: S3 E. c
函数HAL_JPEG_MspInit用于初始化JPEG的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。" T2 U) R5 b$ Y
如果形参hjpeg的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量JPEG_HandleTypeDef JpegHandle。5 @) s8 Q& n5 L% q  O0 ^' z# n
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_JPEG_STATE_RESET  = 0x00U。5 H2 i0 i3 i+ R) L* ]: s; y2 q

2 Y* I$ k1 {( D$ y: v' N7 H解决办法有三
; E9 A4 s7 A* R/ z2 S( s5 R5 J( k0 \! F- h' d  ]; J9 d
方法1:用户自己初始JPEG底层。
9 r' n; }' F# ]% k
8 i4 E9 X+ s$ z- q方法2:定义JPEG_HandleTypeDef JpegHandle为全局变量。
" s7 m( M! v9 U8 K, z# _% H* a, Y: W
方法3:下面的方法
% K' w+ `9 K& H, _6 G
" M' ?" g+ H$ l1 B& {5 d
  1. if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
    $ \8 A/ a2 U' U+ z& U; v
  2. {6 Z7 m# V6 f( v9 w. N) l
  3.     Error_Handler();$ I! i) Q8 u6 |0 t" {
  4. }  0 m% w1 [- c6 F! D
  5. if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK): p2 u9 i. x, A' a
  6. {
    & h( T" |. ^* F/ w1 s4 ]
  7.     Error_Handler();
    8 Q6 L8 T! j7 m! A
  8. }
复制代码

! o  }3 E8 h! k% h* D* M( d使用举例:
% i! n( p# G6 q7 y
  1. JPEG_HandleTypeDef    JPEG_Handle;8 W3 C7 W7 }  s: s1 c' E
  2. JPEG_Handle.Instance = JPEG;
    % L4 j5 G0 }( @
  3. HAL_JPEG_Init(&JPEG_Handle);
复制代码
7 z! {! ^8 b+ J8 q. ]$ V
57.4.2 函数HAL_JPEG_GetInfo* c. P- O- \. ]4 h8 d9 Y/ N
函数原型:5 J- J- H3 J: ~) r
" p) @+ E" h; u) R  f6 g/ n1 G
  1. HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
    : E! ^# A9 c1 p' I7 F) @9 M
  2. {* g9 I* p. \. x' R& }
  3.   uint32_t yblockNb, cBblockNb, cRblockNb;
    $ @- B! \+ a; R  J5 }$ X4 B3 ^
  4. 8 Z9 ~. |& Q/ i9 _$ L# ?
  5.   /* 检测句柄是否有效 */
    0 L+ M2 b$ W! G- {" U, x
  6.   if((hjpeg == NULL) || (pInfo == NULL))( i, _4 P# a) a: a7 G
  7.   {
    " i+ ]3 B9 i* t4 W& F: k
  8.     return HAL_ERROR;
    & C- D$ y) M+ \. L5 ]) f
  9.   }
    6 ~9 y1 v. ^! q" @  {2 A. e' M

  10. 7 a: M8 s) ?  e( ]4 p; \6 H
  11.   /* 读取配置参数 */' e) u5 R0 n  _/ ~
  12.   if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
    5 n1 T+ {: n/ P" }" L
  13.   {
    + H6 G$ L* H  z* w7 a: h% ]
  14.     pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;   
    1 X4 |$ N$ `7 q( ?$ ^2 Y
  15.   }   
    1 ]* Q6 d7 S/ w! b. |4 f
  16.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
    9 L. |* q3 q5 ?7 Q: x
  17.   {
    6 u- t9 X2 E- F/ ~6 d) o  j  S. [9 _! I
  18.     pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
    ; E3 A: `0 d0 i7 H8 ?& V! P
  19.   }' i* W! t! I; X! m. I$ W
  20.   else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
    ! v5 r! q  h4 o$ `2 r: j
  21.   {8 l0 x  ^2 O: W. [2 s
  22.     pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;   
    ) Q! q* N# O8 V% w6 S
  23.   }" t$ }: t) s8 m# x

  24. - F% J% l' {  a. V
  25.   pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
    ( M# o8 \2 X3 G- R
  26.   pInfo->ImageWidth  = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
    & D6 J6 L) o9 r6 G

  27. + b+ ~, n/ a) O) D% T  \3 J
  28.   if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))) m! X, w8 q! Y, V5 n0 f* |: k
  29.   {5 X9 u& _. O1 v( Y
  30.     yblockNb  = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;1 Q0 @+ N5 J2 _% U
  31.     cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;- |6 S' O- Y" f& {8 k
  32.     cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
    # C$ u# X2 s' f8 N5 ^3 R1 D

  33. ; o" t  P% z1 p* A/ u8 q+ h
  34.     if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
    / n, p. ~5 H4 p7 }
  35.     {
    , z, ]# u4 E& S' r4 i5 A! K
  36.       pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
    : c5 d7 a5 ?: u( v4 U6 z! g' o6 Q
  37.     }3 H: U/ X' p  g. X( n
  38.     else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
    $ ?; G1 \  [# P, }) V; ]
  39.     {
    / W) n2 X$ S5 ?" K2 _3 x
  40.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    , I4 u( w' E1 A# o8 D+ L1 g
  41.     }
    * m# @# G% a( B" C
  42.     else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))6 ^. X$ N1 Y  E
  43.     {
    * M: v' }8 p: m, U
  44.       pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;5 f: F4 r& Q) M+ U; C% m
  45.     }+ j. t: |2 |: ~: c+ C. k' Y
  46.     else /* 默认是 4:4:4*/
    3 o6 K. E' `0 {1 }0 G6 I" O
  47.     {( b$ N0 [8 W2 j. {
  48.       pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
    # P& J. @  p: j9 e3 G6 l
  49.     }
    ) J1 v) m' w6 L+ F* J; w0 H
  50.   }" f0 H. h  @$ F& i. E
  51.   else : a. I& T0 B2 P# i6 r6 B- e5 W$ A
  52.   {
    + x  P2 N5 Z& ]4 S" ^6 f4 ^
  53.     pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;. g# E, N+ a1 }
  54.   }
    7 f7 p- Y: M3 I! u5 r) Z# |7 k2 @
  55. 2 [; {9 v( N) H" p4 [
  56.   pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
    5 a+ Z" I. A* P& W
  57. ; i& V/ V% _; l" L' D
  58.   /* 返回HAL_OK */  i3 S  U1 d, R: B4 Y; a. D( ?
  59.   return HAL_OK;
    6 {/ r" [% I0 X3 i0 k+ i
  60. }9 W+ N5 f  b2 d1 Y1 P6 x& ?# g/ A8 q
复制代码
! t& l9 c/ ^5 Z
函数描述:
; v/ c( A. K: M( d9 @/ N. E) D$ s3 h
1 P8 _! v7 q5 w# C$ [此函数主要用于解码JPEG时获取相关图像信息,比如图像质量,图像长宽等。
$ C/ f# e2 l; B% _7 P# F% B$ P* |4 f2 a
函数参数:
4 E$ T7 _5 v7 X( A6 c- `1 f4 o  Z; P! t# n4 S- C
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。$ T* ?' W; m; ?3 u4 W0 X7 G
  第2个参数是JPEG_ConfTypeDef类型结构体指针变量,用于获取JPEG的配置信息,结构体变量成员的详细介绍看本章3.2小- d- i/ m  _& A) o1 T* _
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。2 e, @# C3 l1 N& e2 f$ h$ @4 L1 f

3 [) y$ @$ w* J1 @9 J; L9 a) I/ q& v; _
使用举例:0 l- e' H( Z5 ]8 d8 z
  1. JPEG_HandleTypeDef    JPEG_Handle;! t4 t6 C0 U1 A
  2. JPEG_ConfTypeDef      JPEG_Info;
    6 O5 V" M# d+ q. p. _1 {# X

  3. 5 ~0 o1 s5 B# f% L" }! j0 S; Y2 f/ `
  4. HAL_JPEG_GetInfo(&JPEG_Handle, &JPEG_Info);  
复制代码

, j% g& J; W. x6 m+ j2 b: M57.4.3 函数HAL_JPEG_Decode_DMA( y: x0 e0 r0 ]: f& p& g( R1 E
函数原型:0 N5 l. o& l  {4 N1 M$ a1 x

8 J+ N, f" d$ O0 m
  1. HAL_StatusTypeDef  HAL_JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg ,uint8_t *pDataIn ,uint32_t InDataLength ,uint8_t *pDataOutMCU ,uint32_t OutDataLength)0 ?( g& L+ W# g3 ~" V" |
  2. {
    % C4 q8 G5 Y/ Z4 O8 g3 W
  3.   /* 检测参数 */
    ) o1 g& Z1 N0 y8 f% t
  4.   assert_param((InDataLength >= 4));/ `0 @' S( t4 D1 q1 x
  5.   assert_param((OutDataLength >= 4));7 p, ^8 y) L* i8 [
  6. $ Y; G, u+ f8 e% L
  7.   /* 检测参数 */' [4 J% H' c3 m4 ]! Z+ k  V
  8.   if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
    * a  z" W/ {& L# J( s0 m$ b% v. z
  9.   {9 F+ R8 Q0 q% l6 h: {
  10.     return HAL_ERROR;
    2 X- I9 q9 v/ k
  11.   }; S& C% v% w; N4 g* @# h5 a
  12. 2 L2 r# [* M  i" T7 G! X  e
  13.   /* 上锁 */
    8 x8 [% @/ [% h
  14.   __HAL_LOCK(hjpeg);
    ! T3 o3 O$ k7 A1 W1 G2 b5 V/ `

  15. 9 S, {5 w# R# b, @) A+ j. Z
  16.   if(hjpeg->State == HAL_JPEG_STATE_READY)" Z# i: T' G* }6 G$ I! f9 }6 @4 D3 h
  17.   {" l, k$ I; I: E7 H1 G. j4 V
  18.     /* 设置JPEG忙 */% d1 n' Q1 n. h$ f5 T
  19.     hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;3 Z3 \- {$ t8 R  f) [- R
  20. $ N+ w1 |+ E( C& y
  21.     /* 设置JPEG上下文,工作在DMA界面状态 */3 G, a! g! p! H, J" h
  22.     hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
    1 I8 [/ E" U2 v  S
  23.     hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);         
    : m7 Q3 e( F) N' @, Z" g

  24. 2 Z; u1 u" B1 b6 a4 r% p* D
  25.     /* 设置输入输出缓冲地址和大小 */
    ! Q4 V! c/ O4 M* T1 k: u6 C9 `) T
  26.     hjpeg->pJpegInBuffPtr = pDataIn;
      v& P: J, q, ]
  27.     hjpeg->pJpegOutBuffPtr = pDataOutMCU;6 a+ U. e0 b# k. e, h8 x
  28.     hjpeg->InDataLength = InDataLength;6 J+ o6 \& w7 D: y
  29.     hjpeg->OutDataLength = OutDataLength;- C9 I4 n( U6 w1 j' g
  30. : _9 H- A: h9 U- x0 x) t! E
  31.     /* 复位输入输出缓冲计数 */
    0 W* }7 S2 s" m4 `5 w6 n5 U# u, M
  32.     hjpeg->JpegInCount = 0;   
    7 ?; s' k' K# J- P1 H8 M. N8 h
  33.     hjpeg->JpegOutCount = 0;   
      A: p+ V) m# E7 B$ b/ o3 K( R

  34. . ~' v" x" T8 p
  35.     /* 初始化解码处理 */
    & I3 b& z0 z5 o: ^# {# Z% o& c' |, J
  36.     JPEG_Init_Process(hjpeg);
      W4 z; C: R: R7 N4 S0 w

  37. * C3 V" I" x4 x
  38.     /* 启动JPEG解码处理,使用DMA方式 */: d- }' F- l# \1 q* y) i4 |
  39.     JPEG_DMA_StartProcess(hjpeg);( ]" A$ M1 G% n0 Z& c: ~9 N" V: y; U
  40. 6 Q. w, z' d/ _
  41.   }
    ) D' t0 a, [* F0 z
  42.   else
      t& [# f+ C$ N5 j4 v$ }$ k
  43.   {& R& j8 O; G2 r1 n5 S6 F6 c
  44.     /* 解锁 */
    8 S! g# F8 S* l1 ~1 H) V$ r
  45.     __HAL_UNLOCK(hjpeg);6 |5 h3 B7 u8 d/ B; h& M$ E4 u; b3 L
  46. 4 S1 k& y3 c: }, J! Z
  47.     return HAL_BUSY;' Q$ x" l. v$ G# k% H5 z' l
  48.   }" {/ x; `! z0 G9 n. t) b" D
  49. * m5 j! K, q$ q. y0 t. u4 G: H1 g, U, {
  50.   /* 返回HAL_OK */
    " C; N# ~3 Z% n3 o! c9 O6 t) b( ~
  51.   return HAL_OK;2 _) A5 }6 [9 i1 m
  52. }# {5 I( k7 v* v
复制代码
+ k% U& t7 y/ u6 _1 _

# U' F! \' K4 S- \5 I函数描述:
2 o% `% B$ s% P7 z; q* z8 m5 j0 v% j' i) E
此函数用于启动JPEG的DMA方式解码。+ ^  v" s; A' }' z
" u: x, L( ?! k2 k4 y- l1 ], L5 b
函数参数:! m  [  O4 @6 B
( N  t& A8 ]4 d3 J
  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
3 E! K& f+ T" h3 p  第2个参数是输入数据缓冲地址。
# y" z# G# ]0 y8 O- Z  第3个参数输入数据大小,单位字节。" H9 R' T0 D* |# ?; b
  第4个参数是输出缓冲地址。; L$ V* o" r- j1 H9 M
  第5个参数是输出缓冲大小,单位字节。: t7 T. G& ?) \, b8 g# m. I6 R
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。, Z# M( r1 r8 _6 N
% X/ f, V5 \: E# n
使用举例:& Z$ ^/ z( v6 A

; g! X& }8 ]9 R
  1. /*! `5 N9 q7 j! Y  r9 ~* l& ~
  2. *********************************************************************************************************
    : l1 D+ V- \2 L
  3. *    函 数 名: JPEG_Decode_DMA7 X; d6 a5 M. q) y. R, j8 _
  4. *    功能说明: JPEG解码
      ?2 }: C) {( N2 z- k" Z
  5. *    形    参: hjpeg               JPEG_HandleTypeDef句柄指针" e3 {$ C( T( C  Z3 C% T6 i
  6. *             FrameSourceAddress  数据地址% u" }/ n! H, n7 [9 G5 h
  7. *             FrameSize           数据大小
      Z$ U9 u4 a5 q
  8. *             DestAddress         目的数据地址
    ! r& G( o+ o6 r% E
  9. *    返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功
      ]0 K0 ~1 f6 J8 d" g
  10. *             HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
    6 B3 h# Z! \0 R
  11. *********************************************************************************************************9 a9 |5 W  Y& R' M
  12. */; j2 \2 ?- z1 V* n% e6 e, w/ x
  13. uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)4 z/ ~" O+ A3 L
  14. {6 E* S# C$ d) e7 _2 u
  15.     JPEGSourceAddress =  FrameSourceAddress ;
      a* q2 U, e: T7 ^
  16.     FrameBufferAddress = DestAddress;
    ( }' c$ ~: ^& }) A3 o
  17.     Input_frameIndex = 0;! U# x, j( y) {7 p, u
  18.     Input_frameSize = FrameSize;
    / m% s( u$ Y1 m, o2 y5 K
  19. . I4 x+ w; Z2 a+ g& G0 L
  20.     /* 设置标志,0表示开始解码,1表示解码完成 */
    ! ]5 Z7 r% N+ L- J1 W' e
  21.     Jpeg_HWDecodingEnd = 0;
    - t3 p! |9 I; s# ?8 I& V

  22. 3 x: J, h; I! w# a
  23.     /* 启动JPEG解码 */% T! J' B6 X# \2 l  L
  24.     HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,( B5 D& H7 J4 Z
  25. (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);! A; t7 q, ^3 Z

  26. - V& a) P& |/ ~" ~
  27.     return HAL_OK;' D6 [$ U/ m) |9 G6 w5 F8 R1 H# o" c
  28. }
复制代码
: A* m- B" a3 o$ I; Q1 O
57.4.4 函数HAL_JPEG_ConfigInputBuffer3 W4 s3 p8 ]0 s; Q
函数原型:
, Y. z5 u; B) v. C; G6 J) g6 m; T1 w' O
  1. void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)/ O, T" x0 u: x
  2. {& k6 P) l2 g0 ?& M" Y8 i' p* W
  3.   hjpeg->pJpegInBuffPtr =  pNewInputBuffer;
    % J' x% |; q8 B. u
  4.   hjpeg->InDataLength = InDataLength;' t# \( v& X9 d1 T
  5. }
复制代码

3 \+ T% }) ^; v1 Z6 r函数描述:
( u% c) u4 W  l; B5 _  V3 \9 Q- B2 t- ~3 A( A* `8 g  ^
此函数用于配置编解码输入缓冲地址和数据大小。
) g7 P2 B5 A. h# j, u2 L) N$ M* D( {5 S$ e- _' t$ n- _
函数参数:# H9 m! X- l2 L$ Z$ ~) z

) x& T$ Y  \* c, Y  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。5 H$ z( _- E( |( d3 Y
  第2个参数是输入缓冲地址。8 D- Q  E% V# ~4 j
  第3个参数是输入缓冲大小,单位字节。- W- L/ n3 J  t
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
% x6 S' [" L6 ]使用举例:
& K  ]" Q- H7 x, J7 j+ I; w$ Z. L3 g
  1. /*7 S  C3 [) |- A& K0 L$ ]( v
  2. *********************************************************************************************************
    % ], ^5 w+ j, p: {4 a- N  e( ]
  3. *    函 数 名: HAL_JPEG_GetDataCallback) n8 K" \& a4 l; |* `
  4. *    功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码* W; L& F  F$ A
  5. *    形    参: hjpeg          JPEG_HandleTypeDef 句柄指针
    : o# h  i7 x0 ^8 p( J' p
  6. *             NbDecodedData  上一轮已经解码的数据大小,单位字节  
    $ I9 r0 {7 a% [* T: a9 \
  7. *    返 回 值: 无% m! i3 x4 b, _7 R* N+ Q- S
  8. *********************************************************************************************************' ^% t- h5 \3 m/ r7 o  T3 \8 I$ m
  9. *// w9 ]0 b- V2 @* r3 y5 g3 M) F
  10. void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)& X, H1 {% x( q) N: R0 _% L& I
  11. {
    3 A" r% Y/ m7 e% B$ d1 j/ P
  12.     uint32_t inDataLength;
    8 T' {/ z" K& s
  13. $ `5 ]( O% _6 H/ X
  14.     /* 更新已经解码的数据大小 */
    ' I) }4 |( ]6 S
  15.     Input_frameIndex += NbDecodedData;
    + L3 X3 j! Q) l! _" B& I
  16. 4 Q' v' M( Q' j" A! U
  17.     /* 如果当前已经解码的数据小于总文件大小,继续解码 */, T- J3 u& R2 u
  18.     if( Input_frameIndex < Input_frameSize)
    * p5 Y/ o% U9 a( s
  19.     {
    4 h0 h: L8 q: h" s
  20.         /* 更新解码数据位置 */" H) L9 |: L. _( o7 ?7 {( ]
  21.         JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
    6 ?, e, y! Z7 W; ~/ x4 M

  22. 8 B2 H8 }; B& l' N9 ?
  23.         /* 更新下一轮要解码的数据大小 */
    " t$ x3 j' _/ H' m& U9 q6 j
  24.         if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
    & ^/ {* B9 R3 j3 p3 s  c  \7 d
  25.         {4 D/ ^1 W5 }8 C, p8 i& u- u
  26.             inDataLength = CHUNK_SIZE_IN;
    8 |+ b  V6 |( a% T+ S" Y
  27.         }* w0 R% E. N( D" w4 l
  28.         else
    8 d" ?& v' q; Y
  29.         {
    " x8 h4 v( J0 t, w# Y0 V; ^
  30.             inDataLength = Input_frameSize - Input_frameIndex;4 o( ~# S4 Z5 @3 G
  31.         }    " T; |7 l7 c4 K0 r; s6 ?0 W
  32.     }& b$ i, F  r4 J0 w1 h; T+ j
  33.     else' x, o$ w- e3 H* ?: z" ~- w
  34.     {7 u/ ~% K. E' R2 |
  35.         inDataLength = 0; ( e9 r* D. o: e& @
  36.     }* y9 r( n3 p- K6 t$ V
  37. 2 |5 q! d' D0 m
  38.     /* 更新输入缓冲 */
    & d, d( a; L0 E7 k* p
  39.     HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength);    + Z' u. G5 E" \" v" B
  40. }
复制代码

  s5 w* ?2 j2 r+ I2 I0 W
" g# w/ S1 T; o# ]% U57.4.5 函数HAL_JPEG_ConfigOutputBuffer
7 t3 K+ w/ E2 R4 @& c: W8 l函数原型:
4 Z3 v: d" U9 }' f$ z. w2 X
  n, a8 y9 h) N
  1. void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)& x* z% q4 {6 D! Z8 n
  2. {
    7 x( ~% ]. G8 ~' ~: E9 k8 W
  3.   hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;3 t+ S, n9 W1 p; k: I
  4.   hjpeg->OutDataLength = OutDataLength;  
    / E# t! i4 V% ^; ^1 W' V
  5. }
复制代码

0 I+ N* S: s( g" E4 N. C. h. ]
/ V1 L8 O$ |3 V9 l: Y函数描述:
7 K# ~& B7 k/ s
/ p2 j' I* |) G; a此函数用于配置编解码输出缓冲地址和数据大小。
8 p7 p  t$ |1 ?3 v. {4 n3 w4 ?
函数参数:
& D% F$ ], g/ t  o6 Y( ~- j
. j' ~& O5 [3 l0 C. u  第1个参数是JPEG_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.3小节。
5 \  a* W/ {& H! N; {# Z  ?9 y8 W  第2个参数是输出缓冲地址。+ J0 q5 Z" N9 g2 F) b; D7 F$ @
  第3个参数是输出缓冲大小,单位字节。
* }, ?# |/ Q3 n% X- @6 f6 W: j+ `7 |  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
! }& U/ _; `" c9 O7 A使用举例:
& e, `' Y8 U( g; w6 s% Q+ \; |" }9 x4 |
  1. /*. ?; e- H- f, G0 Q5 c% ?6 @
  2. *********************************************************************************************************
    4 ^% ^: @) f) o( b% p" r! q
  3. *    函 数 名: HAL_JPEG_DataReadyCallback* h& L. Q! I& x2 z/ ~1 H
  4. *    功能说明: JPEG回调函数,用于输出缓冲地址更新. B* S% t! r& x( s; ]3 Q
  5. *    形    参: hjpeg         JPEG_HandleTypeDef 句柄指针
    ! z: Q% r- S" i) G" D
  6. *             pDataOut      输出数据缓冲: U) o5 |2 K8 X0 V" G* S" V6 y
  7. *             OutDataLength 输出数据大小,单位字节
    6 O) |5 W2 l) l
  8. *    返 回 值: 无/ n3 w. i# g- C/ I" f
  9. *********************************************************************************************************# s6 T% g, x5 i
  10. */
    ; K9 N6 W. h6 I. g1 s2 L/ q+ p
  11. void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
    6 c7 X1 q: D$ c9 L
  12. {. Q3 o+ v9 H' T
  13.     /* 更新JPEG输出地址 */  
    9 t3 G/ }8 t& O& t1 |4 H: t1 T9 n
  14.     FrameBufferAddress += OutDataLength;2 O, b5 C6 m5 e# G

  15. % p. e5 D) x& u
  16.     HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
    " [: [% y% J1 N
  17. }
复制代码

# _' n* c" N( \; C0 M1 S2 }57.5 总结5 @1 v( j0 a8 n; R, N) u! U, m$ t
本章节就为大家讲解这么多,JPEG功能用到的地方还是比较多的,建议熟练使用。
- {9 m& g" S- z; D. c
; d9 ?% B2 A3 M0 w6 d$ j& s" F! e* R' n
3 Y0 o# ?) {$ x7 D! L, F
收藏 评论0 发布时间:2021-12-21 21:46

举报

0个回答

所属标签

相似分享

官网相关资源

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