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