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