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