OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 26977|回复: 50

关于USB转SD卡的一个离奇的故事

[复制链接]

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
发表于 2013-8-26 21:33:35 | 显示全部楼层 |阅读模式
题目没错,是 USB转SD卡,而不是常见到反过来。之所以说离奇,不过是因为平时没见过这种用法,故而应属少有。在网上也查了一段时间资料,几乎没有找到相关的做法。
对于STM32,两年多前,用f207做过一个CDC之类的小项目。具体是USB口链接一个移动设备,按照modem协议,通过at指令,控制和收发数 据,然后用串口转给另一边的一台设备。时间有点久了,之后再没有接触过STM32。所以,这次这个USB转SD卡,一时还没有多少思路。看了一些有关SD 卡SPI协议的资料,还没有深入。
活总是要干的,现在开始正式整理思路,以及要解决的问题。以前在这个论坛,也得到过大家的帮助,这次也期望各位同道中人能多多帮忙。尤其是原子老大,先谢了哈。

这个项目大体是这样,用f107,做一个USB转SD的小板。一端做成SD卡触脚形式,插到另一台设备的SD卡插槽,f107的u口接U盘。原来设备读写SD卡的功能一点不动,完全通过stm32翻译、转换,实现USB转SD卡。也就是将平时用的读卡器给反过来用。

目前思路如下:
1. 安装EWARM,下载了6.1版本。上次的是什么版本早忘了,软件已经卸载,有点郁闷。
2. 学习SPI通信,因为是通过stm32的spi接口,和其它设备的SD插槽连接,实现SD卡的spi协议。
3. 学习sd卡的spi协议,整理常用的命令。读上位机读写SD卡的代码,看看都是怎么操作SD卡的 。
4. 学习FAT文件系统相关知识。 这个是我最郁闷的地方。因为我觉得上位机发来一条命令比如读一个文件,应该是按照文件系统的方式进行的吧,按照扇区读?将读sd扇区的命令转换到读U盘的扇区? 对此我表示现在还很晕,期待大家的指点:)
5. 硬件有了后,写程序框架,调试spi通信。捕捉spi接收到的读写指令。分析。
6. 读写USB。
7. 。。。

