main
esea_info 2 years ago
parent 54c1bd6725
commit 17be148c1c
  1. 4
      README.md
  2. 58
      base/Inc/base.h
  3. 26
      base/Inc/myrtos.h
  4. 372
      base/Src/base.c
  5. 71
      base/Src/myrtos.c
  6. 58
      bsp/Inc/bsp_dma2d.h
  7. 189
      bsp/Inc/bsp_lcd.h
  8. 187
      bsp/Inc/bsp_ltdc.h
  9. 103
      bsp/Inc/bsp_nand.h
  10. 57
      bsp/Inc/bsp_sdram.h
  11. 117
      bsp/Inc/bsp_spiflash.h
  12. 143
      bsp/Inc/bsp_uart.h
  13. 37
      bsp/Inc/ftl.h
  14. 88
      bsp/Inc/malloc.h
  15. 99
      bsp/Src/bsp_dma2d.c
  16. 905
      bsp/Src/bsp_lcd.c
  17. 882
      bsp/Src/bsp_ltdc.c
  18. 722
      bsp/Src/bsp_nand.c
  19. 171
      bsp/Src/bsp_sdram.c
  20. 481
      bsp/Src/bsp_spiflash.c
  21. 205
      bsp/Src/bsp_uart.c
  22. 481
      bsp/Src/ftl.c
  23. 216
      bsp/Src/malloc.c
  24. 143
      font/Inc/fonts.h
  25. 1464
      font/Src/font12.c
  26. 1844
      font/Src/font16.c
  27. 2223
      font/Src/font20.c
  28. 2600
      font/Src/font24.c
  29. 1084
      font/Src/font8.c
  30. 220
      font/Src/fontcn.c
  31. 250
      port/easylogger/elog_port.c

@ -1,3 +1,5 @@
# MyStm32Code
不含stm32 底层的代码
不含stm32 底层的代码
DOC 文档 教程

@ -0,0 +1,58 @@
#ifndef __407_BASE_H
#define __407_BASE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef USE_ELOG
#define USE_ELOG
#endif
#if !defined(LOG_TAG)
#define LOG_TAG "BASE"
#endif
#undef LOG_LVL
#if defined(BASE_LOG_LVL)
#define LOG_LVL BASE_LOG_LVL
#endif
#ifdef USE_ELOG
#include "elog.h"
#undef LOG_LVL
#if !defined(LOG_TAG)
#define LOG_TAG "BASE"
#endif
#undef LOG_LVL
#if defined(BASE_LOG_LVL)
#define LOG_LVL BASE_LOG_LVL
#endif
#define BASE_INFO(fmt,arg...) log_i(""fmt"",##arg)
#else
#include <stdio.h>
#define BASE_INFO(fmt,arg...) printf("[Base] -> "fmt"\n",##arg)
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#include "usart.h"
#include "stm32f4xx.h"
#include "myrtos.h"
#include "bsp_sdram.h"
#include "bsp_nand.h"
#include "malloc.h"
#include "bsp_dma2d.h"
#include "bsp_lcd.h"
// #include "bsp_ltdc.h"
// #include "bsp_gt9xx.h"
#include "bsp_spiflash.h"
#include "fatfs.h"
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,26 @@
#ifndef __MY_RTOS_H
#define __MY_RTOS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
extern osThreadId_t measureTaskHandle;
extern const osThreadAttr_t measureTask_attributes ;
extern osTimerId_t measureTimerHandle;
extern const osTimerAttr_t measureTimer_attributes ;
extern void RTOS_Port(void);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,372 @@
#include "base.h"
uint8_t MyBuffer[4096] ={0};
// #define USE_USB_HS
extern osSemaphoreId_t elog_dma_lockHandle;
int _write(int fd, char *ch, int len)
{
if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever))
{
// #ifdef LOG_MENU_485
// log_menu_send_enable();
// #endif
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)ch, len);
}
return len;
}
uint8_t test_send_buf[8] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x04, 0x44, 0x09};
uint8_t test_send_buf_2[6] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x04};
uint8_t test_rcv_buf[14] = {0};
uint8_t test_rcv_buf_2[13] = {0};
void MY_INIT( )
{
// SDRAM_Init();
// HAL_Delay(100);
// SDRAM_Test();
}
static void Default_Task_Init()
{
log_i(" GCC Version -> %d ",__GNUC__);
// log_i(" GCC SDRAM_BANK_ADDR -> %d\n",SDRAM_BANK_ADDR);
// my_eeprom.init();
// // uint8_t a[2] = { 0xFF, 0xFF };
// // Eeprom_Transmit( eeprom, &a, 2 );
// // osDelay(5);
// // Eeprom_Begin_Rcv( eeprom, test_rcv_buf, 1);
// // osDelay(5);
// //初始化SDRAM模块
// extern MY_SDRAM_TypeDef my_sdram;
my_sdram.init();
// SDRAM_Init();
if (my_sdram.test(32)){
// if (SDRAM_Test(32)){
log_i( "SDRAM 32 Bytes Test OK ...");
}else{
log_i( "SDRAM 32 Bytes Test Faiure ...");
}
uint8_t *ex_buf;
ex_buf=mymalloc(SRAMEX,512); //申请一个扇区的缓存
if (ex_buf != NULL)
log_i("Malloc SRAMEX, Test ->>> PASS ! ...");
myfree(SRAMEX,ex_buf);
if (ex_buf == NULL)
log_i("Malloc Free OK ...");
my_nand.init();
while(FTL_Init()) //检测NAND FLASH,并初始化FTL
{
log_w("NAND Error!");
HAL_Delay(500);
log_w("Please Check");
HAL_Delay(500);
}
// my_nand.init();
log_i("NAND ID : %08X " , my_nand.id );
log_i("NAND Size : %dMB " , (my_nand.block_totalnum/1024)*(my_nand.page_mainsize/1024)*my_nand.block_pagenum); //显示NAND容量
log_i("NAND total Block Num: %d , page bytes %d , good block %d , valid sector Num: %d " ,
my_nand.block_totalnum , my_nand.page_mainsize, my_nand.good_blocknum,my_nand.valid_blocknum );
if(my_nand.id==MT29F16G08ABABA) //NAND为MT29F16G08ABABA
{
log_i("NAND Type : MT29F16G08ABABA 16GB" );
}
else if(my_nand.id==W29N01GVSIAA) //NAND为W29N01GVSIAA
{
log_i("NAND Type : W29N01GVSIAA 1GB" );
}else if (my_nand.id==W29N01HVSINA) //NAND为 W29N01HVSINA
{
log_i("NAND Type : W29N01HVSINA 512MB" );
}
else
{
log_e("NAND Type : Error" );
}
// uint8_t *nand_sector0_buf;
// nand_sector0_buf = malloc(512);
// FTL_ReadSectors(nand_sector0_buf,2,NAND_ECC_SECTOR_SIZE,1);//预先读取扇区0到备份区域,防止乱写导致文件系统损坏.
spiflash_init();
log_i("SPI FLASH Type : %02X ", g_spiflash_type);
// UI_Port();
// 初始化触摸屏/
// GTP_Init_Panel();
// Disable_NAND_CS();
// // /* LCD 端口初始化 */
LCD_Init( );
log_i(" LTDC id %04X *** " , my_ltdc.id);
log_i(" Layer Addrr %08X %08X " , my_lcd.layeraddr[0],my_lcd.layeraddr[1]);
log_i(" Layer hsw vsw %d %d " , my_ltdc.hsw,my_ltdc.vsw);
DMA2D_Fill( (uint32_t) my_lcd.layeraddr[0], 480, 272, 0, DMA2D_ARGB8888, LCD_COLOR_ORANGE );
DMA2D_Fill( (uint32_t) my_lcd.layeraddr[1], 480, 272, 0, DMA2D_ARGB8888, LCD_COLOR_GREEN );
// // DMA2D_MemCopy(DMA2D_ARGB8888, my_lcd.layeraddr[1], my_lcd.layeraddr[0],
// // 480,272,0,0);
// LTDC_Select_Layer(0);
LCD_DrawLine(100,100,200,200);
// // LCD_Fill(100,100,300,250, LCD_COLOR_GREEN);
LCD_DisplayStringLine( 1, (uint8_t* )"LTDC TEST" );
LCD_DisplayStringLine_EN_CH( 2, (uint8_t* )"");
// GTP_Init_Panel();
// log_i( "touch ic version %s", tp_dev.ic_version);
// DrawChar( 20, 20, &("LTDC TEST") );
// LCD_DisplayNumber( 2, 789,10 );
// LCD_DisplayNumber( 3, 666.99,10 );
// LCD_SetTransparency(0, 255);
// // LTDC_Clear(LCD_COLOR_GREEN);
// LTDC_FillBuffer(0, LCD_FB_START_ADDRESS, 480, 272, 0, LCD_COLOR_GREEN);
// LTDC_FillBuffer(1, LCD_FB_START_ADDRESS+(LCD_GetXSize()*LCD_GetYSize()*4), 480, 272, 0, LCD_COLOR_GREEN);
// LTDC_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex);
// // /* 选择LCD第一层 */
// LCD_SelectLayer(0);
// // /* 第一层清屏,显示全黑 */
// LCD_Clear(LCD_COLOR_BLACK);
// // /* 选择LCD第二层 */
// LCD_SelectLayer(1);
// // /* 第二层清屏,显示全黑 */
// LCD_Clear(LCD_COLOR_TRANSPARENT);
// // // /* 配置第一和第二层的透明度,最小值为0,最大值为255*/
// LCD_SetTransparency(0, 255);
// LCD_SetTransparency(1, 0);
// log_i("lcd set layer Clear... ok...... ");
// // /* 选择LCD第一层 */
// LCD_SelectLayer(0);
// // /* 清屏,显示全黑 */
// LCD_Clear(LCD_COLOR_GRAY);
// // /*设置字体颜色及字体的背景颜色(此处的背景不是指LCD的背景层!注意区分)*/
// LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
// // /*选择字体*/
// LCD_SetFont(&LCD_DEFAULT_FONT);
// LCD_DisplayStringLine(1,(uint8_t* )"BH 5.0 inch LCD para: 正");
// LCD_DisplayStringLine(2,(uint8_t* )"Image resolution:800x480 px");
// LCD_DisplayStringLine(3,(uint8_t* )"Touch pad:5 point touch supported");
// LCD_DisplayStringLine(4,(uint8_t* )"Use STM32-LTDC directed driver,");
// LCD_DisplayStringLine(5,(uint8_t* )"no need extern driver,RGB888,24bits data bus");
// LCD_DisplayStringLine(6,(uint8_t* )"Touch pad use IIC to communicate");
// Palette_Init(); // 有中文字符,还得解决
// Enable_NAND_CS();
// my_led.init();
// my_led.port( 200);
// led_set_state(LED_SEQ_0, LED_STATE_FLICKER_SLOW);
// led_set_state(LED_COLOR_GREEN, LED_STATE_FLICKER_SLOW);
RTOS_Port();
osTimerStart( measureTimerHandle, 3000 );
// SD_Test();
// test_Port();
// MX_USB_DEVICE_Init();
}
void StartDefaultTask(void *argument)
{
// uart6_power_enable();
Init_Logger();
log_i(" *** System is initiating *** ");
Default_Task_Init();
// MX_USB_DEVICE_Init(); /* USB 初始化需要写在任务中 */
for (;;)
{
osDelay(1000 );
}
}
void measureTimer_Callback(void *argument)
{
log_i("measureTimer ........................... ");
}
void measureTask(void *argument)
{
for (;;)
{
// log_i("measure task .... ");
osDelay(2000);
}
}
void USART1_IRQHandler(void)
{
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) != RESET)
{
osSemaphoreRelease(elog_dma_lockHandle);
huart1.gState = HAL_UART_STATE_READY;
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TC);
}
HAL_UART_IRQHandler(&huart1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// if (huart->Instance == huart3.Instance)
// {
// log_i("....huart3 rx callback.... " );
// // Oscar_Rcv_Cplt_Callback( oscar );
// // Viper_Rcv_Cplt_Callback( viper );
// // Sample_Rcv_Cplt_Callback( sample );
// __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
// }
}
// void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
// {
// if (huart->Instance == huart3.Instance)
// {
// /* 拷贝数据 到菜单 */
// log_i("huart3 idle -> ****** HAL_UARTEx_RxEventCallback ");
// __HAL_UART_CLEAR_IDLEFLAG(&huart3);
// }
// }
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
// if (huart->Instance == huart3.Instance)
// {
// // max3160_485_receive_mode();
// // huart3.gState = HAL_UART_STATE_READY;
// __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_TC);
// }
}
static void Hardware_Init(void)
{
/*中断优先级分组*/
/*硬件初始化1*/
/* ......*/
/*硬件初始化n*/
}
void Soft_Reboot()
{
__set_FAULTMASK(1);//关闭总中断
NVIC_SystemReset();//请求单片机重启
}
// FATFS fs; /* FatFs文件系统对象 */
// FIL fnew; /* 文件对象 */
// FRESULT res_flash; /* 文件操作结果 */
// UINT fnum; /* 文件成功读写数量 */
// BYTE ReadBuffer[1024]={0}; /* 读缓冲区 */
// BYTE WriteBuffer[] = "这是一个测试程序\r\n";
// // /* 挂载外部flash */
// res_flash = f_mount( &fs,"1:",1);
// // log_i(" mount res %08X \r\n",NAND_ReadID());
// log_i(" mount res %d \r\n", res_flash);
// // /* 如果没有文件系统就格式化创建创建文件系统 */
// if(res_flash == FR_NO_FILESYSTEM)
// {
// log_i("fmount no file system");
// /* 格式化 */
// res_flash=f_mkfs("1:",FM_ANY,0,MyBuffer,_MIN_SS); // FM_ANY 不能为0
// if(res_flash == FR_OK)
// {
// log_i(" mkfs format ok ! " );
// // 格式化后,先取消挂载 /
// res_flash = f_mount(NULL,"1:",1);
// // 重新挂载
// res_flash = f_mount(&fs,"1:",1);
// log_i("fmount OK.. %d", res_flash);
// }
// else
// {
// log_i(" format failure .... %d ",res_flash);
// }
// }
// else if(res_flash != FR_OK)
// {
// // 红灯常亮
// log_i("fmount failure");
// }
// /* 打开文件,如果没有文件就创建 */
// res_flash = f_open(&fnew, "1:FatFs.txt", FA_CREATE_ALWAYS | FA_WRITE );
// log_i(" f_open %d \r\n",res_flash);
// if ( res_flash == FR_OK )
// {
// /* 将指定存储区内容写入到文件内 */
// res_flash = f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
// log_i(" f_write %d \r\n",res_flash);
// if(res_flash == FR_OK)
// {
// /* 蓝灯亮 */
// log_i("write file success ... ");
// }
// else
// {
// /* 不再读写,关闭文件 */
// f_close(&fnew);
// /* 红灯常亮 */
// log_i("write file failure");
// }
// /* 不再读写,关闭文件 */
// f_close(&fnew);
// }
// else
// {
// log_i("write file failure ..... ");
// }

@ -0,0 +1,71 @@
#include "myrtos.h"
osThreadId_t measureTaskHandle;
const osThreadAttr_t measureTask_attributes = {
.name = "measureTask",
.stack_size = 6144 * 4,
.priority = (osPriority_t) osPriorityLow,
};
__weak void measureTask(void *argument)
{
for (;;)
{
osDelay(1);
}
}
osTimerId_t measureTimerHandle;
const osTimerAttr_t measureTimer_attributes = {
.name = "measureTimer"
};
__weak void measureTimer_Callback(void *argument)
{
}
/* 放在尾部 否则要在头文件 声明函数*/
void RTOS_Port(void)
{
measureTaskHandle = osThreadNew( measureTask, NULL, &measureTask_attributes );
measureTimerHandle = osTimerNew(measureTimer_Callback, osTimerPeriodic, NULL, &measureTimer_attributes);
}
// 事件
// osEventFlagsId_t ads1115EventHandle;
// const osEventFlagsAttr_t ads1115Event_attributes = {
// .name = "ads1115Event"
// };
// typedef enum
// {
// EV_READY, /*!< Startup finished. */
// EV_FRAME_RECEIVED, /*!< Frame received. */
// EV_EXECUTE, /*!< Execute function. */
// EV_FRAME_SENT /*!< Frame sent. */
// } eMBEventType;
// osEventFlagsSet(modbusEventHandle,eEvent);
// osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags)
// recvedEvent = osEventFlagsWait (modbusEventHandle,
// EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE |
// EV_FRAME_SENT, /* 接收任务感兴趣的事件 */
// 0,
// portMAX_DELAY); /* 指定超时事件,无限等待 */
// osMessageQueueId_t TestQQueueueueHandle;
// osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
// osMessageQueueGet(TestQueueHandle,osWaitForever);
// osStatus_t osMessageQueueGet ( osMessageQueueId_t mq_id,
// void * msg_ptr, //储存读取结果的变量地址
// uint8_t * msg_prio, // ==NULL
// uint32_t timeout //阻塞超时时间
// );
// osStatus_t osMessageQueuePut ( osMessageQueueId_t mq_id,
// const void * msg_ptr, //储存写入内容的变量地址
// uint8_t msg_prio, //==0U
// uint32_t timeout //阻塞超时时间
// );
// osMessageQueueReset
// /*获取队列可容纳的消息(变量)数量; []
// 两个参数分别为:消息队列的句柄,等待时间(此时为一直等待)

@ -0,0 +1,58 @@
#ifndef _BSP_DMA2D_H
#define _BSP_DMA2D_H
#include "main.h"
#include "dma2d.h"
// extern uint8_t dma2d_transfering;
void DMA2D_Fill( void * pDst,
uint32_t width, uint32_t height, uint32_t lineOff, uint32_t pixelFormat,
uint32_t color);
void DMA2D_MemCopy(uint32_t pixelFormat,
void * pSrc, void * pDst,
int xSize, int ySize,
int OffLineSrc, int OffLineDst);
void DMA2D_Blend(void* pFg, void* pBg, void* pDst,
uint32_t offlineFg, uint32_t offlineBg, uint32_t offlineDist,
uint16_t xSize, uint16_t ySize,
uint32_t pixelFormat, uint8_t opa);
#endif
/*
Test
uint32_t gpubuf1[200];
uint32_t gpubuf2[200];
DMA2D_Fill( gpubuf1, 25, 8, 0, DMA2D_ARGB8888, 0xFFFFFFFF );
if (gpubuf1[0] ==0xFFFFFFFF && gpubuf1[199] ==0xFFFFFFFF){
log_i( "DMA2d Fill Test Pass %02X " , gpubuf1[199]);
}
dma2d_transfering =1;
DMA2D_MemCopy(DMA2D_ARGB8888, gpubuf1, gpubuf2, 25, 8, 0, 0);
osDelay(100);
if (gpubuf2[0] ==0xFFFFFFFF && gpubuf2[199] ==0xFFFFFFFF){
log_i( "DMA2D MemCopy Test Pass %02X " , gpubuf2[199]);
}
DMA2D->CR |= DMA2D_IT_TC;
DMA2D->CR |= DMA2D_CR_START;
DMA
// DMA 的寄存器启动
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Streamx->CR&=~(1<<0); //关闭DMA传输
while(DMA_Streamx->CR&0X1); //确保DMA可以被设置
DMA_Streamx->NDTR=ndtr; //DMA 存储器0地址
DMA_Streamx->CR|=1<<0; //开启DMA传输
}
// 读 GPIOB pin13 电平
#define NAND_RB (((GPIOB->IDR) >> 13) & 0x1U)
*/

@ -0,0 +1,189 @@
#ifndef __BSP_LCD_H
#define __BSP_LCD_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "stm32f4xx.h"
#include "bsp_ltdc.h"
#include "bsp_dma2d.h"
#include "fonts.h"
#define POLY_X(Z) ((int32_t)((Points + Z)->X))
#define POLY_Y(Z) ((int32_t)((Points + Z)->Y))
#define ABS(X) ((X) > 0 ? (X) : -(X))
//LCD参数
#define LCD_DEFAULT_FONT Font16
/**
* @brief LCD液晶类型
*/
typedef enum
{
INCH_5 = 0x00, /* 野火5寸屏 */
INCH_7, /* 野火7寸屏 */
INCH_4_3, /* 野火4.3寸屏 */
LCD_TYPE_NUM /* LCD类型总数*/
}LCD_TypeDef;
// 前使用的LCD,默认为4.3寸屏 */
extern LCD_TypeDef cur_lcd;
typedef struct
{
uint32_t TextColor;
uint32_t BackColor;
sFONT *pFont;
sFONT *pCnFont;
}LCD_DrawPropTypeDef;
typedef struct
{
int16_t X;
int16_t Y;
}Point, *pPoint;
/**
* @brief
*/
typedef enum
{
CENTER_MODE = 0x01, /* 居中对齐 */
RIGHT_MODE = 0x02, /* 右对齐 */
LEFT_MODE = 0x03 /* 左对齐 */
}Text_AlignModeTypdef;
typedef struct
{
// uint16_t pixel_width; // 像素宽
// uint16_t pixel_height; // 像素高
uint16_t width; //LCD 宽度
uint16_t height; //LCD 高度
uint8_t dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
uint8_t pixelsize; //像素大小。
uint32_t color_format; // Layer2 Addr
uint32_t color;
uint32_t backcolor;
LCD_DrawPropTypeDef draw_prop[2];
uint8_t show_num_mode; // 显示数组模式, 0 多余位补0 , 1 不补0
uint16_t activelayer; //active layer
uint32_t layeraddr[2]; // Layer0 Addr
}MY_LCD_TypeDef;
extern MY_LCD_TypeDef my_lcd; //管理LCD重要参数
void LCD_Init(void);
uint8_t LCD_DeInit(void);
void LCD_DisplayDirection(uint8_t dir);
void LCD_SetLayer( uint8_t layer,uint32_t buf_addr, uint32_t layer_color_format,
uint32_t layer_back_color,uint8_t alpha );
void LCD_Set_Active_layer( uint8_t layer_no );
void LCD_SetTextColor(uint32_t Color);
uint32_t LCD_GetTextColor(void);
void LCD_SetBackColor(uint32_t Color);
uint32_t LCD_GetBackColor(void);
void LCD_SetColors(uint32_t TextColor, uint32_t BackColor);
void LCD_SetFont(sFONT *fonts);
sFONT *LCD_GetFont(void);
void LCD_Draw_Point(uint16_t x,uint16_t y,uint32_t color);
uint32_t LCD_Read_Point(uint16_t x,uint16_t y);
// static void LCD_Draw_Point(uint16_t x,uint16_t y,uint32_t color);
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3);
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void LCD_DrawCircle(uint16_t x, uint16_t y, uint16_t r);
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color);
void LCD_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color);
void LCD_Clear( uint32_t color);
void LCD_DisplayChar(uint16_t x, uint16_t y, uint8_t c); // 显示单个ASCII字符
void LCD_DisplayString( uint16_t x, uint16_t y, char *p);
//>>>>> 显示整数或小数
void LCD_ShowNumMode(uint8_t mode); // 设置显示模式,多余位填充空格还是填充0
void LCD_DisplayNumber( uint16_t Line, int32_t number, uint8_t len) ; // 显示整数
void LCD_DisplayDecimals( uint16_t Line, double decimals, uint8_t len, uint8_t decs) ; // 显示小数
// 中文
void LCD_DispChar_CH (uint16_t Xpos, uint16_t Ypos, uint16_t Text);
void LCD_DisplayStringLine_EN_CH(uint16_t Line, uint8_t *ptr);
void LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode);
void LCD_DisplayStringLine(uint16_t Line, uint8_t *ptr);
void LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii);
void LCD_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
void LCD_FillCircle(uint16_t x, uint16_t y, uint16_t r);
void LCD_DrawImage(uint16_t x,uint16_t y,uint16_t width,uint16_t height,const uint8_t *pImage) ;
//画笔颜色 ARGB8888
#if LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_ARGB8888 || LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_RGB888
#define LCD_COLOR_BLUE ((uint32_t)0xFF0000FF)
#define LCD_COLOR_GREEN ((uint32_t)0xFF00FF00)
#define LCD_COLOR_RED ((uint32_t)0xFFFF0000)
#define LCD_COLOR_CYAN ((uint32_t)0xFF00FFFF)
#define LCD_COLOR_MAGENTA ((uint32_t)0xFFFF00FF)
#define LCD_COLOR_YELLOW ((uint32_t)0xFFFFFF00)
#define LCD_COLOR_LIGHTBLUE ((uint32_t)0xFF8080FF)
#define LCD_COLOR_LIGHTGREEN ((uint32_t)0xFF80FF80)
#define LCD_COLOR_LIGHTRED ((uint32_t)0xFFFF8080)
#define LCD_COLOR_LIGHTCYAN ((uint32_t)0xFF80FFFF)
#define LCD_COLOR_LIGHTMAGENTA ((uint32_t)0xFFFF80FF)
#define LCD_COLOR_LIGHTYELLOW ((uint32_t)0xFFFFFF80)
#define LCD_COLOR_DARKBLUE ((uint32_t)0xFF000080)
#define LCD_COLOR_DARKGREEN ((uint32_t)0xFF008000)
#define LCD_COLOR_DARKRED ((uint32_t)0xFF800000)
#define LCD_COLOR_DARKCYAN ((uint32_t)0xFF008080)
#define LCD_COLOR_DARKMAGENTA ((uint32_t)0xFF800080)
#define LCD_COLOR_DARKYELLOW ((uint32_t)0xFF808000)
#define LCD_COLOR_WHITE ((uint32_t)0xFFFFFFFF)
#define LCD_COLOR_LIGHTGRAY ((uint32_t)0xFFD3D3D3)
#define LCD_COLOR_GRAY ((uint32_t)0xFF808080)
#define LCD_COLOR_DARKGRAY ((uint32_t)0xFF404040)
#define LCD_COLOR_BLACK ((uint32_t)0xFF000000)
#define LCD_COLOR_BROWN ((uint32_t)0xFFA52A2A)
#define LCD_COLOR_ORANGE ((uint32_t)0xFFFFA500)
#define LCD_COLOR_TRANSPARENT ((uint32_t)0xFF000000)
#else
# RGB565
#define LCD_COLOR_WHITE 0xFFFF
#define LCD_COLOR_BLACK 0x0000
#define LCD_COLOR_BLUE 0x001F
#define LCD_COLOR_RED 0xF800
#define LCD_COLOR_MAGENTA 0xF81F
#define LCD_COLOR_GREEN 0x07E0
#define LCD_COLOR_CYAN 0x7FFF
#define LCD_COLOR_YELLOW 0xFFE0
#define LCD_COLOR_BROWN 0XBC40 //棕色
#define LCD_COLOR_GRAY 0X8430 //灰色
#define LCD_COLOR_LIGHTGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LCD_COLOR_BRRED_RGB565 0XFC07 //棕红色
#define LCD_COLOR_BRED_RGB565 0XF81F
#define LCD_COLOR_GRED_RGB565 0XFFE0
#define LCD_COLOR_GBLUE_RGB565 0X07FF
#endif
#ifdef __cplusplus
}
#endif
#endif
/**
* LCD_ShowString(10,80,240,24,24,"LTDC TEST");
*/

@ -0,0 +1,187 @@
#ifndef __BSP_LTDC_H
#define __BSP_LTDC_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "stm32f4xx.h"
#include "ltdc.h"
// #include "fonts.h"
#define LCD_BUF_ADDRESS 0xD0000000
#define LCD_PIXFORMAT LTDC_PIXEL_FORMAT_ARGB8888
#define LTDC_BACKLAYERCOLOR 0X00000000
// #define LCD_DEFAULT_FONT Font16
// extern LTDC_HandleTypeDef *Ltdc_Handler;
extern uint8_t *DISP_BUF[2];
typedef struct
{
uint16_t pixel_width; // 像素宽
uint16_t pixel_height; // 像素高
// uint16_t width; //LCD 宽度
// uint16_t height; //LCD 高度
// uint8_t dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
// uint8_t pixelsize; //像素大小。
uint8_t hbp; //HSYNC后的无效像素
uint8_t vbp; //VSYNC后的无效行数
uint8_t hsw; //HSYNC宽度
uint8_t vsw; //VSYNC宽度
uint8_t hfp; //HSYNC前的无效像素
uint8_t vfp; //VSYNC前的无效行数
uint16_t id; //LCD ID
uint16_t activelayer; //LCD ID
// uint32_t layeraddr[2]; // Layer0 Addr
// uint32_t layer_1_Addr; // Layer1 Addr
}MY_LTDC_TypeDef;
//LCD参数
extern MY_LTDC_TypeDef my_ltdc; //管理LCD重要参数
//LCD的画笔颜色和背景色
extern uint32_t POINT_COLOR;//默认红色
extern uint32_t BACK_COLOR; //背景颜色.默认为白色
#define LTDC_DISP_ON() HAL_GPIO_WritePin(LTDC_BL_GPIO_Port,LTDC_BL_Pin,SET); //LCD背光 PB5
// typedef struct
// {
// /*根据液晶数据手册的参数配置*/
// uint8_t hbp; //HSYNC后的无效像素
// uint8_t vbp; //VSYNC后的无效行数
// uint8_t hsw; //HSYNC宽度
// uint8_t vsw; //VSYNC宽度
// uint8_t hfp; //HSYNC前的无效像素
// uint8_t vfp; //VSYNC前的无效行数
// uint8_t comment_clock_2byte; //rgb565/argb4444等双字节像素时推荐使用的液晶时钟频率
// uint8_t comment_clock_4byte; //Argb8888等四字节像素时推荐使用的液晶时钟频率
// uint8_t dir; //0,竖屏;1,横屏;
// uint8_t activelayer; // 0,第一层;1 第二层
// uint16_t lcd_pixel_width; //液晶分辨率,宽
// uint16_t lcd_pixel_height;//液晶分辨率,高
// // uint8_t pixel_format; // 像素格式
// // uint8_t pixel_bytes; // 像素字节数
// }LCD_PARAM_TypeDef;
/**
* @brief LCD color
*/
#if LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_ARGB8888 || LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_RGB888
#define LTDC_COLOR_BLUE ((uint32_t)0xFF0000FF)
#define LTDC_COLOR_GREEN ((uint32_t)0xFF00FF00)
#define LTDC_COLOR_RED ((uint32_t)0xFFFF0000)
#else
#define LTDC_COLOR_BLUE ((uint16_t)0x001F)
#define LTDC_COLOR_GREEN ((uint16_t)0x07E0)
#define LTDC_COLOR_RED ((uint16_t)0xF800)
#endif
uint16_t LTDC_PanelID_Read(void);
void LTDC_Init(void);
uint8_t LTDC_Clk_Set(uint32_t pllsain, uint32_t pllsair ,uint32_t pllsaidivr);
// void LCD_LayerInit(uint16_t LayerIndex,
// uint16_t sx,uint16_t sy,uint16_t width,uint16_t height,
// uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,
// uint32_t Layer_Address,uint32_t PixelFormat,uint32_t color);
void LTDC_Layer_Window_Config(uint8_t layerx,uint16_t sx,uint16_t sy,uint16_t width,uint16_t height);//LTDC层窗口设置
void LTDC_Layer_Parameter_Config(uint8_t layerx,uint32_t bufaddr,uint8_t pixformat,uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,uint32_t bkcolor);//LTDC基本参数设置
void LTDC_Layer_Switch(uint8_t layerx,uint8_t on_off); //层开关
void LTDC_Enable_Line_IT(uint16_t line);
// void LTDC_Select_Layer(uint8_t layerx); //层选择
// void LTDC_Display_Dir(uint8_t dir); //显示方向控制
// void LTDC_Clear(uint32_t color);
// void LTDC_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color);
// void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color);
// void LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency);
// void LCD_LayerInit(uint16_t LayerIndex, uint32_t FB_Address,uint32_t PixelFormat);
// void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color);
// uint32_t LTDC_Read_Point(uint16_t x,uint16_t y);
#ifdef __cplusplus
}
#endif
#endif
/*
// 配置LTDC行中断
LTDC->LIPCR =my_lcd.vsw+my_lcd.vbp+my_lcd.pixel_height-1;//配置行中断的行数为最后一行
// LTDC->IER |=LTDC_IER_LIE; //使能LTDC行中断
// LTDC->SRCR |= (1<<1);
// 行中断结束 自动改写寄存器 SRCR
// while(LTDC->SRCR & LTDC_SRCR_IMR) {
// if(disp->driver->wait_cb) disp->driver->wait_cb(disp->driver);
// }
*/
// //画笔颜色
// #define WHITE_RGB565 0xFFFF
// #define BLACK_RGB565 0x0000
// #define BLUE_RGB565 0x001F
// #define BRED_RGB565 0XF81F
// #define GRED_RGB565 0XFFE0
// #define GBLUE_RGB565 0X07FF
// #define RED_RGB565 0xF800
// #define MAGENTA_RGB565 0xF81F
// #define GREEN_RGB565 0x07E0
// #define CYAN_RGB565 0x7FFF
// #define YELLOW_RGB565 0xFFE0
// #define BROWN_RGB565 0XBC40 //棕色
// #define BRRED_RGB565 0XFC07 //棕红色
// #define GRAY_RGB565 0X8430 //灰色
// #define LGRAY_RGB565 0XC618 //浅灰色(PANNEL),窗体背景色
// //画笔颜色 ARGB8888
// #define LTDC_COLOR_BLUE ((uint32_t)0xFF0000FF)
// #define LTDC_COLOR_GREEN ((uint32_t)0xFF00FF00)
// #define LTDC_COLOR_RED ((uint32_t)0xFFFF0000)
// #define LTDC_COLOR_CYAN ((uint32_t)0xFF00FFFF)
// #define LTDC_COLOR_MAGENTA ((uint32_t)0xFFFF00FF)
// #define LTDC_COLOR_YELLOW ((uint32_t)0xFFFFFF00)
// #define LTDC_COLOR_LIGHTBLUE ((uint32_t)0xFF8080FF)
// #define LTDC_COLOR_LIGHTGREEN ((uint32_t)0xFF80FF80)
// #define LTDC_COLOR_LIGHTRED ((uint32_t)0xFFFF8080)
// #define LTDC_COLOR_LIGHTCYAN ((uint32_t)0xFF80FFFF)
// #define LTDC_COLOR_LIGHTMAGENTA ((uint32_t)0xFFFF80FF)
// #define LTDC_COLOR_LIGHTYELLOW ((uint32_t)0xFFFFFF80)
// #define LTDC_COLOR_DARKBLUE ((uint32_t)0xFF000080)
// #define LTDC_COLOR_DARKGREEN ((uint32_t)0xFF008000)
// #define LTDC_COLOR_DARKRED ((uint32_t)0xFF800000)
// #define LTDC_COLOR_DARKCYAN ((uint32_t)0xFF008080)
// #define LTDC_COLOR_DARKMAGENTA ((uint32_t)0xFF800080)
// #define LTDC_COLOR_DARKYELLOW ((uint32_t)0xFF808000)
// #define LTDC_COLOR_WHITE ((uint32_t)0xFFFFFFFF)
// #define LTDC_COLOR_LIGHTGRAY ((uint32_t)0xFFD3D3D3)
// #define LTDC_COLOR_GRAY ((uint32_t)0xFF808080)
// #define LTDC_COLOR_DARKGRAY ((uint32_t)0xFF404040)
// #define LTDC_COLOR_BLACK ((uint32_t)0xFF000000)
// #define LTDC_COLOR_BROWN ((uint32_t)0xFFA52A2A)
// #define LTDC_COLOR_ORANGE ((uint32_t)0xFFFFA500)
// #define LTDC_COLOR_TRANSPARENT ((uint32_t)0xFF000000)

