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