现在觉得好难啊:(
列位,支持一下哈。
锄禾日当午,汗滴禾下土。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-8-26 21:34:54 | 显示全部楼层
又过了几天,长征路上在继续。

1.安装了IAR6.1,不能编译以前的程序。没细看是为什么,准备重新装一下6.4.
2.整理思路,在网上四处乱撞,想到什么就搜索什么,以拓宽思路。补了一下FAT表相关知识,也看了一些读卡器的设计原理。

对于后续工作,目前阶段思路如下:
1.原来设备实现了一个FAT文件系统,那从SPI发来的数据,应该是遵循SD卡SPI协议的命令,比如CMD开头的一系列命令。
2.如果果如上述,我需要做得,是解析这些命令,并做出相应的操作到USB。比如,如果发来的是CMD读取一个扇区命令,我则去读取USB一个相应的扇区,并将数据发送到SPI的发送端口。
3.那么,我需要做的,就是能将USB的0扇区、FAT1、FAT2扇区、根目录扇区能在上位机请求的情况下,原原本本发送给上位机,上位机据此整理出FAT文件系统。

上述思路不知正确与否,需要继续分析与验证。学习,真正是无止境!

我请求原子版主,以及各位同道,对我上述思路给些指点。
郑重道谢。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-8-26 21:48:34 | 显示全部楼层
楼主是接项目做,还是在公司做?
这个是设计一个SD卡设备,该设备对外的接口是2个:

1,SD卡接口,连接外部设备,本设备做从机。
2,USB接口,连接电脑,本设备还是做从机。

不知道我理解对不对?如果对,那么,第一个要求比较雷人,如果是私人项目,建议直接推掉,因为这是个吃力的活,最关键是就算你做出来,此物也作用甚微,除了你的项目需求之外,估计这辈子都不会第二次用到。
做项目,我觉得能学到东西固然重要,但是学到有用的东西,才是好项目。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-8-26 23:23:17 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
多谢原子兄建议。这是在接项目做,熟人,不好推辞。

1.SD卡接口,连接外部设备,本设备做从机。 
   拟用SPI接口链接外部设备的SD卡槽。
2.USB接口,连接U盘,不是电脑。本设备是做主机。

想问一下原子兄,为什么第一个需求不好做?从SPI接口收到的命令,如果是遵循spi协议的命令,我直接将U盘的内容读出来再回送给上位机。这是我的初步设想,是否实现这个设想有很大的障碍?
请明示,多谢。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-8-27 11:05:52 | 显示全部楼层
哦,你是想把U盘模拟成SD卡用是吧?
你如果不能推辞,那就慢慢做吧,先做模拟SD卡。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-8-28 22:04:02 | 显示全部楼层
回复【5楼】正点原子:

哦,你是想把U盘模拟成SD卡用是吧?
你如果不能推辞,那就慢慢做吧,先做模拟SD卡。

---------------------------------

这两天忙别的,没顾上这个,也没上论坛。
首先,感谢原子兄的建议。
你指的先做模拟SD卡,能否给点具体指点?
我的思路是,将开发部的SPI接到上位机的SD卡槽,或者电脑、甚至读卡器的SD卡槽里面,读取上位机发来的数据,进行分析,理清这条通路和具体的协议,调通如何按照SD卡协议回复上位机。
以上是不是就是先做模拟SD卡?
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-8-28 23:15:49 | 显示全部楼层
回复【6楼】angryBird:
---------------------------------
可以。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-8-29 23:42:04 | 显示全部楼层
回复【7楼】正点原子:

回复【6楼】angryBird:
---------------------------------
可以。

---------------------------------
谢谢原子兄。

这两天在详细看spi协议,准备整理出来一份文档,集中一下。
硬件还没有做出来,我准备用读卡器改造一个可以用来调试的东西。将读卡器拆开,把那四根线,连到开发板的spi上。这样,插到电脑的USB口,应该能有点数据过来。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-8-29 23:43:35 | 显示全部楼层
开发板是f207的,我找不到spi的例程。哪位朋友有,或者给个链接,多谢啊!
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

0

主题

13

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2013-9-1
在线时间
1 小时
发表于 2013-9-1 22:06:20 | 显示全部楼层
回复【9楼】angryBird:
---------------------------------
ST官网上应该有的,楼主上去找找
我要重回研发!!!
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-2 22:44:16 | 显示全部楼层
又过去了三天,孩子开学,忙忙活活的,日子过得真快。
继续看SD卡spi协议相关资料和一些读写SD卡的例程,熟悉通信的过程。
终于找到了两年前做项目用到的EWARM安装程序,原来是6.2版本。再次安装起来编译调试环境。
将原来的项目打开,编译,一堆错误。经过仔细回想,以及网上查找,至此总算能把原来的工程编译过去了,下载到开发板上,正常运行。也算今晚的一点小成绩。

在EWARM上修改了一下内容,做个备忘。
1. 在options里面,target要选择相应的CPU型号,这里是 f207。
2. 在options里面,C/C++ Compiler->preprocessor选项里面,要将用到的头文件的路径全部包括进去。这个我倒有点纳闷,头文件有多个路径,在preprocessor里面,要一个一个全部罗列出来。
3. options->General Options->Library Configuration里面,Library选择 full,否则,文件里面有一个重定向打印信息的函数报错,报FILE not defined 错误。
4. options->General Options->Library Configuration里面,勾选上Use CMSIS,不用自己的core_cm3.h 。具体什么原因忘了。
5. options->linker->config里面,选择自己工程下面的那个.icf文件,否则,运行时会报错,说从0地址写如程序。

以上是今晚的工作。明天准备将程序的框架搭起来。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-2 23:09:50 | 显示全部楼层
回复【11楼】angryBird:
---------------------------------
支持
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-3 23:47:27 | 显示全部楼层
回复【12楼】正点原子:
---------------------------------
多谢原子兄支持。

今天用读卡器做一个调试用的工具,结果读卡器是坏的。倒是拆开看清楚了,后面再找一个好的,按照9个脚,接出来相应的四根线。和开发板上哪几个管脚接,还没有看。

建立了项目workspace,但是还没有开始写代码。先找到了例程里面的spi flash的代码,想着应该先看看例程跑起来是什么样子。于是,在IAR上新建一个例子工程。几经周折,总算编译过去了,下载到了开发板上,也能执行。但是除了在LCD上显示了我打印的字,没看出来什么其它的信息。没看这部分的代码,所以也不知道具体是什么了。

建立新工程的过程,有几点要记录一下:
1. 固件库里面的c文件,基本上都复制过来用了;eval开发办相关的c文件,也拿来了不少
2. 关于.icf文件,忘了是怎么生成的了。所以,download and debug 程序,根本跑不起来。对比了一下原来工程在Linker里面,config选项卡中,是edit过的,在edit中,设置了f207的vector table, memory regions等。照着找个在新工程上也做一遍,结果.icf自动生成。
3. 经过上述,再下载执行,还是不对。结果发现,还要在 debugger->download 里面,选上use flash loader。
至此,程序在开发板上跑起来了。
4. 另外,头文件不用加到工程里面来,在C/C++ Compiler->preprocessor选项里面,要将用到的头文件的路径全部包括进去就行了。当然,加到工程里面,打开查看方便。

期间,有一个疑问,想请原子兄解答一下。 固件库里面很多文件,哪些是需要加到自己工程里面来的,是根据什么筛选的呢?谢谢。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-4 11:31:24 | 显示全部楼层
回复【13楼】angryBird:
---------------------------------
固件库的文件根据你用到的资源来刷选,比如你用了fsmc,那就必须包含stm32f10x_fsmc.c。
如果用了gpio,那就必须包含stm32f10x_gpio.c。
以此类推。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

46

主题

1579

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1970
金钱
1970
注册时间
2011-7-17
在线时间
4 小时
发表于 2013-9-4 16:39:27 | 显示全部楼层
楼主,你想搞USB-OTG吗?
Time?And?Relative?Dimension?In?Space.
回复 支持 反对

使用道具 举报

0

主题

21

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2013-2-22
在线时间
0 小时
发表于 2013-9-6 15:57:07 | 显示全部楼层
是不是把U盘插到你做的设备上,然后你做的设备插到读卡器里面用。
如果是的话,只能说世界之大无奇不有,嘿嘿。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-7 22:43:58 | 显示全部楼层
回复【16楼】wahahaheihei:
---------------------------------
要不怎么叫离奇的故事呢!呵呵。

这两天在编写代码,一边写,一边参考例程。
有一个two board 通信的例子,slave模式spi接收使用的是中断模式,master发送也是中断模式。在网上看的其它一些例子,接收似乎不是使用中断。总之,目前处于代码编写的前期阶段。
搞了一个改造的读卡器,飞线出来,用示波器看波形。卡能正常读写,但是一直看不到SD卡第5个引脚(SD CLK)上有标准的方波,只有在写SD卡的时候,有一段一段的类似正弦波的波形出现。在网上查了查,PC上,或者读卡器使用的似乎都是SD协议,如果是这样的话,做出来这个工具用处不大了。调试是个问题。
为啥不能一直看到时钟信号呢?难道是只有在读写的时候,主机才发送时钟信号?求解答。

改造SD卡,把里面的的9跟线印出来,直接插到上位机的SD卡槽里面,目前只有这个办法了,因为上位机肯定使用的是SPI协议。

艰苦摸索中。。。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-8 23:43:30 | 显示全部楼层
回复【14楼】正点原子:

请教原子兄一个小问题,整了一个小时没看明白,只好求助了。
关于SPI2的定义:

#define SPIx                           SPI2
再查:#define SPI2                ((SPI_TypeDef *) SPI2_BASE)
再查:#define SPI2_BASE             (APB1PERIPH_BASE + 0x3800)
再查:#define APB1PERIPH_BASE       ERIPH_BASE
再查:#define ERIPH_BASE           ((uint32_t)0x40000000)

那就是SPI2_BASE的地址应该是 0x40003800 ,对吧。可是,我翻看文档,没找到这是对应哪个PORT。
PA, B, C, D。。。
各个PORT的定义,在哪个文档里呢?pdf翻了一遍,也没找到。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-9 14:13:58 | 显示全部楼层
回复【18楼】angryBird:
---------------------------------
0x40003800 这是SPI2控制寄存器组的首地址,而不是PA,PB之类的IO口控制地址。
你要看SPI2的引脚定义?那你看STM32的管脚描述,就知道了,引脚上有标SPI2_SCK,SPI2_MISO,SPI2_MOSI之类的 ,就是SPI2的复用引脚。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-9 15:36:44 | 显示全部楼层
回复【19楼】正点原子:
---------------------------------
谢谢。我现在是要把自己改造的SD卡的飞线,接到开发板上的引脚上。程序现在用的是SPI2,根据头文件定义的pin,我找不到是哪个GPIO,所以就确定不了该怎么连接。
郁闷中,原子兄再给点提示吧。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-9 16:09:07 | 显示全部楼层
按照原子兄的提示,我查找datasheet文档,找到了SPI2_开头的pin描述,好多啊,呵呵,我再确定程序中使用的到底是哪个。




锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-9 17:24:11 | 显示全部楼层
这两个是的啊。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-9 17:30:22 | 显示全部楼层
回复【22楼】正点原子:
---------------------------------
PC也有,PI也有,PB也有,所以要确定到底是哪个
刚又看程序:
#define SPIx_SCK_PIN                   GPIO_Pin_1
#define SPIx_SCK_GPIO_PORT             GPIOI
#define SPIx_SCK_GPIO_CLK              RCC_AHB1Periph_GPIOI
#define SPIx_SCK_SOURCE                GPIO_PinSource1
#define SPIx_SCK_AF                    GPIO_AF_SPI2

是不是已经给出来定义了,用的是GPIOI,也就是SPIx_SCK_PIN就是PI1。原子兄,对否?
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-9 19:05:50 | 显示全部楼层
回复【23楼】angryBird:
---------------------------------
你这是F1,还是F4啊?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-9 19:06:05 | 显示全部楼层
F4没搞过...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-9 20:02:22 | 显示全部楼层
F2,F207
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-23 23:16:22 | 显示全部楼层
回复【25楼】正点原子:
---------------------------------
好长时间没有进论坛了。一直在折腾代码。
板子前几天做回来了,用的是F205RE。加上开发板,可以连起来调试了。
将板子的PC10,11,12连到SPI3上,将开发板的PI1,2,3连到SPI2上。然后用导线将两个板子的CLK、MOSI、MISO连接起来。
开发板一端做master,另一个板子做slave。
master端采用中断发送发式,slave端采用中断接收。master端发送的数据,slave端都能正确收到。
但是,我在slave端,不用中断方式发送,而直接调用库函数 SPI_I2S_SendData(SPIx, 0x01); 发送一个数据1给master端。
master端用查询方式接收数据,怎么也收不到,接收代码如下,在while循环中:
if (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) != RESET)
 {
        RxBuffer[Rx_Idx++] = SPI_I2S_ReceiveData(SPIx);
        sprintf(logBuffer, "get: %02x\n", RxBuffer[Rx_Idx-1]);
        LCD_UsrLog(logBuffer);
 }

