打印
[STM32]

STM32F10x 尝试移植最新库 V3.6.1 固件库 + V4.0.0 USB库 + 0.10a Fatfs

[复制链接]
7533|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
前两天官网上下载的STM32_USB-FS-Device_Driver固件库,当时是最新的。。以后当然就不是最新的了。。别说我骗你。。

V3.6.1 固件库 + V4.0.0 USB库 + 0.10a Fatfs + V5.1.0 SDIO_SDCARD

昨天忙了一天,把这几样东西移到了一起,基本上没什么难的,但是有一些比较蛋疼的地方,研究了很久,才搞定,在此记录一下,避免其他人走弯路。感觉新版本的移植,比旧版本容易一点。网络上目前现有的资料,版本都相当古老,新版本的资料除了官网的例程以外,几乎没有。所以稍微讲讲移植中要注意的问题吧。

现在FATFS的版本是0.10a,和之前0.07,0.09版本最大的不同,就是盘符可以支持字母了。f_mount的用法有变,不再用数字了,而用一个字符串表示盘符,最后一个参数表示是否立刻挂载。如果不立刻挂载,下次调用其他函数的时候,会自动挂载:
res = f_mount(&fs, "1:", 1);

FATFS移植,只要修改diskio.c就可以了。
disk_initialize()里面,直接改成这样就可以:
result = SD_Init();
if(result == SD_OK)
  return RES_OK;

disk_read()比较坑,用以前的代码直接复制进去,结果只能读2048个字节,一次读取超过2048个,则卡死在disk_read里面,这类问题之前也有很多人遇到,但是我没找到什么有用的经验。参考官方SDIO的例程,发现V5.1.0的stm3210e_eval_sdio_sd的用法有一点点小变化:
result = SD_ReadMultiBlocks((uint8_t *)buff, sector << 9, _MAX_SS, count);
SD_WaitReadOperation();
while(SD_GetStatus() != SD_TRANSFER_OK);

后面两句一定不能少,之前我用的版本V4.7.0,没有调用SD_WaitReadOperation(),但是现在这个版本如果缺了这句,会出现只能读取2048个的问题。

disk_write()跟read一样的,SD_WaitWriteOperation();要加上。

FATFS移植就讲到这。然后看看USB。之前我一直用的都是V3.1.1的USB库,前两天下载官方例程,发现里面的USB库已经更新到V4.0.0了,应该更新了无数次了吧?当时就想想,已经好久没更新了,就想试一下换新版本。先试了一下Joystick,然后修改成USB HID 键盘,整个修改过程和之前V3.1.1没有很大差别,网络上的各种资料仍然适用,就不多说了。。

然后Mass Storage,其实Mass Storage移植,跟FATFS差不多的,我们需要修改mass_mal.c,这个文件就好比FATFS的diskio.c,要在里面实现init、read、write、get_status这几个方法。

官方例程是在eval板上跑的,里面掺杂了很多LED控制之类的,和一般的开发板不能通用。移植过来,第一步,就把LED相关的东西,全换成这样:比如LED1_ON() LED2_OFF()之类,然后用
#define LEDx_ON NOP_PROCESS
这样先把它编译过去,这个灯之类的,以后可以根据不同的开发板,#define成不同的东西,不用去一大堆源代码里面找,比较方便。

platform_config.h里面的东西,只有一个有用,
#define         ID1          (0x1FFFF7E8)
#define         ID2          (0x1FFFF7EC)
#define         ID3          (0x1FFFF7F0)
#define USB_DISCONNECT                    GPIOA  
#define USB_DISCONNECT_PIN                GPIO_Pin_8
#define RCC_APB2Periph_GPIO_DISCONNECT    RCC_APB2Periph_GPIOA

前三个无所谓,后面三个换成自己开发板上的引脚,其他内容,统统删了,没用。

hw_config.c里面
Set_System()里面一堆东西,无非初始化一下引脚之类。留下这些就行了。
GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);

  GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);

  EXTI_ClearITPendingBit(EXTI_Line18);
  EXTI_InitStructure.EXTI_Line = EXTI_Line18;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
  MAL_Config();

USB_Interrupts_Config()里面有一个东西很坑,就是
NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;
不知道这个SD_SDIO_DMA_IRQn是哪个中断号,在我的工程里是没有定义的,而且默认的范例工程,这句话是不编译的,把范例工程改成stm32f10x_hd的工程,编译跟踪这个玩意,发现:
#define SD_SDIO_DMA_IRQn                 DMA2_Channel4_5_IRQn
#define SD_SDIO_DMA_IRQHANDLER           DMA2_Channel4_5_IRQHandler

简直令人吐血。。好吧,我对STM32的IRQ还不是很了解。。
直接把它替换成DMA2_Channel4_5_IRQn,并在stm32_it.c里面,把USB中断相关的代码,全复制到自己的工程的stm32f10x_it.c里,把其中一个SD_SDIO_DMA_IRQHANDLER(),换成DMA2_Channel4_5_IRQHandler()

