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