@ -0,0 +1,103 @@
#ifndef _NAND_H
#define _NAND_H
#include "stm32f4xx.h"
#include "fmc.h"
//升级说明
//V1.1 20160520
//1,新增硬件ECC支持(仅在以NAND_ECC_SECTOR_SIZE大小为单位进行读写时处理)
//2,新增NAND_Delay函数,用于等待tADL/tWHR
//3,新增NAND_WritePageConst函数,用于搜寻坏块.
//V1.2 20160525
//1,去掉NAND_SEC_SIZE宏定义,由NAND_ECC_SECTOR_SIZE替代
//2,去掉my_nand结构体里面的secbuf指针,用不到
//////////////////////////////////////////////////////////////////////////////////
#define NAND_MAX_PAGE_SIZE 2048 //定义NAND FLASH的最大的PAGE大小(不包括SPARE区),默认4096字节
#define NAND_ECC_SECTOR_SIZE 512 //执行ECC计算的单元大小,默认512字节
//NAND属性结构体
typedef struct
{
void (*init)(void);
uint16_t page_totalsize; //每页总大小,main区和spare区总和
uint16_t page_mainsize; //每页的main区大小
uint16_t page_sparesize; //每页的spare区大小
uint8_t block_pagenum; //每个块包含的页数量
uint16_t plane_blocknum; //每个plane包含的块数量
uint16_t block_totalnum; //总的块数量
uint16_t good_blocknum; //好块数量
uint16_t valid_blocknum; //有效块数量(供文件系统使用的好块数量)
uint32_t id; //NAND FLASH ID
uint16_t *lut; //LUT表,用作逻辑块-物理块转换
uint32_t ecc_hard; //硬件计算出来的ECC值
uint32_t ecc_hdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC硬件计算值缓冲区
uint32_t ecc_rdbuf[NAND_MAX_PAGE_SIZE/NAND_ECC_SECTOR_SIZE];//ECC读取的值缓冲区
}nand_attriute;
extern nand_attriute my_nand; //nand重要参数结构体
#define NAND_RB (((GPIOB->IDR) >> 13) & 0x1U)//NAND Flash的闲/忙引脚
#define NAND_ADDRESS 0X80000000 //nand flash的访问地址,接NCE3,地址为:0X8000 0000
#define NAND_CMD 1<<16 //发送命令
#define NAND_ADDR 1<<17 //发送地址
//NAND FLASH命令
#define NAND_READID 0X90 //读ID指令
#define NAND_FEATURE 0XEF //设置特性指令
#define NAND_RESET 0XFF //复位NAND
#define NAND_READSTA 0X70 //读状态
#define NAND_AREA_A 0X00
#define NAND_AREA_TRUE1 0X30
#define NAND_WRITE0 0X80
#define NAND_WRITE_TURE1 0X10
#define NAND_ERASE0 0X60
#define NAND_ERASE1 0XD0
#define NAND_MOVEDATA_CMD0 0X00
#define NAND_MOVEDATA_CMD1 0X35
#define NAND_MOVEDATA_CMD2 0X85
#define NAND_MOVEDATA_CMD3 0X10
//NAND FLASH状态
#define NSTA_READY 0X40 //nand已经准备好
#define NSTA_ERROR 0X01 //nand错误
#define NSTA_TIMEOUT 0X02 //超时
#define NSTA_ECC1BITERR 0X03 //ECC 1bit错误
#define NSTA_ECC2BITERR 0X04 //ECC 2bit以上错误
//NAND FLASH型号和对应的ID号
#define MT29F4G08ABADA 0XDC909556 //MT29F4G08ABADA
#define MT29F16G08ABABA 0X48002689 //MT29F16G08ABABA
#define W29N01GVSIAA 0XF1809500 //W29N01GVSIAA
#define W29N01HVSINA 0XF1009500 //W29N01HVSINA
//MPU相关设置
#define NAND_REGION_NUMBER MPU_REGION_NUMBER3 //NAND FLASH使用region0
#define NAND_ADDRESS_START 0X80000000 //NAND FLASH区的首地址
#define NAND_REGION_SIZE MPU_REGION_SIZE_256MB //NAND FLASH区大小
uint8_t NAND_Init(void);
uint8_t NAND_ModeSet(uint8_t mode);
uint32_t NAND_ReadID(void);
uint8_t NAND_ReadStatus(void);
uint8_t NAND_WaitForReady(void);
uint8_t NAND_Reset(void);
uint8_t NAND_WaitRB(volatile uint8_t rb);
void NAND_MPU_Config(void);
uint8_t NAND_ReadPage(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToRead);
uint8_t NAND_ReadPageComp(uint32_t PageNum,uint16_t ColNum,uint32_t CmpVal,uint16_t NumByteToRead,uint16_t *NumByteEqual);
uint8_t NAND_WritePage(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToWrite);
uint8_t NAND_WritePageConst(uint32_t PageNum,uint16_t ColNum,uint32_t cval,uint16_t NumByteToWrite);
uint8_t NAND_CopyPageWithoutWrite(uint32_t Source_PageNum,uint32_t Dest_PageNum);
uint8_t NAND_CopyPageWithWrite(uint32_t Source_PageNum,uint32_t Dest_PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToWrite);
uint8_t NAND_ReadSpare(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToRead);
uint8_t NAND_WriteSpare(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToRead);
uint8_t NAND_EraseBlock(uint32_t BlockNum);
void NAND_EraseChip(void);
uint16_t NAND_ECC_Get_OE(uint8_t oe,uint32_t eccval);
uint8_t NAND_ECC_Correction(uint8_t* data_buf,uint32_t eccrd,uint32_t ecccl);
#endif

@ -0,0 +1,57 @@
#ifndef __BSP_SDRAM_H
#define __BSP_SDRAM_H
#ifdef __cplusplus
extern "C" {
#endif
#include "fmc.h"
// extern uint32_t SDRAM_BANK_ADDR;
// extern void SDRAM_WriteBuffer(uint32_t *pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize);
// extern void SDRAM_ReadBuffer(uint32_t *pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize);
// extern uint8_t SDRAM_Test( uint32_t count);
#define Bank4_SDRAM_ADDR ((uint32_t)(0XD0000000))
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define FMC_BANK_SDRAM FMC_Bank2_SDRAM
#define FMC_COMMAND_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK2
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
typedef struct
{
void (*init)(void);
uint8_t (*test)( uint32_t );
}MY_SDRAM_TypeDef;
extern MY_SDRAM_TypeDef my_sdram;
void SDRAM_Init(void);
//void SDRAM_MPU_Config(void);
uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval);
void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t n);
void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t n);
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);
uint8_t SDRAM_Test(uint32_t count);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,117 @@
/**
****************************************************************************************************
* @file norflash.h
* @author
* @version V1.0
* @date 2021-10-26
* @brief NOR FLASH(25QXX)
* @license Copyright (c) 2020-2032
****************************************************************************************************
*/
#ifndef __BSP_SPIFLASH_H
#define __BSP_SPIFLASH_H
#include "main.h"
#include "spi.h"
/*
2022-7-27 W25Q256JV 32M spi flash没有问题
spi配置是 沿 ---> CPOL =0 CPOA=0 CPOL=1 CPOA=1
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
W25Q16JVSSIQ 2M spi flash没有问题
*/
/* SPI总线速度设置 */
#define SPI_SPEED_2 0
#define SPI_SPEED_4 1
#define SPI_SPEED_8 2
#define SPI_SPEED_16 3
#define SPI_SPEED_32 4
#define SPI_SPEED_64 5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7
/******************************************************************************************/
/* NORFLASH 片选 引脚 定义 */
// #define spiflash_CS_GPIO_PORT GPIOA
// #define spiflash_CS_GPIO_PIN GPIO_PIN_2
// #define spiflash_CS_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PI口时钟使能 */
/******************************************************************************************/
extern uint16_t g_spiflash_type; /* 定义FLASH芯片型号 */
/* NORFLASH 片选信号 */
#define spiflash_CS(x) do{ x ? \
HAL_GPIO_WritePin(SPI5_CS_GPIO_Port, SPI5_CS_Pin, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(SPI5_CS_GPIO_Port, SPI5_CS_Pin, GPIO_PIN_RESET); \
}while(0)
/* FLASH芯片列表 */
#define W25Q80 0XEF13 /* W25Q80 芯片ID */
#define W25Q16 0XEF14 /* W25Q16 芯片ID */
#define W25Q32 0XEF15 /* W25Q32 芯片ID */
#define W25Q64 0XEF16 /* W25Q64 芯片ID */
#define W25Q128 0XEF17 /* W25Q128 芯片ID */
#define W25Q256 0XEF18 /* W25Q256 芯片ID */
#define BY25Q64 0X6816 /* BY25Q64 芯片ID */
#define BY25Q128 0X6817 /* BY25Q128 芯片ID */
#define NM25Q64 0X5216 /* NM25Q64 芯片ID */
#define NM25Q128 0X5217 /* NM25Q128 芯片ID */
/* 指令表 */
#define FLASH_WriteEnable 0x06
#define FLASH_WriteDisable 0x04
#define FLASH_ReadStatusReg1 0x05
#define FLASH_ReadStatusReg2 0x35
#define FLASH_ReadStatusReg3 0x15
#define FLASH_WriteStatusReg1 0x01
#define FLASH_WriteStatusReg2 0x31
#define FLASH_WriteStatusReg3 0x11
#define FLASH_ReadData 0x03
#define FLASH_FastReadData 0x0B
#define FLASH_FastReadDual 0x3B
#define FLASH_FastReadQuad 0xEB
#define FLASH_PageProgram 0x02
#define FLASH_PageProgramQuad 0x32
#define FLASH_BlockErase 0xD8
#define FLASH_SectorErase 0x20
#define FLASH_ChipErase 0xC7
#define FLASH_PowerDown 0xB9
#define FLASH_ReleasePowerDown 0xAB
#define FLASH_DeviceID 0xAB
#define FLASH_ManufactDeviceID 0x90
#define FLASH_JedecDeviceID 0x9F
#define FLASH_Enable4ByteAddr 0xB7
#define FLASH_Exit4ByteAddr 0xE9
#define FLASH_SetReadParam 0xC0
#define FLASH_EnterQPIMode 0x38
#define FLASH_ExitQPIMode 0xFF
/* 静态函数 */
static void spiflash_wait_busy(void); /* 等待空闲 */
static void spiflash_send_address(uint32_t address);/* 发送地址 */
static void spiflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen); /* 写入page */
static void spiflash_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen); /* 写flash,不带擦除 */
/* 普通函数 */
void spiflash_init(void); /* 初始化25QXX */
uint16_t spiflash_read_id(void); /* 读取FLASH ID */
void spiflash_write_enable(void); /* 写使能 */
uint8_t spiflash_read_sr(uint8_t regno); /* 读取状态寄存器 */
void spiflash_write_sr(uint8_t regno,uint8_t sr); /* 写状态寄存器 */
void spiflash_erase_chip(void); /* 整片擦除 */
void spiflash_erase_sector(uint32_t saddr); /* 扇区擦除 */
void spiflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen); /* 读取flash */
void spiflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen); /* 写入flash */
void spi_flash_test();
#endif

@ -0,0 +1,143 @@
#ifndef __BSP_UART_H
#define __BSP_UART_H
#include "stm32f4xx.h"
/**
* 使 232 485 max3160
* GPIO操作
*
*/
/* 485 3160 启用一个, 两个接口都有 MAX3160_ENABLE */
#define MAX485_ENABLE 0
#define MAX3160_ENABLE 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "main.h"
// #if MAX3160_ENABLE
// #define DUPLEX_HALF 1
// #define DUPLEX_FULL 0
// #define SEL_485 1
// #define SEL_232 0
// #define ENABLE_485_Trans 1
// #define DISABLE_485_Trans 0
// # endif
// #if MAX485_ENABLE
// #define ENABLE_485_Trans 1
// #define DISABLE_485_Trans 0
// # endif
/* ----------------------- variables ---------------------------------*/
extern UART_HandleTypeDef huart3;
UART_HandleTypeDef *pMyUart = &huart3;
typedef void ( *enable_func) (void);
typedef int ( *callback_fun) (void *obj, void *buf, uint16_t size);
typedef struct
{
UART_HandleTypeDef *huart;
uint8_t interface_type; /* 0: common, 1: 485 ,2:3160*/
uint8_t enable_idle_it;
// #if MAX485_ENABLE
// GPIO_TypeDef *de485_gpio;
// uint16_t de485_pin;
// uint8_t de485;
// #endif
// #if MAX3160_ENABLE
// GPIO_TypeDef *de485_gpio;
// uint16_t de485_pin;
// GPIO_TypeDef *sel_gpio;
// GPIO_TypeDef *dplx_gpio;
// uint16_t sel_pin;
// uint16_t dplx_pin;
// uint8_t sel;
// uint8_t dplx;
// #endif
// uint8_t dplx;
// uint8_t sel;
// uint8_t de485;
uint8_t trans_mode; /* 0 :polling, 1: IT 2: DMA*/
// uint8_t *send_buf;
// uint16_t size_send;
// uint8_t *rcv_buf;
// uint16_t size_rcv;
volatile uint8_t send_flag;
volatile uint8_t send_tc_flag; /* 0 开始发送, 1 发送完成*/
// uint32_t timebase;
void (*enable_snd)(void);
void (*enable_rcv)(void);
void * obj;
callback_fun callback;
// 这个是供外部调用的; 中断是统一管理的, 中断会找到这里的接收回调,然后返回回去
}MYUART_TypeDef;
extern MYUART_TypeDef *myuart;
MYUART_TypeDef * Myuart_Init( );
void Myuart_Set_Huart(MYUART_TypeDef * myuart, UART_HandleTypeDef *huart);
int Myuart_Setup_Transmod( MYUART_TypeDef * myuart, uint8_t trans_mode );
int Myuart_Set_enable_snd_func( MYUART_TypeDef * myuart, enable_func enable_snd_func );
int Myuart_Set_enable_rcv_func( MYUART_TypeDef * myuart, enable_func enable_rcv_func);
int Myuart_Set_enable_idle( MYUART_TypeDef * myuart, uint8_t enable_idle);
int Myuart_Set_Callback( MYUART_TypeDef * myuart, void *obj, callback_fun func);
// void Myuart_Set_Sel_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin);
// void Myuart_Set_Dplx_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin);
// void Myuart_Set_DE485_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin);
// void Myuart_Set_232(MYUART_TypeDef * myuart);
// void Myuart_Set_485(MYUART_TypeDef * myuart);
int Myuart_Trans(MYUART_TypeDef * myuart, uint8_t *buf, uint16_t size);
// int __Myuart_Trans(MYUART_TypeDef * myuart , uint8_t *buf, uint16_t size);
int Myuart_Trans_TxCplt_Callback( MYUART_TypeDef * myuart );
/* 接收方式 也有三种类型 */
int Myuart_Start_Rcv(MYUART_TypeDef * myuart, uint8_t *buf, uint16_t size);
#endif
/*
485
enable rcv
HAL_GPIO_WritePin(myuart->de485_gpio, myuart->de485_pin, 0);
enable send
HAL_GPIO_WritePin(myuart->de485_gpio, myuart->de485_pin, 1);
3160 485 -- (232 - )
enable rcv
HAL_GPIO_WritePin(myuart->dplx_gpio, myuart->dplx_gpio , 1);
HAL_GPIO_WritePin(myuart->de485_gpio, myuart->de485_pin, 0);
enable send
HAL_GPIO_WritePin(myuart->dplx_gpio, myuart->dplx_gpio , 0);
HAL_GPIO_WritePin(myuart->de485_gpio, myuart->de485_pin, 1);
myuart = Myuart_Init();
Myuart_Set_Huart( myuart, phuart),
Myuart_Setup_Transmod( myuart, 2 );
Myuart_Set_enable_snd_func( myuart, NULL );
Myuart_Set_enable_rcv_func( myuart, NULL);
Myuart_Set_enable_idle( myuart, enable_idle);
Myuart_Set_enable_rcv_func( myuart, obj, (callback_fun) func);
*/

@ -0,0 +1,37 @@
#ifndef __FTL_H
#define __FTL_H
#include "stm32f4xx.h"
//升级说明
//V1.1 20160124
//修改FTL_CopyAndWriteToBlock和FTL_WriteSectors函数,提高非0XFF时的写入速度.
//V1.2 20160520
//1,修改FTL_ReadSectors,增加ECC出错判断,检测坏块处理,并增加多块连读,提高速度
//2,新增FTL_BlockCompare和FTL_SearchBadBlock函数,用于搜寻坏块
//3,修改FTL_Format坏块检测方式,增加FTL_USE_BAD_BLOCK_SEARCH宏
//V1.3 20160530
//修改当1bit ECC错误出现时,读取2次,来确认1bit 错误,以防错误的修改数据
//////////////////////////////////////////////////////////////////////////////////
//坏块搜索控制
//如果设置为1,将在FTL_Format的时候,搜寻坏块,耗时久(512M,3分钟以上),且会导致RGB屏乱闪
#define FTL_USE_BAD_BLOCK_SEARCH 0 //定义是否使用坏块搜索
uint8_t FTL_Init(void);
void FTL_BadBlockMark(uint32_t blocknum);
uint8_t FTL_CheckBadBlock(uint32_t blocknum);
uint8_t FTL_UsedBlockMark(uint32_t blocknum);
uint32_t FTL_FindUnusedBlock(uint32_t sblock,uint8_t flag);
uint32_t FTL_FindSamePlaneUnusedBlock(uint32_t sblock);
uint8_t FTL_CopyAndWriteToBlock(uint32_t Source_PageNum,uint16_t ColNum,uint8_t *pBuffer,uint32_t NumByteToWrite);
uint16_t FTL_LBNToPBN(uint32_t LBNNum);
uint8_t FTL_WriteSectors(uint8_t *pBuffer,uint32_t SectorNo,uint16_t SectorSize,uint32_t SectorCount);
uint8_t FTL_ReadSectors(uint8_t *pBuffer,uint32_t SectorNo,uint16_t SectorSize,uint32_t SectorCount);
uint8_t FTL_CreateLUT(uint8_t mode);
uint8_t FTL_BlockCompare(uint32_t blockx,uint32_t cmpval);
uint32_t FTL_SearchBadBlock(void);
uint8_t FTL_Format(void);
#endif

@ -0,0 +1,88 @@
#ifndef __MALLOC_H
#define __MALLOC_H
#include "stm32f4xx.h"
#ifndef NULL
#define NULL 0
#endif
#ifndef __MEMORY_AT
#define __MEMORY_AT(x) __attribute__((section(".#x")))
#endif
//定义两个内存池
#define SRAMIN 0 //内部内存池
#define SRAMEX 1 //外部内存池
// #define SRAMDISP 2 //外部内存池
#define SRAMBANK 2 //定义支持的SRAM块数.
//mem1内存参数设定.mem1完全处于内部SRAM里面.
#define MEM1_BLOCK_SIZE 32 //内存块大小为32字节
#define MEM1_MAX_SIZE 20*1024 //最大管理内存 40K
#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小
//mem2内存参数设定.mem2的内存池处于外部SRAM里面
#define MEM2_BLOCK_SIZE 32 //内存块大小为32字节
#define MEM2_MAX_SIZE 15*1024*1024 // 16M malloc不能分配
#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存表大小
//mem3内存参数设定.mem2的内存池处于外部SRAM里面
// #define MEM3_BLOCK_SIZE 32 //内存块大小为32字节
// #define MEM3_MAX_SIZE 1*1024*1024 // 16M malloc不能分配
// #define MEM3_ALLOC_TABLE_SIZE MEM3_MAX_SIZE/MEM3_BLOCK_SIZE //内存表大小
//内存管理控制器
struct _m_mallco_dev
{
void ( * init ) ( uint8_t ); //初始化
uint8_t ( * perused ) ( uint8_t ); //内存使用率
uint8_t * membase [ SRAMBANK ]; //内存池 管理SRAMBANK个区域的内存
uint16_t * memmap [ SRAMBANK ]; //内存管理状态表
uint8_t memrdy [ SRAMBANK ]; //内存管理是否就绪
};
extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义
void mymemset(void *s,uint8_t c,uint32_t count); //设置内存
void mymemcpy(void *des,void *src,uint32_t n); //复制内存
void my_mem_init(uint8_t memx); //内存管理初始化函数(外/内部调用)
uint32_t my_mem_malloc(uint8_t memx,uint32_t size); //内存分配(内部调用)
uint8_t my_mem_free(uint8_t memx,uint32_t offset); //内存释放(内部调用)
uint8_t my_mem_perused(uint8_t memx); //获得内存使用率(外/内部调用)
//用户调用函数
void myfree(uint8_t memx,void *ptr); //内存释放(外部调用)
void *mymalloc(uint8_t memx,uint32_t size); //内存分配(外部调用)
void *myrealloc(uint8_t memx,void *ptr,uint32_t size); //重新分配内存(外部调用)
#endif
/*
// // 初始化外部内存池
mallco_dev.init( SRAMEX );
uint8_t *malloc_ex_buf;
uint8_t *malloc_in_buf;
malloc_ex_buf=mymalloc(SRAMEX,512); //申请一个扇区的缓存
malloc_in_buf=mymalloc(SRAMIN,512); //申请一个扇区的缓存
if (malloc_ex_buf != NULL)
log_i("Malloc SRAMEX, Test OK ...");
if (malloc_in_buf != NULL)
log_i("Malloc SRAMIN, Test OK ...");
myfree(SRAMEX, malloc_ex_buf );
myfree(SRAMIN, malloc_in_buf );
log_i("Free SRAMEX SRAMIN, Test OK ...");
*/

@ -0,0 +1,99 @@
#include "bsp_dma2d.h"
#include "elog.h"
// uint8_t dma2d_transfering =0;
// DMA2D->CR & DMA2D_CR_START 可作为标记
void DMA2D_Fill( void * pDst, uint32_t width, uint32_t height, uint32_t lineOff, uint32_t pixelFormat, uint32_t color)
{
/* DMA2D配置 */
// DMA2D->CR = DMA2D_R2M; // 配置为寄存器到储存器模式
DMA2D->CR = 0x00030000UL; // 配置为寄存器到储存器模式
DMA2D->OCOLR = color; // 设置填充使用的颜色,格式应该与设置的颜色格式相同
DMA2D->OMAR = (uint32_t)pDst; // 填充区域的起始内存地址
DMA2D->OOR = lineOff; // 行偏移,即跳过的像素,注意是以像素为单位
DMA2D->OPFCCR = pixelFormat; // 设置颜色格式
DMA2D->NLR = (uint32_t)(width << 16) | (uint16_t)height; // 设置填充区域的宽和高,单位是像素
// 传输中断
// DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
// DMA2D->CR |= DMA2D_CR_START;
// 启动传输 阻塞 -- 阻塞一般用于清屏,R2M 模式
DMA2D->CR |= DMA2D_CR_START;
while (DMA2D->CR & DMA2D_CR_START) {}
}
void DMA2D_MemCopy(uint32_t pixelFormat, void * pSrc, void * pDst, int xSize, int ySize, int OffLineSrc, int OffLineDst)
{
/* DMA2D配置 */
// DMA2D->CR = DMA2D_M2M;
DMA2D->CR = 0x00000000UL;
DMA2D->FGMAR = (uint32_t)pSrc;
DMA2D->OMAR = (uint32_t)pDst;
DMA2D->FGOR = OffLineSrc;
DMA2D->OOR = OffLineDst;
DMA2D->FGPFCCR = pixelFormat;
DMA2D->FGPFCCR = pixelFormat;
DMA2D->NLR = (uint32_t)(xSize << 16) | (uint16_t)ySize;
// 传输中断 用于数据传输 M2M模式
// __HAL_DMA2D_ENABLE_IT(&hdma2d, DMA2D_IT_TC);
// DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
DMA2D->CR |= DMA2D_IT_TC;
DMA2D->CR |= DMA2D_CR_START;
// // 启动传输 阻塞
// DMA2D->CR |= DMA2D_CR_START;
// while (DMA2D->CR & DMA2D_CR_START) {}
}
void DMA2D_Blend(void* pFg, void* pBg, void* pDst,
uint32_t offlineFg, uint32_t offlineBg, uint32_t offlineDist,
uint16_t xSize, uint16_t ySize,
uint32_t pixelFormat, uint8_t opa) {
DMA2D->CR = 0x00020000UL; // 设置工作模式为存储器到存储器并带颜色混合
DMA2D->FGMAR = (uint32_t)pFg; // 设置前景数据内存地址
DMA2D->BGMAR = (uint32_t)pBg; // 设置背景数据内存地址
DMA2D->OMAR = (uint32_t)pDst; // 设置数据输出内存地址
DMA2D->FGOR = offlineFg; // 设置前景数据传输偏移
DMA2D->BGOR = offlineBg; // 设置背景数据传输偏移
DMA2D->OOR = offlineDist; // 设置数据输出传输偏移
DMA2D->NLR = (uint32_t)(xSize << 16) | (uint16_t)ySize; // 设置图像数据宽高(像素)
DMA2D->FGPFCCR = pixelFormat // 设置前景色颜色格式
| (1UL << 16) // 忽略前景颜色数据中的Alpha通道
| ((uint32_t)opa << 24); // 设置前景色不透明度
DMA2D->BGPFCCR = pixelFormat; // 设置背景颜色格式
DMA2D->OPFCCR = pixelFormat; // 设置输出颜色格式
/* 启动传输 */
DMA2D->CR |= DMA2D_CR_START;
/* 等待DMA2D传输完成 */
while (DMA2D->CR & DMA2D_CR_START) {}
}
void DMA2D_IRQHandler(void)
{
/* USER CODE BEGIN DMA2D_IRQn 0 */
if (DMA2D->CR &DMA2D_IT_TC){
log_i(" DMA2D_IRQHandler -> TC " );
DMA2D->CR &= ~DMA2D_CR_START;
DMA2D->CR &= ~DMA2D_IT_TC;
}
log_i(" ...... " );
// DMA2D->CR &= ~DMA2D_IT_TC;
/* USER CODE END DMA2D_IRQn 0 */
// HAL_DMA2D_IRQHandler(&hdma2d);
/* USER CODE BEGIN DMA2D_IRQn 1 */
/* USER CODE END DMA2D_IRQn 1 */
}

