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