然后还有mass_mal.c,按照编译错误,稍微改改,就编译通过了。于是连上电脑,显示出了一个盘符,而且容量显示为59MB,没有提示要格式化,但是里面是空的,而且点格式化,提示“Windows无法完成格式化”。按理来说,这个工程应该显示出两个盘符,一个SDCARD,一个NAND。现在出现容量显示不正确的情况,怀疑mass_mal.c里面有问题。

想试一下,直接把之前V3.1.1的mass_mal代码复制进来,发现这两个版本,代码相差甚大,很多函数调用都不一样,不好改,于是作罢。
这个mass_mal.c,是官方提供的,版本也是V4.0.0,按理来说应该不会有问题啊。找了很久了毛病,最后,终于发现,问题出在MAL_GetStatus()里面。把相关的#ifdef之类,都给去掉,这样代码会比较清晰,然后看到这一句
Mass_Memory_Size[0] = Mass_Block_Count[0] * Mass_Block_Size[0];
之前V3.1.1的代码,是没有类似的内容的,把它注释掉以后,连上电脑,显示两个盘符,SD卡的盘符工作完全正常,NAND盘显示需要格式化。NAND之前用V3.1.1的时候也是这样,可能因为我并不需要NAND,所以一直也懒得去调它。
把mass_mal.h的MAX_LUN改成0,把usb_prop.c最上面的Max_Lun的定义改成:
uint32_t Max_Lun = MAX_LUN;
这样连接电脑,就只显示一个SD卡的盘符,不显示NAND的了。

官方提供的代码,在MAL_GetStatus()有问题,而且只不过多了一句代码。。实在不明白为何官方的代码经常有这种奇怪的错误。。
然后测试了一下,用128MB的TF卡,和16GB的TF卡,均没有问题,写入速度250K左右,读取速度600K左右,没快,跟之前的差不多。。囧。。也不知道新版的库改进在哪了。。

相关帖子

沙发
yuyi1005|  楼主 | 2014-2-11 17:35 | 只看该作者
我是新来的:lol
混个脸熟,大家多多关照

使用特权

评论回复
板凳
星火燎原| | 2014-2-15 21:59 | 只看该作者
支持,顶

使用特权

评论回复
地板
bu2zhouzhu| | 2014-2-19 09:04 | 只看该作者
本帖最后由 bu2zhouzhu 于 2014-2-19 09:57 编辑

楼主,为啥我写SD卡的速度特别慢呢?代码贴出来你看看。
这段是diskio.c里的disk_write()函数。
/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */

#if _READONLY == 0
DRESULT disk_write (
        BYTE drv,                        /* Physical drive nmuber (0..) */
        const BYTE *buff,        /* Data to be written */
        DWORD sector,                /* Sector address (LBA) */
        BYTE count                        /* Number of sectors to write (1..255) */
)
{

        if (count > 1)
        {
                SD_WriteMultiBlocks((uint8_t *)buff, sector*BLOCK_SIZE, BLOCK_SIZE, count);
               
                /* Check if the Transfer is finished */
                SD_WaitWriteOperation();         
                while(SD_GetStatus() != SD_TRANSFER_OK);
        }
        else
        {
                SD_WriteBlock((uint8_t *)buff,sector*BLOCK_SIZE, BLOCK_SIZE);
               
                /* Check if the Transfer is finished */
                SD_WaitWriteOperation();
                while(SD_GetStatus() != SD_TRANSFER_OK);
        }
        return RES_OK;
}
#endif /* _READONLY */