@ -0,0 +1,905 @@
#include "bsp_lcd.h"
#include "elog.h"
LCD_TypeDef cur_lcd = INCH_4_3;
LCD_DrawPropTypeDef DrawProp[2];
MY_LCD_TypeDef my_lcd = {
0, 0, // 宽度 高度
0, 4, // 横屏还是竖屏控制:0,竖屏;1,横屏,像素大小。
LTDC_PIXEL_FORMAT_ARGB8888, // PIXEL Format
LCD_COLOR_WHITE, // color
LCD_COLOR_BLACK, // back_color
NULL, // LCD_DrawPropTypeDef draw_prop[2];
0, // show_num_mode
0, //active layer
{LCD_BUF_ADDRESS,LCD_BUF_ADDRESS}, // Layer0 Addr
};
// static void LCD_Draw_Point(uint16_t x, uint16_t y, uint32_t color);
// static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
extern void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c);
void LCD_Init()
{
LTDC_Init();
// TODO my_lcd 调用LTDC画点,无需考虑坐标切换
LCD_DisplayDirection(1);
#if LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_ARGB8888 || LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_RGB888
my_lcd.pixelsize = 4; // 每个像素占4个字节
#else
my_lcd.pixelsize = 2; // 每个像素占2个字节
#endif
my_lcd.layeraddr[0] = LCD_BUF_ADDRESS;
my_lcd.layeraddr[1] = LCD_BUF_ADDRESS + my_lcd.width * my_lcd.height * my_lcd.pixelsize;
LCD_SetLayer(0, my_lcd.layeraddr[0] , my_lcd.color_format, LCD_COLOR_GREEN,255);
LCD_SetLayer(1, my_lcd.layeraddr[1], my_lcd.color_format, LCD_COLOR_GREEN,0);
LCD_Set_Active_layer(0);
LCD_Clear(LTDC_COLOR_GREEN); //清屏
LTDC_DISP_ON();
// LTDC_Display_Dir(1);
// my_lcd.width = my_ltdc.width;
// my_lcd.height = my_ltdc.height;
// my_lcd.activelayer = my_ltdc.activelayer;
// TODO 添加 DrawProp[2] 定义
my_lcd.draw_prop[0].BackColor = LCD_COLOR_WHITE; // 设置层的字体颜色
my_lcd.draw_prop[0].pFont = &Font16; // 设置层的字体类型
my_lcd.draw_prop[0].pCnFont = &CH_Font16; // 设置层的字体类型
my_lcd.draw_prop[0].TextColor = LCD_COLOR_BLACK; // 设置层的字体背景颜色
my_lcd.draw_prop[1].BackColor = LCD_COLOR_WHITE; // 设置层的字体颜色
my_lcd.draw_prop[1].pFont = &Font16; // 设置层的字体类型
my_lcd.draw_prop[1].pCnFont = &CH_Font16; // 设置层的字体类型
my_lcd.draw_prop[1].TextColor = LCD_COLOR_BLACK; // 设置层的字体背景颜色
}
void LCD_DisplayDirection(uint8_t dir){
my_lcd.dir = dir;
// my_ltdc.dir = dir; // 显示方向
if(dir==0) //竖屏
{
my_lcd.width=my_ltdc.pixel_height;
my_lcd.height=my_ltdc.pixel_width;
}else if(dir==1) //横屏
{
my_lcd.width=my_ltdc.pixel_width;
my_lcd.height=my_ltdc.pixel_height;
}
}
void LCD_Set_Active_layer( uint8_t layer_no )
{
my_lcd.activelayer = layer_no;
my_ltdc.activelayer = layer_no;
}
void LCD_SetLayer( uint8_t layer,uint32_t buf_addr, uint32_t layer_color_format,
uint32_t layer_back_color,uint8_t alpha )
{
LTDC_Layer_Parameter_Config( layer,buf_addr,my_lcd.color_format,alpha,
0,6,7,LCD_COLOR_GREEN);//层参数配置
LTDC_Layer_Window_Config(layer,0,0,my_ltdc.pixel_width,my_ltdc.pixel_height); //层窗口配置,以LCD面板坐标系为基准,不要随便修改!
}
/**
* @brief LCD当前层文字颜色
* @param Color:
* @retval
*/
void LCD_SetTextColor(uint32_t Color)
{
my_lcd.draw_prop[my_lcd.activelayer].TextColor = Color;
}
/**
* @brief LCD当前层文字颜色
* @retval
*/
uint32_t LCD_GetTextColor(void)
{
return my_lcd.draw_prop[my_lcd.activelayer].TextColor;
}
/**
* @brief LCD当前层的文字背景颜色
* @param Color:
* @retval
*/
void LCD_SetBackColor(uint32_t Color)
{
my_lcd.draw_prop[my_lcd.activelayer].BackColor = Color;
}
/**
* @brief LCD当前层的文字背景颜色
* @retval
*/
uint32_t LCD_GetBackColor(void)
{
return my_lcd.draw_prop[my_lcd.activelayer].BackColor;
}
/**
* @brief LCD文字的颜色和背景的颜色
* @param TextColor:
* @param BackColor:
* @retval
*/
void LCD_SetColors(uint32_t TextColor, uint32_t BackColor)
{
LCD_SetTextColor (TextColor);
LCD_SetBackColor (BackColor);
}
/**
* @brief LCD当前层显示的字体
* @param fonts:
* @retval None
*/
void LCD_SetFont(sFONT *fonts)
{
my_lcd.draw_prop[my_lcd.activelayer].pFont = fonts;
}
/**
* @brief LCD当前层显示的字体
* @retval
*/
sFONT *LCD_GetFont(void)
{
return my_lcd.draw_prop[my_lcd.activelayer].pFont;
}
/*******************************************************************************
*******************************************************************************/
// static void LCD_Draw_Point(uint16_t x, uint16_t y, uint32_t color)
// {
// LTDC_Draw_Point(x, y, color);
// }
//画点函数
//x,y:写入坐标
//color:颜色值
void LCD_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
{
if(my_lcd.dir) //横屏
{
*(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.width*y+x))=color;
}else //竖屏
{
*(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.height*(my_lcd.width-x)+y))=color;
// *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x)+y))=color;
}
}
//读点函数
//x,y:读取点的坐标
//返回值:颜色值
uint32_t LCD_Read_Point(uint16_t x,uint16_t y)
{
// return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x));
if(my_lcd.dir) //横屏
{
return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.width*y+x));
}else //竖屏
{
return *(uint32_t*)((uint32_t)my_lcd.layeraddr[my_lcd.activelayer]+my_lcd.pixelsize*(my_lcd.height*(my_lcd.width-x)+y));
}
}
/**
* @brief
* @param Xpos:
* @param Ypos:
* @param c:
* @retval
*/
void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c)
{
uint32_t i = 0, j = 0;
uint16_t height, width;
uint8_t offset;
uint8_t *pchar;
uint8_t tempchar;
uint32_t line;
uint8_t t,t1;
uint8_t y0 = Ypos;
height = my_lcd.draw_prop[my_lcd.activelayer].pFont->Height;//获取正在使用字体高度
width = my_lcd.draw_prop[my_lcd.activelayer].pFont->Width; //获取正在使用字体宽度
offset = 8 *((width + 7)/8) - width ;//计算字符的每一行像素的偏移值,实际存储大小-字体宽度
for(i = 0; i < height; i++)//遍历字体高度绘点
{
pchar = ((uint8_t *)c + (width + 7)/8 * i);//计算字符的每一行像素的偏移地址
switch( ((width + 7)/8) )//根据字体宽度来提取不同字体的实际像素值
{
case 1:
line = pchar[0]; //提取字体宽度小于8的字符的像素值
break;
case 2:
line = (pchar[0]<< 8) | pchar[1]; //提取字体宽度大于8小于16的字符的像素值
break;
case 3:
default:
line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; //提取字体宽度大于16小于24的字符的像素值
break;
}
for (j = 0; j < width; j++)//遍历字体宽度绘点
{
if( line & (1 << (width- j + offset- 1)) ) //根据每一行的像素值及偏移位置按照当前字体颜色进行绘点
{
LCD_Draw_Point((Xpos + j), Ypos, my_lcd.draw_prop[my_lcd.activelayer].TextColor);
}
else //如果这一行没有字体像素则按照背景颜色绘点
{
LCD_Draw_Point((Xpos + j), Ypos, my_lcd.draw_prop[my_lcd.activelayer].BackColor);
}
}
Ypos++;
}
}
/***************************************************************************************************************
* : LCD_DisplayChar
*
* : x - 0~799
* y - 0~479
* c - ASCII字符
*
* :
*
* : 1. 使 LCD_SetFont(&Font24) 2412ASCII字体
* 2. 使 LCD_SetColor(0xff0000FF)
* 3. 使 LCD_SetBackColor(0xff000000)
* 4. 使 LCD_DisplayChar( 10, 10, 'a') (10,10) 'a'
*
***************************************************************************************************************/
/**
* @brief
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Ascii: ascii , 0x20 0x7E
* @retval
*/
void LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii)
{
// DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\
// DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]);
DrawChar(Xpos, Ypos, &my_lcd.draw_prop[my_lcd.activelayer].pFont->table[(Ascii-' ') * \
my_lcd.draw_prop[my_lcd.activelayer].pFont->Height * \
((my_lcd.draw_prop[my_lcd.activelayer].pFont->Width + 7) / 8)] );
}
/**
* @brief
* @param Xpos: X轴起始坐标
* @param Ypos: Y轴起始坐标
* @param Text:
* @param Mode: CENTER_MODERIGHT_MODELEFT_MODE
* @retval None
*/
void LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode)
{
uint16_t ref_column = 1, i = 0;
uint32_t size = 0, xsize = 0;
uint8_t *ptr = Text;
/* 获取字符串大小 */
while (*ptr++) size ++ ;
/* 每一行可以显示字符的数量 */
xsize = (my_lcd.width/my_lcd.draw_prop[my_lcd.activelayer].pFont->Width);
switch (Mode)
{
case CENTER_MODE:
{
ref_column = Xpos + ((xsize - size)* my_lcd.draw_prop[my_lcd.activelayer].pFont->Width) / 2;
break;
}
case LEFT_MODE:
{
ref_column = Xpos;
break;
}
case RIGHT_MODE:
{
ref_column = - Xpos + ((xsize - size)*my_lcd.draw_prop[my_lcd.activelayer].pFont->Width);
break;
}
default:
{
ref_column = Xpos;
break;
}
}
/*检查起始行是否在显示范围内 */
if ((ref_column < 1) || (ref_column >= 0x8000))
{
ref_column = 1;
}
/* 使用字符显示函数显示每一个字符*/
while ( (*Text != 0) & (((my_lcd.width - (i*my_lcd.draw_prop[my_lcd.activelayer].pFont->Width)) & 0xFFFF) \
>= my_lcd.draw_prop[my_lcd.activelayer].pFont->Width) )
{
/* 显示一个字符 */
LCD_DisplayChar( ref_column, Ypos, *Text );
/* 根据字体大小计算下一个偏移位置 */
ref_column += my_lcd.draw_prop[my_lcd.activelayer].pFont->Width;
/* 指针指向下一个字符 */
Text++;
i++;
}
}
/**
* @brief (60)
* @param Line:
* @param ptr:
* @retval
*/
void LCD_DisplayStringLine(uint16_t Line, uint8_t *ptr)
{
LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE);
}
void LCD_DisplayNumber( uint16_t Line, int32_t number, uint8_t len)
{
char Number_Buffer[15]; // 用于存储转换后的字符串
// if( LCD.ShowNum_Mode == Fill_Zero) // 多余位补0
if( my_lcd.show_num_mode ==0) // 多余位补0
{
sprintf( Number_Buffer , "%0.*d",len, number ); // 将 number 转换成字符串,便于显示
}
else // 多余位补空格
{
sprintf( Number_Buffer , "%*d",len, number ); // 将 number 转换成字符串,便于显示
}
LCD_DisplayStringAt(0, LINE(Line), (char *)Number_Buffer , LEFT_MODE) ; // 将转换得到的字符串显示出来
}
/***************************************************************************************************************************************
* : LCD_DisplayDecimals
*
* : x - 0~799
* y - 0~479
* decimals - , double型取值1.7 x 10^-308~ 1.7 x 10^+30815~16
*
* len -
* 1 -123.123 len <=8 -123.123
* 2 -123.123 len =10 -123.123()
* 3 -123.123 len =10 LCD_ShowNumMode() 0 -00123.123
*
* decs -
* 1.12345 decs 41.1235
*
* :
*
* : 1. 使 LCD_SetTextFont(&CH_Font24) 24242412ASCII字符字体
* 2. 使 LCD_SetColor(0xff0000FF)
* 3. 使 LCD_SetBackColor(0xff000000)
* 4. 使 LCD_DisplayDecimals( 10, 10, a, 5, 3) (10,10)a,53
*
*****************************************************************************************************************************************/
void LCD_DisplayDecimals( uint16_t Line, double decimals, uint8_t len, uint8_t decs)
{
char Number_Buffer[20]; // 用于存储转换后的字符串
// if( LCD.ShowNum_Mode == Fill_Zero) // 多余位填充0模式
if( my_lcd.show_num_mode ==0) // 多余位补0
{
sprintf( Number_Buffer , "%0*.*lf",len,decs, decimals ); // 将 number 转换成字符串,便于显示
}
else // 多余位填充空格
{
sprintf( Number_Buffer , "%*.*lf",len,decs, decimals ); // 将 number 转换成字符串,便于显示
}
LCD_DisplayStringAt(0, LINE(Line), (char *)Number_Buffer, LEFT_MODE) ; // 将转换得到的字符串显示出来
}
/**
* @brief
* @param usX X坐标
* @param usY Y坐标
* @param usChar
* @retval
*/
void LCD_DispChar_CH (uint16_t Xpos, uint16_t Ypos, uint16_t Text)
{
uint32_t i = 0, j = 0;
uint16_t height, width;
uint8_t offset;
uint8_t *pchar;
// uint8_t Buffer[HEIGHT_CH_CHAR*3];
uint8_t Buffer[HEIGHT_CH_CHAR*3];
uint32_t line;
GetGBKCode (Buffer, Text ); // TODO 获得Buffer
// height = HEIGHT_CH_CHAR;//取字模数据//获取正在使用字体高度
// width = WIDTH_CH_CHAR; //获取正在使用字体宽度
height = my_lcd.draw_prop[my_lcd.activelayer].pCnFont->Height;//获取正在使用字体高度
width = my_lcd.draw_prop[my_lcd.activelayer].pCnFont->Width; //获取正在使用字体宽度
offset = 8 *((width + 7)/8) - width ;//计算字符的每一行像素的偏移值,实际存储大小-字体宽度
for(i = 0; i < height; i++)//遍历字体高度绘点
{
pchar = ((uint8_t *)Buffer + (width + 7)/8 * i);//计算字符的每一行像素的偏移地址
switch(((width + 7)/8))//根据字体宽度来提取不同字体的实际像素值
{
case 1:
line = pchar[0]; //提取字体宽度小于8的字符的像素值
break;
case 2:
line = (pchar[0]<< 8) | pchar[1]; //提取字体宽度大于8小于16的字符的像素值
break;
case 3:
default:
line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; //提取字体宽度大于16小于24的字符的像素值
break;
}
for (j = 0; j < width; j++)//遍历字体宽度绘点
{
if(line & (1 << (width- j + offset- 1))) //根据每一行的像素值及偏移位置按照当前字体颜色进行绘点
{
LCD_Draw_Point((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor);
}
else//如果这一行没有字体像素则按照背景颜色绘点
{
LCD_Draw_Point((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor);
}
}
Ypos++;
}
}
/**
* @brief
Font24格式
* @param Line: LINE(0) - LINE(N)
* @param *ptr:
* @retval None
*/
void LCD_DisplayStringLine_EN_CH(uint16_t Line, uint8_t *ptr)
{
uint16_t refcolumn = 0;
/* 判断显示位置不能超出液晶的边界 */
while ((refcolumn < LCD_PIXEL_WIDTH) && ((*ptr != 0) & (((refcolumn + DrawProp[ActiveLayer].pFont->Width) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)))
{
/* 使用LCD显示一个字符 */
if ( * ptr <= 126 ) //英文字符
{
LCD_DisplayChar(refcolumn, LINE(Line), *ptr);
/* 根据字体偏移显示的位置 */
refcolumn += DrawProp[ActiveLayer].pFont->Width;
/* 指向字符串中的下一个字符 */
ptr++;
}
else //汉字字符
{
uint16_t usCh;
/*一个汉字两字节*/
usCh = * ( uint16_t * ) ptr;
/*交换编码顺序*/
usCh = ( usCh << 8 ) + ( usCh >> 8 );
/*显示汉字*/
LCD_DispChar_CH ( refcolumn,LINE(Line) , usCh );
/*显示位置偏移*/
refcolumn += WIDTH_CH_CHAR;
/* 指向字符串中的下一个字符 */
ptr += 2;
}
}
}
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
curpixel = 0;
deltax = ABS(x2 - x1); /* 求x轴的绝对值 */
deltay = ABS(y2 - y1); /* 求y轴的绝对值 */
x = x1; /* 第一个像素的x坐标起始值 */
y = y1; /* 第一个像素的y坐标起始值 */
if (x2 >= x1) /* x坐标值为递增 */
{
xinc1 = 1;
xinc2 = 1;
}
else /* x坐标值为递减 */
{
xinc1 = -1;
xinc2 = -1;
}
if (y2 >= y1) /* y坐标值为递增 */
{
yinc1 = 1;
yinc2 = 1;
}
else /* y坐标值为递减 */
{
yinc1 = -1;
yinc2 = -1;
}
if (deltax >= deltay) /* 每个 y 坐标值至少有一个x坐标值*/
{
xinc1 = 0; /* 当分子大于或等于分母时不要改变 x */
yinc2 = 0; /* 不要为每次迭代更改 y */
den = deltax;
num = deltax / 2;
num_add = deltay;
num_pixels = deltax; /* x比y多的值 */
}
else /* 每个 x 坐标值至少有一个y坐标值 */
{
xinc2 = 0; /* 不要为每次迭代更改 x */
yinc1 = 0; /* 当分子大于或等于分母时不要改变 y */
den = deltay;
num = deltay / 2;
num_add = deltax;
num_pixels = deltay; /* y比x多的值 */
}
for (curpixel = 0; curpixel <= num_pixels; curpixel++)
{
LCD_Draw_Point(x, y, DrawProp[my_ltdc.activelayer].TextColor); /* 绘制当前像素点 */
num += num_add; /* 在分数的基础上增加分子 */
if (num >= den) /* 检查分子大于或等于分母 */
{
num -= den; /* 计算新的分子值 */
x += xinc1; /* x值递增 */
y += yinc1; /* y值递增 */
}
x += xinc2; /* y值递增 */
y += yinc2; /* y值递增 */
}
}
/**
* @brief
* @param x1: X坐标值
* @param y1: Y坐标值
* @param x2: X坐标值
* @param y2: Y坐标值
* @param x3: X坐标值
* @param y3: Y坐标值
* @retval
*/
void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3)
{
int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
curpixel = 0;
deltax = ABS(x2 - x1); /* 求x轴的绝对值 */
deltay = ABS(y2 - y1); /* 求y轴的绝对值 */
x = x1; /* 第一个像素的x坐标起始值 */
y = y1; /* 第一个像素的y坐标起始值 */
if (x2 >= x1) /* x坐标值为递增*/
{
xinc1 = 1;
xinc2 = 1;
}
else /* x坐标值为递减 */
{
xinc1 = -1;
xinc2 = -1;
}
if (y2 >= y1) /* y坐标值为递增*/
{
yinc1 = 1;
yinc2 = 1;
}
else /* y坐标值为递减 */
{
yinc1 = -1;
yinc2 = -1;
}
if (deltax >= deltay) /* 每个 y 坐标值至少有一个x坐标值*/
{
xinc1 = 0; /* 当分子大于或等于分母时不要改变 x */
yinc2 = 0; /* 不要为每次迭代更改 y */
den = deltax;
num = deltax / 2;
num_add = deltay;
num_pixels = deltax; /* x比y多的值 */
}
else /* 每个 x 坐标值至少有一个y坐标值 */
{
xinc2 = 0; /* 不要为每次迭代更改 x */
yinc1 = 0; /* 当分子大于或等于分母时不要改变 y */
den = deltay;
num = deltay / 2;
num_add = deltax;
num_pixels = deltay; /* y比x多的值 */
}
for (curpixel = 0; curpixel <= num_pixels; curpixel++)
{
LCD_DrawLine(x, y, x3, y3);
num += num_add; /* 在分数的基础上增加分子 */
if (num >= den) /* 判断分子是否大于或等于分母 */
{
num -= den; /* 计算新的分子值 */
x += xinc1; /* x值递增 */
y += yinc1; /* y值递增 */
}
x += xinc2; /* x值递增 */
y += yinc2; /* y值递增 */
}
}
// 画矩形
//(x1,y1),(x2,y2):矩形的对角坐标
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
LCD_DrawLine(x1, y1, x2, y1);
LCD_DrawLine(x1, y1, x1, y2);
LCD_DrawLine(x1, y2, x2, y2);
LCD_DrawLine(x2, y1, x2, y2);
}
// 在指定位置画一个指定大小的圆
//(x,y):中心点
// r :半径
void LCD_DrawCircle(uint16_t x, uint16_t y, uint16_t r)
{
int Xadd = -r, Yadd = 0, err = 2-2*r, e2;
do {
LCD_Draw_Point(x-Xadd,y+Yadd,my_lcd.color);
LCD_Draw_Point(x+Xadd,y+Yadd,my_lcd.color);
LCD_Draw_Point(x+Xadd,y-Yadd,my_lcd.color);
LCD_Draw_Point(x-Xadd,y-Yadd,my_lcd.color);
e2 = err;
if (e2 <= Yadd) {
err += ++Yadd*2+1;
if (-Xadd == Yadd && e2 <= Xadd) e2 = 0;
}
if (e2 > Xadd) err += ++Xadd*2+1;
}
while (Xadd <= 0);
}
// 在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
// color:要填充的颜色
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
// TODO: 未测试正确
uint32_t offline;
uint32_t address;
offline = my_lcd.width - (ex-sx+1);
address = my_lcd.layeraddr[my_lcd.activelayer] + my_lcd.pixelsize*(sy*my_lcd.width +sx);
// DMA2D->CR = 0x00030000UL; // 配置为寄存器到储存器模式
// DMA2D->OCOLR = color; // 设置填充使用的颜色,格式应该与设置的颜色格式相同
// DMA2D->OMAR = (uint32_t)address; // 填充区域的起始内存地址
// DMA2D->OOR = offline; // 行偏移,即跳过的像素,注意是以像素为单位
// DMA2D->OPFCCR = my_lcd.color_format; // 设置颜色格式
// DMA2D->NLR = (uint32_t)( (ex-sx+1) << 16) | (uint16_t)(ey-sy+1); // 设置填充区域的宽和高,单位是像素
// // 传输中断
// // DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
// // DMA2D->CR |= DMA2D_CR_START;
// // 启动传输 阻塞 -- 阻塞一般用于清屏,R2M 模式
// DMA2D->CR |= DMA2D_CR_START;
// while (DMA2D->CR & DMA2D_CR_START) {}
DMA2D_Fill(address, (ex-sx+1), (ey-sy+1), offline, my_lcd.color_format, color);
}
// 在指定区域内填充指定颜色块
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
// color:要填充的颜色
// 注意两个地址的offline
void LCD_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
// LTDC_Color_Fill(sx, sy, ex, ey, color);
uint32_t offline;
offline = my_lcd.width - (ex-sx+1);
DMA2D_MemCopy(my_lcd.color_format,
color, (uint32_t)my_lcd.layeraddr[my_lcd.activelayer],
(ex-sx+1), (ey-sy+1), offline, offline );
}
void LCD_Clear( uint32_t color)
{
LCD_Fill( 0, 0, my_lcd.width, my_lcd.height, color );
}
/***************************************************************************************************************************************
* : LCD_FillRect
*
* : x - 0~799
* y - 0~479
* width - 800
* height - 480
*
* : (x,y)
*
* : 1. 使DMA2D实现
* 2.
*
*****************************************************************************************************************************************/
void LCD_FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
DMA2D->CR &= ~(DMA2D_CR_START); // 停止DMA2D
DMA2D->CR = DMA2D_R2M; // 寄存器到SDRAM
DMA2D->OPFCCR = my_lcd.color_format; // 设置颜色格式
DMA2D->OCOLR = my_lcd.color; // 颜色
// if(my_lcd.dir == 1) //横屏填充
// {
// DMA2D->OOR = my_lcd.width - width; // 设置行偏移
// DMA2D->OMAR = my_ltdc.layeraddr[my_ltdc.activelayer] + LCD.BytesPerPixel*(my_lcd.width * y + x); // 地址;
// DMA2D->NLR = (width<<16)|(height); // 设定长度和宽度
// }
// else //竖屏填充
// {
// DMA2D->OOR = my_lcd.width - height; // 设置行偏移
// DMA2D->OMAR = my_ltdc.layeraddr[my_ltdc.activelayer] + LCD.BytesPerPixel*((my_lcd.height - x - 1 - width)*LCD_Width + y); // 地址
// DMA2D->NLR = (width)|(height<<16); // 设定长度和宽度
// }
DMA2D->OOR = my_lcd.width - width; // 设置行偏移
DMA2D->OMAR = my_lcd.layeraddr[my_lcd.activelayer] + my_lcd.pixelsize*(my_lcd.width * y + x); // 地址;
DMA2D->NLR = (width<<16)|(height); // 设定长度和宽度
DMA2D->CR |= DMA2D_CR_START; // 启动DMA2D
while (DMA2D->CR & DMA2D_CR_START) ; // 等待传输完成
}
/***************************************************************************************************************************************
* : LCD_FillCircle
*
* : x - 0~799
* y - 0~479
* r -
*
* : (x,y) r
*
* : 1. ST官方评估板的例程
* 2.
*
*****************************************************************************************************************************************/
void LCD_FillCircle(uint16_t x, uint16_t y, uint16_t r)
{
int32_t D; /* Decision Variable */
uint32_t CurX;/* Current X Value */
uint32_t CurY;/* Current Y Value */
D = 3 - (r << 1);
CurX = 0;
CurY = r;
while (CurX <= CurY)
{
if(CurY > 0)
{
LCD_DrawLine(x - CurX, y - CurY,x - CurX,y - CurY + 2*CurY);
LCD_DrawLine(x + CurX, y - CurY,x + CurX,y - CurY + 2*CurY);
}
if(CurX > 0)
{
LCD_DrawLine(x - CurY, y - CurX,x - CurY,y - CurX + 2*CurX);
LCD_DrawLine(x + CurY, y - CurX,x + CurY,y - CurX + 2*CurX);
}
if (D < 0)
{
D += (CurX << 2) + 6;
}
else
{
D += ((CurX - CurY) << 2) + 10;
CurY--;
}
CurX++;
}
LCD_DrawCircle(x, y, r);
}
/***************************************************************************************************************************************
* : LCD_DrawImage
*
* : x - 0~799
* y - 0~479
* width - 800
* height - 480
* *pImage -
*
* :
*
* : 使 LCD_SetColor()
*
*****************************************************************************************************************************************/
void LCD_DrawImage(uint16_t x,uint16_t y,uint16_t width,uint16_t height,const uint8_t *pImage)
{
uint8_t disChar; //字模的值
uint16_t Xaddress = x; //水平坐标
uint16_t i=0,j=0,m=0;
for(i = 0; i <height; i++)
{
for(j = 0; j <(float)width/8; j++)
{
disChar = *pImage;
for(m = 0; m < 8; m++)
{
if(disChar & 0x01)
{
LCD_Draw_Point(Xaddress,y,my_lcd.color); //当前模值不为0时,使用画笔色绘点
}
else
{
LCD_Draw_Point(Xaddress,y,my_lcd.color); //否则使用背景色绘制点
}
disChar >>= 1;
Xaddress++; //水平坐标自加
if( (Xaddress - x)==width ) //如果水平坐标达到了字符宽度,则退出当前循环
{ //进入下一行的绘制
Xaddress = x;
y++;
break;
}
}
pImage++;
}
}
}