改成中断方式收,可以有几次中断,但是收到的数据都是0x00,而不是0x01

请问原子兄,我是否可以将发送和接收中断同时打开使用?
收不到01,而是00有可能是什么原因?
如果用查询方式接收,难道必须要先发送一个字节,才能接收一个字节吗?那样的话,另一端岂不是一直收到无用的数据?

spi有点进展,但是初次涉及spi通信,还是比较迷茫,请原子兄指教,谢谢。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-24 10:24:47 | 显示全部楼层
可以同时打开。
可能你数据收发有问题,检查下MISO的数据是不是0X01?
SPI所有的通信都是由主机发起,主机必须提供sck,而发送字节则是产生SCK的必要条件。所以从机必定会收到无效数据的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-24 20:36:37 | 显示全部楼层
回复【28楼】正点原子:

可以同时打开。
可能你数据收发有问题,检查下MISO的数据是不是0X01?
SPI所有的通信都是由主机发起,主机必须提供sck,而发送字节则是产生SCK的必要条件。所以从机必定会收到无效数据的。

---------------------------------
难道slave端发送数据,要等到master端有数据来之后才能发送?要是中断方式接收,在主程序中,收到一个或者多个字节的数据,收完后,master端早已经发送完成了,master端的中断也可能禁止了。这时候,slave端要想再发送数据给master端,哪里还有时钟?要是slave端要发送512个字节的数据怎么办,我的意思是master端是要一直提供发送这512字节的时钟信号吗?比如一直发送0xff?
slave端要是收到海量的无效数据,会影响解析有用的数据吧,比如解析spi的6字节长的cmd。

