查看: 16444|回复: 41

[分享] 【YL-KL26Z试用】KL26_SD卡SPI模式移植pfatfs文件系统(非PE)

[复制链接]
  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
    发表于 2015-5-21 01:18:20 | 显示全部楼层 |阅读模式
    本帖最后由 suyong_yq 于 2015-5-21 01:29 编辑

    SD卡SPI模式移植pfatfs文件系统
    ——基于YL-KL26Z开发板

    suyong_yq  2015-05



    pfatfs情缘】SDSPI驱动】
        【sdcard_spi简介】
        【移植sdcard_spi】
    pfatfs的移植】
    总结


    pfatfs情缘】

    今天我们的主角是pfatfs,但要先提一下fatfs。


    Fatfs是一种可以在小型嵌入式应用中使用的FAT文件系统,完全由C89标准的C语言编写而成,并且在设计的时候做了非常好的分层,核心软件部分与具体平台无关,这就意味着它非常容易移植到各种不同的嵌入式平台上。事实上,在很多资源非常有限的小型嵌入式平台上都可以运行fatfs文件系统作为海量存储的扩展组件,比如说经典的8051、PIC、AVR等,当红小生ARM单片机自然也广泛使用了fatfs文件系统。总之,我们知道fatfs能让吊丝单片机搞定高大上的文件系统,真是个好东西。


    但随着fatfs软件的不断发展,功能越来越完善,代码变得越来越复杂,对应用系统的资源占用也变大。当然,现在的单片机配置也在不断提高,完全能够满足应用程序日益增长的复杂度。但是,作为一个思想传统的电子工程师,我还是很怀念当初小巧精悍的单片机小程序。其实在单片机的应用中,对单个组件强大功能的需求并不是那么强烈,只要够用就好,更复杂的内容应该放在应用程序的设计上。我猜fatfs的作者ChaN也是这样的想法,因此在fatfs诞生之后,他还继续发挥余热,创作了pfatfs。突然想起来,uIP也是在LwIP之后由同一个作者搞出来的,大道至简才是硬道理。


    pfatfs是fatfs的一个子集,特别适用于资源更加受限的8位单片机,甚至RAM比一个扇区还小都能搞得定(~o^,SD卡的一个扇区的典型大小是512字节)。

    pfatfs在分层的架构设计上继承了fatfs结构清晰的优良作风,但是代码更简单,占用资源更少。其关键特性如下:

    · 超小的RAM内存消耗(44字节的静态内存占用+栈空间)。
    · 超小的ROM代码占用(2K - 4K字节)。
    · 支持FAT12, FAT16和FAT32文件系统。
    · 只支持单个卷和单文件操作。
    · 将文件作为数据流进行操作,在写入文件的时候有一些限制。


    总之,同fatfs相比,pfatfs的特点就是“小”,真的是太小了。


    从架构上看,pfatfs对硬件的需求比fatfs小很多,如图1所示。


    figure_1_a.png figure_1_b.png
    图1-a fatfs结构
    图1-b pfatfs结构
    图1 fatfs vs pfatfs结构


    本着够用就好的原则 ,pfatfs仅仅提供了常用的API,没有fatfs那么花哨:

    · pf_mount:挂在一个卷
    · pf_open:打开文件
    · pf_read:读文件
    · pf_write:写文件
    · pf_lseek:移动读写文件的指针
    · pf_opendir:打开目录
    · pf_readdir:读一个目录


    不过可惜的是,这里没有提供创建文件和删除文件的API,否则pfatfs就真的圆满了。


    pfatfs在移植上也比fatfs简单不少,只需要实现三个底层的函数:

    · disk_initialize:初始化存储介质
    · disk_readp:读一个扇区
    · disp_writep:写一个扇区


    而在移植fatfs的时候,要实现六个底层的函数,除了disk_initialize、disk_read和disk_write,还有disk_status、disk_ioctl和get_fattime,其中getfattime还需要硬件上提供一个定时器,而disk_ioctl更是隐含地包含了无数个需要实现的功能。这样看来pfatfs真是太有良心啦。


    fatfs的项目主页链接是:http://elm-chan.org/fsw/ff/00index_e.html
    pfatfs的项目主页链接是:http://elm-chan.org/fsw/ff/00index_p.html


    在项目主页上可以戳开各个函数的说明页面,了解它们的详细用法。


    SDSPI驱动】

    【sdcard_spi简介】

    在上一节提到,我们要移植pfatfs,需要实现与底层相关的三个函数disk_initialize,disk_readp,disk_writep,分别实现对存储介质的初始化,读扇区和写扇区。我们比较常用的大容量存储介质当然是SD卡啦,这个东东可以使用SPI总线驱动,当然用专用的SDIO总线驱动性能更好,但SDIO一般都是在高端单片机配置,屌丝单片机用SPI也是不错的。


    关于使用SPI驱动SD卡过程,ChaN的网站上也有说明,不得不感叹,这个日本兄弟真是活力无限啊。当然,网页是用英文写的(还好不是日文),如果觉得看得费劲,还在baidu.com中搜索“SD卡编程指南”可以找到这份文档的中文翻译版本,那是我早年翻译的作品,原稿已经在某次硬盘崩溃中遗失了,却不成想有人竟然把PDF版本的文档放到了网上,感慨。。。


    如果连中文也不愿意看,这里我还有一个大招,就是代码库。哈哈,这次连编译都不需要了。我照虎画猫,将对SD卡的SPI操作逻辑也做了一个封装,做了一个sdcard_spi的构件,只要在具体的平台上实现标准的SPI驱动并注册到sdcard_spi中,就可以方便地用sdcard_spi的API操作SD卡,“从此妈妈再也不用担心我在写SD卡驱动浪费时间啦。。。”


    sdcard_spi构件提供了一个sdcard_spi.lib的库文件,这是在KEIL中已经编译好的库,被封装起来了,不会被用户不小心改掉代码。对应地,还有描述用户接口的sdcard_spi.h文件,预览其内容如下:

    1. /* sdcard_spi.h */
    2. #ifndef __SDCARD_SPI_H__
    3. #define __SDCARD_SPI_H__
    4. #include <stdint.h>
    5. #include <stdbool.h>
    6. #define SDC_BLOCK_SIZE_BYTE     (512U)
    7. typedef struct
    8. {
    9.     void    (*SPI_InitFunc)(void);
    10.     uint8_t (*SPI_SwapByteFunc)(uint8_t txData);
    11.     void    (*SPI_SetBaudrateFunc)(uint32_t baudrate);
    12.     void    (*SPI_AssertCsFunc)(bool enable);
    13.     uint32_t Baudrate;
    14. } SDC_SPICallback_T;
    15. typedef enum
    16. {
    17.     eSDCCardUnknown    = 0U,
    18.     eSDCCardTypeOfSDv2 = 1U,
    19.     eSDCCardTypeOfSDHC = 2U
    20. } SDC_CardType_T;
    21. typedef struct
    22. {
    23.     SDC_CardType_T CardType;
    24.     uint32_t CardBlkCnt;
    25. } SDC_Info_T;
    26. bool SDC_Install(const SDC_SPICallback_T *ioPtr);
    27. bool SDC_InitCard(SDC_Info_T *infoPtr);
    28. bool SDC_WriteBlock(uint32_t blkIdx, uint8_t *txPtr);
    29. bool SDC_ReadBlock(uint32_t blkIdx, uint8_t *rxPtr);
    30. uint32_t SDC_WriteBlocks(uint32_t blkIdx, uint32_t blkCnt, uint8_t *txPtr);
    31. uint32_t SDC_ReadBlocks(uint32_t blkIdx, uint32_t blkCnt, uint8_t *rxPtr);
    32. #endif /* __SDCARD_SPI_H__ */
    复制代码


    另外,还提供了功能完备的测试应用代码demo_main.c和demo_inc.h,可以在移植成功后进行验证。


    【移植sdcard_spi】

    之前参加社区活动,收到了一块YL-KL26的板子,板子上有MicroSD卡的插座,并且就是用SPI接口进行连接的,刚好可以作为实验平台。我一时手痒,就在这块板子上移植了sdcard_spi组件。


    首先,当然是要准备KL26芯片的SPI驱动程序了,我使用的是自家维护的LiteFwLib固件库中的fsl_spi驱动程序,预览一下接口文件fsl_spi.h。

    1. /* fsl_spi.h */

    2. #ifndef __FSL_SPI_H__
    3. #define __FSL_SPI_H__

    4. #include <stdint.h>
    5. #include <stdbool.h>

    6. /*
    7. * Enumeration.
    8. */
    9. typedef enum
    10. {
    11. /* Clock line is low when idle. Tx data line is high when idle.
    12.      * Data valid when at rising edge.
    13.      * CPOL = 0, CPHA = 0 */
    14.     eSPI_PolPhaMode0 = 0U,
    15.     /* Clock line is low when idle. Tx data line is high when idle.
    16.      * Data valid when at falling edge.
    17.      * CPOL = 0, CPHA = 1 */
    18.     eSPI_PolPhaMode1 = 1U,
    19.     /* Clock line is high when idle. Tx data line is high when idle.
    20.      * Data valid when at falling edge.
    21.      * CPOL = 1, CPHA = 0 */
    22.     eSPI_PolPhaMode2 = 2U,
    23.     /* Clock line is high when idle. Tx data line is high when idle.
    24.      * Data valid when at rising edge.
    25.      * CPOL = 1, CPHA = 1 */
    26.     eSPI_PolPhaMode3 = 3U
    27. } SPI_PolPhaMode_T;

    28. /*
    29. * Structure.
    30. */
    31. /* Defaultly work as master. */
    32. typedef struct
    33. {
    34.     uint32_t BusClkHz;
    35.     uint32_t Baudrate;
    36.     SPI_PolPhaMode_T PolPhaMode;
    37.     bool enAutoCs; /* Default is controlled by GPIO. */
    38.     bool enLSB; /* Default is MSB. */
    39. } SPI_MasterConfig_T;

    40. typedef struct
    41. {
    42.     SPI_PolPhaMode_T PolPhaMode;
    43.     bool enLSB; /* Default is MSB. */
    44. } SPI_SlaveConfig_T;

    45. /*
    46. * API.
    47. */
    48. /* Config. */
    49. bool SPI_ConfigMaster(uint32_t idx, const SPI_MasterConfig_T *configPtr);
    50. bool SPI_ConfigSlave(uint32_t idx, const SPI_SlaveConfig_T *configPtr);
    51. uint32_t SPI_SetMasterBaudrate(uint32_t idx, uint32_t busClkHz, uint32_t baudrate);
    52. void SPI_SetTxEmptyIntEnable(uint32_t idx, bool enable);
    53. void SPI_SetRxFullIntEnable(uint32_t idx, bool enable);
    54. void SPI_SetTxEmptyDmaEnable(uint32_t idx, bool enable);
    55. void SPI_SetRxFullDmaEnable(uint32_t idx, bool enable);

    56. /* Tx. */
    57. void SPI_PutTxData(uint32_t idx, uint8_t txData);
    58. bool SPI_IsTxBufferEmpty(uint32_t idx);
    59. void SPI_PutTxDataBlocking(uint32_t idx, uint8_t txData);
    60. void SPI_WaitTxDataDoneBlocking(uint32_t idx);

    61. /* Rx. */
    62. uint8_t SPI_GetRxData(uint32_t idx);
    63. bool SPI_IsRxBufferFull(uint32_t idx);
    64. uint8_t SPI_GetRxDataBlocking(uint32_t idx);

    65. #endif /* __FSL_SPI_H__ */
    复制代码


    然后在sdcard_spi_adapter.c文件中实现了KL26的SPI向sdcard_spi的注册,让sdcard_spi在YL-KL26Z板上“接地气”。

    1. /* sdcard_spi_sdapter.c */
    2. #include "app_inc.h"
    3. #define mSDCARD_SPI_BAUDRATE  (1000000U)
    4. static void mSPI_Init(void);
    5. static uint8_t mSPI_SwapByte(uint8_t txData);
    6. static void mSPI_SetBaudrate(uint32_t baudrate);
    7. static void mSPI_AssertCs(bool enable);
    8. const SDC_SPICallback_T gSdcSpiCallbackStruct =
    9. {
    10.     mSPI_Init,              /* SPI_InitFunc */
    11.     mSPI_SwapByte,          /* SPI_SwapByteFunc */
    12.     mSPI_SetBaudrate,       /* SPI_SetBaudrateFunc */
    13.     mSPI_AssertCs,          /* SPI_AssertCsFunc */
    14.     mSDCARD_SPI_BAUDRATE    /* Baudrate */
    15. };
    16. const SPI_MasterConfig_T mSpiMasterConfigStruct =
    17. {
    18.     BSP_CLK_BUSCLK_HZ, /* BusClkHz */
    19.     100000U, /* Baudrate */
    20.     eSPI_PolPhaMode0, /* PolPhaMode */
    21.     false, /* enAuotCs */
    22.     false /* enLSB */
    23. };
    24. static void mSPI_Init(void)
    25. {
    26.     GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,
    27.                 BSP_GPIO_SDCARD_SPI_CS_PIN, true);
    28.     GPIO_SetPinDir(BSP_GPIO_SDCARD_SPI_CS_PORT,
    29.                 BSP_GPIO_SDCARD_SPI_CS_PIN, true);
    30.     SPI_ConfigMaster(BSP_SPI_SDCARD_IDX, &mSpiMasterConfigStruct);
    31. }
    32. static uint8_t mSPI_SwapByte(uint8_t txData)
    33. {
    34.     //return SPI_MasterSwapDataBlocking(BSP_SPI_SDCARD_INSTANCE, txData);
    35.     SPI_PutTxDataBlocking(BSP_SPI_SDCARD_IDX, txData);
    36.     return SPI_GetRxDataBlocking(BSP_SPI_SDCARD_IDX);
    37. }
    38. static void mSPI_SetBaudrate(uint32_t baudrate)
    39. {
    40.     SPI_SetMasterBaudrate(BSP_SPI_SDCARD_IDX, BSP_CLK_BUSCLK_HZ, baudrate);
    41. }
    42. static void mSPI_AssertCs(bool enable)
    43. {
    44.     if (enable)
    45.     {
    46.         GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,
    47.             BSP_GPIO_SDCARD_SPI_CS_PIN, false);
    48.     }
    49.     else
    50.     {
    51.         GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,
    52.             BSP_GPIO_SDCARD_SPI_CS_PIN, true);
    53.     }
    54. }
    55. /* EOF. */
    复制代码

    而应用程序的main函数的逻辑也是在sdcard_spi构件中写好的,直接拿来用就可以编译运行。


    最终样例工程在KEIL中的工程组织如图2所示。

    figure_2.png
    图2 sdcard_spi样例工程文件组织结构


    在附件中提供了完整的程序及工程,大家可以下载代码包,编译工程直接在YL-KL26Z板子上运行。


    打开之中的“05_spi_sdcard”工程,编译下载,然后打开串口终端软件,启动程序可以看到输出log,如图3所示:

    figure_3.png
    图3


    从输出中可以看到卡的类型和大小。实际上我用的是一个2G的卡,一般这个大小的卡都是SDv2的,如果大家用8G的卡,基本上识别出来的都是SDHC卡。
    然后提示说正在进行单个扇区读写的实验,我根据提示信息向第7个块中写“c”这个字符,输出log说已经写进去了,“c”的ASCII码是0x63。如图4所示。

    figure_4.png
    图4


    但是,是真的写进去了么?别急,下面就可以读出来看看了。根据log的提示,设定即将读取块的编号仍为7,这个时候就读出SD卡中存储在第7块中的内容了。如图5所示。

    figure_5.png
    图5


    哈哈,没错,就是0x63!

    figure_6.png
    图6


    如图6所示,这时,log提示要不要继续玩单块读写的实验,如果想再玩几次,输入“Y”即可,读写可以是不同的扇区,大家可以多试试。这里我输入“N”进入下一个实验,多块读写。如图7所示。

    figure_7.png
    图7


    在多块读写实验中,我实际设计的是连续操作两个块,但只要输入较小的块号就可以了。这次要写入的是8-9块,写入内容是“u”,对应的ASCII码是0x75。如图8所示。

    figure_8.png
    图8


    然后再从第7块开始读。等等,为什么不是第8块呢?之前我们在第7块里写了0x63,这次在第8块和第9块中写了0x75,读出来的时候就能看到差别了。好吧,试试看。如图9所示。

    figure_9.png
    图9


    Bingo,又对啦!

    这个实验仍能连续玩多次,输入“Y”继续,输入“N”退出。


    这个应用工程的main函数使用的就是sdcard_spi组件提供的标准验证流程。


    好了,带着大家嗨皮这么久,就是要验证sdcard_spi能够正常工作,现在我们已经可以在板子上玩转SD卡啦。至此,保存代码,关闭工程,向代码仓库提交一次代码。歇一下,喝口水,然后创建下一个工程,向着最终的目标,pfatfs,进发!


    pfatfs的移植】

    有了sdcard_spi的基础,这个阶段已经可以很轻松地读写SD卡了,下面我们就要实现对pfatfs的移植。


    PS:已经移植好到样例工程也在附件的代码包中,为“05_spi_sdcard_pfatfs”工程。如果没空听我在这里鬼扯,可以略过这段,直接看代码。


    从项目主页上下载的pfatfs代码我基本没动,就是在pff.h中把对几个API的支持全部打开了。
    1. #define _USE_READ 1 /* 1:Enable pf_read() */
    2. #define _USE_DIR 1 /* 1:Enable pf_opendir() and pf_readdir() */
    3. #define _USE_LSEEK 1 /* 1:Enable pf_lseek() */
    4. #define _USE_WRITE 1 /* 1:Enable pf_write() */
    5. #define _FS_FAT12 0 /* 1:Enable FAT12 support */
    6. #define _FS_FAT32 1 /* 1:Enable FAT32 support */
    复制代码


    对不需要的API还可以进行裁剪已进行进一步的瘦身,pfatfs真是工程师的贴心小棉袄,考虑得真周到!


    我在pfatfs_diskio.c中仿照原装diskio.c的模板实现了pfatfs向sdcard_spi的对接。

    1. /*-----------------------------------------------------------------------*/
    2. /* Low level disk I/O module skeleton for Petit FatFs (C)ChaN, 2009      */
    3. /*-----------------------------------------------------------------------*/
    4. #include "diskio.h"
    5. #include "app_inc.h"
    6. /*-----------------------------------------------------------------------*/
    7. /* Initialize Disk Drive                                                 */
    8. /*-----------------------------------------------------------------------*/
    9. static uint32_t SDCardRxBufArea[128U];
    10. static uint32_t SDCardTxBufArea[128U];
    11. static uint8_t *SDCardRxBufPtr = (uint8_t *)SDCardRxBufArea;
    12. static uint8_t *SDCardTxBufPtr = (uint8_t *)SDCardTxBufArea;
    13. static DWORD lastWriteSectorIndex = (uint32_t)-1;
    14. static DWORD lastWriteSectorOffset = 0U;
    15. SDC_Info_T gSdcInfoStruct;
    16. DSTATUS disk_initialize (void)
    17. {
    18. DSTATUS stat;
    19.     SDC_Install(&gSdcSpiCallbackStruct);
    20.    
    21. // Put your code here
    22.     /* Enable the Card power. */
    23.     if (SDC_InitCard(&gSdcInfoStruct))
    24.     {
    25.         stat = RES_OK;
    26.     }
    27.     else
    28.     {
    29.         stat = RES_ERROR;
    30.     }
    31. return stat;
    32. }
    33. /*-----------------------------------------------------------------------*/
    34. /* Read Partial Sector                                    */
    35. /*-----------------------------------------------------------------------*/
    36. DRESULT disk_readp (
    37. BYTE* dest, /* Pointer to the destination object */
    38. DWORD sector, /* Sector number (LBA) */
    39. WORD sofs, /* Offset in the sector */
    40. WORD count /* Byte count (bit15:destination) */
    41. )
    42. {
    43. DRESULT res;
    44.     bool bRet;
    45.     uint32_t i;
    46.     // Put your code here
    47.     bRet = SDC_ReadBlock(sector, SDCardRxBufPtr);
    48.     //printf("SDCard_ReadBlocks Sector %d.\r\n", sector);
    49.     if (bRet)
    50.     {
    51.         //lastReadSectorIndex = sector;
    52.         res = RES_OK;
    53.         //dest = SDCardRxBufPtr+sofs;
    54.         for (i = 0U; i < count; i++)
    55.         {
    56.             dest = SDCardRxBufPtr[sofs+i];
    57.         }
    58.     }
    59.     else
    60.     {
    61.         res = RES_ERROR;
    62.     }
    63. return res;
    64. }
    65. /*-----------------------------------------------------------------------*/
    66. /* Write Partial Sector                                    */
    67. /*-----------------------------------------------------------------------*/
    68. DRESULT disk_writep (
    69. const BYTE* buff, /* Pointer to the data to be written,
    70.                    NULL:Initiate/Finalize write operation */
    71. DWORD sc /* Sector number (LBA) or Number of bytes to send */
    72. )
    73. {
    74.     DRESULT res = RES_OK;
    75.     bool bRet;
    76. if (!buff)
    77.     {
    78.         if (sc)
    79.         {
    80.             /* Initiate write process */
    81.             lastWriteSectorIndex = sc;
    82.             bRet = SDC_ReadBlock(sc, SDCardTxBufPtr);
    83.             //printf("SDCard_ReadBlocks Sector %d.\r\n", lastWriteSectorIndex);
    84.             if (bRet)
    85.             {
    86.                 res = RES_OK;
    87.             }
    88.             else
    89.             {
    90.                 res = RES_ERROR;
    91.             }
    92.   } else
    93.         {
    94.         /* Finalize write process */
    95.             bRet = SDC_WriteBlock(lastWriteSectorIndex, SDCardTxBufPtr);
    96.             //printf("SDCard_WriteBlocks Sector %d.\r\n", lastWriteSectorIndex);
    97.             if (bRet)
    98.             {
    99.                 res = RES_OK;
    100.             }
    101.             else
    102.             {
    103.                 res = RES_ERROR;
    104.             }
    105.             lastWriteSectorOffset = 0U;
    106.   }
    107. } else
    108.     {
    109.         /* Send data to the disk */
    110.         while (sc != 0U)
    111.         {
    112.             SDCardTxBufPtr[lastWriteSectorOffset++] = *(uint8_t *)buff++;
    113.             sc--;
    114.         }
    115. }
    116. return res;
    117. }
    复制代码


    关于这三个函数的实现内容,在项目主页中说得很明白了,我就不再这里重复了,但是在具体实现的时候有几个点要特别注意:


    1. disk_writep函数的不同参数组合对应不同的行为,并不是说这个函数只是单纯地向SD写数,在准备写数的过程中还会先从SD卡上把整个块读出来,改掉要写的部分,然后再把整块的数据整个写回去。
    2. 我在移植的时候对读写内容进行了优化,如果连续写一个块,只要读一次就可以了,这样可以减少对SD卡的读写次数,提高整个程序的执行效率,同时延长SD卡的使用寿命。


    样例程序中执行的内容是读出SD卡中的所有文件路径。样例工程的组织结构如图10所示。

    figure_10.png
    图10 sdcard_spi_pfatfs样例工程文件组织结构图


    根据惯例,这里也贴出来样例工程在串口终端输出的log。编译下载工程之后,开始运行,串口终端输出如图11所示。

    figure_11.png
    图11



    至此,大功告成,搞定收工!


    【总结】

    这次在YL-KL26Z板子上折腾了一下SD卡,有了两个阶段性成果:

    1. 移植了sdcard_spi实现对SD卡的读写操作。
    2. 移植了pfatfs在SD上建立起来的文件系统。


    具体地,在LiteFwLib完成了两个样例工程,“05_spi_sdcard”和“05_spi_sdcard_pfatfs”,图12展示了sdcard_spi和pfatfs应用程序的层次结构。

    figure_12_a.jpg
    figure_12_b.jpg
    图12-a sdcard_spi应用结构
    图12-b sdcard_spi_pfatfs应用结构
    图12 sdcard_spi vs sdcard_spi_pfatfs 应用结构


    有了这个知识积累,就可以玩转SD卡了,为后面在YL-KL26上写一个音频播放器的程序奠定了基础。


    - End


    附件:
    文档: AN_SY20150520.pdf (1.12 MB, 下载次数: 60)
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-21 01:31:32 | 显示全部楼层
    不得不吐槽一下,在提交帖子的时候排版好辛苦,大半夜的,真不容易啊。。。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2016-11-30 08:51
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    4

    主题

    138

    帖子

    0

    中级会员

    Rank: 3Rank: 3

    积分
    202
    最后登录
    2022-7-7
    发表于 2015-5-21 08:18:05 | 显示全部楼层
    前来学习,楼主辛苦
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2018-10-30 22:37
  • 签到天数: 28 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    9

    主题

    435

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1107
    最后登录
    2020-8-28
    发表于 2015-5-21 08:54:20 | 显示全部楼层
    传文库那个不厚道
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-21 10:24:19 | 显示全部楼层

    是这样的。后来我想用自己的账户上传,都被baidu给拒了,说是内容重复。不过话说回来,没有别人的备份,这份文档还不知道被我藏在哪个文件夹下呢,本来都快忘掉它了。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    31

    主题

    253

    帖子

    20

    金牌会员

    Rank: 6Rank: 6

    积分
    1532
    最后登录
    2021-7-20
    发表于 2015-5-21 11:05:45 | 显示全部楼层
    好文章,lib文件。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2018-7-23 21:04
  • 签到天数: 103 天

    连续签到: 1 天

    [LV.6]常住居民II

    228

    主题

    5379

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    16710
    最后登录
    1970-1-1
    发表于 2015-5-21 15:19:40 | 显示全部楼层
    多东西,多谢分享
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2018-10-30 22:37
  • 签到天数: 28 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    9

    主题

    435

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1107
    最后登录
    2020-8-28
    发表于 2015-5-22 17:54:37 | 显示全部楼层
    suyong_yq 发表于 2015-5-21 10:24
    是这样的。后来我想用自己的账户上传,都被baidu给拒了,说是内容重复。不过话说回来,没有别人的备份, ...

    拿版权投诉
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-1-17 10:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    38

    主题

    395

    帖子

    3

    高级会员

    Rank: 4

    积分
    780
    最后登录
    2023-11-17
     楼主| 发表于 2015-5-22 20:06:40 | 显示全部楼层

    算了,本来也只是做了一下翻译,而且也没申请版权保护。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    17

    帖子

    0

    注册会员

    Rank: 2

    积分
    66
    最后登录
    1970-1-1
    发表于 2015-5-24 20:34:34 | 显示全部楼层
    不错啊  支持一下啊
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-25 21:07 , Processed in 0.106563 second(s), 29 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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