@ -0,0 +1,882 @@
#include "bsp_ltdc.h"
#include "elog.h"
uint8_t *DISP_BUF[2];
extern LTDC_HandleTypeDef hltdc;
LTDC_HandleTypeDef *Ltdc_Handler = &hltdc;
// LCD_DrawPropTypeDef DrawProp[2]; // 每层的渲染参数
static void LCD_GPIO_Config(void);
MY_LTDC_TypeDef my_ltdc = {
// 0, 0, 0, 0, // 像素宽 像素高 宽度 高度
0, 0, // 像素宽 像素高
// 0,4, // 横屏还是竖屏控制:0,竖屏;1,横屏,像素大小。
0, 0, 0, 0, 0, 0,
//hsw HSYNC宽度 ,vsw VSYNC宽度
// hbp HSYNC后的无效像素, vbp VSYNC后的无效行数
//hfp HSYNC前的无效像素 ,vfp,/VSYNC前的无效行数
0xFFFF, //LCD ID
0, //activelayer
// {LCD_BUF_ADDRESS,LCD_BUF_ADDRESS}, // Layer_Addr
};
// LTDC初始化函数
void LTDC_Init(void)
{
if (Ltdc_Handler->State != HAL_LTDC_STATE_RESET)
{
HAL_LTDC_MspDeInit(Ltdc_Handler); // 去初始化
HAL_Delay(200);
}
if (my_ltdc.id == 0xFFFF)
{
LTDC_PanelID_Read();
}
RCC_PeriphCLKInitTypeDef periph_clk_init_struct;
__HAL_RCC_LTDC_CLK_ENABLE(); // 使能LTDC时钟
__HAL_RCC_DMA2D_CLK_ENABLE(); // 使能LTDC时钟
HAL_LTDC_MspInit(Ltdc_Handler);
// TODO 不同方向会导致 消隐变化??
Ltdc_Handler->Instance = LTDC;
Ltdc_Handler->Init.HorizontalSync = my_ltdc.hsw-1;
Ltdc_Handler->Init.VerticalSync = my_ltdc.vsw-1;
Ltdc_Handler->Init.AccumulatedHBP = my_ltdc.hsw + my_ltdc.hbp-1;
Ltdc_Handler->Init.AccumulatedVBP = my_ltdc.vsw + my_ltdc.vbp-1;
Ltdc_Handler->Init.AccumulatedActiveW = my_ltdc.hsw + my_ltdc.hbp + my_ltdc.pixel_width -1;
Ltdc_Handler->Init.AccumulatedActiveH = my_ltdc.vsw + my_ltdc.vbp+ my_ltdc.pixel_height -1;
Ltdc_Handler->Init.TotalWidth = my_ltdc.hsw + my_ltdc.hbp + my_ltdc.pixel_width + my_ltdc.hfp -1;
Ltdc_Handler->Init.TotalHeigh = my_ltdc.vsw + my_ltdc.vbp+ my_ltdc.pixel_height + my_ltdc.vfp -1;
LTDC_Clk_Set(60, 2,4);
// periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
// periph_clk_init_struct.PLLSAI.PLLSAIN = 60;
// periph_clk_init_struct.PLLSAI.PLLSAIR = 2;
// periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
// HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct);
Ltdc_Handler->Init.HSPolarity = LTDC_HSPOLARITY_AL;
Ltdc_Handler->Init.VSPolarity = LTDC_VSPOLARITY_AL;
Ltdc_Handler->Init.DEPolarity = LTDC_DEPOLARITY_AL;
Ltdc_Handler->Init.PCPolarity = LTDC_PCPOLARITY_IPC;
// if(my_ltdc.id==0X1018)LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IIPC;//像素时钟极性
// else LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC; //像素时钟极性
Ltdc_Handler->Init.Backcolor.Blue = 0;
Ltdc_Handler->Init.Backcolor.Green = 0;
Ltdc_Handler->Init.Backcolor.Red = 0;
/* 初始化LCD的像素宽度和高度 */
Ltdc_Handler->LayerCfg->ImageWidth = my_ltdc.pixel_width;
Ltdc_Handler->LayerCfg->ImageHeight = my_ltdc.pixel_height;
/* 设置LCD背景层的颜色,默认黑色 */
Ltdc_Handler->Init.Backcolor.Red = 0;
Ltdc_Handler->Init.Backcolor.Green = 0;
Ltdc_Handler->Init.Backcolor.Blue = 0;
HAL_LTDC_Init(Ltdc_Handler);
// #if LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_ARGB8888 || LCD_PIXFORMAT == LTDC_PIXEL_FORMAT_RGB888
// my_ltdc.pixelsize = 4; // 每个像素占4个字节
// #else
// my_ltdc.pixelsize = 2; // 每个像素占2个字节
// #endif
// my_ltdc.layeraddr[0] = LCD_BUF_ADDRESS;
// my_ltdc.layeraddr[1] = LCD_BUF_ADDRESS + my_ltdc.pixel_width * my_ltdc.pixel_height * my_ltdc.pixelsize;
// my_ltdc.width = my_ltdc.pixel_width;
// my_ltdc.height = my_ltdc.pixel_height;
//层配置
// LTDC_Layer_Parameter_Config(0,(uint32_t)my_ltdc.layeraddr[0],LCD_PIXFORMAT,255,0,6,7,LTDC_COLOR_GREEN);//层参数配置
// LTDC_Layer_Window_Config(0,0,0,my_ltdc.pixel_width,my_ltdc.pixel_height); //层窗口配置,以LCD面板坐标系为基准,不要随便修改!
// LTDC_Display_Dir(1); // 0竖屏 1横屏
// LTDC_Select_Layer(0); //选择第1层
// LTDC_Clear(LTDC_COLOR_GREEN); //清屏
// LTDC_DISP_ON()
LTDC_Enable_Line_IT( my_ltdc.vsw+my_ltdc.vbp+my_ltdc.pixel_height-1 ); // 行中断设置, 参考寄存器编程开启行中断方法
}
// LTDC时钟(Fdclk)设置函数
// Fvco=Fin*pllsain;
// Fdclk=Fvco/pllsair/2*2^pllsaidivr=Fin*pllsain/pllsair/2*2^pllsaidivr;
// Fvco:VCO频率
// Fin:输入时钟频率一般为1Mhz(来自系统时钟PLLM分频后的时钟,见时钟树图)
// pllsain:SAI时钟倍频系数N,取值范围:50~432.
// pllsair:SAI时钟的分频系数R,取值范围:2~7
// pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2^(pllsaidivr+1)
// 假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
// 例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
// Fdclk=1*396/3/2*2^1=396/12=33Mhz
// 返回值:0,成功;1,失败。
uint8_t LTDC_Clk_Set(uint32_t pllsain, uint32_t pllsair, uint32_t pllsaidivr)
{
RCC_PeriphCLKInitTypeDef PeriphClkIniture;
//LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC; //LTDC时钟
PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;
PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
PeriphClkIniture.PLLSAIDivR=pllsaidivr;
if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkIniture)==HAL_OK) //配置像素时钟
{
return 0; //成功
}
else return 1; //失败
}
// LTDC,层窗口设置,窗口以LCD面板坐标系为基准
// 注意:此函数必须在LTDC_Layer_Parameter_Config之后再设置.另外,当设置的窗口值不等于面板的尺
// 寸时,GRAM的操作(读/写点函数),也要根据窗口的宽高来进行修改,否则显示不正常(本例程就未做修改).
// layerx:层值,0/1.
// sx,sy:起始坐标
// width,height:宽度和高度
void LTDC_Layer_Window_Config(uint8_t layerx, uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
HAL_LTDC_SetWindowPosition(Ltdc_Handler, sx, sy, layerx); //设置窗口的位置
HAL_LTDC_SetWindowSize(Ltdc_Handler, width, height, layerx);//设置窗口大小
}
// LTDC,基本参数设置.
// 注意:此函数,必须在LTDC_Layer_Window_Config之前设置.
// layerx:层值,0/1.
// bufaddr:层颜色帧缓存起始地址
// pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
// alpha:层颜色Alpha值,0,全透明;255,不透明
// alpha0:默认颜色Alpha值,0,全透明;255,不透明
// bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
// bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
// bkcolor:层默认颜色,32位,低24位有效,RGB888格式
// 返回值:无
void LTDC_Layer_Parameter_Config(uint8_t layerx, uint32_t bufaddr, uint8_t pixformat, uint8_t alpha, uint8_t alpha0, uint8_t bfac1, uint8_t bfac2, uint32_t bkcolor)
{
LTDC_LayerCfgTypeDef pLayerCfg;
pLayerCfg.WindowX0=0; //窗口起始X坐标
pLayerCfg.WindowY0=0; //窗口起始Y坐标
pLayerCfg.WindowX1=my_ltdc.pixel_width; //窗口终止X坐标
pLayerCfg.WindowY1=my_ltdc.pixel_height; //窗口终止Y坐标
pLayerCfg.PixelFormat=pixformat; //像素格式
pLayerCfg.Alpha=alpha; //Alpha值设置,0~255,255为完全不透明
pLayerCfg.Alpha0=alpha0; //默认Alpha值
pLayerCfg.BlendingFactor1=(uint32_t)bfac1<<8; //设置层混合系数
pLayerCfg.BlendingFactor2=(uint32_t)bfac2<<8; //设置层混合系数
pLayerCfg.FBStartAdress=bufaddr; //设置层颜色帧缓存起始地址
pLayerCfg.ImageWidth=my_ltdc.pixel_width; //设置颜色帧缓冲区的宽度
pLayerCfg.ImageHeight=my_ltdc.pixel_height; //设置颜色帧缓冲区的高度
pLayerCfg.Backcolor.Red=(uint8_t)(bkcolor&0X00FF0000)>>16; //背景颜色红色部分
pLayerCfg.Backcolor.Green=(uint8_t)(bkcolor&0X0000FF00)>>8; //背景颜色绿色部分
pLayerCfg.Backcolor.Blue=(uint8_t)bkcolor&0X000000FF; //背景颜色蓝色部分
HAL_LTDC_ConfigLayer( Ltdc_Handler,&pLayerCfg,layerx); //设置所选中的层
}
// 开关指定层
// layerx:层号;0,第一层;1,第二层;
// sw:1,打开;0,关闭
void LTDC_Layer_Switch(uint8_t layerx, uint8_t on_off)
{
if(on_off==1) __HAL_LTDC_LAYER_ENABLE(Ltdc_Handler,layerx);
else if(on_off==0) __HAL_LTDC_LAYER_DISABLE(Ltdc_Handler,layerx);
__HAL_LTDC_RELOAD_CONFIG(Ltdc_Handler);
}
void LTDC_Enable_Line_IT(uint16_t line)
{
// 配置LTDC行中断
LTDC->LIPCR = line;//配置行中断的行数为最后一行
// LTDC->IER |=LTDC_IER_LIE; //使能LTDC行中断
// LTDC->SRCR |= (1<<1);
}
// 读取面板参数
// PG6=R7(M0);PI2=G7(M1);PB9=B7(M2);
// M2:M1:M0
// 0 :0 :0 //4.3寸480*272 RGB屏,ID=0X4342
// 0 :0 :1 //7寸800*480 RGB屏,ID=0X7084
// 0 :1 :0 //7寸1024*600 RGB屏,ID=0X7016
// 0 :1 :1 //7寸1280*800 RGB屏,ID=0X7018
// 1 :0 :0 //4.3寸800*480 RGB屏,ID=0X4384
// 1 :0 :1 //10.1寸1280*800 RGB屏,ID=0X1018
// 返回值:LCD ID:0,非法;其他值,ID;
uint16_t LTDC_PanelID_Read(void)
{
uint8_t idx = 0;
GPIO_InitTypeDef GPIO_InitStruct;
// RCC->AHB1ENR|=1<<6|1<<8|1<<1; //使能PG/PI时钟
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
idx = HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6); // 读取M1
idx |= HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_2) << 1; // 读取M0
idx |= HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) << 2; // 读取M2
switch (idx)
{
case 0:
my_ltdc.id = 0X4342;
break;
case 1:
my_ltdc.id = 0X7084;
break;
case 2:
my_ltdc.id = 0X7016;
break;
case 3:
my_ltdc.id = 0X7018;
break;
case 4:
my_ltdc.id = 0X4384;
break;
case 5:
my_ltdc.id = 0X1018;
break;
default:
my_ltdc.id = 0xFFFF;
break;
}
// TODO :hsw hbp反了 vsw vbp反了 4342已改
if (my_ltdc.id == 0X4342)
{
my_ltdc.pixel_width = 480; // 面板宽度,单位:像素
my_ltdc.pixel_height = 272; // 面板高度,单位:像素
my_ltdc.hsw = 41; // 水平同步宽度
my_ltdc.vsw = 10; // 垂直同步宽度
my_ltdc.hbp = 8; // 水平后廊
my_ltdc.vbp = 2; // 垂直后廊
// my_ltdc.hsw = 8; // 水平同步宽度
// my_ltdc.vsw = 2; // 垂直同步宽度
// my_ltdc.hbp = 41; // 水平后廊
// my_ltdc.vbp = 10; // 垂直后廊
my_ltdc.hfp = 4; // 水平前廊
my_ltdc.vfp = 4; // 垂直前廊
// LTDC_Clk_Set(288,4,2); //设置像素时钟 9Mhz
return my_ltdc.id;
}
else if (my_ltdc.id == 0X7084)
{
my_ltdc.pixel_width = 800; // 面板宽度,单位:像素
my_ltdc.pixel_height = 480; // 面板高度,单位:像素
my_ltdc.hsw = 1; // 水平同步宽度
my_ltdc.vsw = 1; // 垂直同步宽度
my_ltdc.hbp = 46; // 水平后廊
my_ltdc.vbp = 23; // 垂直后廊
my_ltdc.hfp = 210; // 水平前廊
my_ltdc.vfp = 22; // 垂直前廊
// LTDC_Clk_Set(396,3,1); //设置像素时钟 33M(如果开双显,需要降低DCLK到:18.75Mhz 300/4/4,才会比较好)
return my_ltdc.id;
}
else if (my_ltdc.id == 0X7016)
{
my_ltdc.pixel_width = 1024; // 面板宽度,单位:像素
my_ltdc.pixel_height = 600; // 面板高度,单位:像素
my_ltdc.hsw = 20; // 水平同步宽度
my_ltdc.vsw = 3; // 垂直同步宽度
my_ltdc.hbp = 140; // 水平后廊
my_ltdc.vbp = 20; // 垂直后廊
my_ltdc.hfp = 160; // 水平前廊
my_ltdc.vfp = 12; // 垂直前廊
// LTDC_Clk_Set(360,2,1); //设置像素时钟 45Mhz
return my_ltdc.id;
}
else if (my_ltdc.id == 0X7018)
{
my_ltdc.pixel_width = 1280; // 面板宽度,单位:像素
my_ltdc.pixel_height = 800; // 面板高度,单位:像素
// 其他参数待定.
}
else if (my_ltdc.id == 0X4384)
{
my_ltdc.pixel_width = 800; // 面板宽度,单位:像素
my_ltdc.pixel_height = 480; // 面板高度,单位:像素
my_ltdc.hbp = 88; // 水平后廊
my_ltdc.hfp = 40; // 水平前廊
my_ltdc.hsw = 48; // 水平同步宽度
my_ltdc.vbp = 32; // 垂直后廊
my_ltdc.vfp = 13; // 垂直前廊
my_ltdc.vsw = 3; // 垂直同步宽度
// LTDC_Clk_Set(396,3,1); //设置像素时钟 33M
return my_ltdc.id;
// 其他参数待定.
}
else if (my_ltdc.id == 0X1018) // 10.1寸1280*800 RGB屏
{
my_ltdc.pixel_width = 1280; // 面板宽度,单位:像素
my_ltdc.pixel_height = 800; // 面板高度,单位:像素
my_ltdc.hbp = 140; // 水平后廊
my_ltdc.hfp = 10; // 水平前廊
my_ltdc.hsw = 10; // 水平同步宽度
my_ltdc.vbp = 10; // 垂直后廊
my_ltdc.vfp = 10; // 垂直前廊
my_ltdc.vsw = 3; // 垂直同步宽度
LTDC_Clk_Set(360, 2, 1); // 设置像素时钟 45Mhz
return my_ltdc.id;
}
return 0XFFFF;
}
void LTDC_IRQHandler(void)
{
log_i(" LTDC_IRQHandler ..... ");
HAL_LTDC_IRQHandler(Ltdc_Handler);
}
// void LCD_LayerInit(uint16_t LayerIndex, uint32_t FB_Address,uint32_t PixelFormat)
// {
// LTDC_LayerCfgTypeDef layer_cfg;
// /* 层初始化 */
// layer_cfg.WindowX0 = 0; //窗口起始位置X坐标
// layer_cfg.WindowX1 = 480; //窗口结束位置X坐标
// layer_cfg.WindowY0 = 0; //窗口起始位置Y坐标
// layer_cfg.WindowY1 = 272; //窗口结束位置Y坐标
// layer_cfg.PixelFormat = PixelFormat; //像素格式
// layer_cfg.FBStartAdress = FB_Address; //层显存首地址
// layer_cfg.Alpha = 255; //用于混合的透明度常量,范围(0—255)0为完全透明
// layer_cfg.Alpha0 = 0; //默认透明度常量,范围(0—255)0为完全透明
// layer_cfg.Backcolor.Blue = 0; //层背景颜色蓝色分量
// layer_cfg.Backcolor.Green = 0; //层背景颜色绿色分量
// layer_cfg.Backcolor.Red = 0; //层背景颜色红色分量
// layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;//层混合系数1
// layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;//层混合系数2
// layer_cfg.ImageWidth = 480;//设置图像宽度
// layer_cfg.ImageHeight = 272;//设置图像高度
// HAL_LTDC_ConfigLayer(Ltdc_Handler, &layer_cfg, LayerIndex); //设置选中的层参数
// DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;//设置层的字体颜色
// DrawProp[LayerIndex].pFont = &LCD_DEFAULT_FONT;//设置层的字体类型
// DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; //设置层的字体背景颜色
// __HAL_LTDC_RELOAD_CONFIG(Ltdc_Handler);//重载层的配置参数
// }
// // 选择层
// // layerx:层号;0,第一层;1,第二层;
// void LTDC_Select_Layer(uint8_t layerx)
// {
// my_ltdc.activelayer = layerx;
// }
// // 设置LCD显示方向
// // dir:0,竖屏;1,横屏
// void LTDC_Display_Dir(uint8_t dir)
// {
// my_ltdc.dir = dir; // 显示方向
// if(dir==0) //竖屏
// {
// my_ltdc.width=my_ltdc.pixel_height;
// my_ltdc.height=my_ltdc.pixel_width;
// }else if(dir==1) //横屏
// {
// my_ltdc.width=my_ltdc.pixel_width;
// my_ltdc.height=my_ltdc.pixel_height;
// }
// }
// LTDC填充矩形,DMA2D填充
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
// 注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
// color:要填充的颜色
// void LTDC_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
// {
// uint32_t psx, psy, pex, pey; // 以LCD面板为基准的坐标系,不随横竖屏变化而变化
// uint32_t timeout = 0;
// uint16_t offline;
// uint32_t addr;
// // 坐标系转换
// if (my_ltdc.dir) // 横屏
// {
// psx = sx;
// psy = sy;
// pex = ex;
// pey = ey;
// }
// else // 竖屏
// {
// psx = sy;
// psy = my_ltdc.height - ex - 1;
// pex = ey;
// pey = my_ltdc.height - sx - 1;
// }
// offline = my_ltdc.width - (pex - psx + 1);
// addr = my_ltdc.layeraddr[my_ltdc.activelayer] + my_ltdc.pixelsize * (my_ltdc.width * psy + psx);
// RCC->AHB1ENR |= 1 << 23; // 使能DM2D时钟
// DMA2D->CR &= ~(1 << 0); // 先停止DMA2D
// DMA2D->CR = 3 << 16; // 寄存器到存储器模式
// DMA2D->OPFCCR = LCD_PIXFORMAT; // 设置颜色格式
// DMA2D->OOR = offline; // 设置行偏移
// DMA2D->OMAR = addr; // 输出存储器地址
// DMA2D->NLR = (pey - psy + 1) | ((pex - psx + 1) << 16); // 设定行数寄存器
// DMA2D->OCOLR = color; // 设定输出颜色寄存器
// // // 启动传输 阻塞
// DMA2D->CR |= 1 << 0; // 启动DMA2D
// while ((DMA2D->ISR & (1 << 1)) == 0) // 等待传输完成
// {
// timeout++;
// if (timeout > 0X1FFFFF)
// break; // 超时退出
// }
// DMA2D->IFCR |= 1 << 1; // 清除传输完成标志
// 传输中断 用于数据传输 M2M模式
// DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
// DMA2D->CR |= DMA2D_CR_START;
// }
// 在指定区域内填充指定颜色块,DMA2D填充
// 此函数仅支持uint16_t,RGB565格式的颜色数组填充.
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
// 注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
// color:要填充的颜色数组首地址
// void LTDC_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
// {
// uint32_t psx, psy, pex, pey; // 以LCD面板为基准的坐标系,不随横竖屏变化而变化
// uint32_t timeout = 0;
// uint16_t offline;
// uint32_t addr;
// // 坐标系转换
// if (my_ltdc.dir) // 横屏
// {
// psx = sx;
// psy = sy;
// pex = ex;
// pey = ey;
// }
// else // 竖屏
// {
// psx = sy;
// psy = my_ltdc.height - ex - 1;
// pex = ey;
// pey = my_ltdc.height - sx - 1;
// }
// offline = my_ltdc.width - (pex - psx + 1);
// // if (my_ltdc.activelayer == 0)
// // {
// // addr = my_ltdc.layeraddr[0] + my_ltdc.pixelsize * (my_ltdc.width * psy + psx);
// // }
// // else
// // {
// // addr = my_ltdc.layeraddr[0] + my_ltdc.pixelsize * (my_ltdc.width * psy + psx);
// // }
// addr = my_ltdc.layeraddr[my_ltdc.activelayer] + my_ltdc.pixelsize * (my_ltdc.width * psy + psx);
// RCC->AHB1ENR |= 1 << 23; // 使能DM2D时钟
// DMA2D->CR &= ~(1 << 0); // 先停止DMA2D
// DMA2D->CR = 0 << 16; // 存储器到存储器模式
// DMA2D->FGPFCCR = LCD_PIXFORMAT; // 设置颜色格式
// DMA2D->FGOR = 0; // 前景层行偏移为0
// DMA2D->OOR = offline; // 设置行偏移
// DMA2D->FGMAR = (uint32_t)color; // 源地址
// DMA2D->OMAR = addr; // 输出存储器地址
// DMA2D->NLR = (pey - psy + 1) | ((pex - psx + 1) << 16); // 设定行数寄存器
// // // 启动传输 阻塞
// // DMA2D->CR |= 1 << 0; // 启动DMA2D
// // while ((DMA2D->ISR & (1 << 1)) == 0) // 等待传输完成
// // {
// // timeout++;
// // if (timeout > 0X1FFFFF)
// // break; // 超时退出
// // }
// // DMA2D->IFCR |= 1 << 1; // 清除传输完成标志
// // 传输中断 用于数据传输 M2M模式
// DMA2D->CR |= DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE;
// DMA2D->CR |= DMA2D_CR_START;
// // // 启动传输 阻塞
// // DMA2D->CR |= DMA2D_CR_START;
// // while (DMA2D->CR & DMA2D_CR_START) {}
// }
// LCD清屏
// color:颜色值
// void LTDC_Clear(uint32_t color)
// {
// LTDC_Fill(0, 0, my_ltdc.width-1, my_ltdc.height-1, color);
// }
// void LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency)
// {
// HAL_LTDC_SetAlpha(Ltdc_Handler, Transparency, LayerIndex);
// }
// if (my_ltdc.id == 0X4342)
// {
// LTDC_Clk_Set(288, 4, 2); // 设置像素时钟 9Mhz
// }
// else if (my_ltdc.id == 0X7084)
// {
// LTDC_Clk_Set(396, 3, 1); // 设置像素时钟 33M(如果开双显,需要降低DCLK到:18.75Mhz 300/4/4,才会比较好)
// }
// else if (my_ltdc.id == 0X7016)
// {
// LTDC_Clk_Set(360, 2, 1); // 设置像素时钟 45Mhz
// }
// else if (my_ltdc.id == 0X7018)
// {
// // 其他参数待定.
// }
// else if (my_ltdc.id == 0X4384)
// {
// LTDC_Clk_Set(396, 3, 1); // 设置像素时钟 33M
// // 其他参数待定.
// }
// else if (my_ltdc.id == 0X1018) // 10.1寸1280*800 RGB屏
// {
// LTDC_Clk_Set(360, 2, 1); // 设置像素时钟 45Mhz
// }
// tempreg = 0 << 28; // 像素时钟极性:不反向
// if (my_ltdc.id == 0X1018)
// tempreg = 1 << 28; // 像素时钟极性:反向
// tempreg |= 0 << 29; // 数据使能极性:低电平有效
// tempreg |= 0 << 30; // 垂直同步极性:低电平有效
// tempreg |= 0 << 31; // 水平同步极性:低电平有效
// LTDC->GCR = tempreg; // 设置全局控制寄存器
// tempreg = (my_ltdc.vsw - 1) << 0; // 垂直脉宽-1
// tempreg |= (my_ltdc.hsw - 1) << 16; // 水平脉宽-1
// LTDC->SSCR = tempreg; // 设置同步大小配置寄存器
// tempreg = (my_ltdc.vsw + my_ltdc.vbp - 1) << 0; // 累加垂直后沿=垂直脉宽+垂直后沿-1
// tempreg |= (my_ltdc.hsw + my_ltdc.hbp - 1) << 16; // 累加水平后沿=水平脉宽+水平后沿-1
// LTDC->BPCR = tempreg; // 设置后沿配置寄存器
// tempreg = (my_ltdc.vsw + my_ltdc.vbp + my_ltdc.height - 1) << 0; // 累加有效高度=垂直脉宽+垂直后沿+垂直分辨率-1
// tempreg |= (my_ltdc.hsw + my_ltdc.hbp + my_ltdc.width - 1) << 16; // 累加有效宽度=水平脉宽+水平后沿+水平分辨率-1
// LTDC->AWCR = tempreg; // 设置有效宽度配置寄存器
// tempreg = (my_ltdc.vsw + my_ltdc.vbp + my_ltdc.height + my_ltdc.vfp - 1) << 0; // 总高度=垂直脉宽+垂直后沿+垂直分辨率+垂直前廊-1
// tempreg |= (my_ltdc.hsw + my_ltdc.hbp + my_ltdc.width + my_ltdc.hfp - 1) << 16; // 总宽度=水平脉宽+水平后沿+水平分辨率+水平前廊-1
// LTDC->TWCR = tempreg; // 设置总宽度配置寄存器
// LTDC->BCCR = LCD_COLOR_GREEN; // 设置背景层颜色寄存器(RGB888格式)
// static void LCD_GPIO_Config(void)
// {
// GPIO_InitTypeDef GPIO_InitStruct;
// /* 使能LCD使用到的引脚时钟 */
// //红色数据线
// LTDC_R0_GPIO_CLK_ENABLE();LTDC_R1_GPIO_CLK_ENABLE();LTDC_R2_GPIO_CLK_ENABLE();\
// LTDC_R3_GPIO_CLK_ENABLE();LTDC_R4_GPIO_CLK_ENABLE();LTDC_R5_GPIO_CLK_ENABLE();\
// LTDC_R6_GPIO_CLK_ENABLE();LTDC_R7_GPIO_CLK_ENABLE();LTDC_G0_GPIO_CLK_ENABLE();\
// LTDC_G1_GPIO_CLK_ENABLE();LTDC_G2_GPIO_CLK_ENABLE();LTDC_G3_GPIO_CLK_ENABLE();\
// LTDC_G3_GPIO_CLK_ENABLE();LTDC_G5_GPIO_CLK_ENABLE();LTDC_G6_GPIO_CLK_ENABLE();\
// LTDC_G7_GPIO_CLK_ENABLE();LTDC_B0_GPIO_CLK_ENABLE();LTDC_B1_GPIO_CLK_ENABLE();\
// LTDC_B2_GPIO_CLK_ENABLE();LTDC_B3_GPIO_CLK_ENABLE();LTDC_B4_GPIO_CLK_ENABLE();\
// LTDC_B5_GPIO_CLK_ENABLE();LTDC_B6_GPIO_CLK_ENABLE();LTDC_B7_GPIO_CLK_ENABLE();\
// LTDC_CLK_GPIO_CLK_ENABLE();LTDC_HSYNC_GPIO_CLK_ENABLE();LTDC_VSYNC_GPIO_CLK_ENABLE();\
// LTDC_DE_GPIO_CLK_ENABLE();LTDC_DISP_GPIO_CLK_ENABLE();LTDC_BL_GPIO_CLK_ENABLE();
// /* GPIO配置 */
// /* 红色数据线 */
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
// GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
// GPIO_InitStruct.Pull = GPIO_PULLUP;
// GPIO_InitStruct.Pin = LTDC_R0_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R0_AF;
// HAL_GPIO_Init(LTDC_R0_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R1_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R1_AF;
// HAL_GPIO_Init(LTDC_R1_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R2_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R2_AF;
// HAL_GPIO_Init(LTDC_R2_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R3_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R3_AF;
// HAL_GPIO_Init(LTDC_R3_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R4_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R4_AF;
// HAL_GPIO_Init(LTDC_R4_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R5_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R5_AF;
// HAL_GPIO_Init(LTDC_R5_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R6_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R6_AF;
// HAL_GPIO_Init(LTDC_R6_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_R7_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_R7_AF;
// HAL_GPIO_Init(LTDC_R7_GPIO_PORT, &GPIO_InitStruct);
// //绿色数据线
// GPIO_InitStruct.Pin = LTDC_G0_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G0_AF;
// HAL_GPIO_Init(LTDC_G0_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G1_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G1_AF;
// HAL_GPIO_Init(LTDC_G1_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G2_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G2_AF;
// HAL_GPIO_Init(LTDC_G2_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G3_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G3_AF;
// HAL_GPIO_Init(LTDC_G3_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G4_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G4_AF;
// HAL_GPIO_Init(LTDC_G4_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G5_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G5_AF;
// HAL_GPIO_Init(LTDC_G5_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G6_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G6_AF;
// HAL_GPIO_Init(LTDC_G6_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_G7_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_G7_AF;
// HAL_GPIO_Init(LTDC_G7_GPIO_PORT, &GPIO_InitStruct);
// //蓝色数据线
// GPIO_InitStruct.Pin = LTDC_B0_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B0_AF;
// HAL_GPIO_Init(LTDC_B0_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B1_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B1_AF;
// HAL_GPIO_Init(LTDC_B1_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B2_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B2_AF;
// HAL_GPIO_Init(LTDC_B2_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B3_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B3_AF;
// HAL_GPIO_Init(LTDC_B3_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B4_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B4_AF;
// HAL_GPIO_Init(LTDC_B4_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B5_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B5_AF;
// HAL_GPIO_Init(LTDC_B5_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B6_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B6_AF;
// HAL_GPIO_Init(LTDC_B6_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_B7_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_B7_AF;
// HAL_GPIO_Init(LTDC_B7_GPIO_PORT, &GPIO_InitStruct);
// //控制信号线
// GPIO_InitStruct.Pin = LTDC_CLK_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_CLK_AF;
// HAL_GPIO_Init(LTDC_CLK_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_HSYNC_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_HSYNC_AF;
// HAL_GPIO_Init(LTDC_HSYNC_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_VSYNC_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_VSYNC_AF;
// HAL_GPIO_Init(LTDC_VSYNC_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_DE_GPIO_PIN;
// GPIO_InitStruct.Alternate = LTDC_DE_AF;
// HAL_GPIO_Init(LTDC_DE_GPIO_PORT, &GPIO_InitStruct);
// //背光BL 及液晶使能信号DISP
// GPIO_InitStruct.Pin = LTDC_DISP_GPIO_PIN;
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_InitStruct.Pull = GPIO_PULLUP;
// HAL_GPIO_Init(LTDC_DISP_GPIO_PORT, &GPIO_InitStruct);
// GPIO_InitStruct.Pin = LTDC_BL_GPIO_PIN;
// HAL_GPIO_Init(LTDC_BL_GPIO_PORT, &GPIO_InitStruct);
// }
// RCC_PeriphCLKInitTypeDef periph_clk_init_struct;
// __HAL_RCC_LTDC_CLK_ENABLE(); // 使能LTDC时钟
// __HAL_RCC_DMA2D_CLK_ENABLE(); // 使能DMA2D时钟
// /* 初始化LCD引脚 */
// HAL_LTDC_MspInit(Ltdc_Handler);
// // LCD_GPIO_Config();
// /* 初始化SDRAM 用作LCD 显存*/
// // SDRAM_Init();
// /* 配置LTDC参数 */
// Ltdc_Handler->Instance = LTDC;
// /* 配置行同步信号宽度(HSW-1) */
// Ltdc_Handler->Init.HorizontalSync =hsw-1;
// /* 配置垂直同步信号宽度(VSW-1) */
// Ltdc_Handler->Init.VerticalSync = vsw-1;
// /* 配置(HSW+HBP-1) */
// Ltdc_Handler->Init.AccumulatedHBP = hsw+hbp-1;
// /* 配置(VSW+VBP-1) */
// Ltdc_Handler->Init.AccumulatedVBP = vsw+vbp-1;
// /* 配置(HSW+HBP+有效像素宽度-1) */
// Ltdc_Handler->Init.AccumulatedActiveW = hsw+hbp+480-1;
// /* 配置(VSW+VBP+有效像素高度-1) */
// Ltdc_Handler->Init.AccumulatedActiveH = vsw+vbp+272-1;
// /* 配置总宽度(HSW+HBP+有效像素宽度+HFP-1) */
// Ltdc_Handler->Init.TotalWidth =hsw+ hbp+480 + hfp-1;
// /* 配置总高度(VSW+VBP+有效像素高度+VFP-1) */
// Ltdc_Handler->Init.TotalHeigh =vsw+ vbp+272 + vfp-1;
// /* 液晶屏时钟配置 */
// /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
// /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
// /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */
// /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */
// periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
// periph_clk_init_struct.PLLSAI.PLLSAIN = 60;
// periph_clk_init_struct.PLLSAI.PLLSAIR = 2;
// periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_4;
// HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct);
// /* 初始化LCD的像素宽度和高度 */
// Ltdc_Handler->LayerCfg->ImageWidth = 480;
// Ltdc_Handler->LayerCfg->ImageHeight = 272;
// /* 设置LCD背景层的颜色,默认黑色 */
// Ltdc_Handler->Init.Backcolor.Red = 0;
// Ltdc_Handler->Init.Backcolor.Green = 0;
// Ltdc_Handler->Init.Backcolor.Blue = 0;
// /* 极性配置 */
// /* 初始化行同步极性,低电平有效 */
// Ltdc_Handler->Init.HSPolarity = LTDC_HSPOLARITY_AL;
// /* 初始化场同步极性,低电平有效 */
// Ltdc_Handler->Init.VSPolarity = LTDC_VSPOLARITY_AL;
// /* 初始化数据有效极性,低电平有效 */
// Ltdc_Handler->Init.DEPolarity = LTDC_DEPOLARITY_AL;
// /* 初始化行像素时钟极性,同输入时钟 */
// Ltdc_Handler->Init.PCPolarity = LTDC_PCPOLARITY_IPC;
// HAL_LTDC_Init(Ltdc_Handler);
// /* 初始化字体 */
// // LCD_SetFont(&LCD_DEFAULT_FONT);
// uint32_t tempreg = 0;
// //画点函数
// //x,y:写入坐标
// //color:颜色值
// void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
// {
// #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
// if(my_ltdc.dir) //横屏
// {
// *(uint32_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x))=color;
// }else //竖屏
// {
// *(uint32_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x)+y))=color;
// }
// #else
// if(my_ltdc.dir) //横屏
// {
// *(uint16_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x))=color;
// }else //竖屏
// {
// *(uint16_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x-1)+y))=color;
// }
// #endif
// }
// //读点函数
// //x,y:读取点的坐标
// //返回值:颜色值
// uint32_t LTDC_Read_Point(uint16_t x,uint16_t y)
// {
// #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
// if(my_ltdc.dir) //横屏
// {
// return *(uint32_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x));
// }else //竖屏
// {
// return *(uint32_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x)+y));
// }
// #else
// if(my_ltdc.dir) //横屏
// {
// return *(uint16_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*y+x));
// }else //竖屏
// {
// return *(uint16_t*)((uint32_t)my_ltdc.layeraddr[my_ltdc.activelayer]+my_ltdc.pixelsize*(my_ltdc.pixel_width*(my_ltdc.pixel_height-x-1)+y));
// }
// #endif
// }