继续混沌中,期待原子兄的指教。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-24 20:41:06 | 显示全部楼层
我的意思是,我编写从机的程序,要向主机发送数据,发送的时机在哪里,什么时候才能发送,怎么才知道有CLK。谢谢
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-24 20:59:30 | 显示全部楼层
在空闲时SCLK 无信号。当MCU发送数据时SCLK才会产生一个8位的sclk信号将数据发送出去。同理,如果MCU一直无动作是不会有sclk信号的,如果想要读取从机的值只能先往从机发送一个无意义的十六进制数。这时才会在SCLK上出现时钟信号,而此时AD才会将数据通过dout发送出去。也就是说由于SPI通信要由主机产生sck时钟信号,只有存在时钟才从机才能把寄存器内数据发送出去,所以要保证发送的数据使得从机不会产生动作(无效数据),SPI不能只接收不发送,在接收的时候必然也在发送数据

这是从网上看的一段资料。
主机为了得到从机的数据,就得不停地发送时钟信号。从机收到主机的有效数据,比如CMD0,要回复R1,是不是就得等着收到无效信号时,才能发送自己那一个字节?这是不是我看别人写得代码,会有一个for循环不停地发送一条指令的原因所在?

主机发送无效无效数据,在spi通信中,有什么约定吗,比如都是发送0xff?那数据中要是有0xff,是不是就得转义?
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-24 22:11:42 | 显示全部楼层
回复【29楼】angryBird:
---------------------------------
必须的,slave的所有数据,都是要等主机发送指令的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-25 00:07:17 | 显示全部楼层
回复【32楼】正点原子:
必须的,slave的所有数据,都是要等主机发送指令的。

