上传初始版本

This commit is contained in:
greedyhao
2019-08-28 16:25:46 +08:00
parent e50de3b0b9
commit 14e0b22e1b
28 changed files with 27144 additions and 0 deletions

View 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)

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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
View 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 ));
}