@ -0,0 +1,722 @@
#include "bsp_nand.h"
#include "stm32f4xx.h"
#include "stm32f4xx_hal_nand.h"
extern NAND_HandleTypeDef hnand2;
NAND_HandleTypeDef *NAND_Handler = &hnand2; //NAND FLASH句柄
static void HAL_NAND_MspInit_Control_IO(NAND_HandleTypeDef *hnand);
nand_attriute my_nand = {
NAND_Init,
0,0,0,0,0,0,0,0,
0xFFFFFFFF, //id
NULL, // Lut
0,
NULL,
NULL,
}; //nand重要参数结构体
/**
* @brief
* @param
* @retval None
*/
static void NAND_Delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for(index = ( nCount); index != 0; index--)
{
}
}
//初始化NAND FLASH
uint8_t NAND_Init(void)
{
FMC_NAND_PCC_TimingTypeDef ComSpaceTiming ;
FMC_NAND_PCC_TimingTypeDef AttSpaceTiming;
// NAND_MPU_Config();
NAND_Handler->Instance=FMC_Bank2_3;
NAND_Handler->Init.NandBank=FMC_NAND_BANK3; //NAND挂在BANK3上
NAND_Handler->Init.Waitfeature=FMC_NAND_PCC_WAIT_FEATURE_DISABLE; //关闭等待特性
NAND_Handler->Init.MemoryDataWidth=FMC_NAND_PCC_MEM_BUS_WIDTH_8; //8位数据宽度
NAND_Handler->Init.EccComputation=FMC_NAND_ECC_DISABLE; //禁止ECC
NAND_Handler->Init.ECCPageSize=FMC_NAND_ECC_PAGE_SIZE_512BYTE; //ECC页大小为512字节
NAND_Handler->Init.TCLRSetupTime=8; //设置TCLR(tCLR=CLE到RE的延时)=(TCLR+TSET+2)*THCLK,THCLK=1/180M=5.5ns
NAND_Handler->Init.TARSetupTime=8; //设置TAR(tAR=ALE到RE的延时)=(TAR+TSET+2)*THCLK,THCLK=1/180M=5.5ns
ComSpaceTiming.SetupTime=8; //建立时间
ComSpaceTiming.WaitSetupTime=8; //等待时间
ComSpaceTiming.HoldSetupTime=8; //保持时间
ComSpaceTiming.HiZSetupTime=8; //高阻态时间
AttSpaceTiming.SetupTime=8; //建立时间
AttSpaceTiming.WaitSetupTime=8; //等待时间
AttSpaceTiming.HoldSetupTime=8; //保持时间
AttSpaceTiming.HiZSetupTime=8; //高阻态时间
// TODO: add Nand Control IO
HAL_NAND_MspInit_Control_IO(NAND_Handler );
HAL_NAND_Init(NAND_Handler,&ComSpaceTiming,&AttSpaceTiming);
NAND_Reset(); //复位NAND
NAND_Delay(100);
my_nand.id=NAND_ReadID(); //读取ID
// printf("NAND ID:%#x\r\n",my_nand.id); // 前面log_i 出来
NAND_ModeSet(4); //设置为MODE4,高速模式
if(my_nand.id==MT29F16G08ABABA) //NAND为MT29F16G08ABABA
{
my_nand.page_totalsize=4320;
my_nand.page_mainsize=4096;
my_nand.page_sparesize=224;
my_nand.block_pagenum=128;
my_nand.plane_blocknum=2048;
my_nand.block_totalnum=4096;
}
else if(my_nand.id==W29N01GVSIAA)//NAND为W29N01GVSIAA
{
my_nand.page_totalsize=2112;
my_nand.page_mainsize=2048;
my_nand.page_sparesize=64;
my_nand.block_pagenum=64;
my_nand.plane_blocknum=1024;
my_nand.block_totalnum=2048;
}else if (my_nand.id==W29N01HVSINA)
{
my_nand.page_totalsize=2112;
my_nand.page_mainsize=2048;
my_nand.page_sparesize=64;
my_nand.block_pagenum=64;
my_nand.plane_blocknum=1024;
my_nand.block_totalnum=1024;
}
else return 1; //错误,返回
return 0;
}
// NAND FALSH底层驱动,引脚配置,时钟使能
// 此函数会被HAL_NAND_Init()调用
// IO : PB13 R/B, PG9 CE, PD4 PD5 PD11 PD12
static void HAL_NAND_MspInit_Control_IO(NAND_HandleTypeDef *hnand)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_FMC_CLK_ENABLE(); //使能FMC时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
// __HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟
__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG时钟
//初始化PB13 R/B引脚
GPIO_Initure.Pin=GPIO_PIN_13;
GPIO_Initure.Mode=GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
//初始化PG9 NCE3引脚
GPIO_Initure.Pin=GPIO_PIN_9;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //输入
GPIO_Initure.Pull=GPIO_NOPULL; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF12_FMC; //复用为FMC
HAL_GPIO_Init(GPIOG,&GPIO_Initure);
GPIO_Initure.Pin= GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12;
GPIO_Initure.Pull=GPIO_NOPULL;
HAL_GPIO_Init(GPIOD,&GPIO_Initure);
//初始化PD0,1,4,5,11,12,14,15
// GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|\
// GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_14|GPIO_PIN_15;
// GPIO_Initure.Pull=GPIO_NOPULL;
// HAL_GPIO_Init(GPIOD,&GPIO_Initure);
// //初始化PE7,8,9,10
// GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
// HAL_GPIO_Init(GPIOE,&GPIO_Initure);
}
//配置MPU的region
void NAND_MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_Initure;
HAL_MPU_Disable(); //配置MPU之前先关闭MPU,配置完成以后在使能MPU
//配置RAM为region1,大小为256MB,此区域可读写
MPU_Initure.Enable=MPU_REGION_ENABLE; //使能region
MPU_Initure.Number=NAND_REGION_NUMBER; //设置region,NAND使用的region0
MPU_Initure.BaseAddress=NAND_ADDRESS_START; //region基地址
MPU_Initure.Size=NAND_REGION_SIZE; //region大小
MPU_Initure.SubRegionDisable=0X00;
MPU_Initure.TypeExtField=MPU_TEX_LEVEL0;
MPU_Initure.AccessPermission=MPU_REGION_FULL_ACCESS; //此region可读写
MPU_Initure.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE; //允许读取此区域中的指令
MPU_Initure.IsShareable=MPU_ACCESS_NOT_SHAREABLE;
MPU_Initure.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;
MPU_Initure.IsBufferable=MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_Initure);
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); //开启MPU
}
//读取NAND FLASH的ID
//返回值:0,成功;
// 其他,失败
uint8_t NAND_ModeSet(uint8_t mode)
{
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_FEATURE;//发送设置特性命令
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=0X01; //地址为0X01,设置mode
*(__IO uint8_t*)NAND_ADDRESS=mode; //P1参数,设置mode
*(__IO uint8_t*)NAND_ADDRESS=0;
*(__IO uint8_t*)NAND_ADDRESS=0;
*(__IO uint8_t*)NAND_ADDRESS=0;
if(NAND_WaitForReady()==NSTA_READY)return 0;//成功
else return 1; //失败
}
//读取NAND FLASH的ID
//不同的NAND略有不同,请根据自己所使用的NAND FALSH数据手册来编写函数
//返回值:NAND FLASH的ID值
uint32_t NAND_ReadID(void)
{
uint8_t deviceid[5];
uint32_t id;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_READID; //发送读取ID命令
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=0X00;
//ID一共有5个字节
deviceid[0]=*(__IO uint8_t*)NAND_ADDRESS;
deviceid[1]=*(__IO uint8_t*)NAND_ADDRESS;
deviceid[2]=*(__IO uint8_t*)NAND_ADDRESS;
deviceid[3]=*(__IO uint8_t*)NAND_ADDRESS;
deviceid[4]=*(__IO uint8_t*)NAND_ADDRESS;
//镁光的NAND FLASH的ID一共5个字节,但是为了方便我们只取4个字节组成一个32位的ID值
//根据NAND FLASH的数据手册,只要是镁光的NAND FLASH,那么一个字节ID的第一个字节都是0X2C
//所以我们就可以抛弃这个0X2C,只取后面四字节的ID值。
id=((uint32_t)deviceid[1])<<24|((uint32_t)deviceid[2])<<16|((uint32_t)deviceid[3])<<8|deviceid[4];
return id;
}
//读NAND状态
//返回值:NAND状态值
//bit0:0,成功;1,错误(编程/擦除/READ)
//bit6:0,Busy;1,Ready
uint8_t NAND_ReadStatus(void)
{
__IO uint8_t data=0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_READSTA;//发送读状态命令
data++;data++;data++;data++;data++; //加延时,防止-O2优化,导致的错误.
data=*(__IO uint8_t*)NAND_ADDRESS; //读取状态值
return data;
}
//等待NAND准备好
//返回值:NSTA_TIMEOUT 等待超时了
// NSTA_READY 已经准备好
uint8_t NAND_WaitForReady(void)
{
uint8_t status=0;
__IO uint32_t time=0;
while(1) //等待ready
{
status=NAND_ReadStatus(); //获取状态值
if(status&NSTA_READY)
{
if (status&0x1)
{
// printf("校验不通过\n");
}
else
{
// printf("校验通过");
}
break;
}
time++;
if(time>=0X1FFFF)return NSTA_TIMEOUT;//超时
}
return NSTA_READY;//准备好
}
//复位NAND
//返回值:0,成功;
// 其他,失败
uint8_t NAND_Reset(void)
{
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_RESET; //复位NAND
if(NAND_WaitForReady()==NSTA_READY)return 0;//复位成功
else return 1; //复位失败
}
//等待RB信号为某个电平
//rb:0,等待RB==0
// 1,等待RB==1
//返回值:0,成功
// 1,超时
uint8_t NAND_WaitRB(__IO uint8_t rb)
{
__IO uint16_t time=0;
while(time<80000)
{
time++;
if(NAND_RB==rb)return 0;
}
return 1;
}
//读取NAND Flash的指定页指定列的数据(main区和spare区都可以使用此函数)
//PageNum:要读取的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要读取的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//*pBuffer:指向数据存储区
//NumByteToRead:读取字节数(不能跨页读)
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_ReadPage(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToRead)
{
__IO uint16_t i=0;
uint8_t res=0;
uint8_t eccnum=0; //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
uint8_t eccstart=0; //第一个ECC值所属的地址范围
uint8_t errsta=0;
uint8_t *p;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_A;
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)ColNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(ColNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_TRUE1;
//下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
//将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
//就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
//闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
//代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
res=NAND_WaitRB(0); //等待RB=0
if(res)return NSTA_TIMEOUT; //超时退出
//下面2行代码是真正判断NAND是否准备好的
res=NAND_WaitRB(1); //等待RB=1
if(res)return NSTA_TIMEOUT; //超时退出
if(NumByteToRead%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
{
//读取NAND FLASH中的值
for(i=0;i<NumByteToRead;i++)
{
*(__IO uint8_t*)pBuffer++ = *(__IO uint8_t*)NAND_ADDRESS;
}
}else
{
eccnum=NumByteToRead/NAND_ECC_SECTOR_SIZE; //得到ecc计算次数
eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
p=pBuffer;
for(res=0;res<eccnum;res++)
{
FMC_Bank2_3->PCR3|=1<<6; //使能ECC校验
for(i=0;i<NAND_ECC_SECTOR_SIZE;i++) //读取NAND_ECC_SECTOR_SIZE个数据
{
*(__IO uint8_t*)pBuffer++ = *(__IO uint8_t*)NAND_ADDRESS;
}
while(!(FMC_Bank2_3->SR3&(1<<6))); //等待FIFO空
my_nand.ecc_hdbuf[res+eccstart]=FMC_Bank2_3->ECCR3;//读取硬件计算后的ECC值
FMC_Bank2_3->PCR3&=~(1<<6); //禁止ECC校验
}
i=my_nand.page_mainsize+0X10+eccstart*4; //从spare区的0X10位置开始读取之前存储的ecc值
NAND_Delay(30);//等待tADL
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=0X05; //随机读指令
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)i;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(i>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=0XE0; //开始读数据
NAND_Delay(30);//等待tADL
pBuffer=(uint8_t*)&my_nand.ecc_rdbuf[eccstart];
for(i=0;i<4*eccnum;i++) //读取保存的ECC值
{
*(__IO uint8_t*)pBuffer++= *(__IO uint8_t*)NAND_ADDRESS;
}
for(i=0;i<eccnum;i++) //检验ECC
{
if(my_nand.ecc_rdbuf[i+eccstart]!=my_nand.ecc_hdbuf[i+eccstart])//不相等,需要校正
{
// log_i("err hd,rd:0x%x,0x%x\r\n",my_nand.ecc_hdbuf[i+eccstart],my_nand.ecc_rdbuf[i+eccstart]);
// log_i("eccnum,eccstart:%d,%d\r\n",eccnum,eccstart);
// log_i("PageNum,ColNum:%d,%d\r\n",PageNum,ColNum);
res=NAND_ECC_Correction(p+NAND_ECC_SECTOR_SIZE*i,my_nand.ecc_rdbuf[i+eccstart],my_nand.ecc_hdbuf[i+eccstart]);//ECC校验
if(res)errsta=NSTA_ECC2BITERR; //标记2BIT及以上ECC错误
else errsta=NSTA_ECC1BITERR; //标记1BIT ECC错误
}
}
}
if(NAND_WaitForReady()!=NSTA_READY)errsta=NSTA_ERROR; //失败
return errsta; //成功
}
//读取NAND Flash的指定页指定列的数据(main区和spare区都可以使用此函数),并对比(FTL管理时需要)
//PageNum:要读取的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要读取的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//CmpVal:要对比的值,以uint32_t为单位
//NumByteToRead:读取字数(以4字节为单位,不能跨页读)
//NumByteEqual:从初始位置持续与CmpVal值相同的数据个数
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_ReadPageComp(uint32_t PageNum,uint16_t ColNum,uint32_t CmpVal,uint16_t NumByteToRead,uint16_t *NumByteEqual)
{
uint16_t i=0;
uint8_t res=0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_A;
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)ColNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(ColNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_AREA_TRUE1;
//下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
//将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
//就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
//闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
//代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
res=NAND_WaitRB(0); //等待RB=0
if(res)return NSTA_TIMEOUT; //超时退出
//下面2行代码是真正判断NAND是否准备好的
res=NAND_WaitRB(1); //等待RB=1
if(res)return NSTA_TIMEOUT; //超时退出
for(i=0;i<NumByteToRead;i++)//读取数据,每次读4字节
{
if(*(__IO uint32_t*)NAND_ADDRESS!=CmpVal)break; //如果有任何一个值,与CmpVal不相等,则退出.
}
*NumByteEqual=i; //与CmpVal值相同的个数
if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
return 0; //成功
}
//在NAND一页中写入指定个字节的数据(main区和spare区都可以使用此函数)
//PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要写入的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//pBbuffer:指向数据存储区
//NumByteToWrite:要写入的字节数,该值不能超过该页剩余字节数!!!
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_WritePage(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToWrite)
{
__IO uint16_t i=0;
uint8_t res=0;
uint8_t eccnum=0; //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
uint8_t eccstart=0; //第一个ECC值所属的地址范围
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE0;
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)ColNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(ColNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>8);
NAND_Delay(30);//等待tADL
if(NumByteToWrite%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
{
for(i=0;i<NumByteToWrite;i++) //写入数据
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
}else
{
eccnum=NumByteToWrite/NAND_ECC_SECTOR_SIZE; //得到ecc计算次数
eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
for(res=0;res<eccnum;res++)
{
FMC_Bank2_3->PCR3|=1<<6; //使能ECC校验
for(i=0;i<NAND_ECC_SECTOR_SIZE;i++) //写入NAND_ECC_SECTOR_SIZE个数据
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
while(!(FMC_Bank2_3->SR3&(1<<6))); //等待FIFO空
my_nand.ecc_hdbuf[res+eccstart]=FMC_Bank2_3->ECCR3; //读取硬件计算后的ECC值
FMC_Bank2_3->PCR3&=~(1<<6); //禁止ECC校验
}
i=my_nand.page_mainsize+0X10+eccstart*4; //计算写入ECC的spare区地址
NAND_Delay(30);//等待
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=0X85; //随机写指令
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)i;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(i>>8);
NAND_Delay(30);//等待tADL
pBuffer=(uint8_t*)&my_nand.ecc_hdbuf[eccstart];
for(i=0;i<eccnum;i++) //写入ECC
{
for(res=0;res<4;res++)
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
}
}
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE_TURE1;
if(NAND_WaitForReady()!=NSTA_READY)
{
return NSTA_ERROR;//失败
}
return 0;//成功
}
//在NAND一页中的指定地址开始,写入指定长度的恒定数字
//PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要写入的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//cval:要写入的指定常数
//NumByteToWrite:要写入的字数(以4字节为单位)
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_WritePageConst(uint32_t PageNum,uint16_t ColNum,uint32_t cval,uint16_t NumByteToWrite)
{
uint16_t i=0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE0;
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)ColNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(ColNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(PageNum>>16);
NAND_Delay(30);//等待tADL
for(i=0;i<NumByteToWrite;i++) //写入数据,每次写4字节
{
*(__IO uint32_t*)NAND_ADDRESS=cval;
}
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_WRITE_TURE1;
if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
return 0;//成功
}
//将一页数据拷贝到另一页,不写入新数据
//注意:源页和目的页要在同一个Plane内!
//Source_PageNo:源页地址,范围:0~(block_pagenum*block_totalnum-1)
//Dest_PageNo:目的页地址,范围:0~(block_pagenum*block_totalnum-1)
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_CopyPageWithoutWrite(uint32_t Source_PageNum,uint32_t Dest_PageNum)
{
uint8_t res=0;
uint16_t source_block=0,dest_block=0;
//判断源页和目的页是否在同一个plane中
source_block=Source_PageNum/my_nand.block_pagenum;
dest_block=Dest_PageNum/my_nand.block_pagenum;
if((source_block%2)!=(dest_block%2))return NSTA_ERROR; //不在同一个plane内
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD0; //发送命令0X00
//发送源页地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)Source_PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Source_PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Source_PageNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD1;//发送命令0X35
//下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
//将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
//就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
//闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
//代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
res=NAND_WaitRB(0); //等待RB=0
if(res)return NSTA_TIMEOUT; //超时退出
//下面2行代码是真正判断NAND是否准备好的
res=NAND_WaitRB(1); //等待RB=1
if(res)return NSTA_TIMEOUT; //超时退出
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD2; //发送命令0X85
//发送目的页地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)Dest_PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Dest_PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Dest_PageNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD3; //发送命令0X10
if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR; //NAND未准备好
return 0;//成功
}
//将一页数据拷贝到另一页,并且可以写入数据
//注意:源页和目的页要在同一个Plane内!
//Source_PageNo:源页地址,范围:0~(block_pagenum*block_totalnum-1)
//Dest_PageNo:目的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNo:页内列地址,范围:0~(page_totalsize-1)
//pBuffer:要写入的数据
//NumByteToWrite:要写入的数据个数
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_CopyPageWithWrite(uint32_t Source_PageNum,uint32_t Dest_PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToWrite)
{
uint8_t res=0;
__IO uint16_t i=0;
uint16_t source_block=0,dest_block=0;
uint8_t eccnum=0; //需要计算的ECC个数,每NAND_ECC_SECTOR_SIZE字节计算一个ecc
uint8_t eccstart=0; //第一个ECC值所属的地址范围
//判断源页和目的页是否在同一个plane中
source_block=Source_PageNum/my_nand.block_pagenum;
dest_block=Dest_PageNum/my_nand.block_pagenum;
if((source_block%2)!=(dest_block%2))return NSTA_ERROR;//不在同一个plane内
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD0; //发送命令0X00
//发送源页地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)0;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)Source_PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Source_PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Source_PageNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD1; //发送命令0X35
//下面两行代码是等待R/B引脚变为低电平,其实主要起延时作用的,等待NAND操作R/B引脚。因为我们是通过
//将STM32的NWAIT引脚(NAND的R/B引脚)配置为普通IO,代码中通过读取NWAIT引脚的电平来判断NAND是否准备
//就绪的。这个也就是模拟的方法,所以在速度很快的时候有可能NAND还没来得及操作R/B引脚来表示NAND的忙
//闲状态,结果我们就读取了R/B引脚,这个时候肯定会出错的,事实上确实是会出错!大家也可以将下面两行
//代码换成延时函数,只不过这里我们为了效率所以没有用延时函数。
res=NAND_WaitRB(0); //等待RB=0
if(res)return NSTA_TIMEOUT; //超时退出
//下面2行代码是真正判断NAND是否准备好的
res=NAND_WaitRB(1); //等待RB=1
if(res)return NSTA_TIMEOUT; //超时退出
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD2; //发送命令0X85
//发送目的页地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)ColNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(ColNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)Dest_PageNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Dest_PageNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(Dest_PageNum>>16);
//发送页内列地址
NAND_Delay(30);//等待tADL
if(NumByteToWrite%NAND_ECC_SECTOR_SIZE)//不是NAND_ECC_SECTOR_SIZE的整数倍,不进行ECC校验
{
for(i=0;i<NumByteToWrite;i++) //写入数据
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
}else
{
eccnum=NumByteToWrite/NAND_ECC_SECTOR_SIZE; //得到ecc计算次数
eccstart=ColNum/NAND_ECC_SECTOR_SIZE;
for(res=0;res<eccnum;res++)
{
FMC_Bank2_3->PCR3|=1<<6; //使能ECC校验
for(i=0;i<NAND_ECC_SECTOR_SIZE;i++) //写入NAND_ECC_SECTOR_SIZE个数据
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
while(!(FMC_Bank2_3->SR3&(1<<6))); //等待FIFO空
my_nand.ecc_hdbuf[res+eccstart]=FMC_Bank2_3->ECCR3; //读取硬件计算后的ECC值
FMC_Bank2_3->PCR3&=~(1<<6); //禁止ECC校验
}
i=my_nand.page_mainsize+0X10+eccstart*4; //计算写入ECC的spare区地址
NAND_Delay(30);//等待
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=0X85; //随机写指令
//发送地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)i;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(i>>8);
NAND_Delay(30);//等待tADL
pBuffer=(uint8_t*)&my_nand.ecc_hdbuf[eccstart];
for(i=0;i<eccnum;i++) //写入ECC
{
for(res=0;res<4;res++)
{
*(__IO uint8_t*)NAND_ADDRESS=*(__IO uint8_t*)pBuffer++;
}
}
}
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_MOVEDATA_CMD3; //发送命令0X10
if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR; //失败
return 0; //成功
}
//读取spare区中的数据
//PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要写入的spare区地址(spare区中哪个地址),范围:0~(page_sparesize-1)
//pBuffer:接收数据缓冲区
//NumByteToRead:要读取的字节数(不大于page_sparesize)
//返回值:0,成功
// 其他,错误代码
uint8_t NAND_ReadSpare(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToRead)
{
uint8_t temp=0;
uint8_t remainbyte=0;
remainbyte=my_nand.page_sparesize-ColNum;
if(NumByteToRead>remainbyte) NumByteToRead=remainbyte; //确保要写入的字节数不大于spare剩余的大小
temp=NAND_ReadPage(PageNum,ColNum+my_nand.page_mainsize,pBuffer,NumByteToRead);//读取数据
return temp;
}
//向spare区中写数据
//PageNum:要写入的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要写入的spare区地址(spare区中哪个地址),范围:0~(page_sparesize-1)
//pBuffer:要写入的数据首地址
//NumByteToWrite:要写入的字节数(不大于page_sparesize)
//返回值:0,成功
// 其他,失败
uint8_t NAND_WriteSpare(uint32_t PageNum,uint16_t ColNum,uint8_t *pBuffer,uint16_t NumByteToWrite)
{
uint8_t temp=0;
uint8_t remainbyte=0;
remainbyte=my_nand.page_sparesize-ColNum;
if(NumByteToWrite>remainbyte) NumByteToWrite=remainbyte; //确保要读取的字节数不大于spare剩余的大小
temp=NAND_WritePage(PageNum,ColNum+my_nand.page_mainsize,pBuffer,NumByteToWrite);//读取
return temp;
}
//擦除一个块
//BlockNum:要擦除的BLOCK编号,范围:0-(block_totalnum-1)
//返回值:0,擦除成功
// 其他,擦除失败
uint8_t NAND_EraseBlock(uint32_t BlockNum)
{
if(my_nand.id==MT29F16G08ABABA)BlockNum<<=7; //将块地址转换为页地址
else if(my_nand.id==MT29F4G08ABADA)BlockNum<<=6;
else if(my_nand.id==W29N01HVSINA)BlockNum<<=6;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_ERASE0;
//发送块地址
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)BlockNum;
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(BlockNum>>8);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_ADDR)=(uint8_t)(BlockNum>>16);
*(__IO uint8_t*)(NAND_ADDRESS|NAND_CMD)=NAND_ERASE1;
if(NAND_WaitForReady()!=NSTA_READY)return NSTA_ERROR;//失败
return 0; //成功
}
//全片擦除NAND FLASH
void NAND_EraseChip(void)
{
uint8_t status;
uint16_t i=0;
for(i=0;i<my_nand.block_totalnum;i++) //循环擦除所有的块
{
status=NAND_EraseBlock(i);
if(status)log_i("Erase %d block fail!!,错误码为%d\r\n",i,status);//擦除失败
}
}
//获取ECC的奇数位/偶数位
//oe:0,偶数位
// 1,奇数位
//eccval:输入的ecc值
//返回值:计算后的ecc值(最多16位)
uint16_t NAND_ECC_Get_OE(uint8_t oe,uint32_t eccval)
{
uint8_t i;
uint16_t ecctemp=0;
for(i=0;i<24;i++)
{
if((i%2)==oe)
{
if((eccval>>i)&0X01)ecctemp+=1<<(i>>1);
}
}
return ecctemp;
}
//ECC校正函数
//eccrd:读取出来,原来保存的ECC值
//ecccl:读取数据时,硬件计算的ECC只
//返回值:0,错误已修正
// 其他,ECC错误(有大于2个bit的错误,无法恢复)
uint8_t NAND_ECC_Correction(uint8_t* data_buf,uint32_t eccrd,uint32_t ecccl)
{
uint16_t eccrdo,eccrde,eccclo,ecccle;
uint16_t eccchk=0;
uint16_t errorpos=0;
uint32_t bytepos=0;
eccrdo=NAND_ECC_Get_OE(1,eccrd); //获取eccrd的奇数位
eccrde=NAND_ECC_Get_OE(0,eccrd); //获取eccrd的偶数位
eccclo=NAND_ECC_Get_OE(1,ecccl); //获取ecccl的奇数位
ecccle=NAND_ECC_Get_OE(0,ecccl); //获取ecccl的偶数位
eccchk=eccrdo^eccrde^eccclo^ecccle;
if(eccchk==0XFFF) //全1,说明只有1bit ECC错误
{
errorpos=eccrdo^eccclo;
// log_i("errorpos:%d\r\n",errorpos);
bytepos=errorpos/8;
data_buf[bytepos]^=1<<(errorpos%8);
}else //不是全1,说明至少有2bit ECC错误,无法修复
{
// log_i("2bit ecc error or more\r\n");
return 1;
}
return 0;
}

@ -0,0 +1,171 @@
#include "fmc.h"
#include "bsp_sdram.h"
extern SDRAM_HandleTypeDef hsdram1;
static FMC_SDRAM_CommandTypeDef Command;
static SDRAM_HandleTypeDef *sdramHandle = &hsdram1;
MY_SDRAM_TypeDef my_sdram ={
SDRAM_Init,
SDRAM_Test,
};
static void SDRAM_delay(__IO uint32_t nCount)
{
__IO uint32_t index = 0;
for (index = (100000 * nCount); index != 0; index--)
{
}
}
void SDRAM_Init()
{
// MX_FMC_Init();
SDRAM_Initialization_Sequence(sdramHandle);
}
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
uint32_t temp = 0;
// SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_CLK_ENABLE, 1, 0); // 时钟配置使能
HAL_Delay(1);
// delay_us(500); //至少延时200us
SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_PALL, 1, 0); // 对所有存储区预充电
SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_AUTOREFRESH_MODE, 8, 0); // 设置自刷新次数
// 配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
// bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
// bit9为指定的写突发模式,bit10和bit11位保留位
temp = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | // 设置突发长度:1(可以是1/2/4/8)
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | // 设置突发类型:连续(可以是连续/交错)
SDRAM_MODEREG_CAS_LATENCY_3 | // 设置CAS值:3(可以是2/3)
SDRAM_MODEREG_OPERATING_MODE_STANDARD | // 设置操作模式:0,标准模式
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; // 设置突发写模式:1,单点访问
SDRAM_Send_Cmd(2, FMC_SDRAM_CMD_LOAD_MODE, 1, temp); // 设置SDRAM的模式寄存器
// 刷新频率计数器(以SDCLK频率计数),计算方法:
// COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
// 我们使用的SDRAM刷新周期为64ms,SDCLK=216/2=108Mhz,行数为8192(2^13).
// 所以,COUNT=64*1000*108/8192-20=823
// 168 MHz COUNT=64*1000*84 /8192-20= 3656
HAL_SDRAM_ProgramRefreshRate(sdramHandle, 823);
}
// 向SDRAM发送命令
// bankx:2,向BANK2上面的SDRAM发送指令 FMC_SDRAM_CMD_TARGET_BANK2 SDCKE1+SDNE1
// 1,向BANK1上面的SDRAM发送指令 FMC_SDRAM_CMD_TARGET_BANK1 SDCKE0+SDNE0
// cmd:指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
// refresh:自刷新次数
// regval:模式寄存器的定义
// 返回值:0,正常;1,失败.
uint8_t SDRAM_Send_Cmd(uint8_t bankx, uint8_t cmd, uint8_t refresh, uint16_t regval)
{
uint32_t target_bank = 0;
FMC_SDRAM_CommandTypeDef Command;
if (bankx == 1)
target_bank = FMC_SDRAM_CMD_TARGET_BANK1;
else if (bankx == 2)
target_bank = FMC_SDRAM_CMD_TARGET_BANK2;
Command.CommandMode = cmd; // 命令
Command.CommandTarget = target_bank; // 目标SDRAM存储区域
Command.AutoRefreshNumber = refresh; // 自刷新次数
Command.ModeRegisterDefinition = regval; // 要写入模式寄存器的值
if (HAL_SDRAM_SendCommand(sdramHandle, &Command, 0X1000) == HAL_OK) // 向SDRAM发送命令
{
return 0;
}
else
return 1;
}
// 在指定地址(WriteAddr+Bank5_SDRAM_ADDR)开始,连续写入n个字节.
// pBuffer:字节指针
// WriteAddr:要写入的地址
// n:要写入的字节数
void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t n)
{
for (; n != 0; n--)
{
*(volatile unsigned char *)(Bank4_SDRAM_ADDR + WriteAddr) = *pBuffer;
WriteAddr++;
pBuffer++;
}
}
// 在指定地址((WriteAddr+Bank5_SDRAM_ADDR))开始,连续读出n个字节.
// pBuffer:字节指针
// ReadAddr:要读出的起始地址
// n:要写入的字节数
void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer, uint32_t ReadAddr, uint32_t n)
{
for (; n != 0; n--)
{
*pBuffer++ = *(volatile unsigned char *)(Bank4_SDRAM_ADDR + ReadAddr);
ReadAddr++;
}
}
uint8_t SDRAM_Test(uint32_t count)
{
/*写入数据计数器*/
uint32_t counter = 0;
uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0;
uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0;
/*按8位格式读写数据,并校验*/
for (counter = 0x00; counter < count; counter++)
{
*(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter) = (uint8_t)0x0;
}
/* 向整个SDRAM写入数据 8位 */
for (counter = 0; counter < count; counter++)
{
*(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter);
}
/* 读取 SDRAM 数据并检测*/
for (counter = 0; counter < count; counter++)
{
ubReaddata_8b = *(__IO uint8_t *)(Bank4_SDRAM_ADDR + counter); // 从该地址读出数据
if (ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) // 检测数据,若不相等,跳出函数,返回检测失败结果。
{
// SDRAM_ERROR("8位数据读写错误!");
return 0;
}
}
/*按16位格式读写数据,并检测*/
/* 把SDRAM数据全部重置为0 */
for (counter = 0x00; counter < count / 2; counter++)
{
*(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter) = (uint16_t)0x00;
}
/* 向整个SDRAM写入数据 16位 */
for (counter = 0; counter < count / 2; counter++)
{
*(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter) = (uint16_t)(uhWritedata_16b + counter);
}
/* 读取 SDRAM 数据并检测*/
for (counter = 0; counter < count / 2; counter++)
{
uhReaddata_16b = *(__IO uint16_t *)(Bank4_SDRAM_ADDR + 2 * counter); // 从该地址读出数据
if (uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) // 检测数据,若不相等,跳出函数,返回检测失败结果。
{
// SDRAM_ERROR("16位数据读写错误!");
return 0;
}
}
/*检测正常,return 1 */
return 1;
}

@ -0,0 +1,481 @@
/**
****************************************************************************************************
* @file norflash.c
* @author
* @version V1.0
* @date 2021-10-26
* @brief NOR FLASH(25QXX)
* @license Copyright (c) 2020-2032
****************************************************************************************************
*/
#include "bsp_spiflash.h"
#include "stdio.h"
#include "elog.h"
extern SPI_HandleTypeDef hspi5;
SPI_HandleTypeDef *SPIFLASHHandle = &hspi5;
uint16_t g_spiflash_type = W25Q256; /* 默认是W25Q256 */
/*需要移植的代码:spi数据收发函数*/
uint8_t flash_spi_read_write_byte(uint8_t send_data)
{
uint8_t recv_data;
HAL_SPI_TransmitReceive(SPIFLASHHandle, &send_data, &recv_data, 1, 0xffff);
return recv_data;
}
/**
* @brief SPI2
* @note SPI2 APB1, PCLK1, 42Mhz
* SPI = PCLK1 / 2^(speed + 1)
* @param speed : SPI2
SPI_BAUDRATEPRESCALER_2~SPI_BAUDRATEPRESCALER_2 256
* @retval
*/
void flash_spi_set_speed(uint8_t speed)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(speed));/* 判断有效性 */
__HAL_SPI_DISABLE(SPIFLASHHandle); /* 关闭 SPI */
SPIFLASHHandle->Instance->CR1 &= 0xFFC7; /* 位 3-5 清零,用来设置波特率 */
SPIFLASHHandle->Instance->CR1 |= speed << 3; /* 设置 SPI 速度 */
__HAL_SPI_ENABLE(SPIFLASHHandle); /* 使能 SPI */
}
/**
* @brief SPI NOR FLASH
* @param
* @retval
*/
void spiflash_init(void)
{
flash_spi_set_speed(SPI_SPEED_4); /* SPI2 切换到高速状态 21Mhz */
uint8_t temp=0;
g_spiflash_type = spiflash_read_id(); /* 读取FLASH ID. */
if (g_spiflash_type == W25Q256) /* SPI FLASH为W25Q256, 必须使能4字节地址模式 */
{
temp = spiflash_read_sr(3); /* 读取状态寄存器3,判断地址模式 */
if ((temp & 0x01) == 0) /* 如果不是4字节地址模式,则进入4字节地址模式 */
{
spiflash_write_enable(); /* 写使能 */
temp |= 1 << 1; /* ADP=1, 上电4位地址模式 */
spiflash_write_sr(3, temp); /* 写SR3 */
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_Enable4ByteAddr); /* 使能4字节地址指令 */
spiflash_CS(1);
}
}
// printf("ID:%x\r\n", g_spiflash_type);
}
/**
* @brief
* @param
* @retval
*/
static void spiflash_wait_busy(void)
{
while ((spiflash_read_sr(1) & 0x01) == 0x01); /* 等待BUSY位清空 */
}
/**
* @brief 25QXX写使能
* @note S1寄存器的WEL置位
* @param
* @retval
*/
void spiflash_write_enable(void)
{
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_WriteEnable); /* 发送写使能 */
spiflash_CS(1);
}
/**
* @brief 25QXX发送地址
* @note , 24ibt / 32bit地址
* @param address :
* @retval
*/
static void spiflash_send_address(uint32_t address)
{
if (g_spiflash_type == W25Q256) /* 只有W25Q256支持4字节地址模式 */
{
flash_spi_read_write_byte((uint8_t)((address) >> 24)); /* 发送 bit31 ~ bit24 地址 */
}
flash_spi_read_write_byte((uint8_t)((address) >> 16)); /* 发送 bit23 ~ bit16 地址 */
flash_spi_read_write_byte((uint8_t)((address) >> 8)); /* 发送 bit15 ~ bit8 地址 */
flash_spi_read_write_byte((uint8_t)address); /* 发送 bit7 ~ bit0 地址 */
}
/**
* @brief 25QXX的状态寄存器25QXX一共有3个状态寄存器
* @note 1
* BIT7 6 5 4 3 2 1 0
* SPR RV TB BP2 BP1 BP0 WEL BUSY
* SPR:0,,WP使用
* TB,BP2,BP1,BP0:FLASH区域写保护设置
* WEL:使
* BUSY:(1,;0,)
* :0x00
*
* 2
* BIT7 6 5 4 3 2 1 0
* SUS CMP LB3 LB2 LB1 (R) QE SRP1
*
* 3
* BIT7 6 5 4 3 2 1 0
* HOLD/RST DRV1 DRV0 (R) (R) WPS ADP ADS
*
* @param regno: :1~3
* @retval
*/
uint8_t spiflash_read_sr(uint8_t regno)
{
uint8_t byte = 0, command = 0;
switch (regno)
{
case 1:
command = FLASH_ReadStatusReg1; /* 读状态寄存器1指令 */
break;
case 2:
command = FLASH_ReadStatusReg2; /* 读状态寄存器2指令 */
break;
case 3:
command = FLASH_ReadStatusReg3; /* 读状态寄存器3指令 */
break;
default:
command = FLASH_ReadStatusReg1;
break;
}
spiflash_CS(0);
flash_spi_read_write_byte(command); /* 发送读寄存器命令 */
byte = flash_spi_read_write_byte(0xFF); /* 读取一个字节 */
spiflash_CS(1);
return byte;
}
/**
* @brief 25QXX状态寄存器
* @note spiflash_read_sr函数说明
* @param regno: :1~3
* @param sr :
* @retval
*/
void spiflash_write_sr(uint8_t regno, uint8_t sr)
{
uint8_t command = 0;
switch (regno)
{
case 1:
command = FLASH_WriteStatusReg1; /* 写状态寄存器1指令 */
break;
case 2:
command = FLASH_WriteStatusReg2; /* 写状态寄存器2指令 */
break;
case 3:
command = FLASH_WriteStatusReg3; /* 写状态寄存器3指令 */
break;
default:
command = FLASH_WriteStatusReg1;
break;
}
spiflash_CS(0);
flash_spi_read_write_byte(command); /* 发送读寄存器命令 */
flash_spi_read_write_byte(sr); /* 写入一个字节 */
spiflash_CS(1);
}
/**
* @brief ID
* @param
* @retval FLASH芯片ID
* @note ID列表见: norflash.h,
*/
uint16_t spiflash_read_id(void)
{
uint16_t deviceid;
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_ManufactDeviceID); /* 发送读 ID 命令 */
flash_spi_read_write_byte(0); /* 写入一个字节 */
flash_spi_read_write_byte(0);
flash_spi_read_write_byte(0);
deviceid = flash_spi_read_write_byte(0xFF) << 8; /* 读取高8位字节 */
deviceid |= flash_spi_read_write_byte(0xFF); /* 读取低8位字节 */
spiflash_CS(1);
return deviceid;
}
/**
* @brief SPI FLASH
* @note
* @param pbuf :
* @param addr : (32bit)
* @param datalen : (65535)
* @retval
*/
void spiflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint16_t i;
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_ReadData); /* 发送读取命令 */
spiflash_send_address(addr); /* 发送地址 */
for (i = 0; i < datalen; i++)
{
pbuf[i] = flash_spi_read_write_byte(0xFF); /* 循环读取 */
}
spiflash_CS(1);
}
/**
* @brief SPI在一页(0~65535)256
* @note 256
* @param pbuf :
* @param addr : (32bit)
* @param datalen : (256),!!!
* @retval
*/
static void spiflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint16_t i;
spiflash_write_enable(); /* 写使能 */
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_PageProgram); /* 发送写页命令 */
spiflash_send_address(addr); /* 发送地址 */
for (i = 0; i < datalen; i++)
{
flash_spi_read_write_byte(pbuf[i]); /* 循环读取 */
}
spiflash_CS(1);
spiflash_wait_busy(); /* 等待写入结束 */
}
/**
* @brief SPI FLASH
* @note 0XFF,0XFF处写入的数据将失败!
*
* ,!
*
* @param pbuf :
* @param addr : (32bit)
* @param datalen : (65535)
* @retval
*/
static void spiflash_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint16_t pageremain;
pageremain = 256 - addr % 256; /* 单页剩余的字节数 */
if (datalen <= pageremain) /* 不大于256个字节 */
{
pageremain = datalen;
}
while (1)
{
/* 当写入字节比页内剩余地址还少的时候, 一次性写完
* , ,
*/
spiflash_write_page(pbuf, addr, pageremain);
if (datalen == pageremain) /* 写入结束了 */
{
break;
}
else /* datalen > pageremain */
{
pbuf += pageremain; /* pbuf指针地址偏移,前面已经写了pageremain字节 */
addr += pageremain; /* 写地址偏移,前面已经写了pageremain字节 */
datalen -= pageremain; /* 写入总长度减去已经写入了的字节数 */
if (datalen > 256) /* 剩余数据还大于一页,可以一次写一页 */
{
pageremain = 256; /* 一次可以写入256个字节 */
}
else /* 剩余数据小于一页,可以一次写完 */
{
pageremain = datalen; /* 不够256个字节了 */
}
}
}
}
/**
* @brief SPI FLASH
* @note , !
* SPI FLASH : 256Page, 4Kbytes为一个Sector, 161Block
* Sector.
*
* @param pbuf :
* @param addr : (32bit)
* @param datalen : (65535)
* @retval
*/
uint8_t g_spiflash_buf[4096]; /* 扇区缓存 */
void spiflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t *spiflash_buf;
spiflash_buf = g_spiflash_buf;
secpos = addr / 4096; /* 扇区地址 */
secoff = addr % 4096; /* 在扇区内的偏移 */
secremain = 4096 - secoff; /* 扇区剩余空间大小 */
//printf("ad:%X,nb:%X\r\n", addr, datalen); /* 测试用 */
if (datalen <= secremain)
{
secremain = datalen; /* 不大于4096个字节 */
}
while (1)
{
spiflash_read(spiflash_buf, secpos * 4096, 4096); /* 读出整个扇区的内容 */
for (i = 0; i < secremain; i++) /* 校验数据 */
{
if (spiflash_buf[secoff + i] != 0XFF)
{
break; /* 需要擦除, 直接退出for循环 */
}
}
if (i < secremain) /* 需要擦除 */
{
spiflash_erase_sector(secpos); /* 擦除这个扇区 */
for (i = 0; i < secremain; i++) /* 复制 */
{
spiflash_buf[i + secoff] = pbuf[i];
}
spiflash_write_nocheck(spiflash_buf, secpos * 4096, 4096); /* 写入整个扇区 */
}
else /* 写已经擦除了的,直接写入扇区剩余区间. */
{
spiflash_write_nocheck(pbuf, addr, secremain); /* 直接写扇区 */
}
if (datalen == secremain)
{
break; /* 写入结束了 */
}
else /* 写入未结束 */
{
secpos++; /* 扇区地址增1 */
secoff = 0; /* 偏移位置为0 */
pbuf += secremain; /* 指针偏移 */
addr += secremain; /* 写地址偏移 */
datalen -= secremain; /* 字节数递减 */
if (datalen > 4096)
{
secremain = 4096; /* 下一个扇区还是写不完 */
}
else
{
secremain = datalen;/* 下一个扇区可以写完了 */
}
}
}
}
/**
* @brief
* @note ...
* @param
* @retval
*/
void spiflash_erase_chip(void)
{
spiflash_write_enable(); /* 写使能 */
spiflash_wait_busy(); /* 等待空闲 */
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_ChipErase); /* 发送读寄存器命令 */
spiflash_CS(1);
spiflash_wait_busy(); /* 等待芯片擦除结束 */
}
/**
* @brief
* @note ,,!!
* :150ms
*
* @param saddr :
* @retval
*/
void spiflash_erase_sector(uint32_t saddr)
{
//printf("fe:%x\r\n", saddr); /* 监视falsh擦除情况,测试用 */
saddr *= 4096;
spiflash_write_enable(); /* 写使能 */
spiflash_wait_busy(); /* 等待空闲 */
spiflash_CS(0);
flash_spi_read_write_byte(FLASH_SectorErase); /* 发送写页命令 */
spiflash_send_address(saddr); /* 发送地址 */
spiflash_CS(1);
spiflash_wait_busy(); /* 等待扇区擦除完成 */
}
void spi_flash_test()
{
int x = 0;
spiflash_init();
uint8_t buf[256];
for(x = 0; x < 256; x++)buf[x] = x;
spiflash_write(buf, 0, 256);
memset(buf, 0, 256);
spiflash_read(buf, 0, 256);
for(x = 0; x < 256; x++)
{
if(buf[x] != x)break;
}
if(x != 256)
{
log_i("spi flash test fail\r\n");
}
else
{
log_i("spi flash test ok\r\n");
}
}