---------------------------------
感谢原子兄恢复,不过,我还是一头雾水,呵呵。

我的问题是从机啥时间点发送数据?比如收到虚拟数据后?那不晚了吗?

看了不少代码,都是主模式的。其中经常有类似这样的函数:

static u8 SPIByte(u8 byte)

{
 
while((SPI2->SR &SPI_I2S_FLAG_TXE)==RESET);
  
SPI_I2S_SendData(SPI2,byte);
 
while((SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE))==RESET);

returnSPI_I2S_ReceiveData(SPI2);

}

意思是发送一个数据,然后读取收到的数据。
从时序上将,从机收到数据后,要有时间解析,然后才能决定回复什么数据。如果发送和接收是同时进行的,等从机确定要发送什么数据的时候,岂不是已经没有时钟了?
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-9-25 22:30:01 | 显示全部楼层
回复【33楼】angryBird:
---------------------------------
这个,都是根据从器件来看的了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-28 14:24:27 | 显示全部楼层
继续艰苦调试,从机发送的数据,主机死活收不到,请原子兄看一下代码,给点指点。

主机代码:
检测到开发板上的“右键”按下,发送数据给从机
switch (PressedButton)
    {
      /* JOY_RIGHT button pressed */
      case JOY_RIGHT:
        recCode = SpiSendByte(0x40);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
        recCode = SpiSendByte(0x00);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
        recCode = SpiSendByte(0x00);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
        recCode = SpiSendByte(0x00);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
        recCode = SpiSendByte(0x00);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
        recCode = SpiSendByte(0x95);
        sprintf(logBuffer, "get: %02x\n", recCode);
        LCD_UsrLog(logBuffer);
。。。。
}
        
        //延时后,试图收到从机的回应:
        zero=0;
      for(nn=0;nn<200;nn++){
        recCode = SpiReadByte();
        for( n=0;n<1000;n++){}
       
        if(recCode==0)zero++;
        else {
          sprintf(logBuffer, "get: %02x\n", recCode);
          LCD_UsrLog(logBuffer);
        }
      }
      sprintf(logBuffer, "zero: %d\n", zero);         
      LCD_UsrLog(logBuffer);
    }

