3.1 初学者重要提示
7 o. x9 N6 J! d# B1、 本章使用的ST专门为STM32H7提供的软件包' S) [, d% g2 \2 j* K5 A, [: `& F" c& H
( v( U9 ~- J: i3 ]: i( n5 N: f( ?% M
2、 本章配套例子使用SD卡模拟一个U盘,使用的MicroUSB接口。
% n, O3 t; Y s' z8 Q* q3 {2 R g* m0 C9 A. L; h/ n
3.2 USBX移植步骤
5 e8 h9 ?/ R# L, ZThreadX USBX的移植步骤如下:
1 \- {( H, B9 o; X }
: }+ l+ ?) S; T, [/ L z5 R3.2.1 第1步,了解整体设计框架) N- j- x% H0 H \
为了方便大家移植,需要大家先对移植好的工程有个整体认识:
8 m, e- i5 O+ j& I* Q8 p$ t7 d5 |1 Z
: S9 [; U6 F9 |1 }/ W, G) {1 A5 n2 Q, J% Z( d
7 E" e. Z% D/ }: s. a, I5 {
3.2.2 第2步,添加USBX和USB驱动到工程
! I4 A- |9 Y* }7 `4 a这里我们在FileX教程做的模板例子基础上添加USBX文件和USB驱动文件,大家可以直接从本章教程提供的例子里面复制。" P& m2 v' T2 T
. }- \% F3 J$ \1 N6 e 模拟U盘驱动文件ux_device_msc.c/.h和ux_device_descriptors.c/.h添加到自己的工程里面,路径不限。8 Y0 D/ J7 D- x2 Y v+ x% X
配套例子是放在\User\usb文件。
" R. C( S% h- |; r! D% x2 b/ s! X9 X0 ~3 P$ g; v: l' Y
USB驱动文件stm32h7xx_hal_hcd.c,stm32h7xx_hal_pcd.c,stm32h7xx_hal_pcd_ex.c和stm32h7xx_ll_usb.c。) v2 S Y _& `) R' t
这个是STM32H7的HAL库自带的。
. p3 M; R4 F3 s( y1 I. n( e8 _# Z
USBX相关源文件。
1 [) r; |. K5 Z k$ F8 @, A- J" O大家可以将所有相关文件都复制到自己的工程里面,配套例子是放在\USBX。
5 J' _( k5 X1 {/ L, ]
0 o+ G; R0 H$ _3 W) e* g/ o3.2.3 第3步,添加工程路径1 u% n7 a' J/ t% V2 M
大家根据自己添加的源文件位置,添加相关路径即可:
" G. s" \! P9 d+ w# G+ E6 {' r2 z5 C+ M) @9 X& _4 m) I
& G G" v1 z( v' {- } k
" X; j" V$ q$ v2 O2 ?, I* R, E
9 p7 F* k; N* j* n
% k& D8 F8 K% n8 j1 X) W6 @3.2.4 第4步,禁止掉添加进来一些文件
" h2 `9 U `0 `8 [4 V3 R/ X; G* x之所以要禁止掉是因为这些文件要用到NetXDUO网络协议栈,或者大家不添加进来都是可以的。添加进来后再禁止的优势是添加时候可以全选添加。
l! Z- F7 P, U) w2 S
, g+ S$ b6 D/ g/ q* j# ~6 m
2 Q+ n% l1 Y* Z+ t
* X4 S1 h# Y: r5 [
8 I3 ~# d6 [0 @' v8 Q5 T# L3 t1 s! o4 d' C' h. [' |
: T8 o* x5 S# O. d2 D/ A
& a2 D3 k2 u" t5 H# A) H% s禁止的方法是右击此文件去掉如下对钩即可:7 A) P& p5 _+ u. p! q# k. [
) A# V6 B& j% p) j" G+ C1 ~3 ~9 t' d! Z
' j P' a* X! f7 q/ ]& p( E) P2 g `6 p8 p9 `7 w" R# o
* a! Z/ |' S+ P4 c" s5 T" {& o3.2.5 第4步,配置GPIO和时钟: Q$ a6 `# i3 ?" ^; H/ B9 Q
USB时钟配置在bsp.c文件的函数SystemClock_Config里面:/ Y) T7 w# _" G8 A
2 S. q' G P# p+ f1 K5 W6 w- {
Z$ H' y# ? \+ ]0 M - /*/ k' g& V7 K8 g6 b
- USB工作需要48MHz的时钟,可以由PLL1Q,PLL3Q和HSI48提供
% Z2 f" D; F0 W" q, Q - PLL1Q用于给SDMMC提供时钟8 h- J6 s& ^6 o) N
- PLL3Q给LTDC提供时钟,也可以跟USB共用,不过得更USB设置相同的频率才可一起用。1 N) G& X6 T3 E9 }) D* g5 k- s1 C2 o! T
- HSI48可以供USB独享,就是精度不是很高。
) p3 l6 ^* Q- X( y - */
5 _: A5 X% \% h - RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};* H: [4 d, ?* D- ^" W/ s
- #if 09 J; `; ?& S; Y% q9 S# @" C
- /* PLL3-Q for USB Clock = 48M */' f2 q& r {/ z# V
- PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
- ?; \( y, J( L9 F - PeriphClkInitStruct.PLL3.PLL3M = 5;* d; F, \7 |) U5 v+ C. f
- PeriphClkInitStruct.PLL3.PLL3N = 48;8 G/ X1 ?/ O2 O- ~0 O, Y
- PeriphClkInitStruct.PLL3.PLL3P = 2;
# Z' K c" T( @9 ~& @0 ?; I - PeriphClkInitStruct.PLL3.PLL3Q = 5;- j: Z2 Y. O1 c% V1 K
- PeriphClkInitStruct.PLL3.PLL3R = 2;
% m1 ^$ Y O' y( j' F* b9 v7 N- V ~ - PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
2 J2 [, T) ?4 B$ ^& ?0 C - PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;- Z0 _% j8 I' g# b
- PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
0 d% E- P- R$ I% d) { U. d - PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;0 d! a. |4 j9 O5 V! O
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct)!= HAL_OK)' x& n+ `9 n8 [1 i& u
- {- x) G. {$ W0 @" g1 G
- Error_Handler(__FILE__, __LINE__);( d6 w6 t0 a' W
- } / h3 L' M: A: ?
- #else$ a1 j$ a4 |* T, G7 F
- PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ i! m/ X3 m. K z: p$ |) e - PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
, R0 l1 ^( A Q& F& e8 e1 C: @( G - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
! Z! V5 i4 {$ U# m- P; u; I - {' d. q! L1 Q Y2 |8 W3 M5 F, _* h
- Error_Handler(__FILE__, __LINE__);) d0 K1 s; ^8 N3 I
- }4 f2 e, @% h; L+ ]) n3 L
- HAL_PWREx_EnableUSBVoltageDetector(); p" O$ O0 d- s" Q8 f/ ^
- #endif
8 e' Z5 P# x7 \, k& |& i- j' M. Z - }
复制代码 # a: [7 y6 C: O* w7 z7 g$ j4 V
USB的GPIO,NVIC初始化在demo_sd_usbx.c:
, N) |. u2 S( k* B: \. }6 t& e0 k% A1 _$ c. t% `
- /* 配置USB GPIO, NVIC */- l5 w8 I+ E* B7 d* b
- {
; F% ~; _8 i8 ]. D, i* I - GPIO_InitTypeDef GPIO_InitStruct = {0};
/ O4 b0 g& O9 A, ? - : B( W& A, d1 C1 y
- __HAL_RCC_GPIOA_CLK_ENABLE();
/ V8 n3 n4 {6 J3 C( H - 9 v( U4 B; L# @& y7 k6 o
- GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);! f2 |. _; D8 o; O" X! N
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
) P$ \% c" o9 D4 Q - GPIO_InitStruct.Pull = GPIO_NOPULL;
' y' w0 M, q5 M$ v+ K- j - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
/ y3 l* x) ?# o% F - GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS;" Q9 P M6 [. G. z; H! s) E6 V3 E
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);8 L9 o2 W( P* m- G: B0 v
) }' O3 d* I b: \( u' Q' M- /* 使能USB FS时钟 */. P. w6 O, j3 e8 E
- __HAL_RCC_USB2_OTG_FS_CLK_ENABLE();
5 a+ i1 F" Z# O) G9 X3 j5 C
# g$ S$ l E# A1 b$ l5 {$ M- /* 在睡眠模式下禁用USB时钟 */
1 \7 a' ]. E8 @0 w1 P - __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE();
6 p) |- g* i- @2 ^" h
: Y; ? @: m7 L; ~- V/ Z7 I- /* 配置USB FS中断 */
h8 M2 s' v' _, ? - HAL_NVIC_SetPriority(OTG_FS_IRQn, 0x2, 0); * l5 F; T/ t9 ^4 l) P
- HAL_NVIC_EnableIRQ(OTG_FS_IRQn);6 r8 E. g, _3 h1 L: r$ ]
- }' [3 M- C. P4 p9 a) f! F
- + V; h, b( F6 F! T
- /* 初始化USB */
5 \, @6 d% w% `& p; i/ b - {8 R! L# w( j" o$ P" A
- HAL_PWREx_EnableUSBVoltageDetector();8 x) m6 f# `8 I' A, q( o1 i
- ) H+ W" |3 Z3 ^6 Q$ [2 U
- memset(&hpcd_USB_OTG_FS, 0x0, sizeof(PCD_HandleTypeDef));; t* d3 Y, m. M! r# k
- hpcd_USB_OTG_FS.Instance = USB2_OTG_FS;# I5 p$ T0 U. D; D8 V% W
- hpcd_USB_OTG_FS.Init.dev_endpoints = 8;
9 ?# d/ {& a& E5 Z - hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = 0;
; {- O1 l# F, i$ j( P- D - hpcd_USB_OTG_FS.Init.ep0_mps = 0x40;' |! y/ r+ X2 N4 O2 _
- hpcd_USB_OTG_FS.Init.low_power_enable = 0;. p4 q, A& l: J: }% A
- hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
8 V J1 N4 r( M - hpcd_USB_OTG_FS.Init.Sof_enable = 0;: M" z- P3 b% g
- hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;( M8 c* \! ~$ C8 Z6 K
- hpcd_USB_OTG_FS.Init.vbus_sensing_enable = 0;8 w+ e7 S8 H8 [1 p1 h4 p" W
- hpcd_USB_OTG_FS.Init.lpm_enable = 0;6 R. n& N& p/ C; t/ k0 ^
- ' _# q; r& L% R
- /* 初始化USB */
, C, p& f- e* W" C - HAL_PCD_Init(&hpcd_USB_OTG_FS);. W6 F2 z* z: i3 \
) p! k5 e; V5 v- b* m0 D- /* 设置TX FIFO和RX FIFO */
0 n( u1 G- M' P( e1 ?7 u - HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 1024);( X4 l/ y( j3 L& Y0 j j$ Y' @
- HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 64);6 k/ M3 N4 y9 W) a- e* R3 q, d
- HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 1024);
$ l0 W. h( L6 V
. x; W4 a2 V7 u7 j- /* 注册STM32到USBX协议栈并初始化 */1 K3 g- i4 a% t" O9 p" n1 s2 w
- status = ux_dcd_stm32_initialize((ULONG)USB2_OTG_FS, (ULONG)&hpcd_USB_OTG_FS);: H! V5 d2 e& b7 u: z4 U
- 1 w2 C- K4 f+ B$ b% l
- if (status != FX_SUCCESS)
# R% s2 B( L2 L. F4 f, ] - {1 e( o' |+ A' f7 z2 b: W9 x
- return;2 U5 r( e, I6 E' x+ s6 U4 }
- }
% I& }/ f V# r, e& q
" ?" y) ^* X/ o# H% I3 c- }
复制代码
, k/ Z8 J% N" Z9 C3.2.6 第5步,MPU配置( V8 _, u% X& g6 @+ I! k1 C8 Q
为了方便大家移植测试,我们这里直接关闭AXI SRAM的读Cache和写Cache(这样就跟使用STM32F1或者STM32F4系列里面的SRAM一样)。此配置是在bsp.c文件的MPU_Config函数里面实现:
. |: y6 {5 Z; q `2 Z; O4 W5 X( \' w3 W+ {% n4 ?" k1 n
- /*
% f- B) {' ^6 k! w; L - *********************************************************************************************************
' _# i% Y/ H6 o$ h& Q6 x% ? - * 函 数 名: MPU_Config( }2 U- T1 b. L) C
- * 功能说明: 配置MPU5 I6 j. O9 r) O0 r' Q. ^9 J3 D
- * 形 参: 无
6 y" G6 y% x$ u# \5 N+ ^ - * 返 回 值: 无
Y* ? \9 C2 B0 \9 e - *********************************************************************************************************
0 N$ W; C8 `9 z6 ` - */, y) W9 ]- Q: J
- static void MPU_Config( void )
. W1 f$ v8 v0 [. e. N* x1 e - {$ a: ^& t8 \; z# e) a) B
- MPU_Region_InitTypeDef MPU_InitStruct;3 g* Q; Q0 ^) F6 C9 o
- " m' h7 X! r' \8 S: ]! t
- /* 禁止 MPU */& w0 e* Q1 r. L) s. s, |/ ^5 X
- HAL_MPU_Disable();( d7 G) j6 `# ~8 t' c& \2 a
0 u9 t* L% t1 u( F5 _- D) r% `- #if 07 _9 Q# t: Y! q7 H; X
- /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */4 ?* r a- l# ] k" d: \' r
- MPU_InitStruct.Enable = MPU_REGION_ENABLE;
& y7 l3 x0 P V3 W# _" R - MPU_InitStruct.BaseAddress = 0x24000000;8 y& {1 I9 _1 l5 w- f$ M' y
- MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
, K- G2 I" f" x7 \6 ^, D - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
$ Q( K6 T R, a4 N, G3 e - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
; ]) E9 m4 i* p - MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;) x* P5 ], e! {" ~/ J
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;# y5 j8 o0 e9 A+ c G
- MPU_InitStruct.Number = MPU_REGION_NUMBER0;
/ N- D2 V, R/ T5 z* U - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
" N5 ~) X3 c3 e$ @" B - MPU_InitStruct.SubRegionDisable = 0x00;
: o# I$ `) Q8 ?! |) ` - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;5 w" x* \6 W6 i2 M1 W) L! q
. f: O0 {2 _7 B; R9 b- HAL_MPU_ConfigRegion(&MPU_InitStruct);
8 t& q: A i. B" M, T - ! u5 Q+ E- I2 |' ]
- #else E+ u* U* y! y4 t- B
- /* 当前是采用下面的配置 */% B. p5 w: v+ l5 i+ {$ v2 ]8 [
- /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */
8 U, Q1 ^* ]3 {: D/ O - MPU_InitStruct.Enable = MPU_REGION_ENABLE;: ?' C% q" f! B$ Y
- MPU_InitStruct.BaseAddress = 0x24000000;0 U$ i- O5 l; O) J! V0 r) X
- MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;" W' G. C; h/ v$ [+ I) e
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
$ Y7 L p- n& { x- q# W0 S) A - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;" h& E0 y/ d; l3 L! b
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;* d! \# S1 X, F- D5 p3 f/ H
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
, ~8 b- s% [" U. F, P! } - MPU_InitStruct.Number = MPU_REGION_NUMBER0;
. |* u( X5 L1 V3 I3 T4 @ - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;! h, r- n- H% U, |: [2 w2 n1 \
- MPU_InitStruct.SubRegionDisable = 0x00;
& E( ?$ x: v# F( Y: a8 Y3 K' J% g( E9 ? - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;! [* W* j0 V% e, b
$ a8 N+ }: `( x& y4 j, d! q- HAL_MPU_ConfigRegion(&MPU_InitStruct);* X# a: i& [% e: Z
- #endif; S# W `. w8 P
- /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
+ z4 |* ]* C a% p - MPU_InitStruct.Enable = MPU_REGION_ENABLE;
7 B& M4 \; ~% S. |; s1 ~7 v/ A - MPU_InitStruct.BaseAddress = 0x60000000;
7 v# E5 C4 d" G7 o2 G - MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB; 4 }; O, m( H- b5 l' E! w! q: m
- MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
2 @: h5 ^3 f' H2 ~ - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;+ T4 E; X! [9 c4 X, W4 e
- MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;/ u+ Z3 Y U4 J
- MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;, {0 P! ?8 C( m" o+ t9 r
- MPU_InitStruct.Number = MPU_REGION_NUMBER1;- h6 _. z( o+ V. Z4 H8 u
- MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
[! ~0 B9 m, m) T - MPU_InitStruct.SubRegionDisable = 0x00;
) g5 n9 B4 A" P% e2 i& X - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
) O5 M2 C' o# d J. ^9 T. N3 d -
/ y* l H E# L% H( E( l1 E% V - HAL_MPU_ConfigRegion(&MPU_InitStruct);% R1 u) U0 Q* M3 S- {1 p2 [
- : e! x6 a, V/ ?" [( q
- /*使能 MPU */( i$ | P$ Z2 k; ^. i/ ~5 v o
- HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
# ?# o7 `; x" E' b6 v - }
复制代码 & s' v; c, c( \* ]& n
3.2.7 第7步,添加应用代码(USB中断,打开U盘和关闭U盘)
! G% C J, z, }! H) c5 W) G& `2 E# P% MUSB操作专门整理到了文件demo_sd_usbx.c。主要三部分,打开U盘,关闭U盘和USB中断服务程序。这三个函数基本是通用的,大家直接复制粘贴使用即可% i: ]: K0 p6 H9 g8 w8 U
7 l0 f9 U: t& J( t
特别注意USB中断服务程序别忘了添加。# m& {4 H$ I$ L5 N
( {) p8 V+ n e, e* F, w3.3 USBX的模拟U盘移植接口文件ux_device_msc.c说明* D, ~: |% E- }
这里将USBX的底层接口文件ux_device_msc.c的实现为大家简单做个说明。
; |0 H6 l6 }6 f, f, L) l( c% _8 t; J# U$ p, @4 @
3.3.1 状态函数app_usb_device_thread_media_status* s! q/ V6 D n( E& B% L. }9 W) `+ ]- ~
代码如下:
8 Q! r/ E' Z6 t0 C8 G o- P2 y6 e8 s8 m! M: v. S# P1 c
- UINT app_usb_device_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
( P- R- f( q1 S k' H - {* T Z7 Z- Z5 X# j3 k+ ^
- D `. p3 S& o
- /* The ATA drive never fails. This is just for app_usb_device only !!!! */8 ~4 G# s, T1 U, s6 B, J1 P
- return (UX_SUCCESS);
. l, z; p, o, a* J9 f Z# {% l8 [ - }
复制代码
. J; i! p( d4 {此函数主要用于获取SD卡模拟U盘的状态。7 `) w. t9 \* ?; N- I+ ~
- @# \+ H' C" D5 h) d: g) E3 R
3.3.2 读取函数app_usb_device_thread_media_read1 y" V8 ~; o o: [ t
代码如下:
( f9 G3 I; F. s8 l: O8 c! }
6 H- [& ]' P7 I% X7 ^- /**
$ C) x' D$ W e) @ - * @brief Function implementing app_usb_device_thread_media_read.1 q' A! _4 J. A+ Z& \8 k& k# w% I
- * @param storage : Not used2 }6 w; m3 c% V
- * @param lun: Logical unit number9 N+ y8 d2 q" I4 K
- * @param lba: Logical block address
% u8 B3 T! h8 c; p8 f) _ - * @param number_blocks: Blocks number: D+ G( }* _' b6 ^$ \) C
- * @param data_pointer: Data9 |0 s, O7 s/ G; Z# W4 f$ d
- * @param media_status: Not used
7 p' Y8 M9 |# e$ |! A$ m( g0 [# n - * @retval Status (0 : OK / -1 : Error)
" ^+ `' }# m. ^7 J$ D - */8 c6 X% F1 k; Y8 ]1 H( u# N, P
- UINT app_usb_device_thread_media_read(VOID *storage, ULONG lun,
6 Q! z, e# n, }! S& r - UCHAR *data_pointer,* L: l) `: D8 j3 {) H ?
- ULONG number_blocks,) C; g e, l S0 d
- ULONG lba, ULONG *media_status)
0 M1 u8 v' {# C! |& n C - {
) Q( B* D0 Z% C - UINT status = 0U;
$ o2 S+ Z1 w" M, |$ B
2 b. ]' j& ]( V( \! S- BSP_SD_ReadBlocks((uint32_t *) data_pointer, lba, number_blocks, 500); 4 u0 N" s+ Z- R5 V! }' s/ P+ v
- //while(BSP_SD_GetCardState() != SD_TRANSFER_OK);' O, R8 E, ~, Q# U9 f
- status = check_sd_status(0);
# g+ S9 O7 s8 c+ i9 x+ @/ j - return (status);
l Q- E- N& P0 J# J - }
复制代码 * n q# o6 R9 G: \6 ^. M7 Y' u
用于实现SD模拟U盘的读取功能。+ \2 z+ Z1 q8 z& U. x
' v- E6 [! |: Y% R+ U, R5 R
3.3.3 写入函数app_usb_device_thread_media_write
$ C- g# Z( Y3 ? F+ x代码如下:
$ B3 g W, D U6 x
& ~0 }2 Z% o5 F( C/ y* W- /**
8 r) h0 \& T8 M; u6 P. |" z" k2 c - * @brief Function implementing app_usb_device_thread_media_write.
) q0 P( v# n# d+ d - * @param storage : Not used# U3 R/ {$ ]$ z& n/ L# E
- * @param lun: Logical unit number
! c& d) B! R- R( S1 ?$ N! k - * @param lba: Logical block address
% J9 g3 \/ K+ w0 z- R - * @param number_blocks: Blocks number, R: `! m& D6 a7 m0 i
- * @param data_pointer: Data
9 G2 u5 W6 W& _2 c) y: L - * @param media_status: Not used: G3 `, J8 b+ r# h4 T4 k! k$ W1 [$ p
- * @retval Status (0 : OK / -1 : Error)
7 x. F5 z. Y# A! W - */; U2 i6 W4 _; ?$ o7 [
- UINT app_usb_device_thread_media_write(VOID *storage, ULONG lun,
+ Z/ p# u6 F/ |+ x3 P - UCHAR *data_pointer,
( m2 p! w4 d& R3 o; A6 O - ULONG number_blocks, h! z3 @8 f( E9 J
- ULONG lba, ULONG *media_status)+ w2 C5 |* u! z1 R" o* q
- {
A; j- V7 Q3 ]) O/ Q9 q, C& A; [) V - UINT status = 0U;
8 R' g* b9 _' I
% R; K( Z m1 S. q2 x2 Y9 B) e- x- BSP_SD_WriteBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
; [ c# L$ Y! ? - //while(BSP_SD_GetCardState() != SD_TRANSFER_OK);
% y/ s- r. {0 u/ N/ \" g5 G - status = check_sd_status(0);
. @) x* i* K4 C' F4 N$ {* ~ - $ e: k& l3 X. V) M$ \* g! C7 x
- return (status);
' Q, m' m6 m" Q5 q - }
复制代码
- J+ Y& I: \/ |( n2 L& z0 l用于实现SD模拟U盘的写入功能。0 R: F/ y X5 {" O7 X; ~
# X Y" y+ [1 E* O }
3.3.4 接口函数注册
& r x- S' b( m9 t' Z, K) @" w$ J) F接口函数的注册是在文件demo_sd_usbx.c里面:% H: Z% X4 {: |; o/ ^& m7 f5 q" \, K2 z
" Y3 I& ~0 y5 E; e
- storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read = app_usb_device_thread_media_read;' c2 n) @2 N1 R1 D; s R3 z3 u
- 8 X* y/ u& W' `+ I6 t: Q
- storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write = app_usb_device_thread_media_write; 1 V j2 m, n: v- w, y
- @7 I* e9 x1 [- storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status = app_usb_device_thread_media_status;
复制代码 3 D$ W+ P5 n) S$ R4 s7 ^: s8 a: e7 c( d
3.4 使用的MicroUSB接口并注意跳线帽设置
1 q8 T' E( l# M( @/ t- J本周教程移植的例子使用内部RAM模拟了一个U盘,效果如下:
8 D8 L) b. @9 }5 L. j. t. S9 k' W$ N; a- T# F
1 [, Z: R( E& y4 ^1 D
& E# N6 L5 Z7 c) j' C6 a注意使用的是MicroUSB接口:5 B8 @/ g( u3 B: v, ?7 ?+ @/ { d
0 p; C) n) F. G: T% d
% ]+ \( K* {9 Q1 h" y6 Y8 r' ~" Z
- o- [( v, C8 W, d& q# I& c9 a ^4 Z7 `3 C
注意板子左下角跳线帽的设置:/ S" `1 K7 b/ O: z0 J4 V% X" f
% i# n; i v. l; ]1 i) ^- n
# f9 x- _" }; w8 p. U
& n9 a1 i2 y# c' h# f
, D f0 v( o) o: P" A
这里是用于选择CAN1 TX使用PB9或者PA12引脚,CAN1 RX使用PB8或者PA11引脚。大家这里可以什么都不接,或者CAN1 TX通过跳线帽短接PA12,CAN1 RX通过跳线帽短接PA11。切记不可以短接到PA12和PA11引脚上,USB要使用这两个引脚。! y4 X8 x3 E9 i- K
) P, d7 M/ c5 B, C' ^+ v; c3.5 实验例程
$ M% o: ?0 }5 E, ~6 R配套例子:
5 u. e; \# s( T9 i
+ Y0 z, L$ U c0 q: DV7-2401_ThreadX USBX Template- E) F/ T" K; B( r2 s5 q- P$ G
5 i/ Z5 a1 p' L$ @1 L. d3 A
实验目的:
9 [. s/ h* x' ~, r
9 U/ L. d) g* b1 r4 p# R学习USBX模板,通过SD来模拟U盘。8 N7 c* j8 v# C: P* I- U
实验内容:5 w& }7 y2 x4 [) f+ e" |; G
7 T7 u' z s" y
1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况
/ B1 \/ p4 Y4 D) t' e& g( s& H c8 W
========================================================
& _3 u% N2 M3 P( Y" x8 T9 {) p' }6 y& S. H" J. q
CPU利用率 = 0.89%% x9 `; J9 H$ `% L; E
- O/ ]2 e' M- Z }6 _4 d
任务执行时间 = 0.586484645s
% M8 M. B: X' @9 [( e& T/ x0 T0 u# H; w& F! D
空闲执行时间 = 85.504470575s
+ K! g; E+ `/ M0 C2 m, y4 I5 V+ r' q" h1 X
中断执行时间 = 0.173225395s9 X ~5 T: ~/ |" |3 u
& ^5 y: U4 Q% O
系统总执行时间 = 86.264180615s
$ F3 |& y: Q, @' m5 h) x, b, j9 I2 l9 I
=======================================================
, x7 J, V# N$ L4 g1 y
; o% | s' J' r 任务优先级 任务栈大小 当前使用栈 最大栈使用 任务名; E% m6 H( p7 j! W( @6 Q) ]7 M
3 I! b7 E# l/ P# X7 v Prio StackSize CurStack MaxStack Taskname+ T* X. J% f/ C( |
( V6 j6 `4 t, ^, I7 R4 m8 v1 E
2 4092 303 459 App Task Start
5 ~* X: M$ c2 Y( G, {# H4 d) ~' w+ p$ @ w& p
5 4092 167 167 App Msp Pro0 Q; C% I& o# ]/ r: y
1 I n- c% i, w8 w& V( w! | m
4 4092 167 167 App Task UserIF
9 k1 v. I1 E6 l0 C l3 i* X3 S, M, e
5 4092 167 167 App Task COM- ~8 a" O: J4 l* q0 X
. ]: D/ B4 g2 i, }' }, X) J 0 1020 191 191 System Timer Thread 5 @3 p( d* u4 f/ ]
! m& a5 O7 w' ^/ h; l+ F串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。$ ^; n# }1 g( R, z, F
; D E: ~, v" P- b
App Task Start任务 :启动任务,这里用作BSP驱动包处理。
* g& Q8 T3 z/ Z$ C* a7 r g; m" e u
App Task MspPro任务 :消息处理。
4 n* h3 }% ` k+ |! K7 }! B! R8 \/ g9 o- x& O
App Task UserIF任务 :按键消息处理。! b" T# c/ i; Q Q( u6 T& X8 M( ]
7 U9 R9 A* p4 S7 X3 m- J! l( A) w {3 z
App Task COM任务 :这里用作LED闪烁。
% j, G6 x; X T. K& M4 Q: Z, j8 q3 D, |# I7 D( B
System Timer Thread任务:系统定时器任务4 @+ B7 |# X0 R# X; M
9 ^& c" }. s" C& a; o9 \) o! Q0 [2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。
; T' ~7 H3 z9 Q1 w1 O ?
- Z/ i5 @4 t' X* s8 ^9 h% s (2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。
2 d" L& a/ z/ u' m1 L/ j6 G
% H5 X$ v8 W! Z9 ?3、默认上电是通过串口打印信息,如果使用RTT打印信息
3 a; K, h8 b# e7 L5 r0 v( T$ A( V- E6 F7 T2 x+ L% p
(1) MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可
5 E5 w% ?. O/ C% C7 c
( ~: ^8 W4 _6 `; j7 ?, q$ `, ^#define Enable_RTTViewer 18 O# W6 p9 W) p2 f6 m; H
/ U1 }. y" | p8 Z! W! @( O+ f
(2) Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。8 [" l. k/ K5 o( m8 O( j8 m. j
6 {# D) O" D0 G( m! u+ D
实验操作:0 n$ \, D7 `3 |( d6 A
( g' A- R9 q5 G; w( _6 ~' I' Q$ F
测试前务必将SD卡插入到开发板左上角的卡座中。
, g7 c% O) z' l# O$ Y% o支持以下6个功能,用户通过电脑端串口软件发送数字1-6给开发板即可
; e# a2 b5 J I# y7 Lprintf("1 - 显示根目录下的文件列表\r\n");3 @% K& [% ?6 {- ?) h
printf("2 - 创建一个新文件armfly.txt\r\n");' j# B' ?8 B2 |
printf("3 - 读armfly.txt文件的内容\r\n");
/ K7 c& _: }9 p$ qprintf("4 - 创建目录\r\n");
2 D2 M- V2 `. m( h) w2 oprintf("5 - 删除文件和目录\r\n");' \, W6 C5 |" u0 X' j# \7 Q' P: t
printf("6 - 读写文件速度测试\r\n");
! y5 o1 k% L/ E" e+ w4 d1 Rprintf("a - 打开SD卡模拟U盘\r\n");5 q$ _" _9 V0 z9 M
printf("b - 关闭SD卡模拟U盘\r\n");
, I/ ^7 ~) L( }. l串口打印的信息:
: k: E% Z3 K2 B) ?/ B4 B; g% Q% ~0 v9 z& \. w) i
波特率 115200,数据位 8,奇偶校验位无,停止位 1
; U* ~! W" Y" x5 V/ c6 k
9 K* \2 A- z( S3 D9 ]- u3 f
6 N9 V$ p9 H8 }8 I$ y% x9 j0 ~2 G$ S" i' C
$ {. A: B: a$ r: l- G) h+ N/ C
& t( _4 e/ v- O9 m, ^8 Q! zRTT打印:
. L1 D5 l2 E5 g6 o2 n. S
4 h$ J. {6 r# A% O ^5 {, u S4 C' ~
2 ^7 v4 H1 H2 F) [# Z# q; L* ]5 d6 ~. w' |! Y8 Y* q; r* b
5 E7 H- I2 c/ G1 {' J! A6 c. ~/ i, q' e6 `7 w* z
3.6 总结
- v: t+ b) L% a( t) K' n2 M本章节就为大家讲解这么多,后面章节再为大家详细讲解USBX的玩法。1 ]! M2 Z9 t2 J5 i
5 d7 g" Z1 ]/ [4 D& N1 z- Z1 O
- J1 s& o( p8 r8 o7 a' f1 }4 }) l$ Z: i! x% v$ Y; C% _
|