@ -0,0 +1,205 @@
#include "bsp_uart.h"
MYUART_TypeDef * Myuart_Init( )
{
MYUART_TypeDef *Handle = (MYUART_TypeDef *)malloc(sizeof(MYUART_TypeDef));
if (Handle == NULL)
{
return NULL;
}
Handle->send_flag = 0;
Handle->send_tc_flag = 0;
Handle->interface_type = 0;
Handle->enable_idle_it = 0;
Handle->enable_rcv =NULL;
Handle->enable_snd =NULL;
// #if MAX485_ENABLE
// Handle->de485_gpio = NULL;
// Handle->interface_type = 1;
// #endif
// #if MAX3160_ENABLE
// Handle->de485_gpio = NULL;
// Handle->sel_gpio = NULL;
// Handle->dplx_gpio = NULL;
// Handle->interface_type = 2;
// #endif
return Handle;
}
void Myuart_Set_Huart(MYUART_TypeDef * myuart, UART_HandleTypeDef *huart)
{
myuart->huart = huart;
}
int Myuart_Setup_Transmod( MYUART_TypeDef * myuart, uint8_t trans_mode )
{
/* 0 :polling, 1: IT 2: DMA*/
myuart->trans_mode = trans_mode;
return 0;
}
int Myuart_Set_enable_snd_func( MYUART_TypeDef * myuart, enable_func enable_snd_func )
{
if (enable_snd_func != NULL) myuart->enable_snd = enable_snd_func;
return 0;
}
int Myuart_Set_enable_rcv_func( MYUART_TypeDef * myuart, enable_func enable_rcv_func)
{
if (enable_rcv_func != NULL) myuart->enable_rcv = enable_rcv_func;
return 0;
}
int Myuart_Set_enable_idle( MYUART_TypeDef * myuart, uint8_t enable_idle)
{
myuart->enable_idle_it = enable_idle;
}
int Myuart_Set_Callback( MYUART_TypeDef * myuart, void *obj, callback_fun func)
{
myuart->obj = obj;
myuart->callback = func;
}
int Myuart_Start_Rcv(MYUART_TypeDef * myuart, uint8_t *buf, uint16_t size)
{
int st;
switch ( myuart->trans_mode)
{
case 0:
st = HAL_UART_Transmit(myuart->huart, buf, size , 0xFFFF);
return st;
break;
case 1:
st = HAL_UART_Transmit_IT(myuart->huart, buf, size);
return st;
break;
case 2:
/* 会出现 st ==2 huart->gState != HAL_UART_STATE_READY */
if (myuart->enable_idle_it == 1)
{
__HAL_USART_ENABLE_IT(myuart->huart, UART_IT_IDLE);
}
st = HAL_UART_Transmit_DMA(myuart->huart, buf, size);
return st;
break;
default:
break;
}
}
int Myuart_Trans(MYUART_TypeDef * myuart, uint8_t *buf, uint16_t size)
{
int st;
if (myuart->enable_snd != NULL)
{
myuart->enable_snd;
}
switch ( myuart->trans_mode)
{
case 0:
st = HAL_UART_Transmit(myuart->huart, buf, size , 0xFFFF);
return st;
break;
case 1:
st = HAL_UART_Transmit_IT(myuart->huart, buf, size);
return st;
break;
case 2:
/* 会出现 st ==2 huart->gState != HAL_UART_STATE_READY */
st = HAL_UART_Transmit_DMA(myuart->huart, buf, size);
return st;
break;
default:
break;
}
return 0;
}
int Myuart_Trans_TxCplt_Callback( MYUART_TypeDef * myuart )
{
if (myuart->enable_rcv != NULL)
{
myuart->enable_rcv;
}
return 0;
}
// void Myuart_Set_Sel_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin)
// {
// #if MAX3160_ENABLE
// myuart->sel_gpio = gpio;
// myuart->sel_pin = pin;
// #endif
// }
// void Myuart_Set_Dplx_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin)
// {
// #if MAX3160_ENABLE
// myuart->dplx_gpio = gpio;
// myuart->dplx_pin = pin;
// #endif
// }
// void Myuart_Set_DE485_GPIO_Pin(MYUART_TypeDef * myuart, GPIO_TypeDef *gpio, uint16_t pin)
// {
// #if MAX3160_ENABLE
// myuart->de485_gpio = gpio;
// myuart->de485_pin = pin;
// #endif
// #if MAX485_ENABLE
// myuart->de485_gpio = gpio;
// myuart->de485_pin = pin;
// #endif
// }
// void Myuart_Set_232(MYUART_TypeDef * myuart)
// {
// #if MAX3160_ENABLE
// myuart->sel = SEL_232;
// HAL_GPIO_WritePin( myuart->sel_gpio, myuart->sel_pin, myuart->sel );
// HAL_GPIO_WritePin( myuart->dplx_gpio, myuart->dplx_pin, DUPLEX_FULL );
// #endif
// }
// void Myuart_Set_485(MYUART_TypeDef * myuart)
// {
// #if MAX3160_ENABLE
// myuart->sel = SEL_485;
// HAL_GPIO_WritePin( myuart->sel_gpio, myuart->sel_pin, myuart->sel );
// HAL_GPIO_WritePin( myuart->dplx_gpio, myuart->dplx_pin, DUPLEX_HALF );
// HAL_GPIO_WritePin( myuart->de485_gpio, myuart->de485_pin, DISABLE_485_Trans );
// #endif
// }
// int __Myuart_Send(MYUART_TypeDef * myuart , uint8_t *buf, uint16_t size)
// {
// uint8_t st;
// switch ( myuart->trans_mode)
// {
// case 0:
// st = HAL_UART_Transmit(myuart->huart, buf, size , 0xFFFF);
// return st;
// break;
// case 1:
// st = HAL_UART_Transmit_IT(myuart->huart, buf, size);
// return st;
// break;
// case 2:
// /* 会出现 st ==2 huart->gState != HAL_UART_STATE_READY */
// st = HAL_UART_Transmit_DMA(myuart->huart, buf, size);
// return st;
// break;
// default:
// break;
// }
// return 0;
// }

@ -0,0 +1,481 @@
#include "ftl.h"
#include "string.h"
#include "bsp_nand.h"
#include "malloc.h"
#include "elog.h"
//每个块,第一个page的spare区,前四个字节的含义:
//第一个字节,表示该块是否是坏块:0XFF,正常块;其他值,坏块.
//第二个字节,表示该块是否被用过:0XFF,没有写过数据;0XCC,写过数据了.
//第三和第四个字节,表示该块所属的逻辑块编号.
//每个page,spare区16字节以后的字节含义:
//第十六字节开始,后续每4个字节用于存储一个扇区(大小:NAND_ECC_SECTOR_SIZE)的ECC值,用于ECC校验
//FTL层初始化
//返回值:0,正常
// 其他,失败
uint8_t FTL_Init(void)
{
uint8_t temp;
if(NAND_Init())
return 1; //初始化NAND FLASH
if(my_nand.lut)
free( my_nand.lut);
// myfree(SRAMEX,my_nand.lut);
// my_nand.lut=mymalloc(SRAMEX,(my_nand.block_totalnum)*2); //给LUT表申请内存
my_nand.lut=malloc( (my_nand.block_totalnum)*2); //给LUT表申请内存
memset(my_nand.lut,0,my_nand.block_totalnum*2); //全部清理
if(!my_nand.lut)
return 1; //内存申请失败
temp=FTL_CreateLUT(1);
if(temp)
{
// log_i("format nand flash...\r\n");
temp=FTL_Format(); //格式化NAND
if(temp)
{
// log_i("format failed!\r\n");
return 2;
}
}
else //创建LUT表成功
{
// log_i("total block num:%d\r\n",my_nand.block_totalnum);
// log_i("good block num:%d\r\n",my_nand.good_blocknum);
// log_i("valid block num:%d\r\n",my_nand.valid_blocknum);
}
return 0;
}
//标记某一个块为坏块
//blocknum:块编号,范围:0~(block_totalnum-1)
void FTL_BadBlockMark(uint32_t blocknum)
{
uint32_t temp=0XAAAAAAAA;//坏块标记mark,任意值都OK,只要不是0XFF.这里写前4个字节,方便FTL_FindUnusedBlock函数检查坏块.(不检查备份区,以提高速度)
NAND_WriteSpare(blocknum*my_nand.block_pagenum,0,(uint8_t*)&temp,4); //在第一个page的spare区,第一个字节做坏块标记(前4个字节都写)
NAND_WriteSpare(blocknum*my_nand.block_pagenum+1,0,(uint8_t*)&temp,4); //在第二个page的spare区,第一个字节做坏块标记(备份用,前4个字节都写)
}
//检查某一块是否是坏块
//blocknum:块编号,范围:0~(block_totalnum-1)
//返回值:0,好块
// 其他,坏块
uint8_t FTL_CheckBadBlock(uint32_t blocknum)
{
uint8_t flag=0;
NAND_ReadSpare(blocknum*my_nand.block_pagenum,0,&flag,1);//读取坏块标志
if(flag==0XFF)//好块?,读取备份区坏块标记
{
NAND_ReadSpare(blocknum*my_nand.block_pagenum+1,0,&flag,1);//读取备份区坏块标志
if(flag==0XFF)return 0; //好块
else return 1; //坏块
}
return 2;
}
//标记某一个块已经使用
//blocknum:块编号,范围:0~(block_totalnum-1)
//返回值:0,成功
// 其他,失败
uint8_t FTL_UsedBlockMark(uint32_t blocknum)
{
uint8_t Usedflag=0XCC;
uint8_t temp=0;
temp=NAND_WriteSpare(blocknum*my_nand.block_pagenum,1,(uint8_t*)&Usedflag,1);//写入块已经被使用标志
return temp;
}
//从给定的块开始找到往前找到一个未被使用的块(指定奇数/偶数)
//sblock:开始块,范围:0~(block_totalnum-1)
//flag:0,偶数快;1,奇数块.
//返回值:0XFFFFFFFF,失败
// 其他值,未使用块号
uint32_t FTL_FindUnusedBlock(uint32_t sblock,uint8_t flag)
{
uint32_t temp=0;
uint32_t blocknum=0;
for(blocknum=sblock+1;blocknum>0;blocknum--)
{
if(((blocknum-1)%2)==flag)//奇偶合格,才检测
{
NAND_ReadSpare((blocknum-1)*my_nand.block_pagenum,0,(uint8_t*)&temp,4);//读块是否被使用标记
if(temp==0XFFFFFFFF)return(blocknum-1);//找到一个空块,返回块编号
}
}
return 0XFFFFFFFF; //未找到空余块
}
//查找与给定块在同一个plane内的未使用的块
//sblock:给定块,范围:0~(block_totalnum-1)
//返回值:0XFFFFFFFF,失败
// 其他值,未使用块号
uint32_t FTL_FindSamePlaneUnusedBlock(uint32_t sblock)
{
static uint32_t curblock=0XFFFFFFFF;
uint32_t unusedblock=0;
if(curblock>(my_nand.block_totalnum-1))curblock=my_nand.block_totalnum-1;//超出范围了,强制从最后一个块开始
unusedblock=FTL_FindUnusedBlock(curblock,sblock%2); //从当前块,开始,向前查找空余块
if(unusedblock==0XFFFFFFFF&&curblock<(my_nand.block_totalnum-1)) //未找到,且不是从最末尾开始找的
{
curblock=my_nand.block_totalnum-1; //强制从最后一个块开始
unusedblock=FTL_FindUnusedBlock(curblock,sblock%2); //从最末尾开始,重新找一遍
}
if(unusedblock==0XFFFFFFFF)return 0XFFFFFFFF; //找不到空闲block
curblock=unusedblock; //当前块号等于未使用块编号.下次则从此处开始查找
return unusedblock; //返回找到的空闲block
}
//将一个块的数据拷贝到另一块,并且可以写入数据
//Source_PageNo:要写入数据的页地址,范围:0~(block_pagenum*block_totalnum-1)
//ColNum:要写入的列开始地址(也就是页内地址),范围:0~(page_totalsize-1)
//pBuffer:要写入的数据
//NumByteToWrite:要写入的字节数,该值不能超过块内剩余容量大小
//返回值:0,成功
// 其他,失败
uint8_t FTL_CopyAndWriteToBlock(uint32_t Source_PageNum,uint16_t ColNum,uint8_t *pBuffer,uint32_t NumByteToWrite)
{
uint16_t i=0,temp=0,wrlen;
uint32_t source_block=0,pageoffset=0;
uint32_t unusedblock=0;
source_block=Source_PageNum/my_nand.block_pagenum; //获得页所在的块号
pageoffset=Source_PageNum%my_nand.block_pagenum; //获得页在所在块内的偏移
retry:
unusedblock=FTL_FindSamePlaneUnusedBlock(source_block);//查找与源块在一个plane的未使用块
if(unusedblock>my_nand.block_totalnum)return 1; //当找到的空余块号大于块总数量的话肯定是出错了
for(i=0;i<my_nand.block_pagenum;i++) //将一个块的数据复制到找到的未使用块中
{
if(i>=pageoffset&&NumByteToWrite) //数据要写入到当前页
{
if(NumByteToWrite>(my_nand.page_mainsize-ColNum))//要写入的数据,超过了当前页的剩余数据
{
wrlen=my_nand.page_mainsize-ColNum; //写入长度等于当前页剩余数据长度
}else wrlen=NumByteToWrite; //写入全部数据
temp=NAND_CopyPageWithWrite(source_block*my_nand.block_pagenum+i,unusedblock*my_nand.block_pagenum+i,ColNum,pBuffer,wrlen);
ColNum=0; //列地址归零
pBuffer+=wrlen; //写地址偏移
NumByteToWrite-=wrlen; //写入数据减少
}else //无数据写入,直接拷贝即可
{
temp=NAND_CopyPageWithoutWrite(source_block*my_nand.block_pagenum+i,unusedblock*my_nand.block_pagenum+i);
}
if(temp) //返回值非零,当坏块处理
{
FTL_BadBlockMark(unusedblock); //标记为坏块
FTL_CreateLUT(1); //重建LUT表
goto retry;
}
}
if(i==my_nand.block_pagenum) //拷贝完成
{
FTL_UsedBlockMark(unusedblock); //标记块已经使用
NAND_EraseBlock(source_block); //擦除源块
//printf("\r\ncopy block %d to block %d\r\n",source_block,unusedblock);//打印调试信息
for(i=0;i<my_nand.block_totalnum;i++) //修正LUT表,用unusedblock替换source_block
{
if(my_nand.lut[i]==source_block)
{
my_nand.lut[i]=unusedblock;
break;
}
}
}
return 0; //成功
}
//逻辑块号转换为物理块号
//LBNNum:逻辑块编号
//返回值:物理块编号
uint16_t FTL_LBNToPBN(uint32_t LBNNum)
{
uint16_t PBNNo=0;
//当逻辑块号大于有效块数的时候返回0XFFFF
if(LBNNum>my_nand.valid_blocknum)return 0XFFFF;
PBNNo=my_nand.lut[LBNNum];
return PBNNo;
}
//写扇区(支持多扇区写),FATFS文件系统使用
//pBuffer:要写入的数据
//SectorNo:起始扇区号
//SectorSize:扇区大小(不能大于NAND_ECC_SECTOR_SIZE定义的大小,否则会出错!!)
//SectorCount:要写入的扇区数量
//返回值:0,成功
// 其他,失败
uint8_t FTL_WriteSectors(uint8_t *pBuffer,uint32_t SectorNo,uint16_t SectorSize,uint32_t SectorCount)
{
uint8_t flag=0;
uint16_t temp;
uint32_t i=0;
uint16_t wsecs; //写页大小
uint32_t wlen; //写入长度
uint32_t LBNNo; //逻辑块号
uint32_t PBNNo; //物理块号
uint32_t PhyPageNo; //物理页号
uint32_t PageOffset; //页内偏移地址
uint32_t BlockOffset;//块内偏移地址
uint32_t markdpbn=0XFFFFFFFF; //标记了的物理块编号
for(i=0;i<SectorCount;i++)
{
LBNNo=(SectorNo+i)/(my_nand.block_pagenum*(my_nand.page_mainsize/SectorSize));//根据逻辑扇区号和扇区大小计算出逻辑块号
PBNNo=FTL_LBNToPBN(LBNNo); //将逻辑块转换为物理块
if(PBNNo>=my_nand.block_totalnum)return 1; //物理块号大于NAND FLASH的总块数,则失败.
BlockOffset=((SectorNo+i)%(my_nand.block_pagenum*(my_nand.page_mainsize/SectorSize)))*SectorSize;//计算块内偏移
PhyPageNo=PBNNo*my_nand.block_pagenum+BlockOffset/my_nand.page_mainsize; //计算出物理页号
PageOffset=BlockOffset%my_nand.page_mainsize; //计算出页内偏移地址
temp=my_nand.page_mainsize-PageOffset; //page内剩余字节数
temp/=SectorSize; //可以连续写入的sector数
wsecs=SectorCount-i; //还剩多少个sector要写
if(wsecs>=temp)wsecs=temp; //大于可连续写入的sector数,则写入temp个扇区
wlen=wsecs*SectorSize; //每次写wsecs个sector
//读出写入大小的内容判断是否全为0XFF
flag=NAND_ReadPageComp(PhyPageNo,PageOffset,0XFFFFFFFF,wlen/4,&temp); //读一个wlen/4大小个数据,并与0XFFFFFFFF对比
if(flag)return 2; //读写错误,坏块
if(temp==(wlen/4)) flag=NAND_WritePage(PhyPageNo,PageOffset,pBuffer,wlen); //全为0XFF,可以直接写数据
else flag=1; //不全是0XFF,则另作处理
if(flag==0&&(markdpbn!=PBNNo)) //全是0XFF,且写入成功,且标记了的物理块与当前物理块不同
{
flag=FTL_UsedBlockMark(PBNNo); //标记此块已经使用
markdpbn=PBNNo; //标记完成,标记块=当前块,防止重复标记
}
if(flag)//不全为0XFF/标记失败,将数据写到另一个块
{
temp=((uint32_t)my_nand.block_pagenum*my_nand.page_mainsize-BlockOffset)/SectorSize;//计算整个block还剩下多少个SECTOR可以写入
wsecs=SectorCount-i; //还剩多少个sector要写
if(wsecs>=temp)wsecs=temp; //大于可连续写入的sector数,则写入temp个扇区
wlen=wsecs*SectorSize; //每次写wsecs个sector
flag=FTL_CopyAndWriteToBlock(PhyPageNo,PageOffset,pBuffer,wlen);//拷贝到另外一个block,并写入数据
if(flag)return 3;//失败
}
i+=wsecs-1;
pBuffer+=wlen;//数据缓冲区指针偏移
}
return 0;
}
//读扇区(支持多扇区读),FATFS文件系统使用
//pBuffer:数据缓存区
//SectorNo:起始扇区号
//SectorSize:扇区大小
//SectorCount:要写入的扇区数量
//返回值:0,成功
// 其他,失败
uint8_t FTL_ReadSectors(uint8_t *pBuffer,uint32_t SectorNo,uint16_t SectorSize,uint32_t SectorCount)
{
uint8_t flag=0;
uint16_t rsecs; //单次读取页数
uint32_t i=0;
uint32_t LBNNo; //逻辑块号
uint32_t PBNNo; //物理块号
uint32_t PhyPageNo; //物理页号
uint32_t PageOffset; //页内偏移地址
uint32_t BlockOffset;//块内偏移地址
for(i=0;i<SectorCount;i++)
{
LBNNo=(SectorNo+i)/(my_nand.block_pagenum*(my_nand.page_mainsize/SectorSize));//根据逻辑扇区号和扇区大小计算出逻辑块号
PBNNo=FTL_LBNToPBN(LBNNo); //将逻辑块转换为物理块
if(PBNNo>=my_nand.block_totalnum)return 1; //物理块号大于NAND FLASH的总块数,则失败.
BlockOffset=((SectorNo+i)%(my_nand.block_pagenum*(my_nand.page_mainsize/SectorSize)))*SectorSize;//计算块内偏移
PhyPageNo=PBNNo*my_nand.block_pagenum+BlockOffset/my_nand.page_mainsize; //计算出物理页号
PageOffset=BlockOffset%my_nand.page_mainsize; //计算出页内偏移地址
rsecs=(my_nand.page_mainsize-PageOffset)/SectorSize; //计算一次最多可以读取多少页
if(rsecs>(SectorCount-i))rsecs=SectorCount-i; //最多不能超过SectorCount-i
flag=NAND_ReadPage(PhyPageNo,PageOffset,pBuffer,rsecs*SectorSize); //读取数据
if(flag==NSTA_ECC1BITERR) //对于1bit ecc错误,可能为坏块
{
flag=NAND_ReadPage(PhyPageNo,PageOffset,pBuffer,rsecs*SectorSize); //重读数据,再次确认
if(flag==NSTA_ECC1BITERR)
{
FTL_CopyAndWriteToBlock(PhyPageNo,PageOffset,pBuffer,rsecs*SectorSize); //搬运数据
flag=FTL_BlockCompare(PhyPageNo/my_nand.block_pagenum,0XFFFFFFFF); //全1检查,确认是否为坏块
if(flag==0)
{
flag=FTL_BlockCompare(PhyPageNo/my_nand.block_pagenum,0X00); //全0检查,确认是否为坏块
NAND_EraseBlock(PhyPageNo/my_nand.block_pagenum); //检测完成后,擦除这个块
}
if(flag) //全0/全1检查出错,肯定是坏块了.
{
FTL_BadBlockMark(PhyPageNo/my_nand.block_pagenum); //标记为坏块
FTL_CreateLUT(1); //重建LUT表
}
flag=0;
}
}
if(flag==NSTA_ECC2BITERR)flag=0; //2bit ecc错误,不处理(可能是初次写入数据导致的)
if(flag)return 2; //失败
pBuffer+=SectorSize*rsecs; //数据缓冲区指针偏移
i+=rsecs-1;
}
return 0;
}
//重新创建LUT表
//mode:0,仅检查第一个坏块标记
// 1,两个坏块标记都要检查(备份区也要检查)
//返回值:0,成功
// 其他,失败
uint8_t FTL_CreateLUT(uint8_t mode)
{
uint32_t i;
uint8_t buf[4]={0x0,0,0,0};
uint32_t LBNnum=0; //逻辑块号
for(i=0;i<my_nand.block_totalnum;i++) //复位LUT表,初始化为无效值,也就是0XFFFF
{
my_nand.lut[i]=0XFFFF;
}
my_nand.good_blocknum=0;
for(i=0;i<my_nand.block_totalnum;i++)
{
NAND_ReadSpare(i*my_nand.block_pagenum,0,buf,4); //读取4个字节
if(buf[0]==0XFF&&mode)
NAND_ReadSpare(i*my_nand.block_pagenum+1,0,buf,1);//好块,且需要检查2次坏块标记
if(buf[0]==0XFF)//是好块
{
LBNnum=((uint16_t)buf[3]<<8)+buf[2]; //得到逻辑块编号
if(LBNnum<my_nand.block_totalnum) //逻辑块号肯定小于总的块数量
{
my_nand.lut[LBNnum]=i; //更新LUT表,写LBNnum对应的物理块编号
}
my_nand.good_blocknum++;
}
else log_i("bad block index:%d\r\n",i);
}
//LUT表建立完成以后检查有效块个数
for(i=0;i<my_nand.block_totalnum;i++)
{
if(my_nand.lut[i]>=my_nand.block_totalnum)
{
my_nand.valid_blocknum=i;
break;
}
}
if(my_nand.valid_blocknum<100)return 2; //有效块数小于100,有问题.需要重新格式化
return 0; //LUT表创建完成
}
//FTL整个Block与某个数据对比
//blockx:block编号
//cmpval:要与之对比的值
//返回值:0,检查成功,全部相等
// 1,检查失败,有不相等的情况
uint8_t FTL_BlockCompare(uint32_t blockx,uint32_t cmpval)
{
uint8_t res;
uint16_t i,j,k;
for(i=0;i<3;i++)//允许3次机会
{
for(j=0;j<my_nand.block_pagenum;j++)
{
NAND_ReadPageComp(blockx*my_nand.block_pagenum,0,cmpval,my_nand.page_mainsize/4,&k);//检查一个page,并与0XFFFFFFFF对比
if(k!=(my_nand.page_mainsize/4))break;
}
if(j==my_nand.block_pagenum)return 0; //检查合格,直接退出
res=NAND_EraseBlock(blockx);
if(res)log_i("error erase block:%d\r\n",i);
else
{
if(cmpval!=0XFFFFFFFF)//不是判断全1,则需要重写数据
{
for(k=0;k<my_nand.block_pagenum;k++)
{
NAND_WritePageConst(blockx*my_nand.block_pagenum+k,0,0,my_nand.page_mainsize/4);//写PAGE
}
}
}
}
log_i("bad block checked:%d\r\n",blockx);
return 1;
}
//FTL初始化时,搜寻所有坏块,使用:擦-写-读 方式
//512M的NAND ,需要约3分钟时间,来完成检测
//对于RGB屏,由于频繁读写NAND,会引起屏幕乱闪
//返回值:好块的数量
uint32_t FTL_SearchBadBlock(void)
{
uint8_t *blktbl;
uint8_t res;
uint32_t i,j;
uint32_t goodblock=0;
blktbl=mymalloc(SRAMEX,my_nand.block_totalnum);//申请block坏块表内存,对应项:0,好块;1,坏块;
NAND_EraseChip(); //全片擦除
for(i=0;i<my_nand.block_totalnum;i++) //第一阶段检查,检查全1
{
res=FTL_BlockCompare(i,0XFFFFFFFF); //全1检查
if(res)blktbl[i]=1; //坏块
else
{
blktbl[i]=0; //好块
for(j=0;j<my_nand.block_pagenum;j++)//写block为全0,为后面的检查准备
{
NAND_WritePageConst(i*my_nand.block_pagenum+j,0,0,my_nand.page_mainsize/4);
}
}
}
for(i=0;i<my_nand.block_totalnum;i++) //第二阶段检查,检查全0
{
if(blktbl[i]==0) //在第一阶段,没有被标记坏块的,才可能是好块
{
res=FTL_BlockCompare(i,0); //全0检查
if(res)blktbl[i]=1; //标记坏块
else goodblock++;
}
}
NAND_EraseChip(); //全片擦除
for(i=0;i<my_nand.block_totalnum;i++) //第三阶段检查,标记坏块
{
if(blktbl[i])FTL_BadBlockMark(i); //是坏块
}
return goodblock; //返回好块的数量
}
//格式化NAND 重建LUT表
//返回值:0,成功
// 其他,失败
uint8_t FTL_Format(void)
{
uint8_t temp;
uint32_t i,n;
uint32_t goodblock=0;
my_nand.good_blocknum=0;
#if FTL_USE_BAD_BLOCK_SEARCH==1 //使用擦-写-读的方式,检测坏块
my_nand.good_blocknum=FTL_SearchBadBlock();//搜寻坏块.耗时很久
#else //直接使用NAND FLASH的出厂坏块标志(其他块,默认是好块)
for(i=0;i<my_nand.block_totalnum;i++)
{
temp=FTL_CheckBadBlock(i); //检查一个块是否为坏块
if(temp==0) //好块
{
temp=NAND_EraseBlock(i);
if(temp) //擦除失败,认为坏块
{
log_i("Bad block:%d\r\n",i);
FTL_BadBlockMark(i); //标记是坏块
}else
my_nand.good_blocknum++; //好块数量加一
}
}
#endif
log_i("good_blocknum:%d\r\n",my_nand.good_blocknum);
if(my_nand.good_blocknum<100) return 1; //如果好块的数量少于100,则NAND Flash报废
goodblock=(my_nand.good_blocknum*93)/100; //%93的好块用于存储数据
n=0;
for(i=0;i<my_nand.block_totalnum;i++) //在好块中标记上逻辑块信息
{
temp=FTL_CheckBadBlock(i); //检查一个块是否为坏块
if(temp==0) //好块
{
NAND_WriteSpare(i*my_nand.block_pagenum,2,(uint8_t*)&n,2);//写入逻辑块编号
n++; //逻辑块编号加1
if(n==goodblock) break; //全部标记完了
}
}
if(FTL_CreateLUT(1))return 2; //重建LUT表失败
return 0;
}

@ -0,0 +1,216 @@
#include "malloc.h"
#include "elog.h"
//内存池(32字节对齐)
__attribute__(( aligned(32) )) uint8_t mem1base[MEM1_MAX_SIZE] ; //内部SRAM内存池
__attribute__(( section(".sdram") , aligned(32) )) uint8_t mem2base[MEM2_MAX_SIZE] ;
// __attribute__(( section(".dispram") , aligned(32) )) uint8_t mem3base[MEM3_MAX_SIZE] ;
//内存管理表
uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE];
__attribute__(( section(".sdrammap") )) uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] ;
// __attribute__(( section(".disprammap") )) uint16_t mem3mapbase[MEM3_ALLOC_TABLE_SIZE] ;
//内存管理参数
const uint32_t memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE }; //内存表大小
const uint32_t memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE }; //内存分块大小
const uint32_t memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE }; //内存总大小
// const uint32_t memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE }; //内存表大小
// const uint32_t memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,MEM3_BLOCK_SIZE }; //内存分块大小
// const uint32_t memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE,MEM3_MAX_SIZE }; //内存总大小
//内存管理控制器
struct _m_mallco_dev mallco_dev=
{
my_mem_init, //内存初始化
my_mem_perused, //内存使用率
mem1base,mem2base , //内存池
mem1mapbase,mem2mapbase , //内存管理状态表
0,0 //内存管理未就绪
};
//复制内存
//*des:目的地址
//*src:源地址
//n:需要复制的内存长度(字节为单位)
void mymemcpy(void *des,void *src,uint32_t n)
{
uint8_t *xdes=des;
uint8_t *xsrc=src;
while(n--)*xdes++=*xsrc++;
}
//设置内存
//*s:内存首地址
//c :要设置的值
//count:需要设置的内存大小(字节为单位)
void mymemset(void *s,uint8_t c,uint32_t count)
{
uint8_t *xs = s;
while(count--)*xs++=c;
}
//内存管理初始化
//memx:所属内存块
void my_mem_init(uint8_t memx)
{
log_i("mem_init.... %d %d ",memsize[memx] , memtblsize[memx]*2);
mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零
mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //内存池所有数据清零
mallco_dev.memrdy[memx]=1; //内存管理初始化OK
}
//获取内存使用率
//memx:所属内存块
//返回值:使用率(0~100)
uint8_t my_mem_perused(uint8_t memx)
{
uint32_t used=0;
uint32_t i;
for(i=0;i<memtblsize[memx];i++)
{
if(mallco_dev.memmap[memx][i])used++;
}
return (used*100)/(memtblsize[memx]);
}
//内存分配(内部调用)
//memx:所属内存块
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
uint32_t my_mem_malloc(uint8_t memx,uint32_t size)
{
signed long offset=0;
uint32_t nmemb; //需要的内存块数
uint32_t cmemb=0;//连续空内存块数
uint32_t i;
if(!mallco_dev.memrdy[memx]) mallco_dev.init(memx);//未初始化,先执行初始化
if(size==0)
return 0XFFFFFFFF;//不需要分配
nmemb=size/memblksize[memx]; //获取需要分配的连续内存块数
if(size%memblksize[memx]) nmemb++;
for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区
{
if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加
else cmemb=0; //连续内存块清零
if(cmemb==nmemb) //找到了连续nmemb个空内存块
{
for(i=0;i<nmemb;i++) //标注内存块非空
{
mallco_dev.memmap[memx][offset+i]=nmemb;
}
return (offset*memblksize[memx]);//返回偏移地址
}
}
return 0XFFFFFFFF;//未找到符合分配条件的内存块
}
//释放内存(内部调用)
//memx:所属内存块
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;
uint8_t my_mem_free(uint8_t memx,uint32_t offset)
{
int i;
if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
{
mallco_dev.init(memx);
return 1;//未初始化
}
if(offset<memsize[memx])//偏移在内存池内.
{
int index=offset/memblksize[memx]; //偏移所在内存块号码
int nmemb=mallco_dev.memmap[memx][index]; //内存块数量
for(i=0;i<nmemb;i++) //内存块清零
{
mallco_dev.memmap[memx][index+i]=0;
}
return 0;
}
else
return 2;//偏移超区了.
}
//释放内存(外部调用)
//memx:所属内存块
//ptr:内存首地址
void myfree(uint8_t memx,void *ptr)
{
uint32_t offset;
if(ptr==NULL)return;//地址为0.
offset=(uint32_t)ptr-(uint32_t)mallco_dev.membase[memx];
my_mem_free(memx,offset); //释放内存
}
//分配内存(外部调用)
//memx:所属内存块
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *mymalloc(uint8_t memx,uint32_t size)
{
uint32_t offset;
offset=my_mem_malloc(memx,size);
if(offset==0XFFFFFFFF)return NULL;
else return (void*)((uint32_t)mallco_dev.membase[memx]+offset);
}
//重新分配内存(外部调用)
//memx:所属内存块
//*ptr:旧内存首地址
//size:要分配的内存大小(字节)
//返回值:新分配到的内存首地址.
void *myrealloc(uint8_t memx,void *ptr,uint32_t size)
{
uint32_t offset;
offset=my_mem_malloc(memx,size);
if(offset==0XFFFFFFFF)return NULL;
else
{
mymemcpy((void*)((uint32_t)mallco_dev.membase[memx]+offset),ptr,size); //拷贝旧内存内容到新内存
myfree(memx,ptr); //释放旧内存
return (void*)((uint32_t)mallco_dev.membase[memx]+offset); //返回新内存首地址
}
}