//发送一个字节
uint8_t SpiSendByte(uint8_t ch)
{
  while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPIx, ch);
 
  for( n=0;n<1000;n++){}

  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET){}
  return SPI_I2S_ReceiveData(SPIx);
}
 
//接收一个字节
uint8_t SpiReadByte()
{
  while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPIx, 0xff);
 
  for( n=0;n<1000;n++){}

  while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET){}
  return SPI_I2S_ReceiveData(SPIx);
}

结果,从机正确收到了 0x40 0x00 0x00 0x00 0x00 0x95,但是后面收回应数据,一直是0x00



锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-28 15:20:01 | 显示全部楼层
从机代码片段:

void arseSpiData()
{
  uint8_t cmd, crc;
  uint32_t arg;
  
  if(spiStatus == SPI_CMD_PARSE){
    cmd = RxBuffer[0];
    
    if(cmd==SPI_CMD_0){ //reset sd card, response 01 to master
      if(RxBuffer[5]==0x95){ //crc right
        SendResponseR1(0x01);
      }
    }
...

当从机收到 0x40 0x00 0x00 0x00 0x00 0x95,即spi协议中的CMD0后,发送R1回应给主机:
发送一个字节函数:
uint8_t SpiSendByte(uint8_t ch)
{
  while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPIx, ch);

  //while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET){}
  return SPI_I2S_ReceiveData(SPIx);

}
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-9-28 15:25:11 | 显示全部楼层
这种由主机提供时钟的通信,如何把握接收、发送的间隔?主机总不能在while循环中一直发送无效数据来提供时钟。
从机发送数据,
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPIx, ch);
是有CLK的时候,上句的while才能跳出,进而执行下面的SPI_I2S_SendData(SPIx, ch);   ???
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-5 22:42:37 | 显示全部楼层
国庆假期正好可以在家调试代码,安静无打扰。

SPI的问题困扰已久,索性放到一边,先把U盘扇区读写的部分做完。
将HOST库加上,使用MSC类,有了上一个项目做USB的经验,只用了一天,就把扇区读写的代码完成。在F207开发板上调试通过,试了3个U盘,读写均没有问题。
代码合并到项目中,再次整理了程序结构。只剩下将SPI双向通信搞通,调试SD卡协议了。