这段是main()函数
int main(void)
{        
        int res;
        FIL fdst;
        FATFS fs;
        UINT bw;                          // File R/W count
        BYTE buffer[512];            // file copy buffer
        CHAR Buf1 = 60;
        CHAR Buf2 = 70;
        
        int i;
        f_mount(0,&fs);
        res = f_open(&fdst, "0:/demo.txt", FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
        if ( res == FR_OK )
          {
                for(i=0;i<100;i++)
                {
                        if((i%2)==0) GPIO_SetBits(GPIOC, GPIO_Pin_13);   //PC13口为LED小灯,此灯闪烁
                        else GPIO_ResetBits(GPIOC, GPIO_Pin_13);

                        f_write(&fdst, &Buf1, sizeof(Buf1), &bw);
                        f_lseek(&fdst, fdst.fsize);
                        f_sync(&fdst);
                        
                        f_write(&fdst, &Buf2, sizeof(Buf2), &bw);
                        f_lseek(&fdst, fdst.fsize);
                        f_sync(&fdst);
                }
                f_close(&fdst);
                f_mount(0, NULL);
                GPIO_SetBits(GPIOA, GPIO_Pin_0);
                //PA0口为另一个LED小灯,写入SD卡完成点亮。从上电到此灯亮,i=100的情况下大概是1分钟。巨慢 - -||
          }      
  while (1){}
}

我用的是V3.5固件库+V4.5 stm32_eval_sdio_sd.c,用示波器量SD卡CLK引脚是24Mhz,并且已确认是4bit、4个SD卡引脚在传输数据。可是上面写入200个8bit  char 数据需要1分钟左右写完。(我用LED灯做的指示)

使用特权

评论回复
5
bu2zhouzhu| | 2014-2-19 10:06 | 只看该作者
本帖最后由 bu2zhouzhu 于 2014-2-19 10:09 编辑

把SD卡从板子上取下插到电脑上打开是这样的。60的ASCII是 < , 70的ASCII是 F  分别100个

使用特权

评论回复
6
bu2zhouzhu| | 2014-2-19 10:20 | 只看该作者
我看有人说写入速度主要是看你disk_write()函数写的怎么样,因为这个是FatFs要求你写好给它用的。我的disk_write()函数是使用野火开发板的代码,如下所示:
/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */

#if _READONLY == 0
DRESULT disk_write (
        BYTE drv,                        /* Physical drive nmuber (0..) */
        const BYTE *buff,        /* Data to be written */
        DWORD sector,                /* Sector address (LBA) */
        BYTE count                        /* Number of sectors to write (1..255) */
)
{

        if (count > 1)
        {
                SD_WriteMultiBlocks((uint8_t *)buff, sector*BLOCK_SIZE, BLOCK_SIZE, count);
               
                  /* Check if the Transfer is finished */
                   SD_WaitWriteOperation();
            while(SD_GetStatus() != SD_TRANSFER_OK);
        }
        else
        {
                SD_WriteBlock((uint8_t *)buff,sector*BLOCK_SIZE, BLOCK_SIZE);
               
                  /* Check if the Transfer is finished */
                           SD_WaitWriteOperation();
            while(SD_GetStatus() != SD_TRANSFER_OK);
        }
        return RES_OK;
}
#endif /* _READONLY */

网上有人说慢后来发现是没有使用SD_WriteMultiBlocks(), 而是完全使用 SD_WriteBlock()。但是我这个用了前者呀。再有一个网上说的单个bolck可以设置为512, 1024, 2048, 4096,这个是在哪里呢?我想看看我现在是多少?(因为用的现成的代码,未加任何修改就直接能用,所以内部很多东西不知道在哪)

使用特权

评论回复
7
bu2zhouzhu| | 2014-2-19 10:37 | 只看该作者
我找到了一个定义BLOCK_SIZE的地方,在diskio.c下有
#define BLOCK_SIZE     512         /* Block Size in Bytes */

可是我改为1024后无法操作SD卡了。创建.txt文件未成功,啥都没创建。

使用特权

评论回复
8
yuyi1005|  楼主 | 2014-3-4 10:21 | 只看该作者
BLOCK_SIZE 是和SD卡相关的,一般SD卡都是每个BLOCK 512字节的,所以就用512。
你一次性写入多个字节才会快,虽然你用了SD_WriteMultiBlocks(),但是你for循环里面,是一个一个字符的发的,每次发完还要找指针,你如果建一个缓冲,把数据都存好,再一次性写入200个字符,会快很多。
还有,f_write好像指针会自动增加的吧,可以不用f_lseek(&fdst, fdst.fsize);和f_sync(&fdst);

使用特权

评论回复
9
insect2006| | 2014-10-8 15:30 | 只看该作者
楼主,我用官方的USB HOST库,貌似不支持盘符号为非0的情况?
比如在disk_read函数里面有这一句:
if (drv || !count) return RES_PARERR;

现在又点头大,我板子上有NAND FLASH已经作为0驱动器
外接的U盘要分配为驱动器1,这样drv=1,就出来很多问题

请问如何解决?

使用特权

评论回复
10
aabb888| | 2014-10-9 21:44 | 只看该作者
看一下...............

使用特权

评论回复
11
当我想飞向蓝天| | 2016-5-25 14:12 | 只看该作者
你好  我找了很多天了  不知道你用的各种库怎么在官网找到的? 是在cube那一块里面吗?望告知  感谢!

使用特权

评论回复
12
当我想飞向蓝天| | 2016-5-25 14:13 | 只看该作者
特别是这个 V5.1.0 SDIO_SDCARD  我不知道在哪里 = =

使用特权

评论回复
13
killer2014| | 2016-5-25 15:01 | 只看该作者
这个好啊,楼主不错,辛苦了

使用特权

评论回复
14
killer2014| | 2016-5-25 15:01 | 只看该作者
希望分享大家的智慧, 让我们新手都动起来,

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

4

帖子

0

粉丝