ADD FLASH(flash.h flash.cpp flash_def.h flash_cfg.h flash_sfdp.cpp)
ADD RunTimer(log.h ticks.h ticks.cpp) ADD sim_key form sdlmain
parent
8f7f72712c
commit
a1176112ce
|
@ -26,7 +26,7 @@ link_directories(easyx/lib64)
|
|||
|
||||
|
||||
file(GLOB_RECURSE SOURCES "demo/*/*.*" "sim/*/*.*")
|
||||
message(${SOURCES})
|
||||
#message(${SOURCES})
|
||||
add_subdirectory(SDL3 EXCLUDE_FROM_ALL)
|
||||
link_libraries(SDL3::SDL3)
|
||||
|
||||
|
@ -36,7 +36,7 @@ add_executable(HW_Lib main.c ${SOURCES})
|
|||
#导入库
|
||||
add_subdirectory(lib)
|
||||
target_link_libraries(HW_Lib HW_LIB_List HW_LIB_Task HW_LIB_Printf HW_LIB_Utils HW_LIB_Iic
|
||||
HW_LIB_Spi HW_LIB_Key HW_LIB_Oled HW_LIB_Font HW_LIB_Tft lvgl::lvgl
|
||||
HW_LIB_Spi HW_LIB_Key HW_LIB_Oled HW_LIB_Font HW_LIB_Tft lvgl::lvgl lvgl::examples lvgl::demos
|
||||
)
|
||||
|
||||
add_custom_command(TARGET HW_Lib POST_BUILD
|
||||
|
|
2
SDL3
2
SDL3
|
@ -1 +1 @@
|
|||
Subproject commit 89c6bc5f5022e71433a9e4eb1a2edc6d79be71f2
|
||||
Subproject commit 1266210685a14b344a9049938677a89a092dfa5c
|
|
@ -2,7 +2,9 @@
|
|||
#include "lv_port_disp.h"
|
||||
#include "lv_port_indev.h"
|
||||
#include "lvgl.h"
|
||||
#include "demos/lv_demos.h"
|
||||
#include <windows.h>
|
||||
//#include <widgets/lv_demo_widgets.h>
|
||||
#include "t_lvgl.h"
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
|
@ -38,8 +40,8 @@ int Test_lvgl(void *pVoid) {
|
|||
lv_port_disp_init();
|
||||
// lv_port_indev_init();
|
||||
|
||||
lv_example_get_started_1();
|
||||
// lv_demo_widgets();
|
||||
// lv_example_get_started_1();
|
||||
lv_demo_widgets();
|
||||
// printf("\nTEST Widgets\n");
|
||||
|
||||
while (1) {
|
||||
|
|
|
@ -131,16 +131,16 @@ int Test_OLED(void *pVoid) {
|
|||
// OLED_ShowPic(&oled, 0, 0, 64, 64, BMP1);
|
||||
OLED_Refresh(&oled);
|
||||
_beginthread(Get_Key, 0, NULL);
|
||||
pageinit();
|
||||
// pageinit();
|
||||
while (1) {
|
||||
if (pageid > 4)pageid = 0;
|
||||
item_h = pagesearch(pageid).item_h;
|
||||
item_w = pagesearch(pageid).item_w;
|
||||
// pagesearch(pageid).page(&oled);
|
||||
// sprintf(buf, "DATA:%d", s);
|
||||
// OLED_ShowString(&oled, 2, 51, buf, 12);
|
||||
OLED_Refresh(&oled);
|
||||
Sleep(200);
|
||||
// if (pageid > 4)pageid = 0;
|
||||
// item_h = pagesearch(pageid).item_h;
|
||||
// item_w = pagesearch(pageid).item_w;
|
||||
//// pagesearch(pageid).page(&oled);
|
||||
//// sprintf(buf, "DATA:%d", s);
|
||||
//// OLED_ShowString(&oled, 2, 51, buf, 12);
|
||||
// OLED_Refresh(&oled);
|
||||
// Sleep(200);
|
||||
}
|
||||
SIM_OLED_STOP();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <sysinfoapi.h>
|
||||
#include "stdio.h"
|
||||
#include "task.h"
|
||||
#include "log.h"
|
||||
|
||||
Task_t *task1;
|
||||
Task_t *task2;
|
||||
|
@ -34,22 +35,28 @@ typedef struct CustomUserData {
|
|||
void exampleTimer4Callback(Task_t *task, void *userData) {
|
||||
CustomUserData *customUserData = (CustomUserData *) userData;
|
||||
customUserData->count--;
|
||||
printf("[%012ld] Task:%p callback-> %s.\r\n", GetTick(), task, customUserData->str);
|
||||
printf("[%012llu] Task:%p callback-> %s.\r\n", GetTick(), task, customUserData->str);
|
||||
if (customUserData->count > 0) {
|
||||
TaskStart(task);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_RUN_TIMER_FUN
|
||||
#define LOG_RUN_TIMER_FUN GetTick()
|
||||
int Test_task(void *pVoid) {
|
||||
TaskInit(GetTick);
|
||||
TaskCreat(task1, 1000, -1, exampleTimer1Callback, "1000ms CYCLE task");
|
||||
TaskCreat(task2, 5000, -1, exampleTimer2Callback, "5000ms ONCE task");
|
||||
TaskCreat(task3, 3456, 2, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE task");
|
||||
CustomUserData customUserData = {
|
||||
.count = 3,
|
||||
.str = "2000ms 3 task"
|
||||
};
|
||||
TaskCreat(task4, 2000, 1, exampleTimer4Callback, &customUserData);
|
||||
LOG_RUN_TIME() {
|
||||
TaskInit(GetTick);
|
||||
TaskCreat(task1, 1000, -1, exampleTimer1Callback, "1000ms CYCLE task");
|
||||
TaskCreat(task2, 5000, -1, exampleTimer2Callback, "5000ms ONCE task");
|
||||
TaskCreat(task3, 3456, 2, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE task");
|
||||
CustomUserData customUserData = {
|
||||
.count = 3,
|
||||
.str = "2000ms 3 task"
|
||||
};
|
||||
TaskCreat(task4, 2000, 1, exampleTimer4Callback, &customUserData);
|
||||
}
|
||||
|
||||
|
||||
while (1) {
|
||||
TaskRun();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "t_tft.h"
|
||||
#include "sim_display.h"
|
||||
#include "tool.h"
|
||||
|
||||
#define LOG_WITH_RUN_TIMER
|
||||
#include "log.h"
|
||||
|
||||
TFT_T demo_tft;
|
||||
|
@ -103,6 +105,10 @@ uint8_t tft_senddata(uint8_t *data, size_t len) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int64_t GetSysCnt64() {
|
||||
|
||||
}
|
||||
|
||||
int Test_tft(void *arg) {
|
||||
//设备信息预填充
|
||||
demo_tft.width = 480;//实际如有支持不用填(如ST7735/7796)
|
||||
|
@ -141,11 +147,11 @@ int Test_tft(void *arg) {
|
|||
TFT_ShowCHString(&demo_tft, 0, 60, "星海科技机械师", 1);
|
||||
|
||||
|
||||
TFT_DrawCircle(&demo_tft, 25, 25, 10);
|
||||
|
||||
|
||||
TFT_DrawCircle(&demo_tft, 25, 25, 15);
|
||||
TFT_DrawRoundedRect(&demo_tft, 200, 0, 100, 30, 8);
|
||||
TFT_DrawArc(&demo_tft, 200, 50, 30, 0, 360);
|
||||
TFT_DrawCross(&demo_tft, 25, 25, 10);
|
||||
|
||||
TFT_DrawXCross(&demo_tft, 25, 25, 10);
|
||||
|
||||
TFT_ShowString(&demo_tft, 60, 20, "JiXieShi", 16, 1);
|
||||
|
||||
|
@ -162,6 +168,7 @@ int Test_tft(void *arg) {
|
|||
//
|
||||
// Sleep(5);
|
||||
// }
|
||||
|
||||
SIM_Display_STOP(&tft_display);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ set(LIBRARIES
|
|||
HW_LIB_Key key key/inc
|
||||
HW_LIB_Oled oled oled/inc
|
||||
HW_LIB_Tft tft tft/inc
|
||||
HW_LIB_Flash flash flash/inc
|
||||
)
|
||||
|
||||
# 循环浏览库列表以创建它们
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,359 @@
|
|||
#include "flash.h"
|
||||
|
||||
/**
|
||||
* JEDEC Standard JESD216 Terms and definitions:
|
||||
*
|
||||
* DWORD: Four consecutive 8-bit bytes used as the basic 32-bit building block for headers and parameter tables.
|
||||
*
|
||||
* Sector: The minimum granularity - size and alignment - of an area that can be erased in the data array
|
||||
* of a flash memory device. Different areas within the address range of the data array may have a different
|
||||
* minimum erase granularity (sector size).
|
||||
*/
|
||||
|
||||
#ifdef FLASH_USING_SFDP
|
||||
|
||||
/* support maximum SFDP major revision by driver */
|
||||
#define SUPPORT_MAX_SFDP_MAJOR_REV 1
|
||||
/* the JEDEC basic flash parameter table length is 9 DWORDs (288-bit) on JESD216 (V1.0) initial release standard */
|
||||
#define BASIC_TABLE_LEN 9
|
||||
/* the smallest eraser in SFDP eraser table */
|
||||
#define SMALLEST_ERASER_INDEX 0
|
||||
/**
|
||||
* SFDP parameter header structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t id; /**< Parameter ID LSB */
|
||||
uint8_t minor_rev; /**< Parameter minor revision */
|
||||
uint8_t major_rev; /**< Parameter major revision */
|
||||
uint8_t len; /**< Parameter table length(in double words) */
|
||||
uint32_t ptp; /**< Parameter table 24bit pointer (byte address) */
|
||||
} sfdp_para_header;
|
||||
|
||||
static flash_err read_sfdp_data(const FLASH_t *flash, uint32_t addr, uint8_t *read_buf, size_t size);
|
||||
|
||||
static bool read_sfdp_header(FLASH_t *flash);
|
||||
|
||||
static bool read_basic_header(const FLASH_t *flash, sfdp_para_header *basic_header);
|
||||
|
||||
static bool read_basic_table(FLASH_t *flash, sfdp_para_header *basic_header);
|
||||
|
||||
extern void flash_log_debug(const char *file, const long line, const char *format, ...);
|
||||
|
||||
extern void flash_log_info(const char *format, ...);
|
||||
|
||||
/**
|
||||
* Read SFDP parameter information
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return true: read OK
|
||||
*/
|
||||
bool flash_read_sfdp(FLASH_t *flash) {
|
||||
FLASH_ASSERT(flash);
|
||||
|
||||
/* JEDEC basic flash parameter header */
|
||||
sfdp_para_header basic_header;
|
||||
if (read_sfdp_header(flash) && read_basic_header(flash, &basic_header)) {
|
||||
return read_basic_table(flash, &basic_header);
|
||||
} else {
|
||||
FLASH_INFO("Warning: Read SFDP parameter header information failed. The %s does not support JEDEC SFDP.",
|
||||
flash->name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read SFDP parameter header
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return true: read OK
|
||||
*/
|
||||
static bool read_sfdp_header(FLASH_t *flash) {
|
||||
flash_sfdp *sfdp = &flash->sfdp;
|
||||
/* The SFDP header is located at address 000000h of the SFDP data structure.
|
||||
* It identifies the SFDP Signature, the number of parameter headers, and the SFDP revision numbers. */
|
||||
/* sfdp parameter header address */
|
||||
uint32_t header_addr = 0;
|
||||
/* each parameter header being 2 DWORDs (64-bit) */
|
||||
uint8_t header[2 * 4] = {0};
|
||||
|
||||
FLASH_ASSERT(flash);
|
||||
|
||||
sfdp->available = false;
|
||||
/* read SFDP header */
|
||||
if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != FLASH_SUCCESS) {
|
||||
FLASH_INFO("Error: Can't read SFDP header.");
|
||||
return false;
|
||||
}
|
||||
/* check SFDP header */
|
||||
if (!(header[0] == 'S' &&
|
||||
header[1] == 'F' &&
|
||||
header[2] == 'D' &&
|
||||
header[3] == 'P')) {
|
||||
FLASH_DEBUG("Error: Check SFDP signature error. It's must be 50444653h('S' 'F' 'D' 'P').");
|
||||
return false;
|
||||
}
|
||||
sfdp->minor_rev = header[4];
|
||||
sfdp->major_rev = header[5];
|
||||
if (sfdp->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
|
||||
FLASH_INFO("Error: This reversion(V%d.%d) of SFDP is not supported.", sfdp->major_rev, sfdp->minor_rev);
|
||||
return false;
|
||||
}
|
||||
FLASH_DEBUG("Check SFDP header is OK. The reversion is V%d.%d, NPN is %d.", sfdp->major_rev, sfdp->minor_rev,
|
||||
header[6]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read JEDEC basic parameter header
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return true: read OK
|
||||
*/
|
||||
static bool read_basic_header(const FLASH_t *flash, sfdp_para_header *basic_header) {
|
||||
/* The basic parameter header is mandatory, is defined by this standard, and starts at byte offset 08h. */
|
||||
uint32_t header_addr = 8;
|
||||
/* each parameter header being 2 DWORDs (64-bit) */
|
||||
uint8_t header[2 * 4] = {0};
|
||||
|
||||
FLASH_ASSERT(flash);
|
||||
FLASH_ASSERT(basic_header);
|
||||
|
||||
/* read JEDEC basic flash parameter header */
|
||||
if (read_sfdp_data(flash, header_addr, header, sizeof(header)) != FLASH_SUCCESS) {
|
||||
FLASH_INFO("Error: Can't read JEDEC basic flash parameter header.");
|
||||
return false;
|
||||
}
|
||||
basic_header->id = header[0];
|
||||
basic_header->minor_rev = header[1];
|
||||
basic_header->major_rev = header[2];
|
||||
basic_header->len = header[3];
|
||||
basic_header->ptp = (long) header[4] | (long) header[5] << 8 | (long) header[6] << 16;
|
||||
/* check JEDEC basic flash parameter header */
|
||||
if (basic_header->major_rev > SUPPORT_MAX_SFDP_MAJOR_REV) {
|
||||
FLASH_INFO("Error: This reversion(V%d.%d) of JEDEC basic flash parameter header is not supported.",
|
||||
basic_header->major_rev, basic_header->minor_rev);
|
||||
return false;
|
||||
}
|
||||
if (basic_header->len < BASIC_TABLE_LEN) {
|
||||
FLASH_INFO("Error: The JEDEC basic flash parameter table length (now is %d) error.", basic_header->len);
|
||||
return false;
|
||||
}
|
||||
FLASH_DEBUG("Check JEDEC basic flash parameter header is OK. The table id is %d, reversion is V%d.%d,"
|
||||
" length is %d, parameter table pointer is 0x%06lX.", basic_header->id, basic_header->major_rev,
|
||||
basic_header->minor_rev, basic_header->len, basic_header->ptp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read JEDEC basic parameter table
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return true: read OK
|
||||
*/
|
||||
static bool read_basic_table(FLASH_t *flash, sfdp_para_header *basic_header) {
|
||||
flash_sfdp *sfdp = &flash->sfdp;
|
||||
/* parameter table address */
|
||||
uint32_t table_addr = basic_header->ptp;
|
||||
/* parameter table */
|
||||
uint8_t table[BASIC_TABLE_LEN * 4] = {0}, i, j;
|
||||
|
||||
FLASH_ASSERT(flash);
|
||||
FLASH_ASSERT(basic_header);
|
||||
|
||||
/* read JEDEC basic flash parameter table */
|
||||
if (read_sfdp_data(flash, table_addr, table, sizeof(table)) != FLASH_SUCCESS) {
|
||||
FLASH_INFO("Warning: Can't read JEDEC basic flash parameter table.");
|
||||
return false;
|
||||
}
|
||||
/* print JEDEC basic flash parameter table info */
|
||||
FLASH_DEBUG("JEDEC basic flash parameter table info:");
|
||||
FLASH_DEBUG("MSB-LSB 3 2 1 0");
|
||||
for (i = 0; i < BASIC_TABLE_LEN; i++) {
|
||||
FLASH_DEBUG("[%04d] 0x%02X 0x%02X 0x%02X 0x%02X", i + 1, table[i * 4 + 3], table[i * 4 + 2], table[i * 4 + 1],
|
||||
table[i * 4]);
|
||||
}
|
||||
|
||||
/* get block/sector 4 KB erase supported and command */
|
||||
sfdp->erase_4k_cmd = table[1];
|
||||
switch (table[0] & 0x03) {
|
||||
case 1:
|
||||
sfdp->erase_4k = true;
|
||||
FLASH_DEBUG("4 KB Erase is supported throughout the device. Command is 0x%02X.", sfdp->erase_4k_cmd);
|
||||
break;
|
||||
case 3:
|
||||
sfdp->erase_4k = false;
|
||||
FLASH_DEBUG("Uniform 4 KB erase is unavailable for this device.");
|
||||
break;
|
||||
default:
|
||||
FLASH_INFO("Error: Uniform 4 KB erase supported information error.");
|
||||
return false;
|
||||
}
|
||||
/* get write granularity */
|
||||
//TODO 目前为 1.0 所提供的方式,后期支持 V1.5 及以上的方式读取 page size
|
||||
switch ((table[0] & (0x01 << 2)) >> 2) {
|
||||
case 0:
|
||||
sfdp->write_gran = 1;
|
||||
FLASH_DEBUG("Write granularity is 1 byte.");
|
||||
break;
|
||||
case 1:
|
||||
sfdp->write_gran = 256;
|
||||
FLASH_DEBUG("Write granularity is 64 bytes or larger.");
|
||||
break;
|
||||
}
|
||||
/* volatile status register block protect bits */
|
||||
switch ((table[0] & (0x01 << 3)) >> 3) {
|
||||
case 0:
|
||||
/* Block Protect bits in device's status register are solely non-volatile or may be
|
||||
* programmed either as volatile using the 50h instruction for write enable or non-volatile
|
||||
* using the 06h instruction for write enable.
|
||||
*/
|
||||
sfdp->sr_is_non_vola = true;
|
||||
FLASH_DEBUG("Target flash status register is non-volatile.");
|
||||
break;
|
||||
case 1:
|
||||
/* block protect bits in device's status register are solely volatile. */
|
||||
sfdp->sr_is_non_vola = false;
|
||||
FLASH_DEBUG("Block Protect bits in device's status register are solely volatile.");
|
||||
/* write enable instruction select for writing to volatile status register */
|
||||
switch ((table[0] & (0x01 << 4)) >> 4) {
|
||||
case 0:
|
||||
sfdp->vola_sr_we_cmd = FLASH_VOLATILE_SR_WRITE_ENABLE;
|
||||
FLASH_DEBUG("Flash device requires instruction 50h as the write enable prior "
|
||||
"to performing a volatile write to the status register.");
|
||||
break;
|
||||
case 1:
|
||||
sfdp->vola_sr_we_cmd = FLASH_CMD_WRITE_ENABLE;
|
||||
FLASH_DEBUG("Flash device requires instruction 06h as the write enable prior "
|
||||
"to performing a volatile write to the status register.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* get address bytes, number of bytes used in addressing flash array read, write and erase. */
|
||||
switch ((table[2] & (0x03 << 1)) >> 1) {
|
||||
case 0:
|
||||
sfdp->addr_3_byte = true;
|
||||
sfdp->addr_4_byte = false;
|
||||
FLASH_DEBUG("3-Byte only addressing.");
|
||||
break;
|
||||
case 1:
|
||||
sfdp->addr_3_byte = true;
|
||||
sfdp->addr_4_byte = true;
|
||||
FLASH_DEBUG("3- or 4-Byte addressing.");
|
||||
break;
|
||||
case 2:
|
||||
sfdp->addr_3_byte = false;
|
||||
sfdp->addr_4_byte = true;
|
||||
FLASH_DEBUG("4-Byte only addressing.");
|
||||
break;
|
||||
default:
|
||||
sfdp->addr_3_byte = false;
|
||||
sfdp->addr_4_byte = false;
|
||||
FLASH_INFO("Error: Read address bytes error!");
|
||||
return false;
|
||||
}
|
||||
/* get flash memory capacity */
|
||||
uint32_t table2_temp = ((long) table[7] << 24) | ((long) table[6] << 16) | ((long) table[5] << 8) | (long) table[4];
|
||||
switch ((table[7] & (0x01 << 7)) >> 7) {
|
||||
case 0:
|
||||
sfdp->capacity = 1 + (table2_temp >> 3);
|
||||
break;
|
||||
case 1:
|
||||
table2_temp &= 0x7FFFFFFF;
|
||||
if (table2_temp > sizeof(sfdp->capacity) * 8 + 3) {
|
||||
sfdp->capacity = 0;
|
||||
FLASH_INFO("Error: The flash capacity is grater than 32 Gb/ 4 GB! Not Supported.");
|
||||
return false;
|
||||
}
|
||||
sfdp->capacity = 1L << (table2_temp - 3);
|
||||
break;
|
||||
}
|
||||
FLASH_DEBUG("Capacity is %ld Bytes.", sfdp->capacity);
|
||||
/* get erase size and erase command */
|
||||
for (i = 0, j = 0; i < FLASH_SFDP_ERASE_TYPE_MAX_NUM; i++) {
|
||||
if (table[28 + 2 * i] != 0x00) {
|
||||
sfdp->eraser[j].size = 1L << table[28 + 2 * i];
|
||||
sfdp->eraser[j].cmd = table[28 + 2 * i + 1];
|
||||
FLASH_DEBUG("Flash device supports %ldKB block erase. Command is 0x%02X.", sfdp->eraser[j].size / 1024,
|
||||
sfdp->eraser[j].cmd);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
/* sort the eraser size from small to large */
|
||||
for (i = 0, j = 0; i < FLASH_SFDP_ERASE_TYPE_MAX_NUM; i++) {
|
||||
if (sfdp->eraser[i].size) {
|
||||
for (j = i + 1; j < FLASH_SFDP_ERASE_TYPE_MAX_NUM; j++) {
|
||||
if (sfdp->eraser[j].size != 0 && sfdp->eraser[i].size > sfdp->eraser[j].size) {
|
||||
/* swap the small eraser */
|
||||
uint32_t temp_size = sfdp->eraser[i].size;
|
||||
uint8_t temp_cmd = sfdp->eraser[i].cmd;
|
||||
sfdp->eraser[i].size = sfdp->eraser[j].size;
|
||||
sfdp->eraser[i].cmd = sfdp->eraser[j].cmd;
|
||||
sfdp->eraser[j].size = temp_size;
|
||||
sfdp->eraser[j].cmd = temp_cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sfdp->available = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static flash_err read_sfdp_data(const FLASH_t *flash, uint32_t addr, uint8_t *read_buf, size_t size) {
|
||||
uint8_t cmd[] = {
|
||||
FLASH_CMD_READ_SFDP_REGISTER,
|
||||
(uint8_t) ((addr >> 16) & 0xFF),
|
||||
(uint8_t) ((addr >> 8) & 0xFF),
|
||||
(uint8_t) ((addr >> 0) & 0xFF),
|
||||
FLASH_DUMMY_DATA,
|
||||
};
|
||||
|
||||
FLASH_ASSERT(flash);
|
||||
FLASH_ASSERT(addr < 1L << 24);
|
||||
FLASH_ASSERT(read_buf);
|
||||
FLASH_ASSERT(flash->spi.wr);
|
||||
|
||||
return flash->spi.wr(&flash->spi, cmd, sizeof(cmd), read_buf, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the most suitable eraser for erase process from SFDP parameter
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param addr start address
|
||||
* @param erase_size will be erased size
|
||||
*
|
||||
* @return the eraser index of SFDP eraser table @see flash_sfdp.eraser[]
|
||||
*/
|
||||
size_t flash_sfdp_get_suitable_eraser(const FLASH_t *flash, uint32_t addr, size_t erase_size) {
|
||||
size_t index = SMALLEST_ERASER_INDEX, i;
|
||||
/* only used when flash supported SFDP */
|
||||
FLASH_ASSERT(flash->sfdp.available);
|
||||
/* the address isn't align by smallest eraser's size, then use the smallest eraser */
|
||||
if (addr % flash->sfdp.eraser[SMALLEST_ERASER_INDEX].size) {
|
||||
return SMALLEST_ERASER_INDEX;
|
||||
}
|
||||
/* Find the suitable eraser.
|
||||
* The largest size eraser is at the end of eraser table.
|
||||
* In order to decrease erase command counts, so the find process is from the end of eraser table. */
|
||||
for (i = FLASH_SFDP_ERASE_TYPE_MAX_NUM - 1;; i--) {
|
||||
if ((flash->sfdp.eraser[i].size != 0) && (erase_size >= flash->sfdp.eraser[i].size)
|
||||
&& (addr % flash->sfdp.eraser[i].size == 0)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
if (i == SMALLEST_ERASER_INDEX) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
#endif /* FLASH_USING_SFDP */
|
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// Created by lydxh on 24-11-27.
|
||||
//
|
||||
|
||||
#ifndef HW_LIB_FLASH_H
|
||||
#define HW_LIB_FLASH_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <flash_cfg.h>
|
||||
#include "flash_def.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* debug print function. Must be implement by user. */
|
||||
#ifdef FLASH_DEBUG_MODE
|
||||
#ifndef FLASH_DEBUG
|
||||
#define FLASH_DEBUG(...) flash_log_debug(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#endif /* FLASH_DEBUG */
|
||||
#else
|
||||
#define FLASH_DEBUG(...)
|
||||
#endif /* FLASH_DEBUG_MODE */
|
||||
|
||||
#ifndef FLASH_INFO
|
||||
#define FLASH_INFO(...) flash_log_info(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* assert for developer. */
|
||||
#ifdef FLASH_DEBUG_MODE
|
||||
#define FLASH_ASSERT(EXPR) \
|
||||
if (!(EXPR)) \
|
||||
{ \
|
||||
FLASH_DEBUG("(%s) has assert failed at %s.", #EXPR, __FUNCTION__); \
|
||||
while (1); \
|
||||
}
|
||||
#else
|
||||
#define FLASH_ASSERT(EXPR)
|
||||
#endif
|
||||
|
||||
typedef struct FLASH_Dev FLASH_t;
|
||||
|
||||
struct FLASH_Dev {
|
||||
char *name; /**< serial flash name */
|
||||
size_t index; /**< index of flash device information table @see flash_table */
|
||||
flash_chip chip; /**< flash chip information */
|
||||
flash_spi spi; /**< SPI device */
|
||||
bool init_ok; /**< initialize OK flag */
|
||||
bool addr_in_4_byte; /**< flash is in 4-Byte addressing */
|
||||
struct {
|
||||
void (*delay)(void); /**< every retry's delay */
|
||||
size_t times; /**< default times for error retry */
|
||||
} retry;
|
||||
|
||||
void *user_data; /**< some user data */
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
flash_qspi_read_cmd_format read_cmd_format; /**< fast read cmd format */
|
||||
#endif
|
||||
|
||||
#ifdef FLASH_USING_SFDP
|
||||
flash_sfdp sfdp; /**< serial flash discoverable parameters by JEDEC standard */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* FLASH library initialize.
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_init(void);
|
||||
|
||||
/**
|
||||
* FLASH initialize by flash device
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_device_init(FLASH_t *flash);
|
||||
|
||||
/**
|
||||
* get flash device by its index which in the flash information table
|
||||
*
|
||||
* @param index the index which in the flash information table @see flash_table
|
||||
*
|
||||
* @return flash device
|
||||
*/
|
||||
FLASH_t *flash_get_device(size_t index);
|
||||
|
||||
/**
|
||||
* get flash device total number on flash device information table @see flash_table
|
||||
*
|
||||
* @return flash device total number
|
||||
*/
|
||||
size_t flash_get_device_num(void);
|
||||
|
||||
/**
|
||||
* get flash device information table @see flash_table
|
||||
*
|
||||
* @return flash device table pointer
|
||||
*/
|
||||
const FLASH_t *flash_get_device_table(void);
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
/**
|
||||
* Enbale the fast read mode in QSPI flash mode. Default read mode is normal SPI mode.
|
||||
*
|
||||
* it will find the appropriate fast-read instruction to replace the read instruction(0x03)
|
||||
* fast-read instruction @see FLASH_FLASH_EXT_INFO_TABLE
|
||||
*
|
||||
* @note When Flash is in QSPI mode, the method must be called after flash_device_init().
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param data_line_width the data lines max width which QSPI bus supported, such as 1, 2, 4
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_qspi_fast_read_enable(FLASH_t *flash, uint8_t data_line_width);
|
||||
#endif /* FLASH_USING_QSPI */
|
||||
|
||||
/**
|
||||
* read flash data
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param addr start address
|
||||
* @param size read size
|
||||
* @param data read data pointer
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_read(const FLASH_t *flash, uint32_t addr, size_t size, uint8_t *data);
|
||||
|
||||
/**
|
||||
* erase flash data
|
||||
*
|
||||
* @note It will erase align by erase granularity.
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param addr start address
|
||||
* @param size erase size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_erase(const FLASH_t *flash, uint32_t addr, size_t size);
|
||||
|
||||
/**
|
||||
* write flash data (no erase operate)
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param addr start address
|
||||
* @param data write data
|
||||
* @param size write size
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_write(const FLASH_t *flash, uint32_t addr, size_t size, const uint8_t *data);
|
||||
|
||||
/**
|
||||
* erase and write flash data
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param addr start address
|
||||
* @param size write size
|
||||
* @param data write data
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_erase_write(const FLASH_t *flash, uint32_t addr, size_t size, const uint8_t *data);
|
||||
|
||||
/**
|
||||
* erase all flash data
|
||||
*
|
||||
* @param flash flash device
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_chip_erase(const FLASH_t *flash);
|
||||
|
||||
/**
|
||||
* read flash register status
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param status register status
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_read_status(const FLASH_t *flash, uint8_t *status);
|
||||
|
||||
/**
|
||||
* write status register
|
||||
*
|
||||
* @param flash flash device
|
||||
* @param is_volatile true: volatile mode, false: non-volatile mode
|
||||
* @param status register status
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
flash_err flash_write_status(const FLASH_t *flash, bool is_volatile, uint8_t status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_FLASH_H
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by lydxh on 24-11-27.
|
||||
//
|
||||
|
||||
#ifndef HW_LIB_FLASH_CFG_H
|
||||
#define HW_LIB_FLASH_CFG_H
|
||||
|
||||
#define FLASH_DEBUG_MODE
|
||||
|
||||
#define FLASH_USING_SFDP
|
||||
|
||||
// #define FLASH_USING_FAST_READ
|
||||
|
||||
#define FLASH_USING_FLASH_INFO_TABLE
|
||||
|
||||
enum {
|
||||
FLASH_XXXX_DEVICE_INDEX = 0,
|
||||
};
|
||||
|
||||
#define FLASH_FLASH_DEVICE_TABLE \
|
||||
{ \
|
||||
[FLASH_XXXX_DEVICE_INDEX] = {.name = "XXXX", .spi.name = "SPIX"}, \
|
||||
}
|
||||
|
||||
#define FLASH_USING_QSPI
|
||||
|
||||
#endif //HW_LIB_FLASH_CFG_H
|
|
@ -0,0 +1,406 @@
|
|||
//
|
||||
// Created by lydxh on 24-11-27.
|
||||
//
|
||||
|
||||
#ifndef HW_LIB_FLASH_DEF_H
|
||||
#define HW_LIB_FLASH_DEF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <flash_cfg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* flash program(write) data mode
|
||||
*/
|
||||
enum flash_write_mode {
|
||||
FLASH_WM_PAGE_256B = 1 << 0, /**< write 1 to 256 bytes per page */
|
||||
FLASH_WM_BYTE = 1 << 1, /**< byte write */
|
||||
FLASH_WM_AAI = 1 << 2, /**< auto address increment */
|
||||
FLASH_WM_DUAL_BUFFER = 1 << 3, /**< dual-buffer write, like AT45DB series */
|
||||
};
|
||||
|
||||
/* manufacturer information */
|
||||
typedef struct {
|
||||
char *name;
|
||||
uint8_t id;
|
||||
} flash_mf;
|
||||
|
||||
/* flash chip information */
|
||||
typedef struct {
|
||||
char *name; /**< flash chip name */
|
||||
uint8_t mf_id; /**< manufacturer ID */
|
||||
uint8_t type_id; /**< memory type ID */
|
||||
uint8_t capacity_id; /**< capacity ID */
|
||||
uint32_t capacity; /**< flash capacity (bytes) */
|
||||
uint16_t write_mode; /**< write mode @see flash_write_mode */
|
||||
uint32_t erase_gran; /**< erase granularity (bytes) */
|
||||
uint8_t erase_gran_cmd; /**< erase granularity size block command */
|
||||
} flash_chip;
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
/* QSPI flash chip's extended information compared with SPI flash */
|
||||
typedef struct {
|
||||
uint8_t mf_id; /**< manufacturer ID */
|
||||
uint8_t type_id; /**< memory type ID */
|
||||
uint8_t capacity_id; /**< capacity ID */
|
||||
uint8_t read_mode; /**< supported read mode on this qspi flash chip */
|
||||
} flash_qspi_flash_ext_info;
|
||||
#endif
|
||||
|
||||
/* FLASH support manufacturer JEDEC ID */
|
||||
#define FLASH_MF_ID_CYPRESS 0x01
|
||||
#define FLASH_MF_ID_FUJITSU 0x04
|
||||
#define FLASH_MF_ID_EON 0x1C
|
||||
#define FLASH_MF_ID_ATMEL 0x1F
|
||||
#define FLASH_MF_ID_MICRON 0x20
|
||||
#define FLASH_MF_ID_AMIC 0x37
|
||||
#define FLASH_MF_ID_NOR_MEM 0x52
|
||||
#define FLASH_MF_ID_SANYO 0x62
|
||||
#define FLASH_MF_ID_INTEL 0x89
|
||||
#define FLASH_MF_ID_ESMT 0x8C
|
||||
#define FLASH_MF_ID_FUDAN 0xA1
|
||||
#define FLASH_MF_ID_HYUNDAI 0xAD
|
||||
#define FLASH_MF_ID_SST 0xBF
|
||||
#define FLASH_MF_ID_MACRONIX 0xC2
|
||||
#define FLASH_MF_ID_GIGADEVICE 0xC8
|
||||
#define FLASH_MF_ID_ISSI 0xD5
|
||||
#define FLASH_MF_ID_WINBOND 0xEF
|
||||
#define FLASH_MF_ID_PUYA 0x85
|
||||
|
||||
/* FLASH supported manufacturer information table */
|
||||
#define FLASH_MF_TABLE \
|
||||
{ \
|
||||
{"Cypress", FLASH_MF_ID_CYPRESS}, \
|
||||
{"Fujitsu", FLASH_MF_ID_FUJITSU}, \
|
||||
{"EON", FLASH_MF_ID_EON}, \
|
||||
{"Atmel", FLASH_MF_ID_ATMEL}, \
|
||||
{"Micron", FLASH_MF_ID_MICRON}, \
|
||||
{"AMIC", FLASH_MF_ID_AMIC}, \
|
||||
{"Sanyo", FLASH_MF_ID_SANYO}, \
|
||||
{"Intel", FLASH_MF_ID_INTEL}, \
|
||||
{"ESMT", FLASH_MF_ID_ESMT}, \
|
||||
{"Fudan", FLASH_MF_ID_FUDAN}, \
|
||||
{"Hyundai", FLASH_MF_ID_HYUNDAI}, \
|
||||
{"SST", FLASH_MF_ID_SST}, \
|
||||
{"GigaDevice", FLASH_MF_ID_GIGADEVICE}, \
|
||||
{"ISSI", FLASH_MF_ID_ISSI}, \
|
||||
{"Winbond", FLASH_MF_ID_WINBOND}, \
|
||||
{"Macronix", FLASH_MF_ID_MACRONIX}, \
|
||||
{"NOR-MEM", FLASH_MF_ID_NOR_MEM}, \
|
||||
{"PUYA", FLASH_MF_ID_PUYA}, \
|
||||
}
|
||||
|
||||
#ifdef FLASH_USING_FLASH_INFO_TABLE
|
||||
/* FLASH supported flash chip information table. If the flash not support JEDEC JESD216 standard,
|
||||
* then the FLASH will find the flash chip information by this table. You can add other flash to here then
|
||||
* notice me for update it. The configuration information name and index reference the flash_flash_chip structure.
|
||||
* | name | mf_id | type_id | capacity_id | capacity | write_mode | erase_gran | erase_gran_cmd |
|
||||
*/
|
||||
#define FLASH_FLASH_CHIP_TABLE \
|
||||
{ \
|
||||
{"AT45DB161E", FLASH_MF_ID_ATMEL, 0x26, 0x00, 2L*1024L*1024L, FLASH_WM_BYTE|FLASH_WM_DUAL_BUFFER, 512, 0x81}, \
|
||||
{"W25Q40BV", FLASH_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25X40CL", FLASH_MF_ID_WINBOND, 0x30, 0x13, 512L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25X16AV", FLASH_MF_ID_WINBOND, 0x30, 0x15, 2L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q16BV", FLASH_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q32BV", FLASH_MF_ID_WINBOND, 0x40, 0x16, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q64CV", FLASH_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q64DW", FLASH_MF_ID_WINBOND, 0x60, 0x17, 8L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q128BV", FLASH_MF_ID_WINBOND, 0x40, 0x18, 16L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"W25Q256FV", FLASH_MF_ID_WINBOND, 0x40, 0x19, 32L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"SST25VF080B", FLASH_MF_ID_SST, 0x25, 0x8E, 1L*1024L*1024L, FLASH_WM_BYTE|FLASH_WM_AAI, 4096, 0x20}, \
|
||||
{"SST25VF016B", FLASH_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, FLASH_WM_BYTE|FLASH_WM_AAI, 4096, 0x20}, \
|
||||
{"M25P32", FLASH_MF_ID_MICRON, 0x20, 0x16, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 64L*1024L, 0xD8}, \
|
||||
{"M25P80", FLASH_MF_ID_MICRON, 0x20, 0x14, 1L*1024L*1024L, FLASH_WM_PAGE_256B, 64L*1024L, 0xD8}, \
|
||||
{"M25P40", FLASH_MF_ID_MICRON, 0x20, 0x13, 512L*1024L, FLASH_WM_PAGE_256B, 64L*1024L, 0xD8}, \
|
||||
{"EN25Q32B", FLASH_MF_ID_EON, 0x30, 0x16, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"GD25Q64B", FLASH_MF_ID_GIGADEVICE, 0x40, 0x17, 8L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"GD25Q16B", FLASH_MF_ID_GIGADEVICE, 0x40, 0x15, 2L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"GD25Q32C", FLASH_MF_ID_GIGADEVICE, 0x40, 0x16, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"S25FL216K", FLASH_MF_ID_CYPRESS, 0x40, 0x15, 2L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"S25FL032P", FLASH_MF_ID_CYPRESS, 0x02, 0x15, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"A25L080", FLASH_MF_ID_AMIC, 0x30, 0x14, 1L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"F25L004", FLASH_MF_ID_ESMT, 0x20, 0x13, 512L*1024L, FLASH_WM_BYTE|FLASH_WM_AAI, 4096, 0x20}, \
|
||||
{"PCT25VF016B", FLASH_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L, FLASH_WM_BYTE|FLASH_WM_AAI, 4096, 0x20}, \
|
||||
{"NM25Q128EVB", FLASH_MF_ID_NOR_MEM, 0x21, 0x18, 16L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"P25D05H", FLASH_MF_ID_PUYA, 0x60, 0x13, 5L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"P25D10H", FLASH_MF_ID_PUYA, 0x60, 0x12, 1L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"P25D20H", FLASH_MF_ID_PUYA, 0x60, 0x11, 2L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"P25D40H", FLASH_MF_ID_PUYA, 0x60, 0x10, 4L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
{"P25Q80H", FLASH_MF_ID_PUYA, 0x30, 0x14, 8L*1024L*1024L, FLASH_WM_PAGE_256B, 4096, 0x20}, \
|
||||
}
|
||||
#endif /* FLASH_USING_FLASH_INFO_TABLE */
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
/* This table saves flash read-fast instructions in QSPI mode,
|
||||
* FLASH can use this table to select the most appropriate read instruction for flash.
|
||||
* | mf_id | type_id | capacity_id | qspi_read_mode |
|
||||
*/
|
||||
#define FLASH_FLASH_EXT_INFO_TABLE \
|
||||
{ \
|
||||
/* W25Q40BV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x13, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* W25Q80JV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* W25Q16BV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* W25Q32BV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_OUTPUT|QUAD_IO}, \
|
||||
/* W25Q64JV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||
/* W25Q128JV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||
/* W25Q256FV */ \
|
||||
{FLASH_MF_ID_WINBOND, 0x40, 0x19, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||
/* EN25Q32B */ \
|
||||
{FLASH_MF_ID_EON, 0x30, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT|QUAD_IO}, \
|
||||
/* S25FL216K */ \
|
||||
{FLASH_MF_ID_CYPRESS, 0x40, 0x15, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* A25L080 */ \
|
||||
{FLASH_MF_ID_AMIC, 0x30, 0x14, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO}, \
|
||||
/* A25LQ64 */ \
|
||||
{FLASH_MF_ID_AMIC, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_IO}, \
|
||||
/* MX25L3206E and KH25L3206E */ \
|
||||
{FLASH_MF_ID_MACRONIX, 0x20, 0x16, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* MX25L51245G */ \
|
||||
{FLASH_MF_ID_MACRONIX, 0x20, 0x1A, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||
/* GD25Q64B */ \
|
||||
{FLASH_MF_ID_GIGADEVICE, 0x40, 0x17, NORMAL_SPI_READ|DUAL_OUTPUT}, \
|
||||
/* NM25Q128EVB */ \
|
||||
{FLASH_MF_ID_NOR_MEM, 0x21, 0x18, NORMAL_SPI_READ|DUAL_OUTPUT|DUAL_IO|QUAD_OUTPUT|QUAD_IO}, \
|
||||
}
|
||||
#endif /* FLASH_USING_QSPI */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* retry process
|
||||
*
|
||||
* @param delay delay function for every retry. NULL will not delay for every retry.
|
||||
* @param retry retry counts
|
||||
* @param result FLASH_ERR_TIMEOUT: retry timeout
|
||||
*/
|
||||
#define FLASH_RETRY_PROCESS(delay, retry, result) \
|
||||
void (*__delay_temp)(void) = (void (*)(void))delay; \
|
||||
if (retry == 0) {result = FLASH_ERR_TIMEOUT;break;} \
|
||||
else {if (__delay_temp) {__delay_temp();} retry --;}
|
||||
|
||||
/* software version number */
|
||||
#define FLASH_SW_VERSION "1.1.0"
|
||||
/*
|
||||
* all defined supported command
|
||||
*/
|
||||
#ifndef FLASH_CMD_WRITE_ENABLE
|
||||
#define FLASH_CMD_WRITE_ENABLE 0x06
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_WRITE_DISABLE
|
||||
#define FLASH_CMD_WRITE_DISABLE 0x04
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_READ_STATUS_REGISTER
|
||||
#define FLASH_CMD_READ_STATUS_REGISTER 0x05
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_VOLATILE_SR_WRITE_ENABLE
|
||||
#define FLASH_VOLATILE_SR_WRITE_ENABLE 0x50
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_WRITE_STATUS_REGISTER
|
||||
#define FLASH_CMD_WRITE_STATUS_REGISTER 0x01
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_PAGE_PROGRAM
|
||||
#define FLASH_CMD_PAGE_PROGRAM 0x02
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_AAI_WORD_PROGRAM
|
||||
#define FLASH_CMD_AAI_WORD_PROGRAM 0xAD
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_ERASE_CHIP
|
||||
#define FLASH_CMD_ERASE_CHIP 0xC7
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_READ_DATA
|
||||
#define FLASH_CMD_READ_DATA 0x03
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_FAST_READ_DATA
|
||||
#define FLASH_CMD_FAST_READ_DATA 0x0B
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_DUAL_OUTPUT_READ_DATA
|
||||
#define FLASH_CMD_DUAL_OUTPUT_READ_DATA 0x3B
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_DUAL_IO_READ_DATA
|
||||
#define FLASH_CMD_DUAL_IO_READ_DATA 0xBB
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_QUAD_IO_READ_DATA
|
||||
#define FLASH_CMD_QUAD_IO_READ_DATA 0xEB
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_QUAD_OUTPUT_READ_DATA
|
||||
#define FLASH_CMD_QUAD_OUTPUT_READ_DATA 0x6B
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_MANUFACTURER_DEVICE_ID
|
||||
#define FLASH_CMD_MANUFACTURER_DEVICE_ID 0x90
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_JEDEC_ID
|
||||
#define FLASH_CMD_JEDEC_ID 0x9F
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_READ_UNIQUE_ID
|
||||
#define FLASH_CMD_READ_UNIQUE_ID 0x4B
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_READ_SFDP_REGISTER
|
||||
#define FLASH_CMD_READ_SFDP_REGISTER 0x5A
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_ENABLE_RESET
|
||||
#define FLASH_CMD_ENABLE_RESET 0x66
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_RESET
|
||||
#define FLASH_CMD_RESET 0x99
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_ENTER_4B_ADDRESS_MODE
|
||||
#define FLASH_CMD_ENTER_4B_ADDRESS_MODE 0xB7
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_CMD_EXIT_4B_ADDRESS_MODE
|
||||
#define FLASH_CMD_EXIT_4B_ADDRESS_MODE 0xE9
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_WRITE_MAX_PAGE_SIZE
|
||||
#define FLASH_WRITE_MAX_PAGE_SIZE 256
|
||||
#endif
|
||||
|
||||
/* send dummy data for read data */
|
||||
#ifndef FLASH_DUMMY_DATA
|
||||
#define FLASH_DUMMY_DATA 0xFF
|
||||
#endif
|
||||
|
||||
/* dummy data count for fast read data and etc */
|
||||
#ifndef FLASH_READ_DUMMY_BYTE_CNT
|
||||
#ifdef FLASH_USING_FAST_READ
|
||||
#define FLASH_READ_DUMMY_BYTE_CNT 1
|
||||
#else
|
||||
#define FLASH_READ_DUMMY_BYTE_CNT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* maximum number of erase type support on JESD216 (V1.0) */
|
||||
#define FLASH_SFDP_ERASE_TYPE_MAX_NUM 4
|
||||
|
||||
/**
|
||||
* status register bits
|
||||
*/
|
||||
enum {
|
||||
FLASH_STATUS_REGISTER_BUSY = (1 << 0), /**< busing */
|
||||
FLASH_STATUS_REGISTER_WEL = (1 << 1), /**< write enable latch */
|
||||
FLASH_STATUS_REGISTER_SRP = (1 << 7), /**< status register protect */
|
||||
};
|
||||
|
||||
/**
|
||||
* error code
|
||||
*/
|
||||
typedef enum {
|
||||
FLASH_SUCCESS = 0, /**< success */
|
||||
FLASH_ERR_NOT_FOUND = 1, /**< not found or not supported */
|
||||
FLASH_ERR_WRITE = 2, /**< write error */
|
||||
FLASH_ERR_READ = 3, /**< read error */
|
||||
FLASH_ERR_TIMEOUT = 4, /**< timeout error */
|
||||
FLASH_ERR_ADDR_OUT_OF_BOUND = 5, /**< address is out of flash bound */
|
||||
} flash_err;
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
/**
|
||||
* QSPI flash read cmd format
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t instruction;
|
||||
uint8_t instruction_lines;
|
||||
uint8_t address_size;
|
||||
uint8_t address_lines;
|
||||
uint8_t alternate_bytes_lines;
|
||||
uint8_t dummy_cycles;
|
||||
uint8_t data_lines;
|
||||
} flash_qspi_read_cmd_format;
|
||||
#endif /* FLASH_USING_QSPI */
|
||||
|
||||
/* SPI bus write read data function type */
|
||||
typedef flash_err (*spi_write_read_func)(const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
|
||||
size_t read_size);
|
||||
|
||||
#ifdef FLASH_USING_SFDP
|
||||
/**
|
||||
* the SFDP (Serial Flash Discoverable Parameters) parameter info which used on this library
|
||||
*/
|
||||
typedef struct {
|
||||
bool available; /**< available when read SFDP OK */
|
||||
uint8_t major_rev; /**< SFDP Major Revision */
|
||||
uint8_t minor_rev; /**< SFDP Minor Revision */
|
||||
uint16_t write_gran; /**< write granularity (bytes) */
|
||||
uint8_t erase_4k; /**< 4 kilobyte erase is supported throughout the device */
|
||||
uint8_t erase_4k_cmd; /**< 4 Kilobyte erase command */
|
||||
bool sr_is_non_vola; /**< status register is supports non-volatile */
|
||||
uint8_t vola_sr_we_cmd; /**< volatile status register write enable command */
|
||||
bool addr_3_byte; /**< supports 3-Byte addressing */
|
||||
bool addr_4_byte; /**< supports 4-Byte addressing */
|
||||
uint32_t capacity; /**< flash capacity (bytes) */
|
||||
struct {
|
||||
uint32_t size; /**< erase sector size (bytes). 0x00: not available */
|
||||
uint8_t cmd; /**< erase command */
|
||||
} eraser[FLASH_SFDP_ERASE_TYPE_MAX_NUM]; /**< supported eraser types table */
|
||||
//TODO lots of fast read-related stuff (like modes supported and number of wait states/dummy cycles needed in each)
|
||||
} flash_sfdp, *flash_sfdp_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SPI device
|
||||
*/
|
||||
typedef struct __flash_spi {
|
||||
/* SPI device name */
|
||||
char *name;
|
||||
|
||||
/* SPI bus write read data function */
|
||||
flash_err (*wr)(const struct __flash_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
|
||||
size_t read_size);
|
||||
|
||||
#ifdef FLASH_USING_QSPI
|
||||
|
||||
/* QSPI fast read function */
|
||||
flash_err
|
||||
(*qspi_read)(const struct __flash_spi *spi, uint32_t addr, flash_qspi_read_cmd_format *qspi_read_cmd_format,
|
||||
uint8_t *read_buf, size_t read_size);
|
||||
|
||||
#endif
|
||||
|
||||
/* lock SPI bus */
|
||||
void (*lock)(const struct __flash_spi *spi);
|
||||
|
||||
/* unlock SPI bus */
|
||||
void (*unlock)(const struct __flash_spi *spi);
|
||||
|
||||
/* some user data */
|
||||
void *user_data;
|
||||
} flash_spi, *flash_spi_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_FLASH_DEF_H
|
|
@ -95,15 +95,17 @@ struct OLED_Dev
|
|||
* @return void
|
||||
* @example OLED_Init(&oled_dev);
|
||||
*/
|
||||
void OLED_Init(OLED_T* dev);
|
||||
void OLED_Init(OLED_T *dev);
|
||||
|
||||
/**
|
||||
* @brief OLED初始化
|
||||
* @param dev: [输入] OLED设备指针
|
||||
* @param cmd: [输入] OLED初始化指令表
|
||||
* @param len: [输入] OLED初始化指令表长度
|
||||
* @return void
|
||||
* @example OLED_Init(&oled_dev);
|
||||
*/
|
||||
void OLED_Init_CMD(OLED_T* dev, uint8_t* cmd, uint16_t len);
|
||||
void OLED_Init_CMD(OLED_T *dev, uint8_t *cmd, uint16_t len);
|
||||
/**
|
||||
* @brief 打开OLED显示
|
||||
* @param dev: [输入] OLED设备指针
|
||||
|
|
|
@ -18,8 +18,8 @@ const uint8_t initCmd[] = {
|
|||
0x40, 0x00, // 设置显示起始行
|
||||
0x8D, 0x14, // 电荷泵设置
|
||||
0x20, 0x00, // 设置内存寻址模式
|
||||
0xA0, // 设置段重映射
|
||||
0xC8, // 设置COM输出扫描方向
|
||||
0xA0, // 设置段重映射 从左到右A1 //左右翻转A0
|
||||
0xC8, // 设置COM输出扫描方向 从上到下C8 //上下颠倒C0
|
||||
0xDA, 0x12, // 设置COM引脚硬件配置
|
||||
0x81, 0xCF, // 设置对比度控制
|
||||
0xD9, 0xF1, // 设置预充电周期
|
||||
|
|
|
@ -118,7 +118,6 @@ extern "C" {
|
|||
/**
|
||||
* @brief LCD_Type_Define
|
||||
*/
|
||||
#define ST7735_1_8_inch_screen 0x00U
|
||||
#define ST7735_0_9_inch_screen 0x01U
|
||||
#define ST7735_1_8a_inch_screen 0x02U
|
||||
/**
|
||||
|
@ -135,9 +134,13 @@ extern "C" {
|
|||
|
||||
|
||||
#define ST7735_DELAY 120
|
||||
#define ST7735_PANEL HannStar_Panel
|
||||
#define ST7735_TYPE ST7735_0_9_inch_screen
|
||||
#define ST7735_PANEL BOE_Panel
|
||||
#define ST7735_TYPE ST7735_1_8a_inch_screen
|
||||
|
||||
//#define ST7735_X_OFFSET 0
|
||||
//#define ST7735_Y_OFFSET 0
|
||||
//#define ST7735_X_OFFSET 0
|
||||
//#define ST7735_Y_OFFSET 0
|
||||
|
||||
#if ST7735_TYPE == ST7735_0_9_inch_screen //0.96 ST7735
|
||||
#if ST7735_PANEL == HannStar_Panel
|
||||
|
@ -176,8 +179,11 @@ const uint8_t st7735initcmd[] = {
|
|||
3, ST7735_PWR_CTRL4, 0x8A, 0x2A,
|
||||
3, ST7735_PWR_CTRL5, 0x8A, 0xEE,
|
||||
2, ST7735_VCOMH_VCOML_CTRL1, 0x0E,
|
||||
#if ST7735_PANEL == HannStar_Panel
|
||||
1, ST7735_DISPLAY_INVERSION_ON,//HannStar_Panel
|
||||
// 1,ST7735_DISPLAY_INVERSION_OFF,//BOE_Panel
|
||||
#else
|
||||
1, ST7735_DISPLAY_INVERSION_OFF,//BOE_Panel
|
||||
#endif
|
||||
2, ST7735_COLOR_MODE, ST7735_FORMAT_RBG565,
|
||||
17, ST7735_PV_GAMMA_CTRL, 0x02, 0x1C, 0x07U, 0x12U, 0x37U, 0x32U, 0x29U, 0x2DU, 0x29U, 0x25U, 0x2BU, 0x39U,
|
||||
0x00U, 0x01U, 0x03U, 0x10U,
|
||||
|
|
|
@ -283,6 +283,8 @@ void TFT_DrawRect(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2
|
|||
**/
|
||||
void TFT_DrawCircle(TFT_T *dev, uint16_t x, uint16_t y, uint16_t r);
|
||||
|
||||
void TFT_DrawArc(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t radius, int start_angle, int end_angle);
|
||||
|
||||
/**
|
||||
* @brief 在TFT显示屏上显示单个字符
|
||||
* @param dev: [输入] TFT设备结构体指针
|
||||
|
@ -359,6 +361,17 @@ void TFT_ShowPic(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, T
|
|||
**/
|
||||
void TFT_DrawCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r);
|
||||
|
||||
/**
|
||||
* @brief 在屏幕上绘制一个X字交叉线
|
||||
* @param dev: [输入] TFT设备指针
|
||||
* @param x: [输入] 十字交叉线中心点x坐标
|
||||
* @param y: [输入] 十字交叉线中心点y坐标
|
||||
* @param r: [输入] 十字交叉线长度的一半(即从中心点到横竖线的长度)
|
||||
* @return void
|
||||
* @example TFT_DrawCross(&tft_dev, 100, 80, 5);
|
||||
**/
|
||||
void TFT_DrawXCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r);
|
||||
|
||||
/**
|
||||
* @brief 在屏幕上显示进度条
|
||||
* @param dev: [输入] TFT设备指针
|
||||
|
@ -372,6 +385,17 @@ void TFT_DrawCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r);
|
|||
**/
|
||||
void TFT_ShowBar(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float progress);
|
||||
|
||||
/**
|
||||
* @brief 绘制带圆角的矩形
|
||||
* @param dev: [输入] TFT设备指针
|
||||
* @param x: [输入] 矩形左上角x坐标
|
||||
* @param y: [输入] 矩形左上角y坐标
|
||||
* @param width: [输入] 矩形宽度
|
||||
* @param height: [输入] 矩形高度
|
||||
* @param radius: [输入] 圆角半径
|
||||
* @return void
|
||||
**/
|
||||
void TFT_DrawRoundedRect(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius);
|
||||
|
||||
#ifdef LVGL_FONT
|
||||
|
||||
|
@ -392,6 +416,19 @@ void TFT_DisplayString(TFT_T *dev, const lv_font_t *font, uint8_t *s, uint16_t x
|
|||
#endif
|
||||
|
||||
|
||||
#define ARGB_TO_RGB565(...) \
|
||||
_ARGB_TO_RGB565_NARG(__VA_ARGS__, _ARGB_TO_RGB565_4, _ARGB_TO_RGB565_1)(__VA_ARGS__)
|
||||
|
||||
#define _ARGB_TO_RGB565_NARG(...) _ARGB_TO_RGB565_NARG_(__VA_ARGS__, _ARGB_TO_RGB565_RSEQ_N())
|
||||
#define _ARGB_TO_RGB565_NARG_(...) _ARGB_TO_RGB565_ARG_N(__VA_ARGS__)
|
||||
|
||||
#define _ARGB_TO_RGB565_ARG_N(_1, _2, _3, _4, N, ...) N
|
||||
#define _ARGB_TO_RGB565_RSEQ_N() 4, 3, 2, 1, 0
|
||||
|
||||
#define _ARGB_TO_RGB565_1(argb) (((((argb) >> 8) & 0xF800) | (((argb) >> 5) & 0x07E0) | ((argb) >> 3) & 0x001F)
|
||||
|
||||
#define _ARGB_TO_RGB565_4(a, r, g, b) (((((a) & 0xFF) >> 3) << 11) | ((((r) & 0xFF) >> 2) << 5) | (((g) & 0xFF) >> 3))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
182
lib/tft/tft.cpp
182
lib/tft/tft.cpp
|
@ -1,3 +1,4 @@
|
|||
#include <valarray>
|
||||
#include "tft.h"
|
||||
#include "ascii_font.h"
|
||||
|
||||
|
@ -201,11 +202,11 @@ void TFT_FillColor(TFT_T *dev,TFT_Color_t color){
|
|||
dev->sendData(color.u8, 2);
|
||||
}
|
||||
|
||||
|
||||
#define swap_(a, b) (a=(a)+(b),b=(a)-(b),a=(a)-(b))
|
||||
|
||||
void TFT_DrawLine(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
|
||||
uint16_t i, k, k1, k2;
|
||||
if ((x1 < 0) || (x2 > dev->width) || (y1 < 0) || (y2 > dev->height) || (x1 > x2) || (y1 > y2))return;
|
||||
uint16_t i;
|
||||
if ((x1 < 0) || (x2 > dev->width) || (y1 < 0) || (y2 > dev->height))return;
|
||||
if (x1 == x2) //画竖线
|
||||
{
|
||||
for (i = 0; i < (y2 - y1); i++) {
|
||||
|
@ -217,12 +218,50 @@ void TFT_DrawLine(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2
|
|||
TFT_SetPixel(dev, x1 + i, y1,POINT_COLOR);
|
||||
}
|
||||
} else //画斜线
|
||||
{
|
||||
k1 = y2 - y1;
|
||||
k2 = x2 - x1;
|
||||
k = k1 * 10 / k2;
|
||||
for (i = 0; i < (x2 - x1); i++) {
|
||||
TFT_SetPixel(dev, x1 + i, y1 + i * k / 10,POINT_COLOR);
|
||||
{//Bresenham算法
|
||||
int p, twoDy, twoDyMinusDx, s1, s2;
|
||||
int dx = abs(x2 - x1), dy = abs(y2 - y1);
|
||||
if (dy > dx) //斜率大于1
|
||||
{
|
||||
p = 2 * dx - dy;
|
||||
twoDy = 2 * dx;
|
||||
twoDyMinusDx = 2 * (dx - dy);
|
||||
if (y1 > y2)//斜率为负时 反转斜率
|
||||
{
|
||||
swap_(x1, x2);
|
||||
swap_(y1, y2);
|
||||
}
|
||||
s1 = x2 > x1 ? 1 : -1;
|
||||
TFT_SetPixel(dev, x1, y1, POINT_COLOR);
|
||||
while (y1 < y2) {
|
||||
y1++;
|
||||
if (p < 0) { p += twoDy; }
|
||||
else {
|
||||
x1 += s1;
|
||||
p += twoDyMinusDx;
|
||||
}
|
||||
TFT_SetPixel(dev, x1, y1, POINT_COLOR);
|
||||
}
|
||||
} else {
|
||||
p = 2 * dy - dx;
|
||||
twoDy = 2 * dy;
|
||||
twoDyMinusDx = 2 * (dy - dx);
|
||||
if (x1 > x2)//斜率为负时 反转斜率
|
||||
{
|
||||
swap_(x1, x2);
|
||||
swap_(y1, y2);
|
||||
}
|
||||
s2 = y2 > y1 ? 1 : -1;
|
||||
TFT_SetPixel(dev, x1, y1, POINT_COLOR);
|
||||
while (x1 < x2) {
|
||||
x1++;
|
||||
if (p < 0) { p += twoDy; }
|
||||
else {
|
||||
y1 += s2;
|
||||
p += twoDyMinusDx;
|
||||
}
|
||||
TFT_SetPixel(dev, x1, y1, POINT_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,29 +273,98 @@ void TFT_DrawRect(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2
|
|||
TFT_DrawLine(dev, x1, y2, x2, y2); // Bottom side
|
||||
}
|
||||
|
||||
void TFT_DrawCircle(TFT_T *dev, uint16_t x, uint16_t y, uint16_t r) {
|
||||
int a, b, num;
|
||||
a = 0;
|
||||
b = r;
|
||||
while (2 * b * b >= r * r) {
|
||||
TFT_SetPixel(dev, x + a, y - b,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x - a, y - b,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x - a, y + b,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x + a, y + b,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x + b, y + a,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x + b, y - a,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x - b, y - a,POINT_COLOR);
|
||||
TFT_SetPixel(dev, x - b, y + a,POINT_COLOR);
|
||||
void TFT_DrawCircle(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t radius) {
|
||||
int x = radius;
|
||||
int y = 0;
|
||||
int decision = 1 - x;
|
||||
|
||||
a++;
|
||||
num = (a * a + b * b) - r * r;//计算画的点离圆心的距离
|
||||
if (num > 0) {
|
||||
b--;
|
||||
a--;
|
||||
while (y <= x) {
|
||||
TFT_SetPixel(dev, x0 + x, y0 + y, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 + y, y0 + x, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 - y, y0 + x, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 - x, y0 + y, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 - x, y0 - y, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 - y, y0 - x, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 + y, y0 - x, POINT_COLOR);
|
||||
TFT_SetPixel(dev, x0 + x, y0 - y, POINT_COLOR);
|
||||
|
||||
y++;
|
||||
|
||||
if (decision <= 0) {
|
||||
decision += 2 * y + 1;
|
||||
} else {
|
||||
x--;
|
||||
decision += 2 * (y - x) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
//void TFT_DrawArc(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t radius, int start_angle, int end_angle) {
|
||||
// int x = radius;
|
||||
// int y = 0;
|
||||
// int decision = 1 - x;
|
||||
// int change = 4 * (1 - x);
|
||||
//
|
||||
// int angle = start_angle;
|
||||
//
|
||||
// while (y <= x) {
|
||||
// if (angle >= start_angle && angle <= end_angle) {
|
||||
// TFT_SetPixel(dev, x0 + x, y0 + y, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 + y, y0 + x, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 - y, y0 + x, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 - x, y0 + y, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 - x, y0 - y, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 - y, y0 - x, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 + y, y0 - x, POINT_COLOR);
|
||||
// TFT_SetPixel(dev, x0 + x, y0 - y, POINT_COLOR);
|
||||
// }
|
||||
//
|
||||
// if (decision <= 0) {
|
||||
// decision += 2 * y + 1;
|
||||
// change += 2;
|
||||
// } else {
|
||||
// x--;
|
||||
// decision += 2 * (y - x) + 1;
|
||||
// change += 4 * ((y - x) + 1);
|
||||
// }
|
||||
//
|
||||
// y++;
|
||||
// angle = (int)(0.5 + (atan((double)y / x) * 180.0 / PI));
|
||||
// }
|
||||
//}
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
void TFT_DrawArc(TFT_T *dev, uint16_t x, uint16_t y, uint16_t radius, int start_angle, int end_angle) {
|
||||
// 修复输入角度范围
|
||||
if (start_angle < 0) {
|
||||
start_angle = 0;
|
||||
} else if (start_angle > 360) {
|
||||
start_angle = 360;
|
||||
}
|
||||
if (end_angle < 0) {
|
||||
end_angle = 0;
|
||||
} else if (end_angle > 360) {
|
||||
end_angle = 360;
|
||||
}
|
||||
double angle;
|
||||
unsigned int cirx, ciry, lastX, lastY;
|
||||
cirx = x;
|
||||
ciry = y;
|
||||
|
||||
angle = start_angle;
|
||||
while (angle <= end_angle) {
|
||||
lastX = cirx + radius * sin(angle * PI / 180);
|
||||
lastY = ciry - radius * cos(angle * PI / 180);
|
||||
TFT_SetPixel(dev, lastX, lastY, POINT_COLOR);
|
||||
angle = angle + 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
void TFT_ShowChar(TFT_T *dev, uint16_t x, uint16_t y, uint8_t chr, uint16_t size,bool mode) {
|
||||
uint16_t i, m, temp, size2, chr1;
|
||||
uint16_t ys = y;
|
||||
|
@ -446,6 +554,26 @@ void TFT_DrawCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r) {
|
|||
TFT_DrawLine(dev, x, y - r, x, y + r);
|
||||
}
|
||||
|
||||
void TFT_DrawXCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r) {
|
||||
TFT_DrawLine(dev, x - r, y - r, x + r, y + r);
|
||||
TFT_DrawLine(dev, x - r, y + r, x + r, y - r);
|
||||
}
|
||||
|
||||
void TFT_DrawRoundedRect(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius) {
|
||||
// 画四条直线
|
||||
TFT_DrawLine(dev, x + radius, y, x + width - radius, y); // 上方横线
|
||||
TFT_DrawLine(dev, x + radius, y + height, x + width - radius, y + height); // 下方横线
|
||||
|
||||
TFT_DrawLine(dev, x, y + radius, x, y + height - radius); // 左侧竖线
|
||||
TFT_DrawLine(dev, x + width, y + radius, x + width, y + height - radius); // 右侧竖线
|
||||
|
||||
// 画四个圆角
|
||||
TFT_DrawArc(dev, x + radius, y + radius, radius, 270, 360); // 左上角
|
||||
TFT_DrawArc(dev, x + width - radius, y + radius, radius, 0, 90); // 右上角
|
||||
TFT_DrawArc(dev, x + width - radius, y + height - radius, radius, 90, 180); // 右下角
|
||||
TFT_DrawArc(dev, x + radius, y + height - radius, radius, 180, 270); // 左下角
|
||||
}
|
||||
|
||||
uint16_t invertRGB565(uint16_t color) {
|
||||
// 分离颜色分量
|
||||
uint8_t r = (color >> 11) & 0x1F; // 取出红色分量
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
////////////////////////
|
||||
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOG_RUN_TIMER_FUN GetSysCnt32()
|
||||
#define LOG_RUN_TIMER_FUN GetTickCount64()
|
||||
#define LOG_RUN_TIMER_FMT "-T(%lums)"
|
||||
#else
|
||||
#define LOG_RUN_TIMER_FUN 0
|
||||
#define LOG_RUN_TIMER_FMT "-T(%lu)"
|
||||
#define LOG_RUN_TIMER_FUN GetTickCount64()
|
||||
#define LOG_RUN_TIMER_FMT "(%llums)"
|
||||
#endif
|
||||
|
||||
#ifdef LOG_LINE_END_CRLF
|
||||
|
@ -65,6 +65,9 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#define LOG_OUT_FUNC printf
|
||||
|
||||
|
||||
#define LOG_BASE_FILENAME \
|
||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \
|
||||
strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
|
@ -101,9 +104,9 @@
|
|||
// 带时钟输出
|
||||
#if defined(LOG_TIMER)
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGT(tag, fmt, ...) do{ printf(LOG_COLOR_BLUE "[" tag "]" LOG_RUN_TIMER_FMT ": " fmt LOG_END,LOG_RUN_TIMER_FUN, ##__VA_ARGS__); } while(0)
|
||||
#define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]" LOG_RUN_TIMER_FMT ": " fmt LOG_END,LOG_RUN_TIMER_FUN, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGT(tag, fmt, ...) do{ printf(LOG_COLOR_BLUE "[" tag "]: " fmt LOG_END, ##__VA_ARGS__); } while(0)
|
||||
#define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]: " fmt LOG_END, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGT(fmt, ...) ((void)0)
|
||||
|
@ -112,9 +115,9 @@
|
|||
// 等级输出
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_FATAL
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGF(fmt, ...) do{ printf(LOG_COLOR_CYAN "[F]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#else
|
||||
#define LOGF(fmt, ...) do{ printf(LOG_COLOR_CYAN "[F]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGF(fmt, ...) ((void)0)
|
||||
|
@ -122,9 +125,9 @@
|
|||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_ERROR
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGE(fmt, ...) do{ printf(LOG_COLOR_RED "[E]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGE(fmt, ...) do{ printf(LOG_COLOR_RED "[E]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGE(fmt, ...) ((void)0)
|
||||
|
@ -132,9 +135,9 @@
|
|||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_WARN
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGW(fmt, ...) do{ printf(LOG_COLOR_CARMINE "[W]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGW(fmt, ...) do{ printf(LOG_COLOR_CARMINE "[W]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGW(fmt, ...) ((void)0)
|
||||
|
@ -142,9 +145,9 @@
|
|||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_INFO
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGI(fmt, ...) do{ printf(LOG_COLOR_YELLOW "[I]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGI(fmt, ...) do{ printf(LOG_COLOR_YELLOW "[I]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGI(fmt, ...) ((void)0)
|
||||
|
@ -152,9 +155,9 @@
|
|||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_DEBUG
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGD(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[D]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGD(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[D]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGD(fmt, ...) ((void)0)
|
||||
|
@ -162,11 +165,164 @@
|
|||
|
||||
#if LOG_OUTPUT_LVL >= LOG_LVL_VERBOSE
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOGV(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[V]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define LOGV(fmt, ...) do{ printf(LOG_COLOR_DEFAULT "[V]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0)
|
||||
#endif
|
||||
#else
|
||||
#define LOGV(fmt, ...) ((void)0)
|
||||
#endif
|
||||
#endif //HW_LIB_LOG_H
|
||||
|
||||
|
||||
#ifndef LOG_RUN_TIME
|
||||
#ifndef __PLOOC_VA_NUM_ARGS_IMPL
|
||||
# define __PLOOC_VA_NUM_ARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
|
||||
_12, _13, _14, _15, _16, __N, ...) __N
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS
|
||||
#define __PLOOC_VA_NUM_ARGS(...) \
|
||||
__PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
|
||||
8,7,6,5,4,3,2,1,0)
|
||||
#endif
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
|
||||
/* default implementation */
|
||||
#if defined(__clang__) || __IS_COMPILER_GCC__
|
||||
# define __ticks_sync_barrier__(...) __sync_synchronize()
|
||||
#else
|
||||
# define __ticks_sync_barrier__(...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#undef __CONNECT2
|
||||
#undef __CONNECT3
|
||||
#undef __CONNECT4
|
||||
#undef __CONNECT5
|
||||
#undef __CONNECT6
|
||||
#undef __CONNECT7
|
||||
#undef __CONNECT8
|
||||
#undef __CONNECT9
|
||||
|
||||
#undef CONNECT2
|
||||
#undef CONNECT3
|
||||
#undef CONNECT4
|
||||
#undef CONNECT5
|
||||
#undef CONNECT6
|
||||
#undef CONNECT7
|
||||
#undef CONNECT8
|
||||
#undef CONNECT9
|
||||
|
||||
#undef CONNECT
|
||||
|
||||
#undef __MACRO_EXPANDING
|
||||
#define __MACRO_EXPANDING(...) __VA_ARGS__
|
||||
|
||||
#define __CONNECT2(__A, __B) __A##__B
|
||||
#define __CONNECT3(__A, __B, __C) __A##__B##__C
|
||||
#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
|
||||
#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
|
||||
#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
|
||||
#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__A##__B##__C##__D##__E##__F##__G
|
||||
#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H
|
||||
#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H##__I
|
||||
|
||||
#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
|
||||
#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
|
||||
#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
|
||||
#define CONNECT6(__A, __B, __C, __D, __E, __F) \
|
||||
__CONNECT6(__A, __B, __C, __D, __E, __F)
|
||||
#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__CONNECT7(__A, __B, __C, __D, __E, __F, __G)
|
||||
#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
|
||||
#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
|
||||
|
||||
#define CONNECT(...) \
|
||||
ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef __using1
|
||||
#undef __using2
|
||||
#undef __using3
|
||||
#undef __using4
|
||||
#undef using
|
||||
|
||||
#define __using1(__declare) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
)
|
||||
|
||||
#define __using2(__declare, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
|
||||
for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define using(...) \
|
||||
CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#ifdef LOG_WITH_RUN_TIMER
|
||||
#define LOG_RUN_TIME(__STR, ...) \
|
||||
using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = LOG_RUN_TIMER_FUN - _; \
|
||||
__time_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
LOG_OUT_FUNC("\r\n"); \
|
||||
LOG_OUT_FUNC("-[Run Timer]"); \
|
||||
LOG_OUT_FUNC( \
|
||||
"------------------------------------\r\n"); \
|
||||
LOG_OUT_FUNC( \
|
||||
__STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \
|
||||
_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
#else
|
||||
#define LOG_RUN_TIME(__STR, ...) \
|
||||
using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = LOG_RUN_TIMER_FUN - _; \
|
||||
__time_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
LOG_OUT_FUNC("\r\n"); \
|
||||
LOG_OUT_FUNC("-[Run Timer]"); \
|
||||
LOG_OUT_FUNC( \
|
||||
"------------------------------------\r\n"); \
|
||||
LOG_OUT_FUNC( \
|
||||
__STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \
|
||||
_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
#endif
|
||||
#endif
|
||||
#endif //HW_LIB_LOG_H
|
||||
|
|
|
@ -0,0 +1,806 @@
|
|||
//
|
||||
// Created by lydxh on 24-11-27.
|
||||
//
|
||||
|
||||
#ifndef HW_LIB_TICKS_H
|
||||
#define HW_LIB_TICKS_H
|
||||
/*============================ INCLUDES ======================================*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*============================ MACROS ========================================*/
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gHelper 4 Helper
|
||||
* @{
|
||||
*/
|
||||
|
||||
// for IAR
|
||||
#undef __IS_COMPILER_IAR__
|
||||
#if defined(__IAR_SYSTEMS_ICC__)
|
||||
# define __IS_COMPILER_IAR__ 1
|
||||
#endif
|
||||
|
||||
// for arm compiler 5
|
||||
#undef __IS_COMPILER_ARM_COMPILER_5__
|
||||
#if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
|
||||
# define __IS_COMPILER_ARM_COMPILER_5__ 1
|
||||
#endif
|
||||
|
||||
|
||||
//for arm compiler 6
|
||||
|
||||
#undef __IS_COMPILER_ARM_COMPILER_6__
|
||||
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
# define __IS_COMPILER_ARM_COMPILER_6__ 1
|
||||
#endif
|
||||
#undef __IS_COMPILER_ARM_COMPILER__
|
||||
#if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
|
||||
|| defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
|
||||
# define __IS_COMPILER_ARM_COMPILER__ 1
|
||||
#endif
|
||||
|
||||
// for clang
|
||||
#undef __IS_COMPILER_LLVM__
|
||||
#if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
|
||||
# define __IS_COMPILER_LLVM__ 1
|
||||
#else
|
||||
|
||||
// for gcc
|
||||
# undef __IS_COMPILER_GCC__
|
||||
# if defined(__GNUC__) && !(defined(__IS_COMPILER_ARM_COMPILER__) \
|
||||
|| defined(__IS_COMPILER_LLVM__) \
|
||||
|| defined(__IS_COMPILER_IAR__))
|
||||
# define __IS_COMPILER_GCC__ 1
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
# include __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# pragma clang diagnostic ignored "-Wdeclaration-after-statement"
|
||||
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
# pragma clang diagnostic ignored "-Wgnu-statement-expression"
|
||||
# pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
||||
# pragma clang diagnostic ignored "-Wshadow"
|
||||
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
|
||||
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||||
# pragma diag_suppress 550
|
||||
#elif defined(__IS_COMPILER_GCC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wpedantic"
|
||||
# pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
# pragma GCC diagnostic ignored "-Wformat="
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS_IMPL
|
||||
# define __PLOOC_VA_NUM_ARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
|
||||
_12, _13, _14, _15, _16, __N, ...) __N
|
||||
#endif
|
||||
|
||||
#ifndef __PLOOC_VA_NUM_ARGS
|
||||
#define __PLOOC_VA_NUM_ARGS(...) \
|
||||
__PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
|
||||
8,7,6,5,4,3,2,1,0)
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED_PARAM
|
||||
# define UNUSED_PARAM(__VAR) (void)(__VAR)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(__a, __b) ((__a) <= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(__a, __b) ((__a) >= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief an attribute for static variables that no initialisation is required
|
||||
* in the C startup process.
|
||||
*/
|
||||
#ifndef PERF_NOINIT
|
||||
# if defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit"),zero_init))
|
||||
# elif defined(__IS_COMPILER_ARM_COMPILER_6__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
|
||||
# elif defined(__IS_COMPILER_IAR__)
|
||||
# define PERF_NOINIT __no_init
|
||||
# elif (defined(__IS_COMPILER_GCC__) || defined(__IS_COMPILER_LLVM__)) && !defined(__APPLE__)
|
||||
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
|
||||
# else
|
||||
# define PERF_NOINIT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#undef __CONNECT2
|
||||
#undef __CONNECT3
|
||||
#undef __CONNECT4
|
||||
#undef __CONNECT5
|
||||
#undef __CONNECT6
|
||||
#undef __CONNECT7
|
||||
#undef __CONNECT8
|
||||
#undef __CONNECT9
|
||||
|
||||
#undef CONNECT2
|
||||
#undef CONNECT3
|
||||
#undef CONNECT4
|
||||
#undef CONNECT5
|
||||
#undef CONNECT6
|
||||
#undef CONNECT7
|
||||
#undef CONNECT8
|
||||
#undef CONNECT9
|
||||
|
||||
#undef CONNECT
|
||||
|
||||
#undef __MACRO_EXPANDING
|
||||
#define __MACRO_EXPANDING(...) __VA_ARGS__
|
||||
|
||||
#define __CONNECT2(__A, __B) __A##__B
|
||||
#define __CONNECT3(__A, __B, __C) __A##__B##__C
|
||||
#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
|
||||
#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
|
||||
#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
|
||||
#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__A##__B##__C##__D##__E##__F##__G
|
||||
#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H
|
||||
#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__A##__B##__C##__D##__E##__F##__G##__H##__I
|
||||
|
||||
#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
|
||||
#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
|
||||
#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
|
||||
#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
|
||||
#define CONNECT6(__A, __B, __C, __D, __E, __F) \
|
||||
__CONNECT6(__A, __B, __C, __D, __E, __F)
|
||||
#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
|
||||
__CONNECT7(__A, __B, __C, __D, __E, __F, __G)
|
||||
#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
|
||||
__CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
|
||||
#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
|
||||
__CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
|
||||
|
||||
#define CONNECT(...) \
|
||||
ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef __using1
|
||||
#undef __using2
|
||||
#undef __using3
|
||||
#undef __using4
|
||||
#undef using
|
||||
|
||||
#define __using1(__declare) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
)
|
||||
|
||||
#define __using2(__declare, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
|
||||
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
|
||||
for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
|
||||
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
|
||||
((__on_enter_expr),1) : 0; \
|
||||
(__on_leave_expr) \
|
||||
)
|
||||
|
||||
#define using(...) \
|
||||
CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
|
||||
#undef __with2
|
||||
#undef __with3
|
||||
#undef with
|
||||
|
||||
#define __with1(__addr) \
|
||||
using(__typeof__(*__addr) *_=(__addr))
|
||||
|
||||
#define __with2(__type, __addr) \
|
||||
using(__type *_=(__addr))
|
||||
#define __with3(__type, __addr, __item) \
|
||||
using(__type *_=(__addr), *__item = _, _=_,_=_ )
|
||||
|
||||
#define with(...) \
|
||||
CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#undef _
|
||||
|
||||
#ifndef dimof
|
||||
# define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
|
||||
#endif
|
||||
|
||||
|
||||
#define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
|
||||
|
||||
#undef foreach2
|
||||
#undef foreach3
|
||||
#undef foreach
|
||||
|
||||
#define foreach1(__array) \
|
||||
using(__typeof__(__array[0]) *_ = __array) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach2(__type, __array) \
|
||||
using(__type *_ = __array) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach3(__type, __array, __item) \
|
||||
using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
|
||||
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
|
||||
SAFE_NAME(count) > 0; \
|
||||
_++, __item = _, SAFE_NAME(count)-- \
|
||||
)
|
||||
|
||||
#define foreach(...) \
|
||||
CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#ifndef safe_atom_code
|
||||
# define safe_atom_code() \
|
||||
using( ticks_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
ticks_port_disable_global_interrupt(), \
|
||||
ticks_port_resume_global_interrupt(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __WEAK
|
||||
# define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifndef __STATIC_INLINE
|
||||
# define __STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
#ifndef __IRQ_SAFE
|
||||
# define __IRQ_SAFE \
|
||||
using( ticks_global_interrupt_status_t SAFE_NAME(temp) = \
|
||||
ticks_port_disable_global_interrupt(), \
|
||||
ticks_port_resume_global_interrupt(SAFE_NAME(temp)))
|
||||
#endif
|
||||
|
||||
#ifndef __perf_counter_printf__
|
||||
# define __perf_counter_printf__ printf
|
||||
#endif
|
||||
|
||||
/* deprecated macro for backward compatibility */
|
||||
#define user_code_insert_to_systick_handler \
|
||||
ticks_port_insert_to_system_timer_insert_ovf_handler
|
||||
|
||||
#if __PLOOC_VA_NUM_ARGS() != 0
|
||||
#warning Please enable GNU extensions, it is required by __cycleof__() and \
|
||||
__super_loop_monitor__()
|
||||
#endif
|
||||
|
||||
#if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__) \
|
||||
&& (!defined(__TICKS_USE_PORTING__) \
|
||||
|| (defined(__TICKS_USE_PORTING__) && (0 == __TICKS_USE_PORTING__)))
|
||||
|
||||
# if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
|
||||
# pragma import(__ensure_systick_wrapper)
|
||||
# elif (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
|
||||
__asm(".global __ensure_systick_wrapper\n\t");
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
|
||||
/* default implementation */
|
||||
#if defined(__clang__) || __IS_COMPILER_GCC__
|
||||
# define __ticks_sync_barrier__(...) __sync_synchronize()
|
||||
#else
|
||||
# define __ticks_sync_barrier__(...)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*! @} */
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasic 1 Basic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief measure the cycle count of a given code segment
|
||||
* \param[in] __STR a description string for the measurement
|
||||
* \param[in] ... an optional code segement, in which we can read the measured
|
||||
* result from __cycle_count__.
|
||||
* \details Here is an example:
|
||||
E.g.
|
||||
\code
|
||||
__cycleof__("printf") {
|
||||
printf("hello world\r\n");
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cycleof__(__STR, ...) \
|
||||
using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
|
||||
{__ticks_sync_barrier__();}, \
|
||||
{ \
|
||||
__ticks_sync_barrier__(); \
|
||||
_ = get_system_ticks() - _ - g_nOffset; \
|
||||
__cycle_count__ = _; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__("\r\n"); \
|
||||
__perf_counter_printf__("-[Cycle Report]"); \
|
||||
__perf_counter_printf__( \
|
||||
"------------------------------------\r\n"); \
|
||||
__perf_counter_printf__( \
|
||||
__STR " total cycle count: %ld [%08lx]\r\n", \
|
||||
(long)_, (long)_); \
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
})
|
||||
|
||||
/*!
|
||||
* \brief measure the cpu usage for a given code segment and print out the
|
||||
* result in percentage.
|
||||
* \param[in] __CNT generate result on every given iterations
|
||||
* \param[in] ... an optional code segement, in which we can read the measured
|
||||
* result from __usage__ which is a float value.
|
||||
* \details Here is an example, 50% cpu time:
|
||||
E.g.
|
||||
\code
|
||||
while (1) {
|
||||
__cpu_usage__(100) {
|
||||
delay_us(5000);
|
||||
}
|
||||
delay_us(5000);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
#define __cpu_usage__(__CNT, ...) \
|
||||
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
|
||||
static uint32_t SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
using(float __usage__ = 0, ({ \
|
||||
if (0 == SAFE_NAME(s_wLoopCounter)) { \
|
||||
__usage__ = (float)((double)SAFE_NAME(s_lTotal) \
|
||||
/ (double)( get_system_ticks() \
|
||||
- SAFE_NAME(s_lTimestamp))); \
|
||||
__usage__ *= 100.0f; \
|
||||
SAFE_NAME(s_lTimestamp) = 0; \
|
||||
SAFE_NAME(s_lTotal) = 0; \
|
||||
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
|
||||
__perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__);\
|
||||
} else { \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
} \
|
||||
if (0 == SAFE_NAME(s_lTimestamp)) { \
|
||||
SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
|
||||
SAFE_NAME(s_wLoopCounter) = (__CNT); \
|
||||
} \
|
||||
start_task_cycle_counter();}), \
|
||||
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
|
||||
SAFE_NAME(s_wLoopCounter)--;}))
|
||||
|
||||
#define __cpu_time__ __cpu_usage__
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief should not use
|
||||
*/
|
||||
#define ticks_is_time_out_ms0() true
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
* \param[in] __auto_reload whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__ticks_is_time_out(ticks_convert_ms_to_ticks(__ms), \
|
||||
(__timestamp_ptr), (__auto_reload));})
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms2(__ms, __timestamp_ptr) \
|
||||
ticks_is_time_out_ms3((__ms), (__timestamp_ptr), true)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms1(__ms) \
|
||||
ticks_is_time_out_ms3((__ms), &SAFE_NAME(s_lTimestamp), true)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in ms and check the status
|
||||
*
|
||||
* \param[in] __ms a time period in millisecond
|
||||
* \param[in] ... an optional timestamp holder
|
||||
* \param[in] ... an optional indicator for whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_ms(...) \
|
||||
CONNECT2(ticks_is_time_out_ms, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
* \param[in] __auto_reload whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
|
||||
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
|
||||
__ticks_is_time_out(ticks_convert_us_to_ticks(__us), \
|
||||
(__timestamp_ptr), (__auto_reload));})
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us2(__us, __timestamp_ptr) \
|
||||
ticks_is_time_out_us3((__us), (__timestamp_ptr), true)
|
||||
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] __timestamp_ptr an optional timestamp holder
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us1(__us) \
|
||||
ticks_is_time_out_us3((__us), &SAFE_NAME(s_lTimestamp), true)
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period in us and check the status
|
||||
*
|
||||
* \param[in] __us a time period in microsecond
|
||||
* \param[in] ... an optional timestamp holder
|
||||
* \param[in] ... an optional indicator for whether starting next period after a timeout event
|
||||
*
|
||||
* \return bool whether it is timeout
|
||||
*/
|
||||
#define ticks_is_time_out_us(...) \
|
||||
CONNECT2(ticks_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
/*============================ TYPES =========================================*/
|
||||
typedef struct {
|
||||
int64_t lStart;
|
||||
int64_t lUsedTotal;
|
||||
int32_t nUsedRecent;
|
||||
uint16_t hwActiveCount;
|
||||
uint16_t : 15;
|
||||
uint16_t bEnabled: 1;
|
||||
} task_cycle_info_t;
|
||||
|
||||
typedef struct task_cycle_info_agent_t task_cycle_info_agent_t;
|
||||
|
||||
struct task_cycle_info_agent_t {
|
||||
task_cycle_info_t *ptInfo;
|
||||
task_cycle_info_agent_t *ptNext;
|
||||
task_cycle_info_agent_t *ptPrev;
|
||||
};
|
||||
|
||||
extern volatile int64_t g_lLastTimeStamp;
|
||||
extern volatile int32_t g_nOffset;
|
||||
|
||||
|
||||
__attribute__((noinline))
|
||||
extern int64_t get_system_ticks(void);
|
||||
|
||||
|
||||
#ifdef __TICKS_USE_LONG_CLOCK__
|
||||
/*! \note the prototype of this clock() is different from the one defined in
|
||||
*! time.h. As clock_t is usually defined as unsigned int, it is
|
||||
*! not big enough in Cortex-M system to hold a time-stamp. clock()
|
||||
*! defined here returns the timestamp since the begining of main()
|
||||
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
|
||||
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
|
||||
*! NXP, it is very easy to see a counter overflow as clock_t is
|
||||
*! defined as uint32_t in timer.h.
|
||||
*! Since we are not allowed to change the defintion of clock_t in
|
||||
*! official header file, i.e. time.h, I use a compatible prototype
|
||||
*! after I checked the AAPCS spec. So, the return of the clock() is
|
||||
*! int64_t, which will use the R0 to store the lower 32bits and R1
|
||||
*! to store the higher 32bits. When you are using the prototype from
|
||||
*! timer.h, caller will only take the lower 32bits stored in R0 and
|
||||
*! the higher 32bits stored in R1 will be ignored.
|
||||
*!
|
||||
*! If you want to use the non-overflow version of this clock(), please
|
||||
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
|
||||
*! and 2) do not include system header file <time.h>
|
||||
*!
|
||||
*/
|
||||
#if !defined(__IS_COMPILER_IAR__)
|
||||
__attribute__((nothrow))
|
||||
#endif
|
||||
__attribute__((noinline))
|
||||
extern int64_t clock(void);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief try to set a start pointer for the performance counter
|
||||
*/
|
||||
static inline
|
||||
void start_cycle_counter(void) {
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief calculate the elapsed cycle count since the last start point
|
||||
* \note you can have multiple stop_cycle_counter following one start point
|
||||
* \return int32_t the elapsed cycle count
|
||||
*/
|
||||
static inline
|
||||
int64_t stop_cycle_counter(void) {
|
||||
int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
|
||||
|
||||
return lTemp - g_nOffset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasicTimerService 1.2 Timer Service
|
||||
* \ingroup gBasic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief get the system timer frequency
|
||||
* \return uint32_t the system timer frequency in Hz
|
||||
*/
|
||||
extern uint32_t ticks_get_systimer_frequency(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed milliseconds since perf_counter is initialised
|
||||
* \return int64_t the elapsed milliseconds
|
||||
*/
|
||||
extern int64_t get_system_ms(void);
|
||||
|
||||
/*!
|
||||
* \brief get the elapsed microsecond since perf_counter is initialised
|
||||
* \return int64_t the elapsed microsecond
|
||||
*/
|
||||
extern int64_t get_system_us(void);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in microsecond
|
||||
* \param[in] wUs time in microsecond
|
||||
*/
|
||||
extern void delay_us(uint32_t wUs);
|
||||
|
||||
/*!
|
||||
* \brief delay specified time in millisecond
|
||||
* \param[in] wMs time in millisecond
|
||||
*/
|
||||
extern void delay_ms(uint32_t nMs);
|
||||
|
||||
/*!
|
||||
* \brief convert ticks of a reference timer to millisecond
|
||||
*
|
||||
* \param[in] lTick the tick count
|
||||
* \return int64_t the millisecond
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ticks_to_ms(int64_t lTick);
|
||||
|
||||
/*!
|
||||
* \brief convert millisecond into ticks of the reference timer
|
||||
*
|
||||
* \param[in] wMS the target time in millisecond
|
||||
* \return int64_t the ticks
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ms_to_ticks(uint32_t wMS);
|
||||
|
||||
/*!
|
||||
* \brief convert ticks of a reference timer to microsecond
|
||||
*
|
||||
* \param[in] lTick the tick count
|
||||
* \return int64_t the microsecond
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_ticks_to_us(int64_t lTick);
|
||||
|
||||
/*!
|
||||
* \brief convert microsecond into ticks of the reference timer
|
||||
*
|
||||
* \param[in] wUS the target time in microsecond
|
||||
* \return int64_t the ticks
|
||||
*/
|
||||
extern
|
||||
int64_t ticks_convert_us_to_ticks(uint32_t wUS);
|
||||
|
||||
/*!
|
||||
* \brief set an alarm with given period and check the status
|
||||
*
|
||||
* \param[in] lPeriod a time period in ticks
|
||||
* \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
|
||||
* passed, an static local variable inside the function will be used
|
||||
* \param[in] bAutoReload whether starting next period after a timeout event.
|
||||
* \return bool whether it is timeout or not
|
||||
*/
|
||||
extern
|
||||
bool __ticks_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
|
||||
|
||||
/*!
|
||||
* \addtogroup gBasic 1 Basic
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
* Please ignore the following APIs unless you have encountered some known *
|
||||
* special conditions *
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/*! \brief initialise cycle counter service
|
||||
* \note - don't forget to tell the function whether the systick is already
|
||||
* used by user applications.
|
||||
* Don't worry, this cycle counter service won't affect your existing
|
||||
* systick service.
|
||||
*
|
||||
* \note - Usually the perf_counter can initialise itself with the help of
|
||||
* __attribute__((constructor(255))), this works fine in Arm Compiler
|
||||
* 5 (armcc), Arm Compiler 6 (armclang), arm gcc and llvm. It doesn't
|
||||
* work for IAR. So, when you are using IAR, please call this function
|
||||
* manually to initialise the perf_counter service.
|
||||
*
|
||||
* \note - Perf_counter library assumes that:
|
||||
* 1. Your project has already using SysTick
|
||||
* 2. It assumes that you have already implemented the SysTick_Handler
|
||||
* 3. It assumes that you have enabled the exception handling for
|
||||
* SysTick.
|
||||
* If these are not the case, please:
|
||||
* 1. Add an empty SysTick_Handler to your project if you don't have
|
||||
* one
|
||||
* 2. Make sure you have the SysTick Exception handling enabled
|
||||
* 3. And call function init_cycle_counter(false) if you doesn't
|
||||
* use SysTick in your project at all.
|
||||
*
|
||||
* \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
|
||||
* is already used by user application.
|
||||
*
|
||||
* \return false Failed to initialize the timer counter, as the timer is not
|
||||
* available or IO error.
|
||||
* \return true initialization is successful.
|
||||
*/
|
||||
extern bool init_cycle_counter(bool bIsSysTickOccupied);
|
||||
|
||||
|
||||
/*!
|
||||
* \brief a system timer overflow handler
|
||||
*
|
||||
* \note - if you are using a compiler other than armcc or armclang, e.g. iar,
|
||||
* arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
|
||||
* of your target toolchain as it use the $Super$$ which is only supported
|
||||
* by armlink. For this condition, you have to manually put this function
|
||||
* into your existing SysTick_Handler to make the perf_counter library
|
||||
* work.
|
||||
*
|
||||
* \note - if you are using Arm Compiler 5 (armcc) or Arm Compiler 6 (armclang)
|
||||
* you do NOT have to insert this function into your SysTick_Handler,
|
||||
* the systick_wrapper_ual.s will do the work for you.
|
||||
*/
|
||||
extern void ticks_port_insert_to_system_timer_insert_ovf_handler(void);
|
||||
|
||||
/*!
|
||||
* \brief update perf_counter as SystemCoreClock has been updated.
|
||||
*/
|
||||
extern void update_perf_counter(void);
|
||||
|
||||
/*!
|
||||
* \brief prepare for reconfiguration of SysTick timer.
|
||||
*
|
||||
* \note some systems (e.g. FreeRTOS) might reconfigure the systick timer to
|
||||
* fulfil the requirement of their feature. To support this, just
|
||||
* before the reconfiguration, please call this function in order
|
||||
* to make the perf_counter works correctly later.
|
||||
*
|
||||
* \note after the reconfiguration, please call update_perf_counter() to apply
|
||||
* the changes to perf_counter.
|
||||
*
|
||||
* \note this function will stop the SysTick, clear the pending bit and set
|
||||
* the Load register and Current Value register to zero.
|
||||
*/
|
||||
extern void before_cycle_counter_reconfiguration(void);
|
||||
|
||||
|
||||
#ifndef __ticks_sync_barrier__
|
||||
# define __ticks_sync_barrier__(...) do {__DSB();__ISB();} while(0)
|
||||
#endif
|
||||
|
||||
typedef uint32_t ticks_global_interrupt_status_t;
|
||||
|
||||
__STATIC_INLINE
|
||||
ticks_global_interrupt_status_t ticks_port_disable_global_interrupt(void);
|
||||
//{
|
||||
// ticks_global_interrupt_status_t tStatus = __get_PRIMASK();
|
||||
// __disable_irq();
|
||||
//
|
||||
// return tStatus;
|
||||
//}
|
||||
|
||||
__STATIC_INLINE
|
||||
void ticks_port_resume_global_interrupt(ticks_global_interrupt_status_t tStatus);
|
||||
//{
|
||||
// __set_PRIMASK(tStatus);
|
||||
//}
|
||||
|
||||
|
||||
//#if defined(__clang__)
|
||||
//# pragma clang diagnostic pop
|
||||
//#elif defined(__IS_COMPILER_GCC__)
|
||||
//# pragma GCC diagnostic pop
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_TICKS_H
|
|
@ -48,9 +48,9 @@ typedef enum { // 定义枚举类型Type_t,包含不同数据类型
|
|||
default: ((void)0))
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) // 计算数组的元素个数
|
||||
//#define in , // 定义逗号为in
|
||||
|
||||
#define _foreach(e, a) for(size_t e = 0; e < ARRAY_SIZE(a); e++) // 实现foreach宏,遍历数组a,e为当前元素下标
|
||||
#define foreach(exp) _foreach(exp) // 定义foreach宏,用于遍历数组
|
||||
|
||||
|
||||
#define _VA_ARGS_N(_9, _8, _7, _6, _5, _4, _3, _2, _1, _0, N, ...) N
|
||||
#define VA_ARGS_N(...) _VA_ARGS_N(0 __VA_OPT__(,) __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||
|
@ -60,6 +60,7 @@ typedef enum { // 定义枚举类型Type_t,包含不同数据类型
|
|||
#define _range_n_cat(a, b) a ## b
|
||||
#define _range_n(n) _range_n_cat(_range_, n)
|
||||
#define _range(...) _range_n(VA_ARGS_N(__VA_ARGS__)) // 根据传入参数个数选择对应的范围循环宏
|
||||
|
||||
/**
|
||||
* @Name 范围循环
|
||||
* @brief 根据传入参数个数生成不同范围的遍历
|
||||
|
@ -125,7 +126,7 @@ float Str2Float(char *str);
|
|||
* @param fmt: [输入] 格式化字段
|
||||
* @param frame: [输入] 断帧大小
|
||||
* @return void
|
||||
* @example BufPrint("TX", buf, 8, 64, 16); //将长64的8位buf以16个数据断帧打印
|
||||
* @example PRINT_ARRAY(buf, " 0x%02x", 16); //将长64的8位buf以16个数据断帧打印
|
||||
**/
|
||||
#define PRINT_ARRAY(arr, fmt, frame) do { \
|
||||
printf("\n"#arr ":\n"); \
|
||||
|
@ -143,9 +144,41 @@ int :"[int]-> "#v"=%d" END, \
|
|||
float :"[float]-> "#v"=%.2f" END , \
|
||||
double :"[double]-> "#v"=%.2f" END, \
|
||||
default: "[err]-> "#v"=%p" END)
|
||||
|
||||
#define POUT(s) printf(TYPE_F(s) ,s)
|
||||
|
||||
#ifndef GET_BIT
|
||||
#define GET_BIT(x, bit) ((x & (1 << bit)) >> bit)
|
||||
#endif
|
||||
#ifndef SWAP
|
||||
#ifdef __cplusplus
|
||||
#define SWAP(x, y) do { \
|
||||
decltype(x) temp = x; \
|
||||
x = y; \
|
||||
y = temp; \
|
||||
} while(0)
|
||||
#else
|
||||
#define SWAP(x, y) do { \
|
||||
typeof(x) temp = x; \
|
||||
x = y; \
|
||||
y = temp; \
|
||||
} while(0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(__a, __b) ((__a) <= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(__a, __b) ((__a) >= (__b) ? (__a) : (__b))
|
||||
#endif
|
||||
|
||||
#ifndef __WEAK
|
||||
# define __WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,631 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define __IMPLEMENT_PERF_COUNTER
|
||||
|
||||
#include "ticks.h"
|
||||
|
||||
#if defined(__IS_COMPILER_GCC__)
|
||||
# pragma GCC diagnostic ignored "-Wattributes"
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
|
||||
# pragma clang diagnostic ignored "-Wcast-align"
|
||||
# pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#endif
|
||||
|
||||
|
||||
/*============================ MACROS ========================================*/
|
||||
#ifndef PERF_CNT_COMPENSATION_THRESHOLD
|
||||
# define PERF_CNT_COMPENSATION_THRESHOLD 16
|
||||
#endif
|
||||
|
||||
#ifndef PERF_CNT_DELAY_US_COMPENSATION
|
||||
# define PERF_CNT_DELAY_US_COMPENSATION 90
|
||||
#endif
|
||||
|
||||
#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
|
||||
#define MAGIC_WORD_CANARY 0xDEADBEEF
|
||||
|
||||
/*============================ MACROFIED FUNCTIONS ===========================*/
|
||||
/*============================ TYPES =========================================*/
|
||||
|
||||
struct __task_cycle_info_t {
|
||||
task_cycle_info_t tInfo; //!< cycle information
|
||||
int64_t lLastTimeStamp; //!< previous timestamp
|
||||
task_cycle_info_agent_t tList; //!< the root of the agent list
|
||||
uint32_t wMagicWord; //!< an magic word for validation
|
||||
};
|
||||
|
||||
|
||||
/*============================ GLOBAL VARIABLES ==============================*/
|
||||
/*============================ LOCAL VARIABLES ===============================*/
|
||||
volatile int64_t g_lLastTimeStamp = 0;
|
||||
volatile static int64_t s_lOldTimestamp;
|
||||
volatile int32_t g_nOffset = 0;
|
||||
volatile static uint32_t s_wUSUnit = 1;
|
||||
volatile static uint32_t s_wMSUnit = 1;
|
||||
volatile static uint32_t s_wMSResidule = 0;
|
||||
volatile static uint32_t s_wUSResidule = 0;
|
||||
volatile static int64_t s_lSystemMS = 0;
|
||||
volatile static int64_t s_lSystemUS = 0;
|
||||
|
||||
volatile static int64_t s_lSystemClockCounts = 0;
|
||||
|
||||
/*============================ PROTOTYPES ====================================*/
|
||||
|
||||
/* low level interface for porting */
|
||||
extern
|
||||
uint32_t ticks_port_get_system_timer_freq(void);
|
||||
|
||||
extern
|
||||
int64_t ticks_port_get_system_timer_top(void);
|
||||
|
||||
extern
|
||||
bool ticks_port_is_system_timer_ovf_pending(void);
|
||||
|
||||
extern
|
||||
bool ticks_port_init_system_timer(bool bTimerOccupied);
|
||||
|
||||
extern
|
||||
int64_t ticks_port_get_system_timer_elapsed(void);
|
||||
|
||||
extern
|
||||
void ticks_port_clear_system_timer_ovf_pending(void);
|
||||
|
||||
extern
|
||||
void ticks_port_stop_system_timer_counting(void);
|
||||
|
||||
extern
|
||||
void ticks_port_clear_system_timer_counter(void);
|
||||
|
||||
/*============================ INCLUDES ======================================*/
|
||||
|
||||
void ticks_port_insert_to_system_timer_insert_ovf_handler(void) {
|
||||
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||||
s_lSystemClockCounts += lLoad;
|
||||
|
||||
// update system ms counter
|
||||
do {
|
||||
int64_t lTemp = s_wMSResidule + lLoad;
|
||||
|
||||
int64_t lMS = lTemp / s_wMSUnit;
|
||||
s_lSystemMS += lMS;
|
||||
s_wMSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lMS * s_wMSUnit);
|
||||
|
||||
} while (0);
|
||||
|
||||
// update system us counter
|
||||
do {
|
||||
int64_t lTemp = s_wUSResidule + lLoad;
|
||||
|
||||
int64_t lUS = lTemp / s_wUSUnit;
|
||||
s_lSystemUS += lUS;
|
||||
|
||||
s_wUSResidule = (uint32_t) ((int64_t) lTemp - (int64_t) lUS * s_wUSUnit);
|
||||
|
||||
} while (0);
|
||||
|
||||
}
|
||||
|
||||
uint32_t ticks_get_systimer_frequency(void) {
|
||||
return ticks_port_get_system_timer_freq();
|
||||
}
|
||||
|
||||
__WEAK
|
||||
void __perf_os_patch_init(void) {
|
||||
}
|
||||
|
||||
|
||||
void update_perf_counter(void) {
|
||||
uint32_t wSystemFrequency = ticks_port_get_system_timer_freq();
|
||||
s_wUSUnit = wSystemFrequency / 1000000ul;
|
||||
s_wMSUnit = wSystemFrequency / 1000ul;
|
||||
|
||||
__IRQ_SAFE {
|
||||
g_lLastTimeStamp = get_system_ticks();
|
||||
__ticks_sync_barrier__();
|
||||
g_nOffset = get_system_ticks() - g_lLastTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
bool init_cycle_counter(bool bIsSysTickOccupied) {
|
||||
bool bResult = false;
|
||||
__IRQ_SAFE {
|
||||
bResult = ticks_port_init_system_timer(bIsSysTickOccupied); // use the longest period
|
||||
ticks_port_clear_system_timer_ovf_pending();
|
||||
}
|
||||
|
||||
update_perf_counter();
|
||||
s_lSystemClockCounts = 0; // reset system cycle counter
|
||||
s_lSystemMS = 0; // reset system millisecond counter
|
||||
s_lSystemUS = 0; // reset system microsecond counter
|
||||
s_lOldTimestamp = 0;
|
||||
|
||||
__perf_os_patch_init();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
/*! \note this function should only be called when irq is disabled
|
||||
* hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
|
||||
* won't change.
|
||||
*/
|
||||
__STATIC_INLINE int64_t check_systick(void) {
|
||||
int64_t lLoad = ticks_port_get_system_timer_top() + 1;
|
||||
int64_t lTemp = ticks_port_get_system_timer_elapsed();
|
||||
|
||||
/* Since we cannot stop counting temporarily, there are several
|
||||
* conditions which we should take into consideration:
|
||||
* - Condition 1: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the underflow didn't happen but when we check the PENDSTSET bit,
|
||||
* the underflow happens, for this condition, we should not
|
||||
* do any compensation. When this happens, the (LOAD-nTemp) is
|
||||
* smaller than PERF_CNT_COMPENSATION_THRESHOLD (a small value) as
|
||||
* long as LOAD is bigger than (or equals to) the
|
||||
* PERF_CNT_COMPENSATION_THRESHOLD;
|
||||
* - Condition 2: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the VAL is zero and underflow happened and the PENDSTSET bit
|
||||
* is set, for this condition, we should not do any compensation.
|
||||
* When this happens, the (LOAD-nTemp) is equals to zero.
|
||||
* - Condition 3: when assigning nTemp with the register value (LOAD-VAL),
|
||||
* the underflow has already happened, hence the PENDSTSET
|
||||
* is set, for this condition, we should compensate the return
|
||||
* value. When this happens, the (LOAD-nTemp) is bigger than (or
|
||||
* equals to) PERF_CNT_COMPENSATION_THRESHOLD.
|
||||
* The following code implements an equivalent logic.
|
||||
*/
|
||||
if (ticks_port_is_system_timer_ovf_pending()) {
|
||||
if ((lLoad - lTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
|
||||
lTemp += lLoad;
|
||||
}
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
void before_cycle_counter_reconfiguration(void) {
|
||||
__IRQ_SAFE {
|
||||
ticks_port_stop_system_timer_counting();
|
||||
|
||||
if (ticks_port_is_system_timer_ovf_pending()) {
|
||||
ticks_port_clear_system_timer_ovf_pending(); /* clear pending bit */
|
||||
|
||||
ticks_port_insert_to_system_timer_insert_ovf_handler(); /* manually handle exception */
|
||||
|
||||
}
|
||||
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
|
||||
|
||||
ticks_port_clear_system_timer_counter();
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
void __perf_counter_init(void) {
|
||||
init_cycle_counter(true);
|
||||
}
|
||||
|
||||
|
||||
void delay_us(uint32_t wUs) {
|
||||
int64_t lUs = (int64_t) wUs * (int64_t) s_wUSUnit;
|
||||
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||||
? g_nOffset
|
||||
: PERF_CNT_DELAY_US_COMPENSATION;
|
||||
|
||||
if (lUs <= iCompensate) {
|
||||
return;
|
||||
}
|
||||
|
||||
lUs -= iCompensate;
|
||||
|
||||
lUs += get_system_ticks();
|
||||
while (get_system_ticks() < lUs);
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t wMs) {
|
||||
int64_t lMs = (int64_t) wMs * (int64_t) s_wMSUnit;
|
||||
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
|
||||
? g_nOffset
|
||||
: PERF_CNT_DELAY_US_COMPENSATION;
|
||||
|
||||
if (lMs <= iCompensate) {
|
||||
return;
|
||||
}
|
||||
|
||||
lMs -= iCompensate;
|
||||
|
||||
lMs += get_system_ticks();
|
||||
while (get_system_ticks() < lMs);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int64_t get_system_ticks(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = check_systick() + s_lSystemClockCounts;
|
||||
|
||||
/* When calling get_system_ticks() in an exception handler that has a
|
||||
* higher priority than the SysTick_Handler, in some rare cases, the
|
||||
* lTemp might be temporarily smaller than the previous value (i.e.
|
||||
* s_lOldTimestamp), to mitigate the adverse effects of this problem,
|
||||
* we use the following code to avoid time-rolling-back issue.
|
||||
*
|
||||
* NOTE: the issue mentioned above doesn't accumulate or have long-lasting
|
||||
* effects.
|
||||
*/
|
||||
if (lTemp < s_lOldTimestamp) {
|
||||
lTemp = s_lOldTimestamp;
|
||||
} else {
|
||||
s_lOldTimestamp = lTemp;
|
||||
}
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
/*! \note the prototype of this clock() is different from the one defined in
|
||||
*! time.h. As clock_t is usually defined as unsigned int, it is
|
||||
*! not big enough in Cortex-M system to hold a time-stamp. clock()
|
||||
*! defined here returns the timestamp since the begining of main()
|
||||
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
|
||||
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
|
||||
*! NXP, it is very easy to see a counter overflow as clock_t is
|
||||
*! defined as uint32_t in timer.h.
|
||||
*! Since we are not allowed to change the defintion of clock_t in
|
||||
*! official header file, i.e. time.h, I use a compatible prototype
|
||||
*! after I checked the AAPCS spec. So, the return of the clock() is
|
||||
*! int64_t, which will use the R0 to store the lower 32bits and R1
|
||||
*! to store the higher 32bits. When you are using the prototype from
|
||||
*! timer.h, caller will only take the lower 32bits stored in R0 and
|
||||
*! the higher 32bits stored in R1 will be ignored.
|
||||
*!
|
||||
*! If you want to use the non-overflow version of this clock(), please
|
||||
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
|
||||
*! and 2) do not include system header file <time.h>
|
||||
*!
|
||||
*/
|
||||
#if !defined(__IS_COMPILER_IAR__)
|
||||
|
||||
__attribute__((nothrow))
|
||||
#endif
|
||||
__attribute__((noinline))
|
||||
int64_t clock(void) {
|
||||
return get_system_ticks();
|
||||
}
|
||||
|
||||
int64_t get_system_ms(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = s_lSystemMS + ((check_systick() + (int64_t) s_wMSResidule) / s_wMSUnit);
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int64_t get_system_us(void) {
|
||||
int64_t lTemp = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
lTemp = s_lSystemUS + ((check_systick() + (int64_t) s_wUSResidule) / s_wUSUnit);
|
||||
}
|
||||
|
||||
return lTemp;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ticks_to_ms(int64_t lTick) {
|
||||
return lTick / (int64_t) s_wMSUnit;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ms_to_ticks(uint32_t wMS) {
|
||||
int64_t lResult = (int64_t) s_wMSUnit * (int64_t) wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_ticks_to_us(int64_t lTick) {
|
||||
return lTick / (int64_t) s_wUSUnit;
|
||||
}
|
||||
|
||||
int64_t ticks_convert_us_to_ticks(uint32_t wMS) {
|
||||
int64_t lResult = (int64_t) s_wUSUnit * (int64_t) wMS;
|
||||
return lResult ? lResult : 1;
|
||||
}
|
||||
|
||||
|
||||
bool __ticks_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload) {
|
||||
if (NULL == plTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t lTimestamp = get_system_ticks();
|
||||
|
||||
|
||||
if (0 == *plTimestamp) {
|
||||
*plTimestamp = lPeriod;
|
||||
*plTimestamp += lTimestamp;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lTimestamp >= *plTimestamp) {
|
||||
if (bAutoReload) {
|
||||
*plTimestamp = lPeriod + lTimestamp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Setup timer hardware.
|
||||
/// \return status (1=Success, 0=Failure)
|
||||
uint32_t EventRecorderTimerSetup(void) {
|
||||
/* doing nothing at all */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Get timer frequency.
|
||||
/// \return timer frequency in Hz
|
||||
uint32_t EventRecorderTimerGetFreq(void) {
|
||||
return ticks_port_get_system_timer_freq();
|
||||
}
|
||||
|
||||
/// Get timer count.
|
||||
/// \return timer count (32-bit)
|
||||
uint32_t EventRecorderTimerGetCount(void) {
|
||||
return get_system_ticks();
|
||||
}
|
||||
|
||||
|
||||
__WEAK
|
||||
task_cycle_info_t *get_rtos_task_cycle_info(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_task_cycle_counter(void) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(ptRootAgent, 0, sizeof(struct __task_cycle_info_t));
|
||||
|
||||
ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
|
||||
ptRootAgent->tInfo.lStart = get_system_ticks();
|
||||
ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
|
||||
}
|
||||
|
||||
bool ticks_check_task_stack_canary_safe(void) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
do {
|
||||
if (NULL == ptRootAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((MAGIC_WORD_CANARY == ptRootAgent->wMagicWord)
|
||||
|| (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord)) {
|
||||
return true;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
do {
|
||||
if (NULL == ptInfo) {
|
||||
break;
|
||||
}
|
||||
|
||||
memset(ptInfo, 0, sizeof(task_cycle_info_t));
|
||||
|
||||
ptInfo->bEnabled = true;
|
||||
} while (0);
|
||||
|
||||
return ptInfo;
|
||||
}
|
||||
|
||||
bool enable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
if (NULL == ptInfo) {
|
||||
return false;
|
||||
}
|
||||
bool bOrig;
|
||||
__IRQ_SAFE {
|
||||
bOrig = ptInfo->bEnabled;
|
||||
ptInfo->bEnabled = true;
|
||||
}
|
||||
return bOrig;
|
||||
}
|
||||
|
||||
bool disable_task_cycle_info(task_cycle_info_t *ptInfo) {
|
||||
if (NULL == ptInfo) {
|
||||
return false;
|
||||
}
|
||||
bool bOrig;
|
||||
__IRQ_SAFE {
|
||||
bOrig = ptInfo->bEnabled;
|
||||
ptInfo->bEnabled = false;
|
||||
}
|
||||
return bOrig;
|
||||
}
|
||||
|
||||
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus) {
|
||||
if (NULL == ptInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
ptInfo->bEnabled = bEnabledStatus;
|
||||
}
|
||||
|
||||
|
||||
task_cycle_info_agent_t *register_task_cycle_agent(task_cycle_info_t *ptInfo,
|
||||
task_cycle_info_agent_t *ptAgent) {
|
||||
__IRQ_SAFE {
|
||||
do {
|
||||
if (NULL == ptAgent || NULL == ptInfo) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
|
||||
|
||||
ptAgent->ptInfo = ptInfo;
|
||||
|
||||
// push to the stack
|
||||
do {
|
||||
// set next-list
|
||||
ptAgent->ptNext = ptRootAgent->tList.ptNext;
|
||||
ptRootAgent->tList.ptNext = ptAgent;
|
||||
|
||||
// set prev-list
|
||||
ptAgent->ptPrev = &(ptRootAgent->tList);
|
||||
if (NULL != ptAgent->ptNext) {
|
||||
ptAgent->ptNext->ptPrev = ptAgent;
|
||||
}
|
||||
} while (0);
|
||||
|
||||
} while (0);
|
||||
}
|
||||
|
||||
return ptAgent;
|
||||
}
|
||||
|
||||
task_cycle_info_agent_t *
|
||||
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent) {
|
||||
__IRQ_SAFE {
|
||||
do {
|
||||
if (NULL == ptAgent) {
|
||||
break;
|
||||
}
|
||||
|
||||
task_cycle_info_agent_t *ptPrev = ptAgent->ptPrev;
|
||||
if (NULL == ptPrev) {
|
||||
break; /* this should not happen */
|
||||
}
|
||||
if (ptPrev->ptNext != ptAgent) {
|
||||
// already removed
|
||||
break;
|
||||
}
|
||||
|
||||
//! remove agent from the next-list
|
||||
ptPrev->ptNext = ptAgent->ptNext;
|
||||
|
||||
if (NULL != ptAgent->ptNext) {
|
||||
// remove agent from the prev-list
|
||||
ptAgent->ptNext->ptPrev = ptPrev;
|
||||
}
|
||||
|
||||
ptAgent->ptNext = NULL;
|
||||
ptAgent->ptPrev = NULL;
|
||||
|
||||
} while (0);
|
||||
}
|
||||
|
||||
return ptAgent;
|
||||
}
|
||||
|
||||
|
||||
void __on_context_switch_in(uint32_t *pwStack) {
|
||||
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||||
int64_t lTimeStamp = get_system_ticks();
|
||||
|
||||
ptRootAgent->lLastTimeStamp = lTimeStamp;
|
||||
ptRootAgent->tInfo.hwActiveCount++;
|
||||
|
||||
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||||
// update all agents
|
||||
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||||
while (NULL != ptAgent) {
|
||||
if (NULL != ptAgent->ptInfo) {
|
||||
if (ptAgent->ptInfo->bEnabled) {
|
||||
ptAgent->ptInfo->hwActiveCount++;
|
||||
}
|
||||
}
|
||||
ptAgent = ptAgent->ptNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __on_context_switch_out(uint32_t *pwStack) {
|
||||
struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *) pwStack;
|
||||
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||||
|
||||
ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
|
||||
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||||
|
||||
if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
|
||||
// update all agents
|
||||
task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
|
||||
while (NULL != ptAgent) {
|
||||
if (NULL != ptAgent->ptInfo) {
|
||||
if (ptAgent->ptInfo->bEnabled) {
|
||||
ptAgent->ptInfo->nUsedRecent = lCycleUsed;
|
||||
ptAgent->ptInfo->lUsedTotal += lCycleUsed;
|
||||
}
|
||||
}
|
||||
ptAgent = ptAgent->ptNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void __start_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return;
|
||||
}
|
||||
|
||||
__IRQ_SAFE {
|
||||
ptRootAgent->lLastTimeStamp = get_system_ticks();
|
||||
ptRootAgent->tInfo.lUsedTotal = 0;
|
||||
|
||||
if (NULL != ptInfo) {
|
||||
ptInfo->lUsedTotal = 0;
|
||||
ptInfo->bEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo) {
|
||||
struct __task_cycle_info_t *ptRootAgent =
|
||||
(struct __task_cycle_info_t *) get_rtos_task_cycle_info();
|
||||
if (NULL == ptRootAgent) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t lCycles = 0;
|
||||
|
||||
__IRQ_SAFE {
|
||||
int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
|
||||
ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
|
||||
|
||||
if (NULL != ptInfo) {
|
||||
if (ptInfo->bEnabled) {
|
||||
ptInfo->nUsedRecent = lCycleUsed;
|
||||
ptInfo->lUsedTotal += lCycleUsed;
|
||||
ptInfo->bEnabled = false;
|
||||
}
|
||||
|
||||
lCycles = ptInfo->lUsedTotal;
|
||||
} else {
|
||||
lCycles = ptRootAgent->tInfo.lUsedTotal;
|
||||
}
|
||||
}
|
||||
|
||||
return lCycles;
|
||||
}
|
8
main.c
8
main.c
|
@ -76,14 +76,14 @@ int main(int argc, char *argv[]) {
|
|||
// return -1;
|
||||
// }
|
||||
// SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||
// SDL_Rect rect1 = { 1, 1, 500, 500 };
|
||||
// SDL_FRect rect1 = { 1, 1, 500, 500 };
|
||||
// SDL_RenderFillRect(renderer, &rect1);
|
||||
//
|
||||
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
//
|
||||
// SDL_RenderLines(renderer, points, POINTS_COUNT);
|
||||
//
|
||||
// SDL_Rect rect = { 200, 300, 100, 100 };
|
||||
// SDL_FRect rect = { 200, 300, 100, 100 };
|
||||
// SDL_RenderRect(renderer, &rect);
|
||||
//
|
||||
// SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
|
||||
|
@ -166,9 +166,9 @@ int main(int argc, char *argv[]) {
|
|||
// Test_Run("List", Test_List,NULL);
|
||||
// Test_RunTime("Key", Test_Key);
|
||||
// Test_RunTime("Queue", Test_Queue);
|
||||
// Test_RunTime("Task", Test_task);
|
||||
Test_RunTime("Task", Test_task);
|
||||
// Test_RunTime("OLED", Test_OLED);
|
||||
Test_RunTime("LVGL", Test_lvgl);
|
||||
// Test_RunTime("LVGL", Test_lvgl);
|
||||
// Test_RunTime("TFT", Test_tft);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -170,11 +170,14 @@ bool SIM_Display_Init(char *name, int width, int height, uint32_t pixcolor, uint
|
|||
|
||||
void SIM_Color_DrawPiexl(SIM_Display_t *display, SIM_Color_t color, uint16_t x, uint16_t y) {
|
||||
SDL_SetRenderDrawColor(display->renderer, color.ch.red, color.ch.green, color.ch.blue, color.ch.alpha);
|
||||
for (int y_ = y * display->scale; y_ < (y * display->scale) + display->scale; ++y_) {
|
||||
for (int x_ = x * display->scale; x_ < (x * display->scale) + display->scale; ++x_) {
|
||||
SDL_RenderPoint(display->renderer, x_, y_);
|
||||
}
|
||||
}
|
||||
SDL_FRect rect1 = {(x * display->scale) * 1.0f, (y * display->scale) * 1.0f, display->scale * 1.0f,
|
||||
display->scale * 1.0f};
|
||||
SDL_RenderFillRect(display->renderer, &rect1);
|
||||
// for (int y_ = y * display->scale; y_ < (y * display->scale) + display->scale; ++y_) {
|
||||
// for (int x_ = x * display->scale; x_ < (x * display->scale) + display->scale; ++x_) {
|
||||
// SDL_RenderPoint(display->renderer, x_, y_);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void SIM_OneColor_DrawFromBuffer(SIM_Display_t *display, uint8_t *buf, uint16_t width, uint16_t height) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "sim_key.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef USER_SDL3
|
||||
#include<easyx.h>
|
||||
#include<conio.h>
|
||||
|
||||
|
@ -80,4 +81,31 @@ uint8_t SIM_Key_SET(uint8_t) {
|
|||
|
||||
uint8_t SIM_Key_RESET(uint8_t) {
|
||||
return GetAsyncKeyState(VK_END);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
uint8_t SIM_Key_Scan() {
|
||||
SDL_Event event;
|
||||
uint8_t key = 0;
|
||||
SDL_PollEvent(&event);
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
return 0;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
if (event.key.key == SDLK_Q)key = SIM_KEY_SET;
|
||||
if (event.key.key == SDLK_UP || event.key.key == SDLK_W)key = SIM_KEY_UP;
|
||||
if (event.key.key == SDLK_DOWN || event.key.key == SDLK_S)key = SIM_KEY_DOWN;
|
||||
if (event.key.key == SDLK_LEFT || event.key.key == SDLK_A)key = SIM_KEY_LEFT;
|
||||
if (event.key.key == SDLK_RIGHT || event.key.key == SDLK_D)key = SIM_KEY_RIGHT;
|
||||
if (event.key.key == SDLK_R)key = SIM_KEY_RESET;
|
||||
if (event.key.key == SDLK_KP_ENTER || event.key.key == SDLK_E)key = SIM_KEY_ENABLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,9 @@ extern "C" {
|
|||
#endif
|
||||
#include "stdint.h"
|
||||
|
||||
//是否启用SDL3获取按键事件
|
||||
#define USER_SDL3
|
||||
|
||||
typedef enum Key_map {
|
||||
SIM_KEY_UP = 1,
|
||||
SIM_KEY_DOWN,
|
||||
|
|
|
@ -736,7 +736,7 @@
|
|||
====================*/
|
||||
|
||||
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
|
||||
#define LV_USE_DEMO_WIDGETS 0
|
||||
#define LV_USE_DEMO_WIDGETS 1
|
||||
#if LV_USE_DEMO_WIDGETS
|
||||
#define LV_DEMO_WIDGETS_SLIDESHOW 0
|
||||
#endif
|
||||
|
|
|
@ -91,17 +91,17 @@ void lv_port_disp_init(void)
|
|||
// lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
|
||||
|
||||
// /* Example for 2) */
|
||||
// static lv_disp_draw_buf_t draw_buf_dsc_2;
|
||||
// static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
|
||||
// static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/
|
||||
// lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
|
||||
static lv_disp_draw_buf_t draw_buf_dsc_2;
|
||||
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
|
||||
static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/
|
||||
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
|
||||
|
||||
/* Example for 3) also set disp_drv.full_refresh = 1 below*/
|
||||
static lv_disp_draw_buf_t draw_buf_dsc_3;
|
||||
static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
|
||||
static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
|
||||
lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
|
||||
MY_DISP_VER_RES * MY_DISP_HOR_RES); /*Initialize the display buffer*/
|
||||
// static lv_disp_draw_buf_t draw_buf_dsc_3;
|
||||
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
|
||||
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
|
||||
// lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
|
||||
// MY_DISP_VER_RES * MY_DISP_HOR_RES); /*Initialize the display buffer*/
|
||||
|
||||
/*-----------------------------------
|
||||
* Register the display in LVGL
|
||||
|
@ -120,7 +120,7 @@ void lv_port_disp_init(void)
|
|||
disp_drv.flush_cb = disp_flush;
|
||||
|
||||
/*Set a display buffer*/
|
||||
disp_drv.draw_buf = &draw_buf_dsc_3;
|
||||
disp_drv.draw_buf = &draw_buf_dsc_2;
|
||||
|
||||
/*Required for Example 3)*/
|
||||
//disp_drv.full_refresh = 1;
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#include "sim_sdl.h"
|
||||
|
||||
|
||||
bool SIM_SDLInit(char *name, int width, int height, int scale, SIM_SDL3_t *sdl3) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
SDL_Log("SDL_Init failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
sdl3->scale = scale;
|
||||
sdl3->window = SDL_CreateWindow(name, width * scale, height * scale, SDL_WINDOW_RESIZABLE);
|
||||
if (!sdl3->window) {
|
||||
SDL_Log("Could not create a window: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
SDL_SetWindowPosition(sdl3->window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
sdl3->renderer = SDL_CreateRenderer(sdl3->window, nullptr);
|
||||
if (!sdl3->renderer) {
|
||||
SDL_Log("Create renderer failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SIM_SDL_Color_DrawPiexl(SIM_SDL3_t *sdl3, uint16_t x, uint16_t y, SIM_Color_t color) {
|
||||
SDL_SetRenderDrawColor(sdl3->renderer, color.ch.red, color.ch.green, color.ch.blue, color.ch.alpha);
|
||||
for (int y_ = y * sdl3->scale; y_ < (y * sdl3->scale) + sdl3->scale; ++y_) {
|
||||
for (int x_ = x * sdl3->scale; x_ < (x * sdl3->scale) + sdl3->scale; ++x_) {
|
||||
SDL_RenderPoint(sdl3->renderer, x_, y_);
|
||||
}
|
||||
}
|
||||
SDL_RenderPresent(sdl3->renderer);
|
||||
}
|
||||
|
||||
void SIM_SDL_Stop(SIM_SDL3_t *sdl3) {
|
||||
SDL_DestroyRenderer(sdl3->renderer);
|
||||
SDL_DestroyWindow(sdl3->window);
|
||||
SDL_Quit();
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#ifndef HW_LIB_SIM_SDL_H
|
||||
#define HW_LIB_SIM_SDL_H
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Event *event;
|
||||
int scale;
|
||||
} SIM_SDL3_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t blue;
|
||||
uint8_t green;
|
||||
uint8_t red;
|
||||
uint8_t alpha;
|
||||
} ch;
|
||||
uint32_t full;
|
||||
} SIM_Color_t;
|
||||
|
||||
|
||||
bool SIM_SDLInit(char *name, int width, int height, int scale, SIM_SDL3_t *sdl3);
|
||||
|
||||
void SIM_SDL_Color_DrawPiexl(SIM_SDL3_t *sdl3, uint16_t x, uint16_t y, SIM_Color_t color);
|
||||
|
||||
void SIM_SDL_Stop(SIM_SDL3_t *sdl3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif //HW_LIB_SIM_SDL_H
|
Loading…
Reference in New Issue