今晚,单独写了个测试程序。在F207的开发板上,将SPI2和SPI3的GPIO用三根线连起来,SPI2做master,SPI3做slave,结果一试,竟然双向互通了!经过调试观察,目前基本理解了主从模式的spi通信的特点。下一步,再次检查代码,看看是哪里初始化不对,还是板子做的有问题,硬件上就不通?USB部分经过测试,发现硬件有问题,在开发板上调试没问题的代码,在板子上无法读取usb数据,停留在xfer阶段。

在艰难中进步,越是困难的时候,越是要见到曙光的时候。加油!
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-5 22:45:11 | 显示全部楼层
祝原子兄节日快乐!
祝坛子里所有的同道朋友节日快乐!

:)
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-6 11:03:18 | 显示全部楼层
回复【39楼】angryBird:
---------------------------------
谢谢,恭喜。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-6 12:08:48 | 显示全部楼层
回复【40楼】正点原子:
---------------------------------
原子兄,为什么f2xx没有 这个定义了:
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

没有GPIO_Mode_AF_PP,只有GPIO_Mode_AF
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-6 12:14:18 | 显示全部楼层
现在两个板子能双向通信,但是各自接收到的数据都是错的。如果只是master发送,slave收到的是对的,要是slave也发送,则两边都错。spi slave端的初始化如下,master端一样,只是mode改为master。请原子兄看看有什么问题:

static void InitSPI(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

  /* Enable the SPI clock */
  SPIx_CLK_INIT(SPIx_CLK, ENABLE);

  /* Enable GPIO clocks */
  RCC_AHB1PeriphClockCmd(SPIx_GPIO_CLK, ENABLE);
  //RCC_AHB1PeriphClockCmd(SPIx_SCK_GPIO_CLK | SPIx_MISO_GPIO_CLK | SPIx_MOSI_GPIO_CLK, ENABLE);
  
  
  // SPI_Cmd(SPIx, ENABLE);//0916 ??? 先禁能?

  
  /* Connect C10 to SPI3_SCK */ 
  GPIO_PinAFConfig(SPIx_GPIO_PORT, SPIx_SCK_SOURCE, SPIx_SCK_AF); 
  /* Connect C11 to SPI1_MOSI */ 
  GPIO_PinAFConfig(SPIx_GPIO_PORT, SPIx_MISO_SOURCE, SPIx_MISO_AF);
  /* Connect C12 to SPI1_MISO */ 
  GPIO_PinAFConfig(SPIx_GPIO_PORT, SPIx_MOSI_SOURCE, SPIx_MOSI_AF); 
  

  
  /* Configure SPI1 pins as alternate function 
  * (No need to configure A4 since NSS will be 
  * managed by software) */
  GPIO_InitStructure.GPIO_Pin = SPIx_SCK_PIN | SPIx_MISO_PIN | SPIx_MOSI_PIN; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;  //GPIO_PuPd_UP
  GPIO_Init(SPIx_GPIO_PORT, &GPIO_InitStructure);
  

 
  /* SPI configuration */
  SPI_I2S_DeInit(SPIx);
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
  SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; 
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; 
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;   // SPI_CPOL_High?
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  //把数据锁定在第一个波形.才不会漏掉最高位 //SPI_CPHA_2Edge ?
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; 
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;  // SPI_BaudRatePrescaler_256 ?
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //高位在前
  SPI_InitStructure.SPI_CRCPolynomial = 7; 
  SPI_Init(SPIx, &SPI_InitStructure);
  

 
  /* Configure the riority Group to 1 bit */                
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  //Configure the SPI interrupt priority 
  NVIC_InitStructure.NVIC_IRQChannel = SPIx_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  // 2 ???
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  /* SysTick configuration ---------------------------------------------------*/
  //SysTickConfig();
  
  /* Enable the Rx buffer not empty interrupt */
  SPI_I2S_ITConfig(SPIx, SPI_I2S_IT_RXNE, ENABLE);
  
  /* Enable the SPI peripheral */
  SPI_Cmd(SPIx, ENABLE);
}
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-6 14:51:52 | 显示全部楼层
回复【41楼】angryBird:
---------------------------------
这我也不太清楚哦。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2013-10-7 19:12:26 | 显示全部楼层
回复【楼主位】angryBird:
---------------------------------
虽然我很想支持楼主,但是楼主这个真心意义不大,虽然很有难度,这是在用STM32做FPGA的工作,USB转SD是两种不同协议的转换,通信协议的实现必然用到状态机。你用STM32去实现协议转换,类似于USB转串口这种东西,你看人家都是做成IC芯片了,没有人用单片机去做一个USB转串口的,协议转换一般用IC芯片设计,用单片机实现真心不靠谱。
原子提到过STM32的USB只能作设备,不能作主机,要把一个U盘封装成一个SD卡,STM32是作为设备还是主机?这个问题值得思考。