@ -0,0 +1,143 @@
/**
******************************************************************************
* @file fonts.h
* @author MCD Application Team
* @version V1.0.0
* @date 18-February-2014
* @brief Header for fonts.c file
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
*
* 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 STMicroelectronics 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FONTS_H
#define __FONTS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
/** @addtogroup Utilities
* @{
*/
/** @addtogroup STM32_EVAL
* @{
*/
/** @addtogroup Common
* @{
*/
/** @addtogroup FONTS
* @{
*/
/** @defgroup FONTS_Exported_Types
* @{
*/
typedef struct _tFont
{
const uint8_t *table;
uint16_t Width;
uint16_t Height;
} sFONT;
extern sFONT Font24; // 3216
extern sFONT Font20; // 2010
extern sFONT Font16; // 1608
extern sFONT Font12; // 1206
extern sFONT Font8; // 1206
/*------------------------------------ 中文字体 ---------------------------------------------*/
extern sFONT CH_Font12 ; // 1212字体
extern sFONT CH_Font16 ; // 1616字体
extern sFONT CH_Font20 ; // 2020字体
extern sFONT CH_Font24 ; // 2424字体
extern sFONT CH_Font32 ; // 3232字体
/**
* @}
*/
/** @defgroup FONTS_Exported_Constants
* @{
*/
#define LINE(x) ((x) * (((sFONT *)LCD_GetFont())->Height))
/**
* @}
*/
/** @defgroup FONTS_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup FONTS_Exported_Functions
* @{
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __FONTS_H */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,220 @@
#include "fonts.h"
/****
*****************************************************************************************************************************************************************************************************************************************
* @
*
* STM32核心板
* https://shop212360197.taobao.com
* QQ交流群536665479
*
>>>>>
*
* 1.ASCII字符集: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
* 2.ASCII字模532162412201016081206
* 3.32322424202016161212
* 4.
* 5.
*
>>>>>
*
* 1. PCtolCD2018
* 2.C51格式
*
*******************************************************************************************************************************************************************************************************************************************FANKE*****
***/
// 汉字字模数据,字体为1212
// 添加新字模时,一定要不超过数组第一维的大小,用户可根据需求自行调整
// 中文标点符号和英文标点符号是不一样的!如果没有对中文标点符号进行取模,显示时要用英文输入标点,使用ASCII的字模
// 每个字模后面都必须要有一个对应的汉字作为索引
//
const uint8_t Chinese_1212[50][24]=
{
// 中(0) 文(1) 字(2) 体(3) :(4) 反(5) 客(6) 科(7) 技(8)
{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xFE,0x03,0x22,0x02,0x22,0x02,0xFE,0x03,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xFF,0x07,0x04,0x01,0x88,0x00,0x50,0x00,0x78,0x00,0x87,0x07,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xFE,0x07,0xF8,0x01,0xC0,0x00,0xFE,0x07,0x20,0x00,0x38,0x00,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x88,0x00,0x84,0x00,0xF4,0x07,0xC6,0x01,0xA6,0x01,0x94,0x02,0xEC,0x05,0x84,0x00,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x07,0x04,0x00,0xFC,0x03,0x14,0x02,0xA4,0x01,0x66,0x00,0x9E,0x07,0x00,0x00,0x00,0x00},{""},
{0x00,0x00,0x00,0x00,0x60,0x00,0xFE,0x07,0xFA,0x03,0x16,0x01,0xFF,0x0F,0xFC,0x03,0x04,0x02,0xFC,0x03,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x01,0x7F,0x01,0x84,0x01,0x3F,0x01,0x4C,0x01,0xF6,0x07,0x05,0x01,0x04,0x01,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x00,0xFF,0x07,0x84,0x00,0xFC,0x03,0x27,0x03,0xC4,0x00,0x37,0x07,0x00,0x00,0x00,0x00},{""},/*8*/
};
// 汉字字模数据,字体为1616
// 添加新字模时,一定要不超过数组第一维的大小,用户可根据需求自行调整
// 中文标点符号和英文标点符号是不一样的!如果没有对中文标点符号进行取模,显示时要用英文输入标点,使用ASCII的字模
// 每个字模后面都必须要有一个对应的汉字作为索引
//
const uint8_t Chinese_1616[50][32]=
{
// 中(0) 文(1) 字(2) 体(3) :(4) 反(5) 客(6) 科(7) 技(8)
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x40,0x00,0xFE,0x1F,0x42,0x10,0x42,0x10,0xFE,0x1F,0x42,0x10,0x40,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x80,0x00,0xFF,0x3F,0x08,0x04,0x08,0x04,0x10,0x02,0x20,0x01,0xC0,0x00,0x38,0x07,0x07,0x38,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x80,0x00,0xFE,0x1F,0x02,0x10,0xF8,0x07,0x00,0x03,0xFF,0x1F,0x80,0x00,0x80,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x01,0x0C,0x01,0xF4,0x1F,0x86,0x03,0x47,0x03,0x65,0x05,0x34,0x09,0xCC,0x17,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x1F,0x04,0x00,0xFC,0x0F,0x14,0x08,0x24,0x04,0x64,0x02,0x86,0x01,0x62,0x07,0x1D,0x38,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xFE,0x1F,0xF2,0x07,0x18,0x02,0xE6,0x01,0x1F,0x3E,0xF8,0x07,0x08,0x04,0xF8,0x07,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xBE,0x09,0x08,0x0B,0xFE,0x08,0x98,0x09,0xEC,0x3F,0x0A,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x02,0xFF,0x3F,0x04,0x02,0xE4,0x1F,0x4C,0x10,0x87,0x08,0x04,0x07,0x84,0x07,0x77,0x38,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*8*/
};
// 汉字字模数据,字体为2020
// 添加新字模时,一定要不超过数组第一维的大小,用户可根据需求自行调整
// 中文标点符号和英文标点符号是不一样的!如果没有对中文标点符号进行取模,显示时要用英文输入标点,使用ASCII的字模
// 每个字模后面都必须要有一个对应的汉字作为索引
//
const uint8_t Chinese_2020[20][60]=
{
// 中(0) 文(1) 字(2) 体(3) :(4) 反(5) 客(6) 科(7) 技(8)
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0xFC,0xFF,0x01,0x04,0x02,0x01,0x04,0x02,0x01,0x04,0x02,0x01,0x04,0x02,0x01,0xFC,0xFF,0x01,0x04,0x02,0x01,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x04,0x00,0xFF,0xFF,0x07,0x10,0x40,0x00,0x10,0x40,0x00,0x20,0x20,0x00,0x40,0x10,0x00,0x80,0x0C,0x00,0x00,0x07,0x00,0x80,0x0D,0x00,0x78,0xF0,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x06,0x00,0xFE,0xFF,0x03,0x02,0x00,0x02,0xF8,0x7F,0x00,0x00,0x30,0x00,0x00,0x0C,0x00,0xFF,0xFF,0x07,0x00,0x02,0x00,0x00,0x02,0x00,0x00,0x02,0x00,0xE0,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x10,0x08,0x00,0xF0,0xFF,0x03,0x08,0x1C,0x00,0x0C,0x2A,0x00,0x0E,0x2A,0x00,0x0A,0x49,0x00,0x88,0xC9,0x00,0xC8,0xFF,0x01,0x68,0x08,0x03,0x38,0x08,0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x03,0xF8,0x1F,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0xF8,0xFF,0x01,0x48,0x80,0x01,0x88,0xC0,0x00,0x08,0x61,0x00,0x08,0x36,0x00,0x04,0x1C,0x00,0x84,0xE3,0x00,0x72,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x03,0x00,0xFE,0xFF,0x01,0x62,0x00,0x01,0xF8,0x7F,0x00,0x7E,0x30,0x00,0x80,0x0F,0x00,0x7F,0xF0,0x03,0xF8,0x7F,0x00,0x08,0x40,0x00,0xF8,0x7F,0x00,0x08,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x40,0x00,0x1E,0x46,0x00,0x10,0x4C,0x00,0x10,0x58,0x00,0xFE,0x43,0x00,0x10,0x46,0x00,0x78,0x4C,0x00,0xDC,0x40,0x00,0x14,0xF0,0x03,0x92,0x4F,0x00,0x10,0x40,0x00,0x10,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x00,0x08,0x10,0x00,0xFF,0xFF,0x03,0x08,0x10,0x00,0x08,0x10,0x00,0xE8,0xFF,0x01,0x1C,0x02,0x01,0x0B,0x86,0x00,0x08,0x6C,0x00,0x08,0x18,0x00,0x08,0x6F,0x00,0xEF,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*8*/
};
// 汉字字模数据,字体为2424
// 添加新字模时,一定要不超过数组第一维的大小,用户可根据需求自行调整
// 中文标点符号和英文标点符号是不一样的!如果没有对中文标点符号进行取模,显示时要用英文输入标点,使用ASCII的字模
// 每个字模后面都必须要有一个对应的汉字作为索引
//
const uint8_t Chinese_2424[200][72]=
{
// 文本显示,可显示中文和字符集用户可根据需求对字库进行增添和删减体:反客科技
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x60,0x00,0xFF,0xFF,0xFF,0x60,0x00,0x0C,0x60,0x00,0x0C,0xC0,0x00,0x06,0xC0,0x00,0x06,0x80,0x01,0x03,0x00,0x83,0x01,0x00,0xC7,0x00,0x00,0x6C,0x00,0x00,0x38,0x00,0x00,0xEE,0x00,0xC0,0x83,0x07,0x78,0x00,0x3C,0x06,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0xFE,0xFF,0xFF,0x00,0x3C,0x00,0x00,0x7E,0x00,0x00,0xDB,0x00,0x80,0x99,0x00,0xC0,0x18,0x01,0x60,0x18,0x02,0x30,0x18,0x0C,0x1C,0x18,0x18,0x0E,0x18,0x70,0xE2,0xFF,0x47,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x18,0x00,0x30,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x18,0x00,0x30,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x04,0xC6,0x20,0x08,0xC6,0x30,0x18,0xC6,0x38,0x30,0xC6,0x18,0x20,0xC6,0x08,0x00,0xC6,0x00,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x30,0x00,0x20,0x30,0x04,0x30,0x30,0x0C,0x38,0x30,0x18,0x18,0x30,0x30,0x0C,0x30,0x60,0x06,0x30,0xC0,0x02,0x30,0x80,0x00,0x30,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0xF8,0x3F,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0xF8,0x3F,0x0C,0x18,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x18,0x00,0x30,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x18,0x00,0x30,0xF8,0xFF,0x3F,0x18,0x00,0x30,0x04,0xC6,0x20,0x08,0xC6,0x30,0x18,0xC6,0x38,0x30,0xC6,0x18,0x20,0xC6,0x08,0x00,0xC6,0x00,0xFE,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x30,0x00,0x20,0x30,0x04,0x30,0x30,0x0C,0x38,0x30,0x18,0x18,0x30,0x30,0x0C,0x30,0x60,0x06,0x30,0xC0,0x02,0x30,0x80,0x00,0x30,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0xFC,0xFF,0x7F,0x0C,0x18,0x60,0x0C,0x18,0x60,0x0C,0x18,0x60,0x0C,0x18,0x60,0x0C,0x18,0x60,0xFC,0xFF,0x7F,0x0C,0x18,0x60,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*8*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x60,0x00,0xFF,0xFF,0xFF,0x60,0x00,0x0C,0x60,0x00,0x0C,0xC0,0x00,0x06,0xC0,0x00,0x06,0x80,0x01,0x03,0x00,0x83,0x01,0x00,0xC7,0x00,0x00,0x6C,0x00,0x00,0x38,0x00,0x00,0xEE,0x00,0xC0,0x83,0x07,0x78,0x00,0x3C,0x06,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*9*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x07,0x00,0x7F,0x00,0x00,0x60,0xE0,0xFF,0x60,0x60,0xC0,0xFF,0x6F,0xC0,0x70,0x60,0xC0,0x70,0x60,0xC0,0xF8,0x61,0xC0,0xF8,0x63,0xC0,0x6C,0x66,0xC0,0x66,0x6C,0xC0,0x63,0x60,0xC0,0x61,0x60,0xC0,0x60,0xE0,0xFF,0x60,0x60,0xC0,0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x00,0x30,0x00,0xFE,0xFF,0xFF,0x06,0x00,0xC0,0x06,0x00,0xC0,0xE0,0xFF,0x0F,0x00,0x00,0x07,0x00,0x80,0x01,0x00,0xE0,0x00,0x00,0x30,0x00,0xFF,0xFF,0xFF,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x80,0x01,0x30,0xC0,0x00,0xF8,0xDF,0xFF,0xC8,0x60,0x06,0x84,0x71,0x0C,0x02,0x39,0x08,0x01,0x10,0x00,0x60,0x00,0x0C,0x70,0x00,0x0C,0xB8,0xFF,0xFF,0x3C,0x00,0x0C,0x36,0x04,0x0C,0x32,0x0C,0x0C,0x30,0x18,0x0C,0x30,0x10,0x0C,0x30,0x00,0x0C,0x30,0x00,0x0C,0x30,0xE0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*12*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x00,0x60,0xE0,0x00,0xF0,0xFF,0xFF,0x38,0x60,0x00,0xF6,0xFF,0xFF,0x33,0x60,0x00,0xF0,0xFF,0xFF,0x30,0x60,0x00,0xF0,0xFF,0xFF,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0xFE,0xFF,0xFF,0x00,0xFE,0x01,0x80,0x31,0x07,0x70,0x30,0x38,0x0F,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*13*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x7F,0x18,0x30,0x60,0x18,0x30,0x60,0x18,0x30,0x60,0x18,0x30,0x60,0xF8,0xFF,0x7F,0x18,0x30,0x60,0x18,0x30,0x60,0x18,0x30,0x60,0x18,0x30,0x60,0xF8,0xFF,0x7F,0x1C,0x30,0x60,0x0C,0x30,0x60,0x0C,0x30,0x60,0x06,0x30,0x60,0x02,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*14*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x00,0x30,0x00,0xF8,0xFF,0x7F,0x18,0x00,0x60,0x18,0x00,0x60,0x18,0x00,0x60,0x18,0x00,0x60,0xF8,0xFF,0x7F,0x18,0x00,0x60,0x18,0x00,0x00,0x18,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x06,0x00,0x00,0x06,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*15*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0xF8,0x3F,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0x18,0x30,0x0C,0xF8,0x3F,0x0C,0x18,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0x00,0x0C,0x00,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*16*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0xF8,0x7F,0x30,0x18,0x60,0xFF,0x1B,0x60,0x30,0xF8,0x7F,0x38,0x18,0x60,0x38,0x18,0x60,0xFC,0x18,0x60,0xB6,0xF9,0x7F,0x36,0x9A,0x01,0x33,0x18,0xC3,0x30,0x18,0x33,0x30,0x18,0x0E,0x30,0x18,0x1D,0x30,0xD8,0x39,0x30,0x7C,0xE0,0x30,0x08,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*17*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0xFE,0x7F,0x30,0x06,0x60,0xFE,0x06,0x60,0x30,0xFE,0x7F,0x30,0x06,0x63,0x30,0x06,0x03,0x30,0xFE,0xFF,0xB0,0x06,0x03,0x78,0x06,0x03,0x36,0x06,0x03,0x30,0xFA,0x7F,0x30,0x1B,0x60,0x30,0x1B,0x60,0xB0,0x19,0x60,0xB0,0xF9,0x7F,0xDE,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*18*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFF,0x7F,0x00,0x18,0x00,0xFE,0xFF,0xFF,0x06,0x18,0xC0,0xF6,0xDB,0xDF,0x00,0x18,0x00,0xF0,0xDB,0x1F,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x18,0x00,0x00,0x18,0x00,0xFC,0xFF,0x3F,0x0C,0xC6,0x30,0x0C,0xC6,0x30,0x0C,0xC6,0x30,0x0C,0xC6,0x30,0x0C,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*19*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x07,0x00,0x30,0x1C,0x00,0x30,0x00,0xFE,0xFF,0xFF,0x00,0x30,0x00,0x08,0x30,0x00,0x10,0x30,0x60,0x30,0x70,0x30,0x60,0xF0,0x18,0x40,0xB0,0x0C,0x00,0xBC,0x03,0x00,0x33,0x07,0xE0,0x30,0x0C,0x18,0x30,0x18,0x06,0x30,0x60,0x00,0x30,0xC0,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*20*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x30,0xFE,0x03,0x30,0x00,0x03,0x30,0x02,0xFB,0xFF,0x0C,0x01,0x30,0x98,0x31,0x30,0xB0,0x61,0x30,0xE0,0xE0,0x30,0xC0,0xC0,0x30,0xE0,0x81,0x30,0xB0,0x03,0x30,0x18,0x03,0x30,0x0C,0x02,0x30,0x06,0x00,0x30,0x03,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*21*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x00,0x30,0x00,0xFE,0xFF,0xFF,0x06,0x00,0xC0,0x06,0x00,0xC0,0xE0,0xFF,0x0F,0x00,0x00,0x07,0x00,0x80,0x01,0x00,0xE0,0x00,0x00,0x30,0x00,0xFF,0xFF,0xFF,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*22*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0xE0,0x00,0xF8,0xFF,0xFF,0x18,0x30,0x00,0x18,0x18,0x00,0xD8,0xFF,0xFF,0x18,0x06,0x00,0x18,0x86,0x01,0x18,0x83,0x01,0x98,0xFF,0xFF,0x18,0x80,0x01,0x18,0x80,0x01,0x0C,0x80,0x01,0xEC,0xFF,0xFF,0x04,0x80,0x01,0x06,0x80,0x01,0x03,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*23*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x18,0x0C,0x18,0x18,0x0C,0x30,0x18,0x0C,0x20,0xFF,0xFF,0x00,0x18,0x0C,0x00,0x18,0x0C,0x3E,0x18,0x0C,0x30,0x18,0x0C,0xB0,0xFF,0xFF,0x30,0x18,0x0C,0x30,0x18,0x0C,0x30,0x1C,0x0C,0x30,0x0C,0x0C,0x30,0x06,0x0C,0x7C,0x02,0x0C,0xCE,0x00,0x00,0x04,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*24*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x60,0xF8,0xFF,0x30,0x00,0x00,0x18,0x00,0x00,0x86,0x00,0x00,0xC3,0x00,0x00,0x60,0x00,0x00,0x30,0xFE,0xFF,0x38,0x00,0x0C,0x3C,0x00,0x0C,0x36,0x00,0x0C,0x33,0x00,0x0C,0x30,0x00,0x0C,0x30,0x00,0x0C,0x30,0x00,0x0C,0x30,0x00,0x0C,0x30,0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*25*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x30,0x0C,0x18,0xFF,0xFF,0x18,0x83,0xC1,0x7F,0x9B,0xD9,0x18,0xB3,0xC7,0x18,0x83,0xC1,0x18,0xFF,0xFF,0x18,0x00,0x00,0x18,0xFE,0x7F,0x18,0x06,0x60,0x18,0x06,0x60,0xD8,0xFE,0x7F,0x3C,0x06,0x60,0x03,0x06,0x60,0x00,0xFE,0x7F,0x00,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*26*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x38,0xFE,0x7F,0x20,0xC0,0x00,0x00,0xC0,0x00,0x00,0x60,0x00,0x83,0xFF,0x7F,0x1E,0x30,0x03,0x10,0x18,0x06,0x00,0x0E,0x0C,0x80,0x63,0x30,0xD8,0x60,0x60,0x18,0x6C,0x1B,0x0C,0x66,0x36,0x0C,0x63,0x66,0x8C,0x63,0xCC,0x06,0x60,0x00,0x06,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*27*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x07,0x00,0x7F,0x00,0x00,0x60,0xE0,0xFF,0x60,0x60,0xC0,0xFF,0x6F,0xC0,0x70,0x60,0xC0,0x70,0x60,0xC0,0xF8,0x61,0xC0,0xF8,0x63,0xC0,0x6C,0x66,0xC0,0x66,0x6C,0xC0,0x63,0x60,0xC0,0x61,0x60,0xC0,0x60,0xE0,0xFF,0x60,0x60,0xC0,0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*28*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFC,0xFC,0xC0,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF,0xFF,0xCF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xC0,0xC6,0xC6,0xC0,0xFE,0xC6,0xC0,0x03,0xFB,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*29*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x04,0x00,0x26,0x0C,0x00,0x46,0x98,0xFF,0xFF,0x90,0x01,0x06,0x80,0xFD,0x06,0x80,0x01,0xC6,0x80,0x01,0x66,0xB0,0xF9,0x66,0xB8,0xD9,0x36,0x98,0xD9,0x34,0x98,0xD9,0x1C,0xCC,0xF8,0x8C,0xCC,0x18,0x8E,0x66,0x00,0x9B,0x20,0xC0,0xF1,0x10,0xC0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*30*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xC0,0x00,0x70,0xC0,0x00,0x30,0xC0,0x00,0x30,0xC0,0x00,0x98,0xFF,0xFF,0x18,0xF0,0x03,0x1C,0xD0,0x02,0x1E,0xD8,0x06,0x1B,0xCC,0x04,0x19,0xC6,0x0C,0x18,0xC6,0x18,0x98,0xC3,0x30,0xD8,0xFC,0xEF,0x78,0xC0,0x80,0x18,0xC0,0x00,0x18,0xC0,0x00,0x18,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xF8,0xFF,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0xF8,0xFF,0x3F,0x98,0x01,0x30,0x98,0x03,0x18,0x18,0x03,0x08,0x18,0x06,0x0C,0x18,0x0C,0x06,0x08,0x18,0x03,0x0C,0xF0,0x00,0x0C,0xF0,0x01,0x06,0x1C,0x07,0x86,0x03,0x3C,0x73,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x70,0x00,0xFC,0xFF,0xFF,0x0C,0x07,0xC0,0x8C,0x03,0xC0,0xC0,0xFF,0x1F,0xF0,0x03,0x0E,0x1C,0x8E,0x03,0x00,0x78,0x00,0xC0,0xC7,0x07,0x3F,0x00,0xF8,0xE0,0xFF,0x1F,0x60,0x00,0x18,0x60,0x00,0x18,0x60,0x00,0x18,0xE0,0xFF,0x1F,0x60,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x80,0x07,0x18,0x7E,0x30,0x18,0x60,0x60,0x18,0x60,0x80,0x19,0x60,0x00,0x1B,0xFE,0x07,0x18,0x60,0x18,0x18,0xF0,0x71,0x18,0x70,0xC3,0x18,0x68,0x06,0x18,0x6C,0x00,0xFF,0x66,0xFE,0x18,0x62,0x00,0x18,0x60,0x00,0x18,0x60,0x00,0x18,0x60,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x03,0x30,0x00,0x03,0x30,0x00,0x03,0x30,0xFC,0xFF,0xFF,0x01,0x03,0x30,0x00,0x03,0x30,0x00,0x03,0x30,0xFE,0x7F,0xF0,0x19,0x60,0x3F,0x38,0x30,0x30,0x30,0x18,0x30,0x60,0x0C,0x30,0xC0,0x06,0x30,0x80,0x03,0x30,0xE0,0x0E,0x30,0x38,0x78,0x1F,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
};
// 汉字字模数据,字体为3232
// 添加新字模时,一定要不超过数组第一维的大小,用户可根据需求自行调整
// 中文标点符号和英文标点符号是不一样的!如果没有对中文标点符号进行取模,显示时要用英文输入标点,使用ASCII的字模
// 每个字模后面都必须要有一个对应的汉字作为索引
//
const uint8_t Chinese_3232[150][128]=
{
// 刷屏测试核心板型号:幕分辨率颜色
// 格式文本显示中字体反客科技
// 变量多余位填充空格正整数负小
// 总计种绘图矩形片制竖三基阶双层背景前
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xF8,0xFF,0x0F,0x60,0xF8,0xFF,0x0F,0x60,0x18,0x00,0x0C,0x63,0x18,0x00,0x0C,0x63,0x18,0x00,0x0C,0x63,0xF8,0xFF,0x0F,0x63,0xF8,0xFF,0x0F,0x63,0x18,0x00,0x0C,0x63,0x18,0x60,0x00,0x63,0x18,0x60,0x00,0x63,0x98,0xFF,0x0F,0x63,0x98,0xFF,0x0F,0x63,0x98,0x61,0x0C,0x63,0x98,0x61,0x0C,0x63,0x98,0x61,0x0C,0x63,0x9C,0x61,0x0C,0x63,0x8C,0x61,0x0C,0x60,0x8C,0x61,0x0C,0x60,0x8E,0xE1,0x0F,0x60,0x86,0xE1,0x07,0x60,0x07,0x60,0x80,0x7F,0x02,0x60,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x30,0xC0,0x61,0x30,0x60,0xC0,0x01,0x30,0x40,0x60,0x00,0xB0,0xFF,0xFF,0x7F,0xB0,0xFF,0xFF,0x7F,0x30,0x60,0x80,0x01,0x30,0x60,0x80,0x01,0x30,0x60,0x80,0x01,0xF0,0xFF,0xFF,0xFF,0xF8,0xFF,0xFF,0xFF,0x18,0x60,0x80,0x01,0x1C,0x60,0x80,0x01,0x0C,0x30,0x80,0x01,0x0E,0x18,0x80,0x01,0x07,0x0E,0x80,0x01,0x02,0x06,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0xC0,0x1E,0xFE,0x1F,0xC0,0x78,0xFE,0x1F,0xC6,0xF0,0x06,0x18,0xC6,0x60,0x06,0x18,0xC6,0x00,0xC6,0x18,0xC6,0x02,0xC6,0x18,0xC6,0x0E,0xC6,0x18,0xC6,0x1C,0xC6,0x18,0xC6,0x38,0xC6,0x18,0xC6,0x10,0xC6,0x18,0xC6,0x00,0xC6,0x18,0xC6,0x00,0xC6,0x18,0xC6,0x10,0xC6,0x18,0xC6,0x30,0xC6,0x18,0xC6,0x18,0x66,0x18,0xC6,0x18,0x60,0x00,0xC6,0x18,0xF0,0x01,0xC0,0x0C,0xB8,0x07,0xC0,0x0C,0x1E,0x0E,0xC0,0x8E,0x0F,0x38,0xC0,0xC6,0x03,0x30,0xFE,0xC0,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x08,0x00,0xC0,0x0C,0x3C,0x00,0xC0,0x7C,0x70,0x00,0xC0,0x30,0xE0,0x00,0xC0,0x00,0xC0,0xFC,0xFF,0xFF,0x00,0xFC,0xFF,0xFF,0x00,0x00,0xC0,0x00,0x3E,0x00,0xC0,0x00,0x3E,0x00,0xC0,0x00,0x30,0x00,0xC0,0x00,0x30,0xFC,0xDF,0x00,0x30,0xFC,0x9F,0x01,0x30,0x80,0x81,0x01,0x30,0x80,0x81,0x01,0x30,0x80,0x81,0x01,0x30,0x84,0x81,0x01,0x30,0x87,0x81,0x83,0xB0,0x87,0x01,0x83,0xF0,0x81,0x39,0x87,0xF0,0xE0,0x3F,0x86,0x78,0xFE,0x07,0xCE,0x10,0x1C,0x00,0xFC,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x60,0x00,0x70,0x00,0x60,0x00,0xE0,0x00,0x60,0x00,0xC0,0x00,0x60,0xF0,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0x07,0x18,0x00,0x60,0x00,0x0C,0x10,0x70,0x00,0x03,0x38,0x70,0x80,0x01,0x1E,0x70,0xC1,0xFF,0x0F,0xF8,0xF3,0xFF,0x87,0x68,0xEF,0xC1,0xC1,0x6C,0x04,0xF0,0xF0,0x66,0x00,0x78,0x38,0x67,0x00,0x1E,0x1C,0x63,0x80,0x07,0x0F,0x60,0xE0,0x83,0x03,0x60,0x7C,0xE0,0x0F,0x60,0x18,0x78,0x3C,0x60,0x00,0x1F,0x78,0x60,0xE0,0x07,0xF0,0x60,0xF8,0x01,0xC0,0x60,0x30,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x1C,0x00,0x00,0x0C,0x38,0x00,0x00,0x0C,0x10,0x08,0x60,0x0C,0x00,0x1C,0x70,0x0C,0x00,0x38,0x30,0x0C,0x00,0x30,0x30,0x0C,0x00,0x60,0x38,0x0C,0x00,0xE0,0x18,0x0C,0x00,0xC0,0x1C,0x0C,0x00,0x80,0x0C,0x0C,0x00,0x80,0x0E,0x0C,0x00,0x08,0x04,0x0C,0x00,0x18,0x00,0x0C,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x1C,0x00,0x0E,0x00,0xF8,0xFF,0x07,0x00,0xF0,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xC0,0x00,0x00,0xF8,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xFF,0x0F,0xC0,0xC0,0x00,0x00,0xFE,0xDF,0x00,0x00,0xFE,0xDF,0x00,0x00,0xC0,0xC0,0x00,0x00,0xE0,0xC0,0xFF,0xFF,0xE0,0xC3,0xFF,0xFF,0xE0,0xC7,0x18,0xC0,0xD0,0xCE,0x18,0x60,0xD8,0xCC,0x18,0x60,0xD8,0xC8,0x30,0x70,0xCC,0xC0,0x70,0x30,0xCE,0xC0,0x60,0x18,0xC6,0xE0,0xC0,0x1C,0xC0,0x60,0xC0,0x0F,0xC0,0x60,0x80,0x07,0xC0,0x70,0xC0,0x0F,0xC0,0x38,0xF8,0x3C,0xC0,0x1C,0x3E,0xF8,0xC0,0xDE,0x0F,0xE0,0xC0,0x84,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xFC,0xFF,0xCF,0x60,0xFC,0xFF,0xCF,0x60,0xC0,0xC0,0xC0,0x60,0xC0,0xC0,0xC0,0x60,0xC0,0xC0,0xC0,0x60,0xFE,0xFF,0xDF,0x60,0xFE,0xFF,0xDF,0x60,0xC0,0xC0,0xC0,0x60,0xE0,0xC0,0xC0,0x60,0x60,0xC0,0x00,0x60,0x30,0xC0,0x00,0x60,0x38,0xC0,0x80,0x7F,0x18,0x00,0x83,0x3F,0x00,0x00,0x03,0x00,0xF0,0xFF,0xFF,0x3F,0xF0,0xFF,0xFF,0x3F,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0xFF,0x1F,0xC0,0xFF,0xFF,0x1F,0xC0,0x00,0x00,0x18,0xC0,0x00,0x00,0x18,0xC0,0x00,0x00,0x18,0xC0,0xFF,0xFF,0x1F,0xC0,0xFF,0xFF,0x1F,0xC0,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x03,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0xFF,0xFF,0x1F,0x80,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0C,0x00,0xE0,0xFF,0x07,0x00,0xE0,0xFF,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*8*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x03,0x00,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0xC0,0x03,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*9*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x30,0xC0,0x61,0x30,0x60,0xC0,0x01,0x30,0x40,0x60,0x00,0xB0,0xFF,0xFF,0x7F,0xB0,0xFF,0xFF,0x7F,0x30,0x60,0x80,0x01,0x30,0x60,0x80,0x01,0x30,0x60,0x80,0x01,0xF0,0xFF,0xFF,0xFF,0xF8,0xFF,0xFF,0xFF,0x18,0x60,0x80,0x01,0x1C,0x60,0x80,0x01,0x0C,0x30,0x80,0x01,0x0E,0x18,0x80,0x01,0x07,0x0E,0x80,0x01,0x02,0x06,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0x60,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x18,0x60,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x0F,0x60,0x00,0x00,0x0C,0xE0,0xFF,0xFF,0x0F,0x60,0x00,0x00,0x0C,0x60,0x00,0x00,0x0C,0xE0,0xFF,0xFF,0x0F,0x60,0x30,0x00,0x0C,0x00,0x0C,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x80,0x03,0x83,0x01,0xC0,0x00,0x03,0x1F,0xF0,0xFF,0xFF,0xFF,0xCC,0x00,0x03,0xC6,0xC2,0x00,0x03,0x06,0xC0,0x00,0x03,0x06,0xC0,0x00,0xF3,0x07,0xC0,0x00,0xF3,0x03,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x1C,0x00,0x00,0x1C,0x38,0x00,0x00,0x0E,0x70,0x00,0x00,0x07,0xE0,0x00,0x80,0x03,0xC0,0x01,0xC0,0x01,0x80,0x03,0xF0,0x00,0x00,0x0F,0x78,0x00,0x00,0x3E,0x3E,0x00,0x00,0xF8,0x0F,0x00,0x00,0xE0,0xE6,0xFF,0xFF,0x87,0xE0,0xFF,0xFF,0x07,0x00,0x18,0x00,0x07,0x00,0x18,0x00,0x07,0x00,0x1C,0x00,0x07,0x00,0x0C,0x00,0x07,0x00,0x0E,0x00,0x03,0x00,0x07,0x00,0x03,0xC0,0x03,0x80,0x03,0xF0,0xE1,0xFF,0x01,0x7E,0xE0,0xFF,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*12*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x06,0x06,0xE0,0x00,0x06,0x0E,0xE0,0x01,0x06,0x1C,0xFE,0x0F,0xF6,0xFF,0xFE,0x0F,0xF6,0xFF,0x00,0x00,0x06,0x00,0x0C,0x64,0x46,0x40,0x0C,0x66,0xC6,0x60,0x08,0x63,0x86,0x30,0x80,0x61,0x06,0x18,0xFF,0x6F,0xF6,0xFF,0xFF,0x3F,0xF6,0xFF,0x60,0x30,0x06,0x0C,0x60,0x30,0x06,0x0C,0x60,0x00,0x06,0x0C,0xFE,0x0F,0xF7,0xFF,0xFE,0x0F,0xF3,0xFF,0x60,0x00,0x03,0x0C,0x60,0x80,0x01,0x0C,0x30,0xC0,0x01,0x0C,0x38,0xE0,0x00,0x0C,0x1C,0x70,0x00,0x0C,0x0F,0x3C,0x00,0x0C,0x06,0x18,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*13*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x80,0x03,0x00,0x18,0xC0,0x01,0x40,0x3C,0xE0,0x20,0xF0,0x70,0x38,0x38,0x78,0xE0,0xFD,0x1F,0x1E,0x80,0xF8,0x07,0x0C,0x00,0x02,0x23,0x04,0x80,0xC7,0x60,0x1E,0xE0,0x71,0xE0,0x78,0x7C,0xFC,0xFF,0xE1,0x1E,0xF8,0xFF,0xC3,0x04,0x00,0x03,0x01,0x00,0x00,0x03,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*14*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0xFE,0xFF,0x00,0x07,0xFE,0xFF,0xFE,0xFF,0x00,0x03,0xFE,0xFF,0x80,0x03,0x20,0x10,0x80,0x01,0x60,0x18,0xFC,0xFF,0x40,0x0C,0xFC,0xFF,0xFC,0xFF,0x0D,0xC0,0xFC,0xFF,0x0D,0xC3,0x0C,0x60,0x0C,0xC3,0x0C,0x3C,0x0C,0xC3,0x0C,0x0F,0x0C,0xC3,0xEC,0x03,0x0C,0xC3,0xCC,0xE0,0x0C,0xC3,0x0C,0x78,0x8C,0xC3,0x0C,0x1F,0x8C,0xC1,0xEC,0x03,0xCC,0xC3,0xCE,0xC0,0xE1,0x0F,0x06,0x78,0x78,0x3C,0x86,0x1F,0x3E,0x70,0xF7,0x83,0x0F,0xC0,0x62,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*15*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0xFF,0xFF,0x00,0xC0,0xFF,0xFF,0x00,0xE0,0x01,0x70,0x00,0x70,0x00,0x38,0x00,0x3C,0x00,0x0E,0x00,0xFF,0xFF,0xFF,0x1F,0xF6,0xFF,0xFF,0x1F,0x30,0x00,0x03,0x18,0x30,0x00,0x03,0x18,0x30,0x00,0x03,0x18,0x30,0x00,0x03,0x18,0xF0,0xFF,0xFF,0x1F,0xF0,0xFF,0xFF,0x1F,0x30,0x00,0x00,0x18,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x80,0x30,0x00,0x00,0x80,0x30,0x00,0x00,0xC0,0x30,0x00,0x00,0xC0,0xF0,0xFF,0xFF,0xFF,0xC0,0xFF,0xFF,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*16*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x0C,0x00,0x60,0x00,0x0E,0x00,0x60,0x00,0x06,0x00,0x60,0x00,0xFF,0x7F,0x60,0x80,0xFF,0x7F,0xFF,0xC7,0x03,0x78,0xFF,0x47,0x07,0x3C,0x60,0x60,0x0E,0x0E,0x70,0x30,0x9C,0x07,0xF0,0x11,0xF0,0x03,0xF0,0x03,0xF8,0x01,0x78,0x0F,0xFF,0x3F,0x78,0xF4,0x07,0xFC,0x6C,0xFC,0x00,0xE0,0x6E,0x18,0x00,0x00,0x67,0xC0,0xFF,0x3F,0x63,0xC0,0xFF,0x3F,0x62,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0xFF,0x3F,0x60,0xC0,0xFF,0x3F,0x60,0xC0,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*17*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x06,0x00,0x00,0x18,0x0E,0x00,0x00,0x18,0x38,0x00,0x00,0x18,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x30,0x00,0xFF,0xFF,0x33,0x00,0xFF,0xFF,0x33,0x00,0x00,0x03,0x30,0x00,0x00,0x03,0x70,0x00,0x00,0x03,0x60,0x00,0x00,0x03,0x60,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0xC0,0x01,0x00,0xE3,0xC7,0x83,0xF0,0xFF,0x87,0x87,0xFF,0x0F,0x00,0xFF,0x0F,0x00,0x00,0xFE,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*18*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x01,0x00,0x06,0x80,0x01,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x06,0x80,0x01,0x00,0x06,0xC0,0x01,0x00,0x0C,0xE0,0x00,0x00,0x18,0x70,0x00,0x00,0x38,0x38,0x00,0x00,0x70,0x1E,0x00,0x00,0xE0,0x0F,0x00,0x00,0x80,0x07,0x00,0x00,0xF0,0x1F,0x00,0x00,0x7C,0x7C,0x00,0x80,0x1F,0xF0,0x03,0xF8,0x03,0x80,0x3F,0x7F,0x00,0x00,0xFC,0x0E,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0xFC,0xFF,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0x00,0x80,0x07,0x00,0x00,0xC0,0x0F,0x00,0x00,0x60,0x1B,0x00,0x00,0x30,0x33,0x00,0x00,0x18,0x73,0x00,0x00,0x0C,0xE3,0x00,0x00,0x07,0xC3,0x01,0x80,0x03,0x83,0x07,0xC0,0x01,0x03,0x0F,0xF0,0x00,0x03,0x3C,0x38,0x00,0x03,0x78,0x1E,0xFF,0xFF,0xF3,0x0C,0xFF,0xFF,0x43,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x10,0x30,0x30,0x20,0x30,0x30,0x30,0x70,0xE0,0x30,0x30,0x38,0xC0,0x31,0x30,0x0C,0x80,0x33,0x30,0x07,0x00,0x31,0x30,0x02,0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x01,0x06,0x02,0x80,0x03,0x06,0x07,0xC0,0x01,0x06,0x1C,0xE0,0x00,0x06,0x38,0x70,0x00,0x06,0x70,0x38,0x00,0x06,0xE0,0x1C,0x00,0x06,0xC0,0x0E,0x00,0x06,0x80,0x04,0x00,0x07,0x00,0x00,0xFE,0x07,0x00,0x00,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0xF8,0xFF,0xFF,0x7F,0xF8,0xFF,0xFF,0x7F,0x18,0x00,0x03,0x60,0x18,0x00,0x03,0x60,0x18,0x00,0x03,0x60,0x18,0x00,0x03,0x60,0x18,0x00,0x03,0x60,0x18,0x00,0x03,0x60,0xF8,0xFF,0xFF,0x7F,0xF8,0xFF,0xFF,0x7F,0x18,0x00,0x03,0x60,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x07,0x00,0xFC,0xFF,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0x0C,0x00,0x00,0xC0,0x0C,0x00,0x00,0xC0,0x0C,0x00,0x00,0xC0,0xCC,0xFF,0xFF,0xC3,0xC0,0xFF,0xFF,0x03,0x00,0x00,0xE0,0x01,0x00,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x07,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x80,0x03,0x00,0x00,0xFE,0x03,0x00,0x00,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x30,0x00,0x80,0x03,0x30,0x00,0x80,0x01,0x30,0x00,0xC0,0x01,0x30,0x00,0xC0,0xFE,0xFF,0xFF,0x60,0xFE,0xFF,0xFF,0x60,0x00,0xFC,0x00,0x70,0x00,0xB6,0x01,0x78,0x00,0xB7,0x01,0x7C,0x00,0xB3,0x03,0x6E,0x80,0x33,0x03,0x66,0xC0,0x31,0x06,0x64,0xE0,0x30,0x0E,0x60,0x70,0x30,0x1C,0x60,0x38,0x30,0x38,0x60,0x1C,0x30,0x70,0x60,0x8F,0xFF,0xE7,0xE0,0x87,0xFF,0xC7,0x60,0x03,0x30,0x80,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x60,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x3F,0xE0,0xFF,0xFF,0x7F,0xE0,0xFF,0x3F,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x3F,0xE0,0xFF,0xFF,0x3F,0x60,0x0C,0x00,0x38,0x60,0x1C,0x00,0x1C,0x60,0x38,0x00,0x0E,0x60,0x30,0x00,0x0E,0x60,0xE0,0x00,0x07,0x60,0xC0,0xC1,0x03,0x70,0x80,0xE3,0x01,0x30,0x00,0xFF,0x00,0x30,0x00,0x3C,0x00,0x38,0x00,0xFF,0x00,0x1C,0xE0,0xE7,0x03,0x1C,0xFE,0x80,0x3F,0xCE,0x3F,0x00,0xFC,0x84,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xC0,0x03,0x00,0x00,0x80,0x03,0x00,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x0C,0x08,0x00,0x60,0x0C,0x0E,0x00,0x60,0x0C,0xFF,0xFF,0x67,0x80,0xFF,0xFF,0x07,0xE0,0x0F,0x80,0x03,0x78,0x1C,0xE0,0x01,0x18,0xF8,0x7C,0x00,0x00,0xC0,0x0F,0x00,0x00,0xFF,0xFF,0x00,0xFF,0x1F,0xF0,0xFF,0x3E,0x00,0x00,0xFC,0xC0,0xFF,0xFF,0x07,0xC0,0xFF,0xFF,0x07,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0xFF,0xFF,0x07,0xC0,0xFF,0xFF,0x07,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x1F,0x00,0x06,0xFF,0x3F,0x02,0x06,0xFE,0x00,0x06,0x06,0xC0,0x00,0x0C,0x06,0xC0,0x00,0x18,0x06,0xC0,0x00,0x30,0x06,0xFF,0x1F,0x20,0x06,0xFF,0x1F,0x00,0x06,0xC0,0x80,0x00,0x06,0xE0,0x80,0x03,0x06,0xE0,0x03,0x07,0x06,0xF0,0x06,0x0C,0x06,0xF0,0x0C,0x08,0x06,0xD8,0x18,0x00,0x06,0xDC,0x10,0xF0,0xFF,0xCE,0xF0,0xFF,0xFF,0xC7,0xF0,0x1F,0x06,0xC7,0x00,0x00,0x06,0xC2,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xC0,0x00,0x60,0x00,0xC0,0x00,0x60,0x00,0xC0,0x00,0x60,0xF0,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0x07,0xC0,0x00,0x60,0x00,0xC0,0x00,0x60,0x00,0xC0,0x00,0x60,0x00,0xC0,0x00,0x60,0xF6,0xFF,0x7F,0xE0,0xF7,0xFF,0x7F,0xFC,0x80,0x01,0x60,0x7F,0x00,0x03,0x30,0x63,0x00,0x03,0x18,0x60,0x00,0x06,0x0C,0x60,0x00,0x0C,0x07,0x60,0x00,0xB8,0x03,0x60,0x00,0xF0,0x01,0x60,0x00,0xF8,0x01,0x60,0x00,0xBE,0x07,0x60,0xE0,0x0F,0x7E,0x7F,0xFC,0x01,0xF8,0x3F,0x38,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x80,0x03,0x00,0x00,0x00,0x07,0x00,0xFC,0xFF,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0x00,0x30,0x30,0x00,0x80,0x30,0x30,0x04,0xE0,0x31,0x30,0x1E,0x70,0x30,0x30,0x38,0x38,0x30,0x30,0xF0,0x1E,0x30,0x30,0xE0,0x04,0x00,0x00,0x80,0xE0,0xFF,0xFF,0x07,0xE0,0xFF,0xFF,0x07,0x00,0x06,0x80,0x03,0x00,0x1C,0xE0,0x01,0x00,0x30,0xF0,0x00,0x00,0xE0,0x3E,0x00,0x00,0x80,0x0F,0x00,0x00,0xF0,0x3F,0x00,0x80,0x7F,0xF8,0x0F,0xFE,0x07,0x80,0xFF,0x3C,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x00,0x0C,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x00,0x0C,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x03,0x0C,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x03,0x0C,0xC0,0x00,0x03,0x0C,0xC0,0xFF,0xFF,0x0F,0xC0,0x00,0x03,0x0C,0x00,0x00,0x03,0x00,0xF8,0xFF,0xFF,0x7F,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x00,0xE0,0x01,0x00,0x00,0xF0,0x00,0x00,0x00,0xFC,0xFF,0x3F,0x00,0xFF,0xFF,0x3F,0xC0,0x07,0x00,0x1E,0xF0,0x01,0x80,0x07,0x7C,0x18,0xF0,0x01,0x18,0x78,0x3E,0x00,0x00,0xE0,0x0F,0x00,0x00,0xFC,0x79,0x00,0xE0,0x1F,0x1C,0x00,0xFE,0x03,0xFF,0xFF,0x1C,0xE0,0xFF,0xFF,0x00,0xF8,0x00,0x70,0x00,0x3F,0x00,0x3C,0xC0,0x8F,0x00,0x0F,0xF8,0xC1,0xC1,0x07,0x30,0x00,0xF7,0x01,0x00,0x00,0x3F,0x00,0x00,0xE0,0x0F,0x00,0x00,0xFF,0x01,0x00,0xFC,0x1F,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x07,0x00,0x00,0xC0,0x07,0x00,0x00,0xE0,0x1E,0x00,0x00,0x78,0x3C,0x00,0x00,0x3C,0x70,0x00,0x00,0x1F,0xE0,0x01,0xC0,0x07,0xC0,0x03,0xF0,0x03,0x00,0x0F,0xFC,0xFF,0xFF,0x7F,0x3F,0xFF,0xFF,0xF3,0x06,0x00,0x03,0xC0,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x03,0x00,0x00,0x02,0x83,0x01,0x80,0x07,0xC3,0x07,0xC0,0x01,0x03,0x0F,0xE0,0x00,0x03,0x3C,0x78,0x00,0x03,0xF8,0x1E,0x00,0x03,0xE0,0x0C,0xFC,0x03,0xC0,0x00,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x10,0x00,0x80,0x03,0x78,0x00,0x80,0x01,0xE0,0x00,0xC0,0x00,0x40,0x00,0xC0,0xFC,0xFF,0xFF,0x60,0xFC,0xFF,0xFF,0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x60,0x78,0x60,0x00,0x70,0x7C,0xE0,0x00,0x30,0x7E,0xC0,0x00,0x38,0x6F,0xC0,0x01,0x18,0x67,0x80,0x01,0x18,0x62,0x80,0x01,0x0C,0x60,0x00,0x03,0x0C,0x60,0x00,0x03,0x06,0x60,0x00,0x07,0x06,0x60,0x00,0x06,0x03,0x60,0x00,0x00,0x03,0x60,0x00,0x80,0x01,0x60,0xFE,0xFF,0xFF,0x60,0xFE,0xFF,0xFF,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0xF8,0xFF,0xFF,0x60,0xF8,0xFF,0xFF,0x60,0x00,0x60,0x00,0x60,0xE0,0xFF,0x3F,0x60,0xE0,0xFF,0x3F,0xFF,0x67,0x00,0x30,0xFF,0x67,0x00,0x30,0x60,0xE0,0xFF,0x3F,0x60,0x60,0x00,0x30,0x60,0x60,0x00,0x30,0x60,0xE0,0xFF,0x3F,0x60,0x60,0x00,0x30,0x60,0x60,0x00,0x30,0x60,0xE6,0xFF,0x3F,0xE0,0x67,0x00,0x30,0xFC,0x61,0x00,0x30,0x3F,0xFC,0xFF,0xFF,0x06,0xFC,0xFF,0xFF,0x00,0x00,0x82,0x01,0x00,0x80,0x03,0x0E,0x00,0xE0,0x00,0x38,0x00,0x38,0x00,0xE0,0x00,0x0C,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0xC0,0x01,0x00,0x00,0x80,0x03,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x78,0x00,0x00,0x00,0x1C,0x60,0x00,0x00,0x0E,0xE0,0x00,0x80,0x03,0x80,0x03,0xC0,0x01,0x00,0x0F,0xE0,0xFF,0xFF,0x1F,0xF8,0xFF,0xFF,0x7F,0x30,0x18,0x18,0x30,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x0C,0x18,0x00,0x00,0x0C,0x18,0x40,0x00,0x06,0x18,0xC0,0x80,0x07,0x18,0xC0,0xC0,0x03,0x18,0xE0,0xF8,0x00,0xF8,0x7F,0x3F,0x00,0xF0,0x3F,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*4*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x00,0xC0,0x03,0x00,0x00,0x80,0x07,0x00,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x0C,0x00,0x00,0x60,0x0C,0x18,0x30,0x60,0x0C,0x3C,0xF8,0x60,0x00,0x0F,0xE0,0x03,0xC0,0x03,0x00,0x0F,0xF0,0x00,0x00,0x3E,0x3E,0x00,0x00,0xF8,0x0C,0x00,0x00,0x60,0xE0,0xFF,0xFF,0x0F,0xE0,0xFF,0xFF,0x0F,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*5*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x0C,0x00,0x60,0x00,0x0E,0x00,0x60,0x00,0x06,0x00,0x60,0x00,0xFF,0x7F,0x60,0x80,0xFF,0x7F,0xFF,0xC7,0x03,0x78,0xFF,0x47,0x07,0x3C,0x60,0x60,0x0E,0x0E,0x70,0x30,0x9C,0x07,0xF0,0x11,0xF0,0x03,0xF0,0x03,0xF8,0x01,0x78,0x0F,0xFF,0x3F,0x78,0xF4,0x07,0xFC,0x6C,0xFC,0x00,0xE0,0x6E,0x18,0x00,0x00,0x67,0xC0,0xFF,0x3F,0x63,0xC0,0xFF,0x3F,0x62,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0x00,0x30,0x60,0xC0,0xFF,0x3F,0x60,0xC0,0xFF,0x3F,0x60,0xC0,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*6*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFF,0xFF,0xFF,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0xFE,0xFF,0xC0,0x00,0xFE,0xFF,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xC0,0x00,0x06,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x80,0x01,0x00,0x06,0xC0,0x00,0xFC,0xFF,0xC7,0x00,0xFC,0xFF,0xE7,0xFF,0x00,0x06,0xF0,0xFF,0xF8,0xFF,0x71,0x60,0x18,0x86,0xD9,0x60,0x18,0x86,0xC9,0x31,0xF8,0xFF,0x81,0x1B,0x98,0x87,0x01,0x1F,0xF0,0x7E,0x00,0x1F,0x3F,0xE6,0xC3,0xFB,0x06,0x06,0xF8,0xE0,0x00,0x00,0x30,0x80,0xF8,0xFF,0xFF,0x7F,0xF8,0xFF,0xFF,0x7F,0x00,0x00,0x06,0x00,0x80,0x01,0x06,0x00,0x80,0x01,0xFE,0x3F,0x80,0x01,0xFE,0x3F,0x80,0x01,0x06,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*8*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x80,0x01,0x08,0x06,0x81,0x01,0x18,0x86,0xC1,0x00,0x70,0xC6,0xC0,0x00,0x20,0x46,0xE0,0x00,0x00,0x06,0xE0,0xFF,0xFE,0xFF,0xF3,0xFF,0xFE,0xFF,0x7B,0x60,0x80,0x07,0x78,0x60,0xC0,0x1F,0x7C,0x60,0x70,0x76,0xFE,0x70,0x1C,0xC6,0xF5,0x30,0x06,0x06,0xE3,0x30,0xC0,0x01,0xE0,0x31,0xFF,0xFF,0xE1,0x39,0xFF,0xFF,0xC1,0x1B,0x70,0x80,0x81,0x1F,0x38,0xC0,0x80,0x0F,0xF8,0x70,0x80,0x0F,0xC0,0x3F,0xC0,0x1F,0x00,0x3E,0xE0,0x3D,0xF0,0xFF,0xF9,0x78,0xFF,0xC0,0x3C,0xF0,0x0E,0x00,0x1F,0xC0,0x00,0x00,0x06,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*9*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0xFF,0xFF,0x00,0x80,0xFF,0xFF,0x00,0xE0,0x00,0x70,0x00,0x70,0x00,0x38,0x00,0x38,0x00,0x0E,0x00,0xEE,0xFF,0xFF,0x1F,0xE6,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x03,0x18,0x60,0x00,0x03,0x18,0x60,0x00,0x03,0x18,0x60,0x00,0x03,0x18,0x60,0x00,0x03,0x18,0x60,0x00,0x03,0x18,0x60,0x80,0x07,0x18,0x60,0x80,0x3F,0x18,0x00,0xE0,0xF8,0x01,0x00,0x7C,0xC0,0x0F,0xC0,0x1F,0x00,0x3F,0xFE,0x03,0x00,0xF8,0x3C,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*10*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x01,0x06,0x02,0x80,0x03,0x06,0x07,0x80,0x01,0x06,0x0E,0xC0,0x00,0x06,0x1C,0xC0,0x00,0x06,0x18,0x60,0x00,0x06,0x30,0x70,0x00,0x06,0x70,0x30,0x00,0x06,0xE0,0x18,0x00,0x06,0xC0,0x1C,0x00,0x06,0xC0,0x0E,0x00,0x06,0x80,0x04,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x06,0x00,0x00,0xFE,0x07,0x00,0x00,0xFE,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*11*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x01,0x00,0x0E,0x80,0x01,0x00,0x1C,0xC0,0x00,0x00,0x10,0x30,0x00,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x00,0x80,0x01,0x00,0x30,0x86,0x03,0x30,0x18,0x06,0x0F,0x70,0x1C,0x06,0x04,0xE1,0x0E,0x06,0x00,0xC3,0x06,0x06,0x80,0x01,0x02,0xFE,0xFF,0x01,0x00,0xFC,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x60,0x00,0x3C,0x00,0x60,0x00,0x78,0x00,0x60,0x00,0xE0,0x00,0x60,0x00,0xC0,0x01,0x60,0x00,0x80,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x7E,0xF8,0xFF,0xFF,0x7E,0xF8,0xFF,0xFF,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x20,0x60,0x00,0x60,0x3C,0x60,0x00,0xE0,0x1F,0x60,0x00,0xE0,0x07,0x60,0x00,0xF0,0x01,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x3E,0xC0,0x00,0xFC,0x3F,0xC0,0x00,0xFC,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x80,0xFF,0xFF,0xC0,0x80,0xFF,0xFF,0xFE,0xBF,0xC1,0xC0,0xFE,0xBF,0xC1,0xC0,0xC0,0x80,0xC1,0xC0,0xE0,0x80,0xC1,0xC0,0xE0,0x82,0xC1,0xC0,0xF0,0x87,0xC1,0xC0,0xF0,0x8E,0xC1,0xC0,0xD8,0x9C,0xFF,0xFF,0xD8,0xB8,0xFF,0xFF,0xCC,0x90,0xC1,0xC0,0xCE,0x00,0xC0,0x00,0xC6,0x00,0xC0,0x00,0xC4,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x70,0x00,0x30,0x00,0x70,0x00,0x30,0x00,0xF8,0x00,0x18,0x00,0xDC,0x01,0x0C,0x02,0x8E,0x03,0x0C,0x07,0x07,0x07,0x86,0xC3,0x03,0x1E,0x83,0xE1,0x01,0x38,0xFF,0xF0,0x00,0xF0,0xFF,0xBC,0xFF,0xFF,0x60,0x98,0xFF,0x9F,0x30,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x8E,0xF7,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0x1F,0x00,0x1C,0x00,0x00,0x00,0x0E,0x02,0x00,0x00,0x07,0x06,0xE0,0x87,0x03,0x0E,0xFF,0xC7,0x01,0x1C,0x1F,0xE0,0x00,0x38,0x00,0xF8,0xFF,0x7F,0x00,0xF0,0xFF,0xE7,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x0C,0x20,0x00,0x60,0x0C,0x38,0x00,0x60,0x0C,0xFC,0xFF,0x61,0x0C,0xFE,0xFF,0x61,0x8C,0x0F,0xE0,0x60,0xCC,0x39,0x78,0x60,0xCC,0xF0,0x1E,0x60,0x0C,0xC0,0x07,0x60,0x0C,0xFC,0xFF,0x60,0xEC,0x1F,0xF0,0x6F,0xCC,0xF1,0x01,0x67,0x0C,0xF8,0x3F,0x60,0x0C,0x00,0x1E,0x60,0x0C,0x7E,0x00,0x60,0x0C,0xFF,0xFF,0x61,0x0C,0xC0,0xFF,0x61,0x0C,0x00,0x00,0x60,0x0C,0x00,0x00,0x60,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x0C,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x30,0x00,0xFF,0xFF,0x30,0x00,0xFF,0xFF,0xF8,0x3F,0x03,0x00,0xF8,0x3F,0x03,0x00,0x1C,0x03,0x03,0x00,0x0C,0x03,0x03,0x00,0x0E,0x03,0xFF,0x7F,0x04,0x03,0xFF,0x7F,0x00,0x03,0x03,0x60,0xFE,0x7F,0x03,0x60,0xFE,0x7F,0x03,0x60,0x00,0x03,0x03,0x60,0x80,0x03,0x03,0x60,0x80,0x01,0xFF,0x7F,0x80,0x07,0xFF,0x7F,0xC0,0x0F,0x03,0x60,0xC0,0x18,0x03,0x00,0xE0,0x30,0x03,0x00,0x70,0x20,0x03,0x00,0x3C,0x00,0xFF,0xFF,0x1E,0x00,0xFF,0xFF,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xFE,0xFF,0x1F,0xF0,0xFE,0xFF,0x1F,0x3C,0x60,0x60,0x00,0x1E,0x60,0x60,0x80,0x07,0x60,0x60,0xF0,0x01,0x60,0x60,0x60,0x80,0x60,0x60,0x00,0xE0,0x60,0x60,0x00,0x70,0xFE,0xFF,0x3F,0x3C,0xFE,0xFF,0x3F,0x0F,0x60,0x60,0xC0,0x07,0x60,0x60,0xF0,0x01,0x60,0x60,0x60,0x00,0x60,0x60,0x00,0x80,0x70,0x60,0x00,0xE0,0x30,0x60,0x00,0x70,0x30,0x60,0x00,0x3C,0x18,0x60,0x00,0x1E,0x1C,0x60,0x80,0x07,0x0E,0x60,0xE0,0x03,0x07,0x60,0xF8,0x00,0x02,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0xFF,0xFF,0xFF,0x80,0xFF,0xFF,0xFF,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0x01,0x00,0x00,0x80,0xFF,0xFF,0x01,0x80,0xFF,0xFF,0x01,0x80,0x01,0x80,0x01,0xC0,0x01,0x80,0x01,0xC0,0x00,0x80,0x01,0xC0,0x00,0x80,0x01,0xE0,0x00,0x80,0x01,0x70,0x00,0x80,0x01,0x38,0x00,0x80,0x01,0x3C,0x00,0x80,0x01,0x10,0x00,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x60,0x60,0x0C,0x00,0x60,0x30,0x0C,0x80,0x61,0xF0,0xFF,0x8F,0x61,0xF8,0xFF,0x8F,0x61,0x0C,0x0C,0x80,0x61,0x04,0x0C,0x80,0x61,0x00,0x0C,0x80,0x61,0xFE,0xFF,0x9F,0x61,0xFE,0xFF,0x9F,0x61,0x00,0x0C,0x80,0x61,0x00,0x0C,0x80,0x61,0x00,0x0C,0x80,0x61,0xF8,0xFF,0x87,0x61,0xF8,0xFF,0x87,0x61,0x18,0x0C,0x86,0x61,0x18,0x0C,0x86,0x61,0x18,0x0C,0x06,0x60,0x18,0x0C,0x06,0x60,0x18,0xEC,0x07,0x60,0x18,0xEC,0x03,0x60,0x00,0x0C,0x80,0x7F,0x00,0x0C,0x80,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x18,0xE6,0xFF,0x7F,0x18,0xE6,0xFF,0x7F,0x18,0x06,0x03,0x38,0x18,0x06,0x06,0x1C,0x18,0x06,0x0C,0x0F,0x18,0x06,0xF8,0x07,0x18,0x06,0xF0,0x01,0x18,0x86,0xFF,0x03,0x18,0xF6,0x0F,0x1F,0x18,0xE6,0x00,0xFC,0x00,0x06,0x03,0xC0,0x00,0x00,0x07,0x00,0xF0,0xFF,0xFF,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x02,0x00,0x03,0x00,0x06,0x80,0x03,0x00,0x0C,0xC0,0x01,0x00,0x38,0xE0,0x00,0x00,0x10,0x30,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0xFF,0x7F,0xF8,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x1F,0xE0,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x00,0x03,0x80,0x01,0x00,0x03,0x80,0x01,0x00,0x03,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x80,0x01,0x00,0x03,0x80,0xFF,0xFF,0x03,0x80,0xFF,0xFF,0x03,0x80,0x01,0x00,0x03,0x80,0xFF,0xFF,0x03,0x80,0xFF,0xFF,0x03,0x80,0x01,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x07,0xE0,0x00,0x80,0x03,0x80,0x01,0xE0,0x80,0x01,0x07,0x7C,0xFF,0xFF,0x3F,0x1F,0xFF,0xFF,0xF9,0x06,0x80,0x01,0xC0,0x00,0x80,0x01,0x00,0xFC,0xFF,0xFF,0x7F,0xFC,0xFF,0xFF,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xFC,0x07,0xF0,0x00,0xFC,0x07,0xF8,0x01,0x0C,0x06,0xBC,0x03,0x0C,0x03,0x0E,0x07,0x0C,0x83,0x07,0x1E,0x8C,0xC1,0x03,0x3C,0x8C,0xF1,0x00,0xF0,0xCC,0x7C,0x00,0xE0,0xCC,0x18,0x03,0x8C,0x8C,0x01,0x03,0x0C,0x0C,0x03,0x03,0x0C,0x0C,0x02,0x03,0x0C,0x0C,0x06,0x03,0x0C,0x0C,0x06,0x03,0x0C,0x0C,0x06,0x03,0x0C,0xFC,0x83,0x03,0x0C,0xFC,0x81,0x01,0x0C,0x0C,0xC0,0x01,0x0C,0x0C,0xC0,0x00,0x0C,0x0C,0x60,0x00,0x0C,0x0C,0x78,0x00,0x0C,0x0C,0x10,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0xFF,0x7F,0xFE,0x3F,0xFF,0x7F,0x00,0x30,0x06,0x60,0x00,0x30,0x06,0x60,0x04,0x30,0x06,0x30,0x0C,0x18,0x0E,0x30,0x1C,0x18,0x0C,0x30,0x38,0x18,0x0C,0x30,0x70,0x1C,0x1C,0x18,0xE0,0x0C,0x18,0x18,0xC0,0x0D,0x38,0x0C,0x80,0x0F,0x30,0x0E,0x00,0x07,0x70,0x06,0x00,0x0F,0xE0,0x03,0x80,0x1F,0xC0,0x01,0xC0,0x1D,0xE0,0x01,0xF0,0x38,0xF0,0x07,0x78,0x70,0x3C,0x1F,0x3C,0x20,0x0F,0x7C,0x0F,0xE0,0x03,0xF0,0x06,0xF8,0x00,0x40,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x60,0xF0,0xFF,0xFF,0x7F,0xF0,0xFF,0xFF,0x7F,0x30,0x00,0x00,0x60,0x30,0x00,0x00,0x00,0x30,0xFE,0xFF,0x3F,0x30,0xFE,0xFF,0x3F,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0xB0,0xFF,0xFF,0xFF,0x98,0xFF,0xFF,0xFF,0x18,0x80,0x03,0x00,0x18,0xE0,0x00,0x03,0x1C,0x70,0x00,0x07,0x0E,0x3C,0x00,0x1C,0x0E,0xFF,0xFF,0x3F,0x07,0xFE,0xFF,0xFF,0x02,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0xE0,0xFE,0x1F,0x18,0xFE,0xFE,0x1F,0xF8,0x3F,0x00,0x18,0xF8,0x81,0xE0,0x1F,0x18,0x80,0xFF,0x1F,0x18,0xC0,0x1F,0x18,0xF8,0xFF,0x00,0x18,0xF0,0x7F,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x0F,0xE0,0xFF,0xFF,0x0F,0x60,0x00,0x00,0x0C,0x60,0x00,0x00,0x0C,0xE0,0xFF,0xFF,0x0F,0xE0,0xFF,0xFF,0x0F,0x60,0x00,0x00,0x0C,0xE0,0xFF,0xFF,0x0F,0xE0,0xFF,0xFF,0x0F,0x60,0x00,0x00,0x0C,0x60,0x00,0x00,0x0C,0x60,0x00,0xFE,0x0F,0x60,0x00,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x00,0x18,0x60,0x00,0x00,0x18,0xE0,0xFF,0xFF,0x1F,0x60,0x00,0x01,0x18,0x00,0x00,0x03,0x00,0xFC,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0xFF,0x1F,0xC0,0x00,0x00,0x18,0xC0,0x00,0x00,0x18,0xC0,0xFF,0xFF,0x1F,0xC0,0x00,0x03,0x18,0x00,0x0C,0xC3,0x00,0x00,0x1F,0xE3,0x07,0xE0,0x03,0x03,0x3F,0xFC,0xF8,0x03,0xF8,0x18,0xF8,0x01,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x80,0x00,0x00,0x1C,0xC0,0x00,0x00,0x38,0x70,0x00,0xFE,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x61,0x30,0xF8,0xFF,0x61,0x30,0x18,0x80,0x61,0x30,0x18,0x80,0x61,0x30,0xF8,0xFF,0x61,0x30,0xF8,0xFF,0x61,0x30,0x18,0x80,0x61,0x30,0x18,0x80,0x61,0x30,0xF8,0xFF,0x61,0x30,0xF8,0xFF,0x61,0x30,0x18,0x80,0x61,0x30,0x18,0x80,0x01,0x30,0x18,0x80,0x01,0x30,0x18,0xFC,0xC1,0x3F,0x18,0xFC,0xC0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{""},/*2*/
};
sFONT CH_Font12 = { Chinese_1212[0], 12, 12 };
sFONT CH_Font16 = { Chinese_1616[0], 16, 16 };
sFONT CH_Font20 = { Chinese_2020[0], 20, 20 };
sFONT CH_Font24 = { Chinese_2424[0], 24, 24 };
sFONT CH_Font32 = { Chinese_3232[0], 32, 32 };

