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