BTW,这个项目,真的能赚钱吗?
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-7 20:10:55 | 显示全部楼层
回复【44楼】EDA3rd:
---------------------------------
朋友之托,钱是次要的,我必须帮这个忙。因为是他们已有设备的一个补充,所以不可能到IC级别。选择这个方法,也是没办法的办法了。
STM32对USB是主机,对于另外一台设备,只是一个SPI的从机。
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2013-10-7 20:23:30 | 显示全部楼层
回复【45楼】angryBird:
---------------------------------
你要把U盘做成SPI 存储器是可以的,做成SD卡就不现实了,光是SD卡协议的实现都够你折腾了,所以估计你不用去折腾SD卡协议了,重点是将stm32设置为SPI从设备,绑定到USB数据,另一块STM32完全不用加SD卡驱动。f107支持USB OTG,祝你早日成功。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-13 22:46:58 | 显示全部楼层
又过了一周。
前几天还是纠结在SPI通信的正确、稳定上,直到昨天,连接板子调试的JTAG被烧坏,没办法在板子上调试了。于是又找了一块F207的开发板,两个开发板连在一起调试。结果,通过试验不同的CPOL与CHPA组合,终于找到了一组稳定传输的组合。如下:
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
除了这种,其它三种组合,在双向传输时,总会发生数据错位的问题。具体原因先不追究了,现在终于能够往下走,调试模拟SD卡的协议。计划使用一台开发板,发送读写SD卡的命令,一台slave模拟SD卡做出回应,以及读写U盘,并转发u盘数据给master。

上个图看看,下面是master,上面是slave。


锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-10-14 14:43:10 | 显示全部楼层
楼主这两个板子价格不菲吧。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-14 20:50:07 | 显示全部楼层
回复【48楼】正点原子:
---------------------------------
对方公司的,我还真没问过多少银子一块 :)
锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

5

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
79
金钱
79
注册时间
2013-8-26
在线时间
0 小时
 楼主| 发表于 2013-10-17 23:31:22 | 显示全部楼层
时间又过了几天。
这几天,实现SD卡的协议并调试。到目前,SPI模式用到的指令,基本上都模拟通了,还剩下多块读写指令没有调试到。
单块读写U盘并传送到master主机已经没有问题。
心情暂时可以放松一下了,等在开发板上调试完毕,还要在板子上调试并连接真正的主机,到时候估计还有一番反复。
上个图,右侧是主机通过spi发送单块读0扇区给从机后,收到的0扇区数据,和用winhex读到的一致。图中光标所在的0xfe是从机发送数据前发送的token。

还有两个问题问一下原子兄,spi协议中有一些控制字符,比如0xfe是数据发送的令牌,0x12是终止数据传送的命令,那在传输的数据中,如果有这些字符的话,是否要转义?
第二个问题,主机发送0xff数据给从机,从机如果没开,或者程序处于中断状态,主机收回来的数据都是0xff,但是从机也在运行时,主机收到的都是0x00,而不是0xff,可能的原因是什么?谢谢。


锄禾日当午,汗滴禾下土。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-10 11:01

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表