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$ _
! 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
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
( 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
- 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* ^
& 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
- typedef struct+ m/ a p6 q2 ^# A$ C9 H
- {! g, y$ Q6 s2 u
- __IO uint32_t CONFR0; ' E" h* `: j* F, A/ p
- __IO uint32_t CONFR1; & j5 {7 u- B3 B1 q
- __IO uint32_t CONFR2;
* M8 n7 H5 U( j/ Z+ O - __IO uint32_t CONFR3;
3 J$ j$ f9 M e& t! c - __IO uint32_t CONFR4;
/ K" M- q- N. o1 o- U - __IO uint32_t CONFR5; $ n# V5 G% z+ T* F
- __IO uint32_t CONFR6; ; h0 s9 g. ^! c n
- __IO uint32_t CONFR7; 9 r) i* ~: v& |/ d1 _' v* Q
- uint32_t Reserved20[4]; 0 q7 M3 H: {/ v" }
- __IO uint32_t CR; ! b0 t) J7 c' b
- __IO uint32_t SR; ) S% F5 j1 @8 ?: U1 `0 K' H. l
- __IO uint32_t CFR;
( o; g. {/ B3 I+ V K - uint32_t Reserved3c; & A/ d# I& `% m E1 C* a$ t
- __IO uint32_t DIR;
$ S! w K- n4 U5 P2 p) C3 I4 E3 k- U - __IO uint32_t DOR; " G7 Z7 S2 W. S- C
- uint32_t Reserved48[2]; # l W, f+ _3 N5 D2 j8 J t
- __IO uint32_t QMEM0[16]; ' _7 ?' n+ D( h# l8 \
- __IO uint32_t QMEM1[16];
$ ~+ N' b1 F2 q# ]+ E+ v - __IO uint32_t QMEM2[16]; ! H1 l7 d! @) r* P% y
- __IO uint32_t QMEM3[16]; ! C% _9 k5 v2 i2 ?' y; e& }- U9 y
- __IO uint32_t HUFFMIN[16];
. E" \5 B; Q @2 i - __IO uint32_t HUFFBASE[32]; 8 i7 |" }& Y# y! }
- __IO uint32_t HUFFSYMB[84];
3 j. B& h" C( R' [ - __IO uint32_t DHTMEM[103]; 6 `& a+ @( v, K j1 F0 Z
- uint32_t Reserved4FC; 4 r( ~; M @' s8 v
- __IO uint32_t HUFFENC_AC0[88]; 9 F8 h" j2 A! N& S, e U& w% |
- __IO uint32_t HUFFENC_AC1[88]; 2 m0 w4 {' Q8 [7 u6 C5 V# ~, Y
- __IO uint32_t HUFFENC_DC0[8]; 4 F. \. Z7 S9 f
- __IO uint32_t HUFFENC_DC1[8]; # u" N7 m/ g. Q+ p
- } 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 ^
- #define __O volatile /*!< Defines 'write only' permissions */
3 d1 d! d; i- t, V' R. B - #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
- #define PERIPH_BASE ((uint32_t)0x40000000)
3 q& u- T Y+ K% b1 p' b - #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000)5 F. A I5 R# R
- #define JPEG ((JPEG_TypeDef *) JPGDEC_BASE)$ L' C7 \* \1 t$ I; c* y
- #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, ?- typedef struct
9 U7 C8 M! e2 K* U7 S! I6 B( q - {6 J! J) U) W; a, h' `
- uint8_t ColorSpace;
/ S L# f" D/ c* [. y - uint8_t ChromaSubsampling;
3 C" ~& L" f3 G' Z1 R" u/ ]+ P - uint32_t ImageHeight;
' p) J3 U+ N% ~$ T7 F2 q1 W - uint32_t ImageWidth; 5 ^4 e2 X7 @ g% _
- uint8_t ImageQuality; / I6 A2 |0 y/ {# k4 Y! }
- }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
- #define JPEG_GRAYSCALE_COLORSPACE ((uint32_t)0x00000000U) /* 灰度(1 个量化表)*/
% ?5 t; }" _! Z& t' _) T - #define JPEG_YCBCR_COLORSPACE JPEG_CONFR1_COLORSPACE_0 /* YUV(2 个量化表) */
4 R5 P4 @2 }4 } - #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
- #define JPEG_444_SUBSAMPLING ((uint32_t)0x00000000U) /* 4:4:4 */
' m9 g# A' {* _, ^! v5 B - #define JPEG_420_SUBSAMPLING ((uint32_t)0x00000001U) /* 4:2:0 */% {8 L/ Q+ l C$ \! \5 @) n
- #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- typedef struct# r/ |( G2 @# t& {/ V
- {
- i4 W7 S, `+ i0 O2 z+ C* h0 Z. J2 F - JPEG_TypeDef *Instance; : H0 ]0 H! H8 Y+ T% j6 F
- JPEG_ConfTypeDef Conf; ' _( B- V" B. c4 }5 |* f" L; ^
- uint8_t *pJpegInBuffPtr;
1 M2 `6 n v2 `: { - uint8_t *pJpegOutBuffPtr;
! j. `' T0 N2 N3 ~) k - __IO uint32_t JpegInCount; 3 k7 i! j; S" Z5 G" ~5 ?
- __IO uint32_t JpegOutCount;
* Z6 X9 A* W4 B8 u6 ]( Z - uint32_t InDataLength; + a5 \' O; _4 E( H
- uint32_t OutDataLength; 3 r. F: D! q; a% @) k" w) f
- MDMA_HandleTypeDef *hdmain; $ E8 P: o5 P1 E. F% U$ J) u
- MDMA_HandleTypeDef *hdmaout;
! S/ ~/ e: @6 p, D& a. w; E - uint8_t CustomQuanTable;
& y: v; Y) c$ A9 l9 o- m0 A0 L - uint8_t *QuantTable0;
' H0 |" W, i% L, c - uint8_t *QuantTable1; 9 @4 R5 r/ \9 Q7 V% B; h4 v
- uint8_t *QuantTable2; % }- W: T8 {, l
- uint8_t *QuantTable3;
" G" [0 ?! i, ^' c1 Y7 X$ k( z4 g - HAL_LockTypeDef Lock; ! J1 c% W- A1 W' J# q. ?9 @* k
- __IO HAL_JPEG_STATETypeDef State;
/ N" C9 N8 F. R* k) m; Y3 x5 L - __IO uint32_t ErrorCode; , c2 n" Z2 s% U- t" l# x7 E0 ^9 W- x" [
- __IO uint32_t Context;
# _4 W% M! L7 t$ x0 w0 ?8 g1 j - }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- HAL_StatusTypeDef HAL_JPEG_Init(JPEG_HandleTypeDef *hjpeg)/ s# U- {1 w. f4 q A; N: u
- {
3 M* c+ e# G& I; T& x% h* i - uint32_t acLum_huffmanTableAddr = (uint32_t)(&JPEG_ACLUM_HuffTable);" V, @/ g2 R/ X9 m8 X( l
- uint32_t dcLum_huffmanTableAddr = (uint32_t)(&JPEG_DCLUM_HuffTable);9 m3 {' c7 U( F4 ^7 ^* t. M! O
- uint32_t acChrom_huffmanTableAddr = (uint32_t)(&JPEG_ACCHROM_HuffTable);
, O" u! G6 W9 ~ P7 A - uint32_t dcChrom_huffmanTableAddr = (uint32_t)(&JPEG_DCCHROM_HuffTable);5 D' x9 u8 k, w9 [% {9 X: l
- 8 j% T; T& x+ I6 P' |, T9 S# d' b
- /* 检测句柄是否有效 */
+ V- e" V1 i( z0 B/ ~2 d" { - if(hjpeg == NULL)" D9 U6 ]$ j$ m& Q
- {; y! D) G% a7 Y# l1 N
- return HAL_ERROR;
2 Y0 u- q* C ^9 x) H9 ^* U - }
+ u8 D w6 i+ B9 ], X" D - / A1 q& @+ s( D2 D' @7 R% {
- if(hjpeg->State == HAL_JPEG_STATE_RESET)
5 c" k4 {. e; [+ a' w - {) a* P6 h1 i9 b V; K0 z8 _
- hjpeg->Lock = HAL_UNLOCKED;
1 K/ [; ^5 V+ z2 `# B - ) v( \ Z) y: c0 P5 T2 v9 h
- /* 初始化GPIO,NVIC等 */- G( {( F1 M# S/ V+ m- _, D
- HAL_JPEG_MspInit(hjpeg);
( Q& ^* g/ J8 z5 i8 [$ M9 ? - }
* }3 q" q3 Y; y - 0 r/ i' G$ f( [# V
- /* 设置JPEG状态 */$ }$ |& d4 N- j/ f
- hjpeg->State = HAL_JPEG_STATE_BUSY;
: R; `5 |; u7 u8 _7 {% e) y' M - 6 ]" D4 I% E7 D# |* }( j2 Z# I
- /* 使能JPEG */
3 R1 a) v$ |% g6 X' a7 k - __HAL_JPEG_ENABLE(hjpeg);
/ M. w1 z; ^) q7 O0 Q" ?$ \+ s
3 J c3 n k7 D' Y- /* 关闭JPEG编解码处理 */' N5 J! Q. c) W
- hjpeg->Instance->CONFR0 &= ~JPEG_CONFR0_START;7 m, s* o5 c0 p
- ) R7 n* Q5 w2 f+ e4 U( F
- /* 关闭JPEG所有中断 */
" X, }! L( q9 S1 f8 _( l) I% b - __HAL_JPEG_DISABLE_IT(hjpeg,JPEG_INTERRUPT_MASK);# ]& a) C- h5 z4 l
6 I8 ^8 S9 [$ W- /* 清空输入输入FIFO缓冲 */9 V4 }9 I$ q9 k8 q! |+ s
- hjpeg->Instance->CR |= JPEG_CR_IFF;
8 ^5 @( R ]) u2 Q; \0 r - hjpeg->Instance->CR |= JPEG_CR_OFF;
9 V3 d1 O" n9 Z+ ?; N* ]6 A9 j
! r& E0 t- x1 f- /* 清除所有标志 */8 Q( w" \. u# b$ H
- __HAL_JPEG_CLEAR_FLAG(hjpeg,JPEG_FLAG_ALL);. h" v3 B; P0 u" r$ w. B
- 3 I7 v9 U, \0 e; q6 Z" W& D6 f
- /* 初始化默认的量化表 */
5 Z I% n! _$ _) B - hjpeg->QuantTable0 = (uint8_t *)((uint32_t)JPEG_LUM_QuantTable);8 Y3 t' | @3 a8 p( o. W7 V
- hjpeg->QuantTable1 = (uint8_t *)((uint32_t)JPEG_CHROM_QuantTable);( q0 d; j& }( n
- hjpeg->QuantTable2 = NULL;3 n5 a& t/ J5 v2 p2 t3 t& W+ Q
- hjpeg->QuantTable3 = NULL;
$ `! @ D3 l/ e8 i1 l# i# t4 D
9 {. Y. t' Z' d! D" Q y- /* 初始化默认的霍夫曼表 */* X: m& Y, h7 S9 @2 m
- 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 - {
( u) ?( b) h2 B& H3 {5 E - hjpeg->ErrorCode = HAL_JPEG_ERROR_HUFF_TABLE;
4 a( m# @4 k3 ~' `
' `" K& @% q# w0 p+ w k- return HAL_ERROR; [! b. K7 e _3 b! H y& M
- }0 }( P5 L* S- R9 t
2 y7 ^- w6 e* e+ s- /* 使能文件头处理 */
& D2 Z6 t, U8 k8 o* ~ - hjpeg->Instance->CONFR1 |= JPEG_CONFR1_HDR;9 e! _/ B/ x8 ?: [& v$ \, ?* r9 J7 ]
% h9 E) k9 i N) z9 f# c2 M/ j- /* 复位JPEG输入输出计数 */
6 b' h% _. n; c: }# P - hjpeg->JpegInCount = 0;
& o, T5 f U$ G0 k2 `! z9 n0 @9 @ - hjpeg->JpegOutCount = 0;3 _4 k8 {* [- y* L
* ~& e% P$ s% Y3 N$ G- /* 设置JPEG就绪 */
' Z* N9 v2 x2 f9 @1 m3 {/ | - hjpeg->State = HAL_JPEG_STATE_READY;3 i- ]7 ~ N0 o6 c) Q( D
* H7 R7 N# C- I6 f- i7 P. E# Q/ u2 U- /* 设置无错误 Reset the JPEG ErrorCode */2 i( u' u1 k$ ~& t* R5 _7 q
- hjpeg->ErrorCode = HAL_JPEG_ERROR_NONE;2 P) }; Z2 B) }, O
- . S* `0 s( K* ^3 A, F/ V4 a
- /* 清除上下文 */( A5 E2 _& p) F: }; W% p
- hjpeg->Context = 0;; a: W) D6 s U5 ~
- 3 [: v) O6 d/ t, q+ l+ Q
- /* 返回HAL_OK */
; M% E+ W) T3 W, {( `9 [/ w - return HAL_OK;
7 H. y/ p5 E/ u - }. O8 }6 B" A5 z2 O+ y
- - 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- if(HAL_JPEG_DeInit(&JpegHandle) != HAL_OK)
$ \8 A/ a2 U' U+ z& U; v - {6 Z7 m# V6 f( v9 w. N) l
- Error_Handler();$ I! i) Q8 u6 |0 t" {
- } 0 m% w1 [- c6 F! D
- if(HAL_JPEG_Init(&Dma2dHandle) != HAL_OK): p2 u9 i. x, A' a
- {
& h( T" |. ^* F/ w1 s4 ] - Error_Handler();
8 Q6 L8 T! j7 m! A - }
复制代码
! o }3 E8 h! k% h* D* M( d使用举例:
% i! n( p# G6 q7 y- JPEG_HandleTypeDef JPEG_Handle;8 W3 C7 W7 } s: s1 c' E
- JPEG_Handle.Instance = JPEG;
% L4 j5 G0 }( @ - 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
- HAL_StatusTypeDef HAL_JPEG_GetInfo(JPEG_HandleTypeDef *hjpeg, JPEG_ConfTypeDef *pInfo)
: E! ^# A9 c1 p' I7 F) @9 M - {* g9 I* p. \. x' R& }
- uint32_t yblockNb, cBblockNb, cRblockNb;
$ @- B! \+ a; R J5 }$ X4 B3 ^ - 8 Z9 ~. |& Q/ i9 _$ L# ?
- /* 检测句柄是否有效 */
0 L+ M2 b$ W! G- {" U, x - if((hjpeg == NULL) || (pInfo == NULL))( i, _4 P# a) a: a7 G
- {
" i+ ]3 B9 i* t4 W& F: k - return HAL_ERROR;
& C- D$ y) M+ \. L5 ]) f - }
6 ~9 y1 v. ^! q" @ {2 A. e' M
7 a: M8 s) ? e( ]4 p; \6 H- /* 读取配置参数 */' e) u5 R0 n _/ ~
- if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF_1)
5 n1 T+ {: n/ P" }" L - {
+ H6 G$ L* H z* w7 a: h% ] - pInfo->ColorSpace = JPEG_YCBCR_COLORSPACE;
1 X4 |$ N$ `7 q( ?$ ^2 Y - }
1 ]* Q6 d7 S/ w! b. |4 f - else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == 0)
9 L. |* q3 q5 ?7 Q: x - {
6 u- t9 X2 E- F/ ~6 d) o j S. [9 _! I - pInfo->ColorSpace = JPEG_GRAYSCALE_COLORSPACE;
; E3 A: `0 d0 i7 H8 ?& V! P - }' i* W! t! I; X! m. I$ W
- else if((hjpeg->Instance->CONFR1 & JPEG_CONFR1_NF) == JPEG_CONFR1_NF)
! v5 r! q h4 o$ `2 r: j - {8 l0 x ^2 O: W. [2 s
- pInfo->ColorSpace = JPEG_CMYK_COLORSPACE;
) Q! q* N# O8 V% w6 S - }" t$ }: t) s8 m# x
- F% J% l' { a. V- pInfo->ImageHeight = (hjpeg->Instance->CONFR1 & 0xFFFF0000U) >> 16;
( M# o8 \2 X3 G- R - pInfo->ImageWidth = (hjpeg->Instance->CONFR3 & 0xFFFF0000U) >> 16;
& D6 J6 L) o9 r6 G
+ b+ ~, n/ a) O) D% T \3 J- if((pInfo->ColorSpace == JPEG_YCBCR_COLORSPACE) || (pInfo->ColorSpace == JPEG_CMYK_COLORSPACE))) m! X, w8 q! Y, V5 n0 f* |: k
- {5 X9 u& _. O1 v( Y
- yblockNb = (hjpeg->Instance->CONFR4 & JPEG_CONFR4_NB) >> 4;1 Q0 @+ N5 J2 _% U
- cBblockNb = (hjpeg->Instance->CONFR5 & JPEG_CONFR5_NB) >> 4;- |6 S' O- Y" f& {8 k
- cRblockNb = (hjpeg->Instance->CONFR6 & JPEG_CONFR6_NB) >> 4;
# C$ u# X2 s' f8 N5 ^3 R1 D
; o" t P% z1 p* A/ u8 q+ h- if((yblockNb == 1) && (cBblockNb == 0) && (cRblockNb == 0))
/ n, p. ~5 H4 p7 } - {
, z, ]# u4 E& S' r4 i5 A! K - pInfo->ChromaSubsampling = JPEG_422_SUBSAMPLING; /*16x8 block*/
: c5 d7 a5 ?: u( v4 U6 z! g' o6 Q - }3 H: U/ X' p g. X( n
- else if((yblockNb == 0) && (cBblockNb == 0) && (cRblockNb == 0))
$ ?; G1 \ [# P, }) V; ] - {
/ W) n2 X$ S5 ?" K2 _3 x - pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
, I4 u( w' E1 A# o8 D+ L1 g - }
* m# @# G% a( B" C - else if((yblockNb == 3) && (cBblockNb == 0) && (cRblockNb == 0))6 ^. X$ N1 Y E
- {
* M: v' }8 p: m, U - pInfo->ChromaSubsampling = JPEG_420_SUBSAMPLING;5 f: F4 r& Q) M+ U; C% m
- }+ j. t: |2 |: ~: c+ C. k' Y
- else /* 默认是 4:4:4*/
3 o6 K. E' `0 {1 }0 G6 I" O - {( b$ N0 [8 W2 j. {
- pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;
# P& J. @ p: j9 e3 G6 l - }
) J1 v) m' w6 L+ F* J; w0 H - }" f0 H. h @$ F& i. E
- else : a. I& T0 B2 P# i6 r6 B- e5 W$ A
- {
+ x P2 N5 Z& ]4 S" ^6 f4 ^ - pInfo->ChromaSubsampling = JPEG_444_SUBSAMPLING;. g# E, N+ a1 }
- }
7 f7 p- Y: M3 I! u5 r) Z# |7 k2 @ - 2 [; {9 v( N) H" p4 [
- pInfo->ImageQuality = JPEG_GetQuality(hjpeg);
5 a+ Z" I. A* P& W - ; i& V/ V% _; l" L' D
- /* 返回HAL_OK */ i3 S U1 d, R: B4 Y; a. D( ?
- return HAL_OK;
6 {/ r" [% I0 X3 i0 k+ i - }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
- JPEG_HandleTypeDef JPEG_Handle;! t4 t6 C0 U1 A
- JPEG_ConfTypeDef JPEG_Info;
6 O5 V" M# d+ q. p. _1 {# X
5 ~0 o1 s5 B# f% L" }! j0 S; Y2 f/ `- 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- 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" |
- {
% C4 q8 G5 Y/ Z4 O8 g3 W - /* 检测参数 */
) o1 g& Z1 N0 y8 f% t - assert_param((InDataLength >= 4));/ `0 @' S( t4 D1 q1 x
- assert_param((OutDataLength >= 4));7 p, ^8 y) L* i8 [
- $ Y; G, u+ f8 e% L
- /* 检测参数 */' [4 J% H' c3 m4 ]! Z+ k V
- if((hjpeg == NULL) || (pDataIn == NULL) || (pDataOutMCU == NULL))
* a z" W/ {& L# J( s0 m$ b% v. z - {9 F+ R8 Q0 q% l6 h: {
- return HAL_ERROR;
2 X- I9 q9 v/ k - }; S& C% v% w; N4 g* @# h5 a
- 2 L2 r# [* M i" T7 G! X e
- /* 上锁 */
8 x8 [% @/ [% h - __HAL_LOCK(hjpeg);
! T3 o3 O$ k7 A1 W1 G2 b5 V/ `
9 S, {5 w# R# b, @) A+ j. Z- if(hjpeg->State == HAL_JPEG_STATE_READY)" Z# i: T' G* }6 G$ I! f9 }6 @4 D3 h
- {" l, k$ I; I: E7 H1 G. j4 V
- /* 设置JPEG忙 */% d1 n' Q1 n. h$ f5 T
- hjpeg->State = HAL_JPEG_STATE_BUSY_DECODING;3 Z3 \- {$ t8 R f) [- R
- $ N+ w1 |+ E( C& y
- /* 设置JPEG上下文,工作在DMA界面状态 */3 G, a! g! p! H, J" h
- hjpeg->Context &= ~(JPEG_CONTEXT_OPERATION_MASK | JPEG_CONTEXT_METHOD_MASK);
1 I8 [/ E" U2 v S - hjpeg->Context |= (JPEG_CONTEXT_DECODE | JPEG_CONTEXT_DMA);
: m7 Q3 e( F) N' @, Z" g
2 Z; u1 u" B1 b6 a4 r% p* D- /* 设置输入输出缓冲地址和大小 */
! Q4 V! c/ O4 M* T1 k: u6 C9 `) T - hjpeg->pJpegInBuffPtr = pDataIn;
v& P: J, q, ] - hjpeg->pJpegOutBuffPtr = pDataOutMCU;6 a+ U. e0 b# k. e, h8 x
- hjpeg->InDataLength = InDataLength;6 J+ o6 \& w7 D: y
- hjpeg->OutDataLength = OutDataLength;- C9 I4 n( U6 w1 j' g
- : _9 H- A: h9 U- x0 x) t! E
- /* 复位输入输出缓冲计数 */
0 W* }7 S2 s" m4 `5 w6 n5 U# u, M - hjpeg->JpegInCount = 0;
7 ?; s' k' K# J- P1 H8 M. N8 h - hjpeg->JpegOutCount = 0;
A: p+ V) m# E7 B$ b/ o3 K( R
. ~' v" x" T8 p- /* 初始化解码处理 */
& I3 b& z0 z5 o: ^# {# Z% o& c' |, J - JPEG_Init_Process(hjpeg);
W4 z; C: R: R7 N4 S0 w
* C3 V" I" x4 x- /* 启动JPEG解码处理,使用DMA方式 */: d- }' F- l# \1 q* y) i4 |
- JPEG_DMA_StartProcess(hjpeg);( ]" A$ M1 G% n0 Z& c: ~9 N" V: y; U
- 6 Q. w, z' d/ _
- }
) D' t0 a, [* F0 z - else
t& [# f+ C$ N5 j4 v$ }$ k - {& R& j8 O; G2 r1 n5 S6 F6 c
- /* 解锁 */
8 S! g# F8 S* l1 ~1 H) V$ r - __HAL_UNLOCK(hjpeg);6 |5 h3 B7 u8 d/ B; h& M$ E4 u; b3 L
- 4 S1 k& y3 c: }, J! Z
- return HAL_BUSY;' Q$ x" l. v$ G# k% H5 z' l
- }" {/ x; `! z0 G9 n. t) b" D
- * m5 j! K, q$ q. y0 t. u4 G: H1 g, U, {
- /* 返回HAL_OK */
" C; N# ~3 Z% n3 o! c9 O6 t) b( ~ - return HAL_OK;2 _) A5 }6 [9 i1 m
- }# {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- /*! `5 N9 q7 j! Y r9 ~* l& ~
- *********************************************************************************************************
: l1 D+ V- \2 L - * 函 数 名: JPEG_Decode_DMA7 X; d6 a5 M. q) y. R, j8 _
- * 功能说明: JPEG解码
?2 }: C) {( N2 z- k" Z - * 形 参: hjpeg JPEG_HandleTypeDef句柄指针" e3 {$ C( T( C Z3 C% T6 i
- * FrameSourceAddress 数据地址% u" }/ n! H, n7 [9 G5 h
- * FrameSize 数据大小
Z$ U9 u4 a5 q - * DestAddress 目的数据地址
! r& G( o+ o6 r% E - * 返 回 值: HAL_ERROR表示配置失败,HAL_OK表示配置成功
]0 K0 ~1 f6 J8 d" g - * HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出
6 B3 h# Z! \0 R - *********************************************************************************************************9 a9 |5 W Y& R' M
- */; j2 \2 ?- z1 V* n% e6 e, w/ x
- uint32_t JPEG_Decode_DMA(JPEG_HandleTypeDef *hjpeg, uint32_t FrameSourceAddress ,uint32_t FrameSize, uint32_t DestAddress)4 z/ ~" O+ A3 L
- {6 E* S# C$ d) e7 _2 u
- JPEGSourceAddress = FrameSourceAddress ;
a* q2 U, e: T7 ^ - FrameBufferAddress = DestAddress;
( }' c$ ~: ^& }) A3 o - Input_frameIndex = 0;! U# x, j( y) {7 p, u
- Input_frameSize = FrameSize;
/ m% s( u$ Y1 m, o2 y5 K - . I4 x+ w; Z2 a+ g& G0 L
- /* 设置标志,0表示开始解码,1表示解码完成 */
! ]5 Z7 r% N+ L- J1 W' e - Jpeg_HWDecodingEnd = 0;
- t3 p! |9 I; s# ?8 I& V
3 x: J, h; I! w# a- /* 启动JPEG解码 */% T! J' B6 X# \2 l L
- HAL_JPEG_Decode_DMA(hjpeg ,(uint8_t *)JPEGSourceAddress ,CHUNK_SIZE_IN ,( B5 D& H7 J4 Z
- (uint8_t *)FrameBufferAddress ,CHUNK_SIZE_OUT);! A; t7 q, ^3 Z
- V& a) P& |/ ~" ~- return HAL_OK;' D6 [$ U/ m) |9 G6 w5 F8 R1 H# o" c
- }
复制代码 : 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
- void HAL_JPEG_ConfigInputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewInputBuffer, uint32_t InDataLength)/ O, T" x0 u: x
- {& k6 P) l2 g0 ?& M" Y8 i' p* W
- hjpeg->pJpegInBuffPtr = pNewInputBuffer;
% J' x% |; q8 B. u - hjpeg->InDataLength = InDataLength;' t# \( v& X9 d1 T
- }
复制代码
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
- /*7 S C3 [) |- A& K0 L$ ]( v
- *********************************************************************************************************
% ], ^5 w+ j, p: {4 a- N e( ] - * 函 数 名: HAL_JPEG_GetDataCallback) n8 K" \& a4 l; |* `
- * 功能说明: JPEG回调函数,用于从输入地址获取新数据继续解码* W; L& F F$ A
- * 形 参: hjpeg JPEG_HandleTypeDef 句柄指针
: o# h i7 x0 ^8 p( J' p - * NbDecodedData 上一轮已经解码的数据大小,单位字节
$ I9 r0 {7 a% [* T: a9 \ - * 返 回 值: 无% m! i3 x4 b, _7 R* N+ Q- S
- *********************************************************************************************************' ^% t- h5 \3 m/ r7 o T3 \8 I$ m
- *// w9 ]0 b- V2 @* r3 y5 g3 M) F
- void HAL_JPEG_GetDataCallback(JPEG_HandleTypeDef *hjpeg, uint32_t NbDecodedData)& X, H1 {% x( q) N: R0 _% L& I
- {
3 A" r% Y/ m7 e% B$ d1 j/ P - uint32_t inDataLength;
8 T' {/ z" K& s - $ `5 ]( O% _6 H/ X
- /* 更新已经解码的数据大小 */
' I) }4 |( ]6 S - Input_frameIndex += NbDecodedData;
+ L3 X3 j! Q) l! _" B& I - 4 Q' v' M( Q' j" A! U
- /* 如果当前已经解码的数据小于总文件大小,继续解码 */, T- J3 u& R2 u
- if( Input_frameIndex < Input_frameSize)
* p5 Y/ o% U9 a( s - {
4 h0 h: L8 q: h" s - /* 更新解码数据位置 */" H) L9 |: L. _( o7 ?7 {( ]
- JPEGSourceAddress = JPEGSourceAddress + NbDecodedData;
6 ?, e, y! Z7 W; ~/ x4 M
8 B2 H8 }; B& l' N9 ?- /* 更新下一轮要解码的数据大小 */
" t$ x3 j' _/ H' m& U9 q6 j - if((Input_frameSize - Input_frameIndex) >= CHUNK_SIZE_IN)
& ^/ {* B9 R3 j3 p3 s c \7 d - {4 D/ ^1 W5 }8 C, p8 i& u- u
- inDataLength = CHUNK_SIZE_IN;
8 |+ b V6 |( a% T+ S" Y - }* w0 R% E. N( D" w4 l
- else
8 d" ?& v' q; Y - {
" x8 h4 v( J0 t, w# Y0 V; ^ - inDataLength = Input_frameSize - Input_frameIndex;4 o( ~# S4 Z5 @3 G
- } " T; |7 l7 c4 K0 r; s6 ?0 W
- }& b$ i, F r4 J0 w1 h; T+ j
- else' x, o$ w- e3 H* ?: z" ~- w
- {7 u/ ~% K. E' R2 |
- inDataLength = 0; ( e9 r* D. o: e& @
- }* y9 r( n3 p- K6 t$ V
- 2 |5 q! d' D0 m
- /* 更新输入缓冲 */
& d, d( a; L0 E7 k* p - HAL_JPEG_ConfigInputBuffer(hjpeg,(uint8_t *)JPEGSourceAddress, inDataLength); + Z' u. G5 E" \" v" B
- }
复制代码
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- void HAL_JPEG_ConfigOutputBuffer(JPEG_HandleTypeDef *hjpeg, uint8_t *pNewOutputBuffer, uint32_t OutDataLength)& x* z% q4 {6 D! Z8 n
- {
7 x( ~% ]. G8 ~' ~: E9 k8 W - hjpeg->pJpegOutBuffPtr = pNewOutputBuffer;3 t+ S, n9 W1 p; k: I
- hjpeg->OutDataLength = OutDataLength;
/ E# t! i4 V% ^; ^1 W' V - }
复制代码
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 |
- /*. ?; e- H- f, G0 Q5 c% ?6 @
- *********************************************************************************************************
4 ^% ^: @) f) o( b% p" r! q - * 函 数 名: HAL_JPEG_DataReadyCallback* h& L. Q! I& x2 z/ ~1 H
- * 功能说明: JPEG回调函数,用于输出缓冲地址更新. B* S% t! r& x( s; ]3 Q
- * 形 参: hjpeg JPEG_HandleTypeDef 句柄指针
! z: Q% r- S" i) G" D - * pDataOut 输出数据缓冲: U) o5 |2 K8 X0 V" G* S" V6 y
- * OutDataLength 输出数据大小,单位字节
6 O) |5 W2 l) l - * 返 回 值: 无/ n3 w. i# g- C/ I" f
- *********************************************************************************************************# s6 T% g, x5 i
- */
; K9 N6 W. h6 I. g1 s2 L/ q+ p - void HAL_JPEG_DataReadyCallback (JPEG_HandleTypeDef *hjpeg, uint8_t *pDataOut, uint32_t OutDataLength)
6 c7 X1 q: D$ c9 L - {. Q3 o+ v9 H' T
- /* 更新JPEG输出地址 */
9 t3 G/ }8 t& O& t1 |4 H: t1 T9 n - FrameBufferAddress += OutDataLength;2 O, b5 C6 m5 e# G
% p. e5 D) x& u- HAL_JPEG_ConfigOutputBuffer(hjpeg, (uint8_t *)FrameBufferAddress, CHUNK_SIZE_OUT);
" [: [% y% J1 N - }
复制代码
# _' 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
|