@ -0,0 +1,250 @@
/*
* This file is part of the EasyLogger Library.
*
* Created on: 2015-04-28
* Modified By Pophu 2023-08-22
*/
#if 1
#include <stdio.h>
#include <elog.h>
#include "main.h"
#include "cmsis_os2.h"
#include "FreeRTOSConfig.h"
#include "usart.h"
// #include "platform.h"
// extern UART_HandleTypeDef huart1;
extern void elog_entry(void *para);
extern void Init_Logger();
#define pLogMenuHuart &huart1
/* **************** 信号量 SemaPhore **************** */
osSemaphoreId_t elog_lockHandle;
const osSemaphoreAttr_t elog_lock_attributes = {
.name = "elog_lock"};
osSemaphoreId_t elog_dma_lockHandle;
const osSemaphoreAttr_t elog_dma_lock_attributes = {
.name = "elog_dma_lock"};
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
osSemaphoreId_t elog_asyncHandle;
const osSemaphoreAttr_t elog_async_attributes = {
.name = "elog_async"};
#endif
/* **************** Easylogger 任务 **************** */
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
osThreadId_t elogHandle;
const osThreadAttr_t elog_attributes = {
.name = "elog",
.stack_size = 256*4,
.priority = (osPriority_t)osPriorityLow,
};
#endif
// extern osSemaphoreId_t elog_lockHandle;
// extern osSemaphoreId_t elog_asyncHandle;
// extern osSemaphoreId_t elog_dma_lockHandle;
// extern osSemaphoreId_t elog_menuHandle;
volatile uint16_t asyncflag = 0;
/**
* EasyLogger port initialize
*
* @return result
*/
ElogErrCode elog_port_init(void)
{
ElogErrCode result = ELOG_NO_ERR;
// osSemaphoreRelease(elog_lockHandle);
// osSemaphoreRelease(elog_dma_lockHandle);
return result;
}
/**
* EasyLogger port deinitialize
*
*/
void elog_port_deinit(void)
{
/* add your code here */
}
/**
* output log port interface
*
* @param log output of log
* @param size log size
*/
void elog_port_output(const char *log, size_t size)
{
/* add your code here */
// #ifdef LOG_MENU_485
// log_menu_send_enable();
// #endif
HAL_UART_Transmit_DMA(pLogMenuHuart, (uint8_t *) log, size);
// HAL_UART_Transmit(&huart1, (uint8_t *) log, size,0xFF);
// printf((uint8_t *)log, size);
}
/**
* output lock
*/
void elog_port_output_lock(void)
{
/* add your code here */
osSemaphoreAcquire(elog_lockHandle, osWaitForever);
}
/**
* output unlock
*/
void elog_port_output_unlock(void)
{
/* add your code here */
osSemaphoreRelease(elog_lockHandle);
}
/**
* get current time interface
*
* @return current time
*/
const char *elog_port_get_time(void)
{
/* add your code here */
static char cur_system_time[16] = "";
snprintf(cur_system_time, 16, "%lu", osKernelGetTickCount());
return cur_system_time;
}
/**
* get current process name interface
*
* @return current process name
*/
const char *elog_port_get_p_info(void)
{
/* add your code here */
return "";
}
/**
* get current thread name interface
*
* @return current thread name
*/
const char *elog_port_get_t_info(void)
{
/* add your code here */
return "";
}
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
void elog_async_output_notice(void)
{
asyncflag++;
osSemaphoreRelease(elog_asyncHandle);
}
/* 借助串口发送完成中断,形成闭环,否则会阻塞 */
void elog_entry(void *para)
{
size_t get_log_size = 0;
static char poll_get_buf[ELOG_LINE_BUF_SIZE - 4];
if (elog_port_init() != ELOG_NO_ERR)
{
goto fail;
}
while (1)
{
if (osOK == osSemaphoreAcquire(elog_asyncHandle, osWaitForever))
{
// printf(" elog_asyncHandle acq ok... \r\n");
while (1)
{
if (osOK == osSemaphoreAcquire(elog_dma_lockHandle, osWaitForever))
{
asyncflag--;
get_log_size = elog_async_get_line_log(poll_get_buf, sizeof(poll_get_buf));
if (get_log_size)
{
elog_port_output(poll_get_buf, get_log_size);
}
else
{
osSemaphoreRelease(elog_dma_lockHandle);
break;
}
}
}
}
// osDelay(10);
}
fail:
osThreadExit();
}
#endif
void Init_Logger()
{
elog_lockHandle = osSemaphoreNew(1, 1, &elog_lock_attributes);
osSemaphoreRelease(elog_lockHandle);
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
elog_asyncHandle = osSemaphoreNew(1, 1, &elog_async_attributes);
elog_dma_lockHandle = osSemaphoreNew(1, 1, &elog_dma_lock_attributes);
osSemaphoreRelease(elog_dma_lockHandle);
#endif
elog_init();
// elog_set_filter_lvl(ELOG_LVL_INFO);
elog_set_output_enabled(ENABLE);
#ifdef ELOG_BUF_OUTPUT_ENABLE
elog_buf_enabled(ENABLE);
#endif
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
elog_async_enabled(ENABLE);
#endif
elog_set_text_color_enabled(ENABLE);
elog_output_lock_enabled(ENABLE);
/* set EasyLogger log format */
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME | ELOG_FMT_FUNC | ELOG_FMT_LINE);
/* start EasyLogger */
// elog_set_filter_tag("Modbus");
elog_start();
#ifdef ELOG_ASYNC_OUTPUT_ENABLE
elogHandle = osThreadNew(elog_entry, NULL, &elog_attributes);
#endif
}
#endif
Loading…
Cancel
Save