上传初始版本
This commit is contained in:
330
gd32v_lcd/src/fatfs/00history.txt
Normal file
330
gd32v_lcd/src/fatfs/00history.txt
Normal file
@ -0,0 +1,330 @@
|
||||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
|
||||
Prototype.
|
||||
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
The first release.
|
||||
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.11a (September 05, 2015)
|
||||
|
||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12 (April 12, 2016)
|
||||
|
||||
Added support for exFAT file system. (_FS_EXFAT)
|
||||
Added f_expand(). (_USE_EXPAND)
|
||||
Changed some members in FINFO structure and behavior of f_readdir().
|
||||
Added an option _USE_CHMOD.
|
||||
Removed an option _WORD_ACCESS.
|
||||
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12a (July 10, 2016)
|
||||
|
||||
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||
f_forward() is available regardless of _FS_TINY.
|
||||
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||
|
||||
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.13 (May 21, 2017)
|
||||
|
||||
Changed heading character of configuration keywords "_" to "FF_".
|
||||
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||
|
||||
|
||||
|
||||
R0.13a (October 14, 2017)
|
||||
|
||||
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
|
||||
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
|
||||
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
|
||||
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
|
||||
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
|
||||
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.13b (April 07, 2018)
|
||||
|
||||
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
|
||||
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
|
||||
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
|
||||
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
|
||||
|
||||
|
||||
|
||||
R0.13c (October 14, 2018)
|
||||
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
|
||||
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
|
||||
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
|
||||
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
|
||||
|
21
gd32v_lcd/src/fatfs/00readme.txt
Normal file
21
gd32v_lcd/src/fatfs/00readme.txt
Normal file
@ -0,0 +1,21 @@
|
||||
FatFs Module Source Files R0.13c
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
ffunicode.c Optional Unicode utility functions.
|
||||
ffsystem.c An example of optional O/S related functions.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You need to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
6554
gd32v_lcd/src/fatfs/ff.c
Normal file
6554
gd32v_lcd/src/fatfs/ff.c
Normal file
File diff suppressed because it is too large
Load Diff
170
gd32v_lcd/src/fatfs/ffsystem.c
Normal file
170
gd32v_lcd/src/fatfs/ffsystem.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample Code of OS Dependent Functions for FatFs */
|
||||
/* (C)ChaN, 2018 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "./fatfs/ff.h"
|
||||
|
||||
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Free the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if FF_FS_REENTRANT /* Mutal exclusion */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object for the volume, such as semaphore and mutex.
|
||||
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
|
||||
|
||||
|
||||
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
|
||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||
FF_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
*sobj = CreateMutex(NULL, FALSE, NULL);
|
||||
return (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
/* uITRON */
|
||||
// T_CSEM csem = {TA_TPRI,1,1};
|
||||
// *sobj = acre_sem(&csem);
|
||||
// return (int)(*sobj > 0);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// *sobj = OSMutexCreate(0, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// *sobj = xSemaphoreCreateMutex();
|
||||
// return (int)(*sobj != NULL);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// *sobj = osMutexCreate(&Mutex[vol]);
|
||||
// return (int)(*sobj != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
|
||||
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)CloseHandle(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(del_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// vSemaphoreDelete(sobj);
|
||||
// return 1;
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexDelete(sobj) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
FF_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
||||
|
||||
/* uITRON */
|
||||
// return (int)(wai_sem(sobj) == E_OK);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OS_ERR err;
|
||||
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
|
||||
// return (int)(err == OS_NO_ERR);
|
||||
|
||||
/* FreeRTOS */
|
||||
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
FF_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
/* Win32 */
|
||||
ReleaseMutex(sobj);
|
||||
|
||||
/* uITRON */
|
||||
// sig_sem(sobj);
|
||||
|
||||
/* uC/OS-II */
|
||||
// OSMutexPost(sobj);
|
||||
|
||||
/* FreeRTOS */
|
||||
// xSemaphoreGive(sobj);
|
||||
|
||||
/* CMSIS-RTOS */
|
||||
// osMutexRelease(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
15597
gd32v_lcd/src/fatfs/ffunicode.c
Normal file
15597
gd32v_lcd/src/fatfs/ffunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
568
gd32v_lcd/src/fatfs/tf_card.c
Normal file
568
gd32v_lcd/src/fatfs/tf_card.c
Normal file
@ -0,0 +1,568 @@
|
||||
#include "fatfs/tf_card.h"
|
||||
|
||||
#define FCLK_SLOW() { SPI_CTL0(SPI1) = (SPI_CTL0(SPI1) & ~0x38) | 0x28; } /* Set SCLK = PCLK2 / 64 */
|
||||
#define FCLK_FAST() { SPI_CTL0(SPI1) = (SPI_CTL0(SPI1) & ~0x38) | 0x00; } /* Set SCLK = PCLK2 / 2 */
|
||||
|
||||
// #define FCLK_SLOW()
|
||||
// #define FCLK_FAST()
|
||||
|
||||
#define CS_HIGH() PB_OUT(12,1)
|
||||
#define CS_LOW() PB_OUT(12,0)
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Module Private Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* MMC/SD command */
|
||||
#define CMD0 (0) /* GO_IDLE_STATE */
|
||||
#define CMD1 (1) /* SEND_OP_COND (MMC) */
|
||||
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
||||
#define CMD8 (8) /* SEND_IF_COND */
|
||||
#define CMD9 (9) /* SEND_CSD */
|
||||
#define CMD10 (10) /* SEND_CID */
|
||||
#define CMD12 (12) /* STOP_TRANSMISSION */
|
||||
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
||||
#define CMD16 (16) /* SET_BLOCKLEN */
|
||||
#define CMD17 (17) /* READ_SINGLE_BLOCK */
|
||||
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
||||
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
|
||||
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
||||
#define CMD24 (24) /* WRITE_BLOCK */
|
||||
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
||||
#define CMD32 (32) /* ERASE_ER_BLK_START */
|
||||
#define CMD33 (33) /* ERASE_ER_BLK_END */
|
||||
#define CMD38 (38) /* ERASE */
|
||||
#define CMD55 (55) /* APP_CMD */
|
||||
#define CMD58 (58) /* READ_OCR */
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Physical drive status */
|
||||
|
||||
// static volatile
|
||||
// UINT Timer1, Timer2; /* 1kHz decrement timer stopped at zero (disk_timerproc()) */
|
||||
static volatile
|
||||
UINT delay_timer1, delay_timer2; /* 1kHz decrement timer stopped at zero (disk_timerproc()) */
|
||||
|
||||
static
|
||||
BYTE CardType; /* Card type flags */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* SPI controls (Platform dependent) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* Initialize MMC interface */
|
||||
static
|
||||
void init_spi(void)
|
||||
{
|
||||
spi_parameter_struct spi_init_struct;
|
||||
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
rcu_periph_clock_enable(RCU_SPI1);
|
||||
|
||||
/* SPI1_SCK(PB13), SPI1_MISO(PB14) and SPI1_MOSI(PB15) GPIO pin configuration */
|
||||
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
|
||||
/* SPI1_CS(PB12) GPIO pin configuration */
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
|
||||
|
||||
/* chip _select invalid*/
|
||||
CS_HIGH();
|
||||
|
||||
/* SPI1 parameter config */
|
||||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||||
spi_init_struct.device_mode = SPI_MASTER;
|
||||
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
|
||||
spi_init_struct.nss = SPI_NSS_SOFT;
|
||||
spi_init_struct.prescale = SPI_PSC_32;
|
||||
spi_init_struct.endian = SPI_ENDIAN_MSB;
|
||||
spi_init(SPI1, &spi_init_struct);
|
||||
|
||||
/* set crc polynomial */
|
||||
spi_crc_polynomial_set(SPI1,7);
|
||||
/* enable SPI1 */
|
||||
spi_enable(SPI1);
|
||||
}
|
||||
|
||||
/* Exchange a byte */
|
||||
static
|
||||
BYTE xchg_spi (
|
||||
BYTE dat /* Data to send */
|
||||
)
|
||||
{
|
||||
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
|
||||
spi_i2s_data_transmit(SPI1, dat);
|
||||
while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
|
||||
return(spi_i2s_data_receive(SPI1)); /* Return received byte */
|
||||
}
|
||||
|
||||
|
||||
/* Receive multiple byte */
|
||||
static
|
||||
void rcvr_spi_multi (
|
||||
BYTE *buff, /* Pointer to data buffer */
|
||||
UINT btr /* Number of bytes to receive (even number) */
|
||||
)
|
||||
{
|
||||
// WORD d;
|
||||
|
||||
// SPI_CTL0(SPI1) = (SPI_CTL0(SPI1) & ~0x800) | 0x800; /* Put SPI into 16-bit mode */
|
||||
|
||||
// spi_i2s_data_transmit(SPI1, 0xFFFF); /* Start the first SPI transaction */
|
||||
// btr -= 2;
|
||||
// do { /* Receive the data block into buffer */
|
||||
// while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE)); /* Wait for end of the SPI transaction */
|
||||
// d = spi_i2s_data_receive(SPI1); /* Get received word */
|
||||
// spi_i2s_data_transmit(SPI1, 0xFFFF); /* Start next transaction */
|
||||
// buff[1] = d; buff[0] = d >> 8; /* Store received data */
|
||||
// buff += 2;
|
||||
// } while (btr -= 2);
|
||||
// while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE)); /* Wait for end of the SPI transaction */
|
||||
// d = spi_i2s_data_receive(SPI1); /* Get last word received */
|
||||
// buff[1] = d; buff[0] = d >> 8; /* Store it */
|
||||
|
||||
// SPI_CTL0(SPI1) = (SPI_CTL0(SPI1) & ~0x800) | 0x00; /* Put SPI into 8-bit mode */
|
||||
do
|
||||
{
|
||||
*buff = xchg_spi(0xff);
|
||||
buff++;
|
||||
} while (btr--);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Wait for card ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int wait_ready ( /* 1:Ready, 0:Timeout */
|
||||
UINT wt /* Timeout [ms] */
|
||||
)
|
||||
{
|
||||
BYTE d;
|
||||
|
||||
// Timer2 = wt;
|
||||
delay_timer2 = wt;
|
||||
do {
|
||||
d = xchg_spi(0xFF);
|
||||
/* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */
|
||||
} while (d != 0xFF && delay_timer2); /* Wait for card goes ready or timeout */
|
||||
|
||||
return (d == 0xFF) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Deselect card and release SPI */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
void deselect (void)
|
||||
{
|
||||
CS_HIGH(); /* Set CS# high */
|
||||
xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Select card and wait for ready */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int _select (void) /* 1:OK, 0:Timeout */
|
||||
{
|
||||
CS_LOW(); /* Set CS# low */
|
||||
xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
|
||||
if (wait_ready(500)) return 1; /* Wait for card ready */
|
||||
|
||||
deselect();
|
||||
return 0; /* Timeout */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a data packet from the MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
int rcvr_datablock ( /* 1:OK, 0:Error */
|
||||
BYTE *buff, /* Data buffer */
|
||||
UINT btr /* Data block length (byte) */
|
||||
)
|
||||
{
|
||||
BYTE token;
|
||||
|
||||
delay_timer1 = 200;
|
||||
do { /* Wait for DataStart token in timeout of 200ms */
|
||||
token = xchg_spi(0xFF);
|
||||
/* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */
|
||||
} while ((token == 0xFF) && delay_timer1);
|
||||
if(token != 0xFE) return 0; /* Function fails if invalid DataStart token or timeout */
|
||||
|
||||
rcvr_spi_multi(buff, btr); /* Store trailing data to the buffer */
|
||||
xchg_spi(0xFF); xchg_spi(0xFF); /* Discard CRC */
|
||||
|
||||
return 1; /* Function succeeded */
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Send a command packet to the MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE send_cmd ( /* Return value: R1 resp (bit7==1:Failed to send) */
|
||||
BYTE cmd, /* Command index */
|
||||
DWORD arg /* Argument */
|
||||
)
|
||||
{
|
||||
BYTE n, res;
|
||||
|
||||
|
||||
if (cmd & 0x80) { /* Send a CMD55 prior to ACMD<n> */
|
||||
cmd &= 0x7F;
|
||||
res = send_cmd(CMD55, 0);
|
||||
if (res > 1) return res;
|
||||
}
|
||||
|
||||
/* Select the card and wait for ready except to stop multiple block read */
|
||||
if (cmd != CMD12) {
|
||||
deselect();
|
||||
if (!_select()) return 0xFF;
|
||||
}
|
||||
|
||||
/* Send command packet */
|
||||
xchg_spi(0x40 | cmd); /* Start + command index */
|
||||
xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xchg_spi((BYTE)arg); /* Argument[7..0] */
|
||||
n = 0x01; /* Dummy CRC + Stop */
|
||||
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
||||
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
||||
xchg_spi(n);
|
||||
|
||||
/* Receive command resp */
|
||||
if (cmd == CMD12) xchg_spi(0xFF); /* Diacard following one byte when CMD12 */
|
||||
n = 10; /* Wait for response (10 bytes max) */
|
||||
do {
|
||||
res = xchg_spi(0xFF);
|
||||
} while ((res & 0x80) && --n);
|
||||
|
||||
return res; /* Return received response */
|
||||
}
|
||||
|
||||
static
|
||||
void init_timer2(void)
|
||||
{
|
||||
timer_parameter_struct timer_initpara;
|
||||
|
||||
rcu_periph_clock_enable(RCU_TIMER2);
|
||||
timer_deinit(TIMER2);
|
||||
/* ((1+TIM_Prescaler )/时钟)*(1+TIM_Period )
|
||||
(108000/108000000)*(1000)=1ms
|
||||
*/
|
||||
timer_initpara.period = (1000 - 1);
|
||||
timer_initpara.prescaler = (108 - 1);
|
||||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
||||
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
||||
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
|
||||
timer_initpara.repetitioncounter = 0;
|
||||
timer_init(TIMER2, &timer_initpara);
|
||||
|
||||
timer_update_event_enable(TIMER2);
|
||||
timer_interrupt_enable(TIMER2,TIMER_INT_UP);
|
||||
timer_flag_clear(TIMER2, TIMER_FLAG_UP);
|
||||
timer_update_source_config(TIMER2, TIMER_UPDATE_SRC_GLOBAL);
|
||||
|
||||
/* TIMER2 counter enable */
|
||||
timer_enable(TIMER2);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief time base IRQ
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static
|
||||
void tfcard_timer_irq (void)
|
||||
{
|
||||
if (RESET != timer_flag_get(TIMER2, TIMER_FLAG_UP)){
|
||||
timer_flag_clear(TIMER2, TIMER_FLAG_UP);
|
||||
|
||||
if (delay_timer1 > 0x00U){
|
||||
delay_timer1--;
|
||||
}
|
||||
if (delay_timer2 > 0x00U){
|
||||
delay_timer2--;
|
||||
}
|
||||
// else {
|
||||
// timer_disable(TIMER2);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief this function handles Timer0 updata interrupt request.
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void TIMER2_IRQHandler(void)
|
||||
{
|
||||
// tfcard_timer_irq();
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Public Functions
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize disk drive */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE drv /* Physical drive number (0) */
|
||||
)
|
||||
{
|
||||
BYTE n, cmd, ty, ocr[4];
|
||||
|
||||
|
||||
if (drv) return STA_NOINIT; /* Supports only drive 0 */
|
||||
init_spi(); /* Initialize SPI */
|
||||
delay_1ms(10);
|
||||
init_timer2();
|
||||
|
||||
if (Stat & STA_NODISK) return Stat; /* Is card existing in the soket? */
|
||||
|
||||
FCLK_SLOW();
|
||||
CS_LOW();
|
||||
for (n = 10; n; n--) xchg_spi(0xFF); /* Send 80 dummy clocks */
|
||||
|
||||
ty = 0;
|
||||
if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */
|
||||
delay_timer1 = 1000; /* Initialization timeout = 1 sec */
|
||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
||||
for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */
|
||||
while (delay_timer1 && send_cmd(ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */
|
||||
if (delay_timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
||||
for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
|
||||
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */
|
||||
}
|
||||
}
|
||||
} else { /* Not SDv2 card */
|
||||
if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */
|
||||
ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */
|
||||
} else {
|
||||
ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
|
||||
}
|
||||
while (delay_timer1 && send_cmd(cmd, 0)) ; /* Wait for end of initialization */
|
||||
if (!delay_timer1 || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */
|
||||
ty = 0;
|
||||
}
|
||||
}
|
||||
CardType = ty; /* Card type */
|
||||
deselect();
|
||||
|
||||
if (ty) { /* OK */
|
||||
FCLK_FAST(); /* Set fast clock */
|
||||
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
|
||||
} else { /* Failed */
|
||||
Stat = STA_NOINIT;
|
||||
}
|
||||
|
||||
return Stat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get disk status */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive number (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only drive 0 */
|
||||
|
||||
return Stat; /* Return disk status */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Read sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE drv, /* Physical drive number (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Number of sectors to read (1..128) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR; /* Check parameter */
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */
|
||||
|
||||
if (count == 1) { /* Single sector read */
|
||||
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(buff, 512)) {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
else { /* Multiple sector read */
|
||||
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!rcvr_datablock(buff, 512)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK; /* Return result */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Write sector(s) */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
DRESULT disk_write (
|
||||
BYTE drv, /* Physical drive number (0) */
|
||||
const BYTE *buff, /* Ponter to the data to write */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Number of sectors to write (1..128) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR; /* Check parameter */
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */
|
||||
if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */
|
||||
|
||||
if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */
|
||||
|
||||
if (count == 1) { /* Single sector write */
|
||||
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(buff, 0xFE)) {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
else { /* Multiple sector write */
|
||||
if (CardType & CT_SDC) send_cmd(ACMD23, count); /* Predefine number of sectors */
|
||||
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!xmit_datablock(buff, 0xFC)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
if (!xmit_datablock(0, 0xFD)) count = 1; /* STOP_TRAN token */
|
||||
}
|
||||
}
|
||||
deselect();
|
||||
|
||||
return count ? RES_ERROR : RES_OK; /* Return result */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Miscellaneous drive controls other than data read/write */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE drv, /* Physical drive number (0) */
|
||||
BYTE cmd, /* Control command code */
|
||||
void *buff /* Pointer to the conrtol data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
BYTE n, csd[16];
|
||||
DWORD *dp, st, ed, csize;
|
||||
|
||||
|
||||
if (drv) return RES_PARERR; /* Check parameter */
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
|
||||
|
||||
res = RES_ERROR;
|
||||
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC : /* Wait for end of internal write process of the drive */
|
||||
if (_select()) res = RES_OK;
|
||||
break;
|
||||
|
||||
case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||
csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
|
||||
*(DWORD*)buff = csize << 10;
|
||||
} else { /* SDC ver 1.XX or MMC ver 3 */
|
||||
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||||
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
||||
*(DWORD*)buff = csize << (n - 9);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
||||
if (CardType & CT_SD2) { /* SDC ver 2.00 */
|
||||
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
|
||||
xchg_spi(0xFF);
|
||||
if (rcvr_datablock(csd, 16)) { /* Read partial block */
|
||||
for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */
|
||||
*(DWORD*)buff = 16UL << (csd[10] >> 4);
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
} else { /* SDC ver 1.XX or MMC */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
|
||||
if (CardType & CT_SD1) { /* SDC ver 1.XX */
|
||||
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
||||
} else { /* MMC */
|
||||
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
||||
}
|
||||
res = RES_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CTRL_TRIM : /* Erase a block of sectors (used when _USE_ERASE == 1) */
|
||||
if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */
|
||||
if (disk_ioctl(drv, MMC_GET_CSD, csd)) break; /* Get CSD */
|
||||
if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */
|
||||
dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */
|
||||
if (!(CardType & CT_BLOCK)) {
|
||||
st *= 512; ed *= 512;
|
||||
}
|
||||
if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) { /* Erase sector block */
|
||||
res = RES_OK; /* FatFs does not check result of this command */
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
deselect();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
673
gd32v_lcd/src/lcd/lcd.c
Normal file
673
gd32v_lcd/src/lcd/lcd.c
Normal file
@ -0,0 +1,673 @@
|
||||
#include "lcd/lcd.h"
|
||||
#include "lcd/oledfont.h"
|
||||
#include "lcd/bmp.h"
|
||||
u16 BACK_COLOR; //背景色
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD串行数据写入函数
|
||||
入口数据:dat 要写入的串行数据
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_Writ_Bus(u8 dat)
|
||||
{
|
||||
#if SPI0_CFG == 1
|
||||
OLED_CS_Clr();
|
||||
|
||||
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
|
||||
spi_i2s_data_transmit(SPI0, dat);
|
||||
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
|
||||
spi_i2s_data_receive(SPI0);
|
||||
|
||||
OLED_CS_Set();
|
||||
#elif SPI0_CFG == 2
|
||||
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
|
||||
#else
|
||||
u8 i;
|
||||
OLED_CS_Clr();
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
OLED_SCLK_Clr();
|
||||
if(dat&0x80)
|
||||
OLED_SDIN_Set();
|
||||
else
|
||||
OLED_SDIN_Clr();
|
||||
OLED_SCLK_Set();
|
||||
dat<<=1;
|
||||
}
|
||||
OLED_CS_Set();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD写入数据
|
||||
入口数据:dat 写入的数据
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_WR_DATA8(u8 dat)
|
||||
{
|
||||
OLED_DC_Set();//写数据
|
||||
LCD_Writ_Bus(dat);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD写入数据
|
||||
入口数据:dat 写入的数据
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_WR_DATA(u16 dat)
|
||||
{
|
||||
OLED_DC_Set();//写数据
|
||||
LCD_Writ_Bus(dat>>8);
|
||||
LCD_Writ_Bus(dat);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD写入命令
|
||||
入口数据:dat 写入的命令
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_WR_REG(u8 dat)
|
||||
{
|
||||
OLED_DC_Clr();//写命令
|
||||
LCD_Writ_Bus(dat);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:设置起始和结束地址
|
||||
入口数据:x1,x2 设置列的起始和结束地址
|
||||
y1,y2 设置行的起始和结束地址
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
|
||||
{
|
||||
if(USE_HORIZONTAL==0)
|
||||
{
|
||||
LCD_WR_REG(0x2a);//列地址设置
|
||||
LCD_WR_DATA(x1+26);
|
||||
LCD_WR_DATA(x2+26);
|
||||
LCD_WR_REG(0x2b);//行地址设置
|
||||
LCD_WR_DATA(y1+1);
|
||||
LCD_WR_DATA(y2+1);
|
||||
LCD_WR_REG(0x2c);//储存器写
|
||||
}
|
||||
else if(USE_HORIZONTAL==1)
|
||||
{
|
||||
LCD_WR_REG(0x2a);//列地址设置
|
||||
LCD_WR_DATA(x1+26);
|
||||
LCD_WR_DATA(x2+26);
|
||||
LCD_WR_REG(0x2b);//行地址设置
|
||||
LCD_WR_DATA(y1+1);
|
||||
LCD_WR_DATA(y2+1);
|
||||
LCD_WR_REG(0x2c);//储存器写
|
||||
}
|
||||
else if(USE_HORIZONTAL==2)
|
||||
{
|
||||
LCD_WR_REG(0x2a);//列地址设置
|
||||
LCD_WR_DATA(x1+1);
|
||||
LCD_WR_DATA(x2+1);
|
||||
LCD_WR_REG(0x2b);//行地址设置
|
||||
LCD_WR_DATA(y1+26);
|
||||
LCD_WR_DATA(y2+26);
|
||||
LCD_WR_REG(0x2c);//储存器写
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_WR_REG(0x2a);//列地址设置
|
||||
LCD_WR_DATA(x1+1);
|
||||
LCD_WR_DATA(x2+1);
|
||||
LCD_WR_REG(0x2b);//行地址设置
|
||||
LCD_WR_DATA(y1+26);
|
||||
LCD_WR_DATA(y2+26);
|
||||
LCD_WR_REG(0x2c);//储存器写
|
||||
}
|
||||
}
|
||||
|
||||
#if SPI0_CFG == 2
|
||||
/*!
|
||||
\brief configure the DMA peripheral
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void dma_config(void)
|
||||
{
|
||||
dma_parameter_struct dma_init_struct;
|
||||
|
||||
/* SPI0 transmit dma config:DMA0,DMA_CH2 */
|
||||
dma_deinit(DMA0, DMA_CH2);
|
||||
dma_struct_para_init(&dma_init_struct);
|
||||
|
||||
dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);
|
||||
dma_init_struct.memory_addr = (uint32_t)image;
|
||||
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
|
||||
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
|
||||
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
|
||||
dma_init_struct.priority = DMA_PRIORITY_LOW;
|
||||
dma_init_struct.number = FRAME_SIZE;
|
||||
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
|
||||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
|
||||
dma_init(DMA0, DMA_CH2, &dma_init_struct);
|
||||
/* configure DMA mode */
|
||||
dma_circulation_disable(DMA0, DMA_CH2);
|
||||
dma_memory_to_memory_disable(DMA0, DMA_CH2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SPI0_CFG == 1
|
||||
/*!
|
||||
\brief configure the SPI peripheral
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_config(void)
|
||||
{
|
||||
spi_parameter_struct spi_init_struct;
|
||||
/* deinitilize SPI and the parameters */
|
||||
OLED_CS_Set();
|
||||
spi_struct_para_init(&spi_init_struct);
|
||||
|
||||
/* SPI0 parameter config */
|
||||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||||
spi_init_struct.device_mode = SPI_MASTER;
|
||||
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
|
||||
spi_init_struct.nss = SPI_NSS_SOFT;
|
||||
spi_init_struct.prescale = SPI_PSC_8;
|
||||
spi_init_struct.endian = SPI_ENDIAN_MSB;
|
||||
spi_init(SPI0, &spi_init_struct);
|
||||
|
||||
spi_crc_polynomial_set(SPI0,7);
|
||||
spi_enable(SPI0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD初始化函数
|
||||
入口数据:无
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void Lcd_Init(void)
|
||||
{
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
|
||||
#if SPI0_CFG == 1
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
rcu_periph_clock_enable(RCU_SPI0);
|
||||
/* SPI0 GPIO config: NSS/PA4, SCK/PA5, MOSI/PA7 */
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 |GPIO_PIN_6| GPIO_PIN_7);
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
|
||||
|
||||
spi_config();
|
||||
|
||||
#elif SPI0_CFG == 2
|
||||
rcu_periph_clock_enable(RCU_DMA0);
|
||||
rcu_periph_clock_enable(RCU_SPI0);
|
||||
|
||||
/* SPI0 GPIO config: NSS/PA4, SCK/PA5, MOSI/PA7 */
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7);
|
||||
/* SPI0 GPIO config: MISO/PA6 */
|
||||
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
|
||||
|
||||
dma_config();
|
||||
|
||||
dma_channel_enable(DMA0,DMA_CH2);
|
||||
#elif SPI0_CFG == 3
|
||||
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
|
||||
|
||||
gpio_bit_reset(GPIOA, GPIO_PIN_5 | GPIO_PIN_7);
|
||||
gpio_bit_reset(GPIOB, GPIO_PIN_2);
|
||||
#endif
|
||||
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1);
|
||||
gpio_bit_reset(GPIOB, GPIO_PIN_0 | GPIO_PIN_1);
|
||||
|
||||
OLED_RST_Clr();
|
||||
delay_1ms(200);
|
||||
OLED_RST_Set();
|
||||
delay_1ms(20);
|
||||
OLED_BLK_Set();
|
||||
|
||||
LCD_WR_REG(0x11);
|
||||
delay_1ms(100);
|
||||
|
||||
LCD_WR_REG(0x21);
|
||||
|
||||
LCD_WR_REG(0xB1);
|
||||
LCD_WR_DATA8(0x05);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
|
||||
LCD_WR_REG(0xB2);
|
||||
LCD_WR_DATA8(0x05);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
|
||||
LCD_WR_REG(0xB3);
|
||||
LCD_WR_DATA8(0x05);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
LCD_WR_DATA8(0x05);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
LCD_WR_DATA8(0x3A);
|
||||
|
||||
LCD_WR_REG(0xB4);
|
||||
LCD_WR_DATA8(0x03);
|
||||
|
||||
LCD_WR_REG(0xC0);
|
||||
LCD_WR_DATA8(0x62);
|
||||
LCD_WR_DATA8(0x02);
|
||||
LCD_WR_DATA8(0x04);
|
||||
|
||||
LCD_WR_REG(0xC1);
|
||||
LCD_WR_DATA8(0xC0);
|
||||
|
||||
LCD_WR_REG(0xC2);
|
||||
LCD_WR_DATA8(0x0D);
|
||||
LCD_WR_DATA8(0x00);
|
||||
|
||||
LCD_WR_REG(0xC3);
|
||||
LCD_WR_DATA8(0x8D);
|
||||
LCD_WR_DATA8(0x6A);
|
||||
|
||||
LCD_WR_REG(0xC4);
|
||||
LCD_WR_DATA8(0x8D);
|
||||
LCD_WR_DATA8(0xEE);
|
||||
|
||||
LCD_WR_REG(0xC5); /*VCOM*/
|
||||
LCD_WR_DATA8(0x0E);
|
||||
|
||||
LCD_WR_REG(0xE0);
|
||||
LCD_WR_DATA8(0x10);
|
||||
LCD_WR_DATA8(0x0E);
|
||||
LCD_WR_DATA8(0x02);
|
||||
LCD_WR_DATA8(0x03);
|
||||
LCD_WR_DATA8(0x0E);
|
||||
LCD_WR_DATA8(0x07);
|
||||
LCD_WR_DATA8(0x02);
|
||||
LCD_WR_DATA8(0x07);
|
||||
LCD_WR_DATA8(0x0A);
|
||||
LCD_WR_DATA8(0x12);
|
||||
LCD_WR_DATA8(0x27);
|
||||
LCD_WR_DATA8(0x37);
|
||||
LCD_WR_DATA8(0x00);
|
||||
LCD_WR_DATA8(0x0D);
|
||||
LCD_WR_DATA8(0x0E);
|
||||
LCD_WR_DATA8(0x10);
|
||||
|
||||
LCD_WR_REG(0xE1);
|
||||
LCD_WR_DATA8(0x10);
|
||||
LCD_WR_DATA8(0x0E);
|
||||
LCD_WR_DATA8(0x03);
|
||||
LCD_WR_DATA8(0x03);
|
||||
LCD_WR_DATA8(0x0F);
|
||||
LCD_WR_DATA8(0x06);
|
||||
LCD_WR_DATA8(0x02);
|
||||
LCD_WR_DATA8(0x08);
|
||||
LCD_WR_DATA8(0x0A);
|
||||
LCD_WR_DATA8(0x13);
|
||||
LCD_WR_DATA8(0x26);
|
||||
LCD_WR_DATA8(0x36);
|
||||
LCD_WR_DATA8(0x00);
|
||||
LCD_WR_DATA8(0x0D);
|
||||
LCD_WR_DATA8(0x0E);
|
||||
LCD_WR_DATA8(0x10);
|
||||
|
||||
LCD_WR_REG(0x3A);
|
||||
LCD_WR_DATA8(0x05);
|
||||
|
||||
LCD_WR_REG(0x36);
|
||||
if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x08);
|
||||
else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC8);
|
||||
else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x78);
|
||||
else LCD_WR_DATA8(0xA8);
|
||||
|
||||
LCD_WR_REG(0x29);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD清屏函数
|
||||
入口数据:无
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_Clear(u16 Color)
|
||||
{
|
||||
u16 i,j;
|
||||
LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
|
||||
for(i=0;i<LCD_W;i++)
|
||||
{
|
||||
for (j=0;j<LCD_H;j++)
|
||||
{
|
||||
LCD_WR_DATA(Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD显示汉字
|
||||
入口数据:x,y 起始坐标
|
||||
index 汉字的序号
|
||||
size 字号
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowChinese(u16 x,u16 y,u8 index,u8 size,u16 color)
|
||||
{
|
||||
u8 i,j;
|
||||
u8 *temp,size1;
|
||||
if(size==16){temp=Hzk16;}//选择字号
|
||||
if(size==32){temp=Hzk32;}
|
||||
LCD_Address_Set(x,y,x+size-1,y+size-1); //设置一个汉字的区域
|
||||
size1=size*size/8;//一个汉字所占的字节
|
||||
temp+=index*size1;//写入的起始位置
|
||||
for(j=0;j<size1;j++)
|
||||
{
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if((*temp&(1<<i))!=0)//从数据的低位开始读
|
||||
{
|
||||
LCD_WR_DATA(color);//点亮
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_WR_DATA(BACK_COLOR);//不点亮
|
||||
}
|
||||
}
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD显示汉字
|
||||
入口数据:x,y 起始坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_DrawPoint(u16 x,u16 y,u16 color)
|
||||
{
|
||||
LCD_Address_Set(x,y,x,y);//设置光标位置
|
||||
LCD_WR_DATA(color);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:LCD画一个大的点
|
||||
入口数据:x,y 起始坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_DrawPoint_big(u16 x,u16 y,u16 color)
|
||||
{
|
||||
LCD_Fill(x-1,y-1,x+1,y+1,color);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:在指定区域填充颜色
|
||||
入口数据:xsta,ysta 起始坐标
|
||||
xend,yend 终止坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
|
||||
{
|
||||
u16 i,j;
|
||||
LCD_Address_Set(xsta,ysta,xend,yend); //设置光标位置
|
||||
for(i=ysta;i<=yend;i++)
|
||||
{
|
||||
for(j=xsta;j<=xend;j++)LCD_WR_DATA(color);//设置光标位置
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:画线
|
||||
入口数据:x1,y1 起始坐标
|
||||
x2,y2 终止坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2,u16 color)
|
||||
{
|
||||
u16 t;
|
||||
int xerr=0,yerr=0,delta_x,delta_y,distance;
|
||||
int incx,incy,uRow,uCol;
|
||||
delta_x=x2-x1; //计算坐标增量
|
||||
delta_y=y2-y1;
|
||||
uRow=x1;//画线起点坐标
|
||||
uCol=y1;
|
||||
if(delta_x>0)incx=1; //设置单步方向
|
||||
else if (delta_x==0)incx=0;//垂直线
|
||||
else {incx=-1;delta_x=-delta_x;}
|
||||
if(delta_y>0)incy=1;
|
||||
else if (delta_y==0)incy=0;//水平线
|
||||
else {incy=-1;delta_y=-delta_x;}
|
||||
if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
|
||||
else distance=delta_y;
|
||||
for(t=0;t<distance+1;t++)
|
||||
{
|
||||
LCD_DrawPoint(uRow,uCol,color);//画点
|
||||
xerr+=delta_x;
|
||||
yerr+=delta_y;
|
||||
if(xerr>distance)
|
||||
{
|
||||
xerr-=distance;
|
||||
uRow+=incx;
|
||||
}
|
||||
if(yerr>distance)
|
||||
{
|
||||
yerr-=distance;
|
||||
uCol+=incy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:画矩形
|
||||
入口数据:x1,y1 起始坐标
|
||||
x2,y2 终止坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color)
|
||||
{
|
||||
LCD_DrawLine(x1,y1,x2,y1,color);
|
||||
LCD_DrawLine(x1,y1,x1,y2,color);
|
||||
LCD_DrawLine(x1,y2,x2,y2,color);
|
||||
LCD_DrawLine(x2,y1,x2,y2,color);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:画圆
|
||||
入口数据:x0,y0 圆心坐标
|
||||
r 半径
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void Draw_Circle(u16 x0,u16 y0,u8 r,u16 color)
|
||||
{
|
||||
int a,b;
|
||||
// int di;
|
||||
a=0;b=r;
|
||||
while(a<=b)
|
||||
{
|
||||
LCD_DrawPoint(x0-b,y0-a,color); //3
|
||||
LCD_DrawPoint(x0+b,y0-a,color); //0
|
||||
LCD_DrawPoint(x0-a,y0+b,color); //1
|
||||
LCD_DrawPoint(x0-a,y0-b,color); //2
|
||||
LCD_DrawPoint(x0+b,y0+a,color); //4
|
||||
LCD_DrawPoint(x0+a,y0-b,color); //5
|
||||
LCD_DrawPoint(x0+a,y0+b,color); //6
|
||||
LCD_DrawPoint(x0-b,y0+a,color); //7
|
||||
a++;
|
||||
if((a*a+b*b)>(r*r))//判断要画的点是否过远
|
||||
{
|
||||
b--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示字符
|
||||
入口数据:x,y 起点坐标
|
||||
num 要显示的字符
|
||||
mode 1叠加方式 0非叠加方式
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 mode,u16 color)
|
||||
{
|
||||
u8 temp;
|
||||
u8 pos,t;
|
||||
u16 x0=x;
|
||||
if(x>LCD_W-16||y>LCD_H-16)return; //设置窗口
|
||||
num=num-' ';//得到偏移后的值
|
||||
LCD_Address_Set(x,y,x+8-1,y+16-1); //设置光标位置
|
||||
if(!mode) //非叠加方式
|
||||
{
|
||||
for(pos=0;pos<16;pos++)
|
||||
{
|
||||
temp=asc2_1608[(u16)num*16+pos]; //调用1608字体
|
||||
for(t=0;t<8;t++)
|
||||
{
|
||||
if(temp&0x01)LCD_WR_DATA(color);
|
||||
else LCD_WR_DATA(BACK_COLOR);
|
||||
temp>>=1;
|
||||
x++;
|
||||
}
|
||||
x=x0;
|
||||
y++;
|
||||
}
|
||||
}else//叠加方式
|
||||
{
|
||||
for(pos=0;pos<16;pos++)
|
||||
{
|
||||
temp=asc2_1608[(u16)num*16+pos]; //调用1608字体
|
||||
for(t=0;t<8;t++)
|
||||
{
|
||||
if(temp&0x01)LCD_DrawPoint(x+t,y+pos,color);//画一个点
|
||||
temp>>=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示字符串
|
||||
入口数据:x,y 起点坐标
|
||||
*p 字符串起始地址
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 color)
|
||||
{
|
||||
while(*p!='\0')
|
||||
{
|
||||
if(x>LCD_W-16){x=0;y+=16;}
|
||||
if(y>LCD_H-16){y=x=0;LCD_Clear(RED);}
|
||||
LCD_ShowChar(x,y,*p,0,color);
|
||||
x+=8;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示数字
|
||||
入口数据:m底数,n指数
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
u32 mypow(u8 m,u8 n)
|
||||
{
|
||||
u32 result=1;
|
||||
while(n--)result*=m;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示数字
|
||||
入口数据:x,y 起点坐标
|
||||
num 要显示的数字
|
||||
len 要显示的数字个数
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowNum(u16 x,u16 y,u16 num,u8 len,u16 color)
|
||||
{
|
||||
u8 t,temp;
|
||||
u8 enshow=0;
|
||||
for(t=0;t<len;t++)
|
||||
{
|
||||
temp=(num/mypow(10,len-t-1))%10;
|
||||
if(enshow==0&&t<(len-1))
|
||||
{
|
||||
if(temp==0)
|
||||
{
|
||||
LCD_ShowChar(x+8*t,y,' ',0,color);
|
||||
continue;
|
||||
}else enshow=1;
|
||||
|
||||
}
|
||||
LCD_ShowChar(x+8*t,y,temp+48,0,color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示小数
|
||||
入口数据:x,y 起点坐标
|
||||
num 要显示的小数
|
||||
len 要显示的数字个数
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowNum1(u16 x,u16 y,float num,u8 len,u16 color)
|
||||
{
|
||||
u8 t,temp;
|
||||
// u8 enshow=0;
|
||||
u16 num1;
|
||||
num1=num*100;
|
||||
for(t=0;t<len;t++)
|
||||
{
|
||||
temp=(num1/mypow(10,len-t-1))%10;
|
||||
if(t==(len-2))
|
||||
{
|
||||
LCD_ShowChar(x+8*(len-2),y,'.',0,color);
|
||||
t++;
|
||||
len+=1;
|
||||
}
|
||||
LCD_ShowChar(x+8*t,y,temp+48,0,color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
函数说明:显示40x40图片
|
||||
入口数据:x,y 起点坐标
|
||||
返回值: 无
|
||||
******************************************************************************/
|
||||
void LCD_ShowPicture(u16 x1,u16 y1,u16 x2,u16 y2)
|
||||
{
|
||||
int i;
|
||||
LCD_Address_Set(x1,y1,x2,y2);
|
||||
for(i=0;i<12800;i++)
|
||||
{
|
||||
// LCD_WR_DATA8(image[i*2+1]);
|
||||
LCD_WR_DATA8(image[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD_ShowLogo(void)
|
||||
{
|
||||
int i;
|
||||
LCD_Address_Set(0,0,159,75);
|
||||
for(i=0;i<25600;i++)
|
||||
{
|
||||
LCD_WR_DATA8(logo_bmp[i]);
|
||||
}
|
||||
}
|
||||
|
109
gd32v_lcd/src/main.c
Normal file
109
gd32v_lcd/src/main.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include "lcd/lcd.h"
|
||||
#include "fatfs/tf_card.h"
|
||||
#include <string.h>
|
||||
|
||||
unsigned char image[12800];
|
||||
FATFS fs;
|
||||
|
||||
void init_uart0(void)
|
||||
{
|
||||
/* enable GPIO clock */
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
/* enable USART clock */
|
||||
rcu_periph_clock_enable(RCU_USART0);
|
||||
|
||||
/* connect port to USARTx_Tx */
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
|
||||
/* connect port to USARTx_Rx */
|
||||
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
|
||||
|
||||
/* USART configure */
|
||||
usart_deinit(USART0);
|
||||
usart_baudrate_set(USART0, 115200U);
|
||||
usart_word_length_set(USART0, USART_WL_8BIT);
|
||||
usart_stop_bit_set(USART0, USART_STB_1BIT);
|
||||
usart_parity_config(USART0, USART_PM_NONE);
|
||||
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
|
||||
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
|
||||
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
|
||||
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
|
||||
usart_enable(USART0);
|
||||
|
||||
usart_interrupt_enable(USART0, USART_INT_RBNE);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
u8 i,m;
|
||||
float t=0;
|
||||
int offset = 0;
|
||||
uint64_t start_mtime, delta_mtime;
|
||||
FIL fil;
|
||||
|
||||
FRESULT fr; /* FatFs return code */
|
||||
UINT br, bw;
|
||||
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_GPIOC);
|
||||
gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
|
||||
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1|GPIO_PIN_2);
|
||||
|
||||
init_uart0();
|
||||
|
||||
Lcd_Init(); // init OLED
|
||||
LCD_Clear(WHITE);
|
||||
BACK_COLOR=WHITE;
|
||||
|
||||
LEDR(1);
|
||||
LEDG(1);
|
||||
LEDB(1);
|
||||
fr = f_mount(&fs, "", 1);
|
||||
|
||||
while(1)
|
||||
{
|
||||
offset = 0;
|
||||
fr = f_open(&fil, "logo.bin", FA_READ);
|
||||
if (fr) printf("open error: %d!\n\r", (int)fr);
|
||||
f_lseek(&fil, offset);
|
||||
fr = f_read(&fil, image, sizeof(image), &br);
|
||||
LCD_ShowPicture(0,0,159,39);
|
||||
offset += 12800;
|
||||
LEDB_TOG;
|
||||
f_lseek(&fil, offset);
|
||||
fr = f_read(&fil, image, sizeof(image), &br);
|
||||
LCD_ShowPicture(0,40,159,79);
|
||||
LEDB_TOG;
|
||||
delay_1ms(1500);
|
||||
f_close(&fil);
|
||||
|
||||
fr = f_open(&fil, "bmp.bin", FA_READ);
|
||||
if (fr) printf("open error: %d!\n\r", (int)fr);
|
||||
offset = 0;
|
||||
|
||||
for (int i=0; i<2189;i++)
|
||||
{
|
||||
fr = f_read(&fil, image, sizeof(image), &br);
|
||||
LCD_ShowPicture(0,0,159,39);
|
||||
offset += 12800;
|
||||
f_lseek(&fil, offset);
|
||||
LEDB_TOG;
|
||||
fr = f_read(&fil, image, sizeof(image), &br);
|
||||
LCD_ShowPicture(0,40,159,79);
|
||||
offset += 12800;
|
||||
f_lseek(&fil, offset);
|
||||
LEDB_TOG;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
f_close(&fil);
|
||||
}
|
||||
}
|
||||
|
||||
int _put_char(int ch)
|
||||
{
|
||||
usart_data_transmit(USART0, (uint8_t) ch );
|
||||
while ( usart_flag_get(USART0, USART_FLAG_TBE)== RESET){
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
57
gd32v_lcd/src/systick.c
Normal file
57
gd32v_lcd/src/systick.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*!
|
||||
\file systick.c
|
||||
\brief the systick configuration file
|
||||
|
||||
\version 2019-6-5, V1.0.0, firmware for GD32VF103
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2019, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gd32vf103.h"
|
||||
#include "systick.h"
|
||||
|
||||
/*!
|
||||
\brief delay a time in milliseconds
|
||||
\param[in] count: count in milliseconds
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void delay_1ms(uint32_t count)
|
||||
{
|
||||
uint64_t start_mtime, delta_mtime;
|
||||
|
||||
// Don't start measuruing until we see an mtime tick
|
||||
uint64_t tmp = get_timer_value();
|
||||
do {
|
||||
start_mtime = get_timer_value();
|
||||
} while (start_mtime == tmp);
|
||||
|
||||
do {
|
||||
delta_mtime = get_timer_value() - start_mtime;
|
||||
}while(delta_mtime <(SystemCoreClock/4000.0 *count ));
|
||||
}
|
Reference in New Issue
Block a user