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