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 sdl
main
JiXieShi 2024-11-27 13:49:34 +08:00
parent 8f7f72712c
commit a1176112ce
29 changed files with 3993 additions and 179 deletions

View File

@ -26,7 +26,7 @@ link_directories(easyx/lib64)
file(GLOB_RECURSE SOURCES "demo/*/*.*" "sim/*/*.*") file(GLOB_RECURSE SOURCES "demo/*/*.*" "sim/*/*.*")
message(${SOURCES}) #message(${SOURCES})
add_subdirectory(SDL3 EXCLUDE_FROM_ALL) add_subdirectory(SDL3 EXCLUDE_FROM_ALL)
link_libraries(SDL3::SDL3) link_libraries(SDL3::SDL3)
@ -36,7 +36,7 @@ add_executable(HW_Lib main.c ${SOURCES})
# #
add_subdirectory(lib) add_subdirectory(lib)
target_link_libraries(HW_Lib HW_LIB_List HW_LIB_Task HW_LIB_Printf HW_LIB_Utils HW_LIB_Iic 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 add_custom_command(TARGET HW_Lib POST_BUILD

2
SDL3

@ -1 +1 @@
Subproject commit 89c6bc5f5022e71433a9e4eb1a2edc6d79be71f2 Subproject commit 1266210685a14b344a9049938677a89a092dfa5c

View File

@ -2,7 +2,9 @@
#include "lv_port_disp.h" #include "lv_port_disp.h"
#include "lv_port_indev.h" #include "lv_port_indev.h"
#include "lvgl.h" #include "lvgl.h"
#include "demos/lv_demos.h"
#include <windows.h> #include <windows.h>
//#include <widgets/lv_demo_widgets.h>
#include "t_lvgl.h" #include "t_lvgl.h"
#include "SDL3/SDL.h" #include "SDL3/SDL.h"
@ -38,8 +40,8 @@ int Test_lvgl(void *pVoid) {
lv_port_disp_init(); lv_port_disp_init();
// lv_port_indev_init(); // lv_port_indev_init();
lv_example_get_started_1(); // lv_example_get_started_1();
// lv_demo_widgets(); lv_demo_widgets();
// printf("\nTEST Widgets\n"); // printf("\nTEST Widgets\n");
while (1) { while (1) {

View File

@ -131,16 +131,16 @@ int Test_OLED(void *pVoid) {
// OLED_ShowPic(&oled, 0, 0, 64, 64, BMP1); // OLED_ShowPic(&oled, 0, 0, 64, 64, BMP1);
OLED_Refresh(&oled); OLED_Refresh(&oled);
_beginthread(Get_Key, 0, NULL); _beginthread(Get_Key, 0, NULL);
pageinit(); // pageinit();
while (1) { while (1) {
if (pageid > 4)pageid = 0; // if (pageid > 4)pageid = 0;
item_h = pagesearch(pageid).item_h; // item_h = pagesearch(pageid).item_h;
item_w = pagesearch(pageid).item_w; // item_w = pagesearch(pageid).item_w;
// pagesearch(pageid).page(&oled); //// pagesearch(pageid).page(&oled);
// sprintf(buf, "DATA:%d", s); //// sprintf(buf, "DATA:%d", s);
// OLED_ShowString(&oled, 2, 51, buf, 12); //// OLED_ShowString(&oled, 2, 51, buf, 12);
OLED_Refresh(&oled); // OLED_Refresh(&oled);
Sleep(200); // Sleep(200);
} }
SIM_OLED_STOP(); SIM_OLED_STOP();
} }

View File

@ -1,6 +1,7 @@
#include <sysinfoapi.h> #include <sysinfoapi.h>
#include "stdio.h" #include "stdio.h"
#include "task.h" #include "task.h"
#include "log.h"
Task_t *task1; Task_t *task1;
Task_t *task2; Task_t *task2;
@ -34,22 +35,28 @@ typedef struct CustomUserData {
void exampleTimer4Callback(Task_t *task, void *userData) { void exampleTimer4Callback(Task_t *task, void *userData) {
CustomUserData *customUserData = (CustomUserData *) userData; CustomUserData *customUserData = (CustomUserData *) userData;
customUserData->count--; 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) { if (customUserData->count > 0) {
TaskStart(task); TaskStart(task);
} }
} }
#undef LOG_RUN_TIMER_FUN
#define LOG_RUN_TIMER_FUN GetTick()
int Test_task(void *pVoid) { int Test_task(void *pVoid) {
TaskInit(GetTick); LOG_RUN_TIME() {
TaskCreat(task1, 1000, -1, exampleTimer1Callback, "1000ms CYCLE task"); TaskInit(GetTick);
TaskCreat(task2, 5000, -1, exampleTimer2Callback, "5000ms ONCE task"); TaskCreat(task1, 1000, -1, exampleTimer1Callback, "1000ms CYCLE task");
TaskCreat(task3, 3456, 2, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE task"); TaskCreat(task2, 5000, -1, exampleTimer2Callback, "5000ms ONCE task");
CustomUserData customUserData = { TaskCreat(task3, 3456, 2, exampleTimer3Callback, "3456ms delay start, 4567ms CYCLE task");
.count = 3, CustomUserData customUserData = {
.str = "2000ms 3 task" .count = 3,
}; .str = "2000ms 3 task"
TaskCreat(task4, 2000, 1, exampleTimer4Callback, &customUserData); };
TaskCreat(task4, 2000, 1, exampleTimer4Callback, &customUserData);
}
while (1) { while (1) {
TaskRun(); TaskRun();
} }

View File

@ -4,6 +4,8 @@
#include "t_tft.h" #include "t_tft.h"
#include "sim_display.h" #include "sim_display.h"
#include "tool.h" #include "tool.h"
#define LOG_WITH_RUN_TIMER
#include "log.h" #include "log.h"
TFT_T demo_tft; TFT_T demo_tft;
@ -103,6 +105,10 @@ uint8_t tft_senddata(uint8_t *data, size_t len) {
return result; return result;
} }
int64_t GetSysCnt64() {
}
int Test_tft(void *arg) { int Test_tft(void *arg) {
//设备信息预填充 //设备信息预填充
demo_tft.width = 480;//实际如有支持不用填(如ST7735/7796) demo_tft.width = 480;//实际如有支持不用填(如ST7735/7796)
@ -141,11 +147,11 @@ int Test_tft(void *arg) {
TFT_ShowCHString(&demo_tft, 0, 60, "星海科技机械师", 1); 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_DrawCross(&demo_tft, 25, 25, 10);
TFT_DrawXCross(&demo_tft, 25, 25, 10);
TFT_ShowString(&demo_tft, 60, 20, "JiXieShi", 16, 1); TFT_ShowString(&demo_tft, 60, 20, "JiXieShi", 16, 1);
@ -162,6 +168,7 @@ int Test_tft(void *arg) {
// //
// Sleep(5); // Sleep(5);
// } // }
SIM_Display_STOP(&tft_display); SIM_Display_STOP(&tft_display);
return 0; return 0;
} }

View File

@ -10,6 +10,7 @@ set(LIBRARIES
HW_LIB_Key key key/inc HW_LIB_Key key key/inc
HW_LIB_Oled oled oled/inc HW_LIB_Oled oled oled/inc
HW_LIB_Tft tft tft/inc HW_LIB_Tft tft tft/inc
HW_LIB_Flash flash flash/inc
) )
# #

1038
lib/flash/flash.cpp Normal file

File diff suppressed because it is too large Load Diff

359
lib/flash/flash_sfdp.cpp Normal file
View File

@ -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 */

208
lib/flash/inc/flash.h Normal file
View File

@ -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

27
lib/flash/inc/flash_cfg.h Normal file
View File

@ -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

406
lib/flash/inc/flash_def.h Normal file
View File

@ -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

View File

@ -95,15 +95,17 @@ struct OLED_Dev
* @return void * @return void
* @example OLED_Init(&oled_dev); * @example OLED_Init(&oled_dev);
*/ */
void OLED_Init(OLED_T* dev); void OLED_Init(OLED_T *dev);
/** /**
* @brief OLED * @brief OLED
* @param dev: [] OLED * @param dev: [] OLED
* @param cmd: [] OLED
* @param len: [] OLED
* @return void * @return void
* @example OLED_Init(&oled_dev); * @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 * @brief OLED
* @param dev: [] OLED * @param dev: [] OLED

View File

@ -18,8 +18,8 @@ const uint8_t initCmd[] = {
0x40, 0x00, // 设置显示起始行 0x40, 0x00, // 设置显示起始行
0x8D, 0x14, // 电荷泵设置 0x8D, 0x14, // 电荷泵设置
0x20, 0x00, // 设置内存寻址模式 0x20, 0x00, // 设置内存寻址模式
0xA0, // 设置段重映射 0xA0, // 设置段重映射 从左到右A1 //左右翻转A0
0xC8, // 设置COM输出扫描方向 0xC8, // 设置COM输出扫描方向 从上到下C8 //上下颠倒C0
0xDA, 0x12, // 设置COM引脚硬件配置 0xDA, 0x12, // 设置COM引脚硬件配置
0x81, 0xCF, // 设置对比度控制 0x81, 0xCF, // 设置对比度控制
0xD9, 0xF1, // 设置预充电周期 0xD9, 0xF1, // 设置预充电周期

View File

@ -118,7 +118,6 @@ extern "C" {
/** /**
* @brief LCD_Type_Define * @brief LCD_Type_Define
*/ */
#define ST7735_1_8_inch_screen 0x00U
#define ST7735_0_9_inch_screen 0x01U #define ST7735_0_9_inch_screen 0x01U
#define ST7735_1_8a_inch_screen 0x02U #define ST7735_1_8a_inch_screen 0x02U
/** /**
@ -135,9 +134,13 @@ extern "C" {
#define ST7735_DELAY 120 #define ST7735_DELAY 120
#define ST7735_PANEL HannStar_Panel #define ST7735_PANEL BOE_Panel
#define ST7735_TYPE ST7735_0_9_inch_screen #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_TYPE == ST7735_0_9_inch_screen //0.96 ST7735
#if ST7735_PANEL == HannStar_Panel #if ST7735_PANEL == HannStar_Panel
@ -176,8 +179,11 @@ const uint8_t st7735initcmd[] = {
3, ST7735_PWR_CTRL4, 0x8A, 0x2A, 3, ST7735_PWR_CTRL4, 0x8A, 0x2A,
3, ST7735_PWR_CTRL5, 0x8A, 0xEE, 3, ST7735_PWR_CTRL5, 0x8A, 0xEE,
2, ST7735_VCOMH_VCOML_CTRL1, 0x0E, 2, ST7735_VCOMH_VCOML_CTRL1, 0x0E,
#if ST7735_PANEL == HannStar_Panel
1, ST7735_DISPLAY_INVERSION_ON,//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, 2, ST7735_COLOR_MODE, ST7735_FORMAT_RBG565,
17, ST7735_PV_GAMMA_CTRL, 0x02, 0x1C, 0x07U, 0x12U, 0x37U, 0x32U, 0x29U, 0x2DU, 0x29U, 0x25U, 0x2BU, 0x39U, 17, ST7735_PV_GAMMA_CTRL, 0x02, 0x1C, 0x07U, 0x12U, 0x37U, 0x32U, 0x29U, 0x2DU, 0x29U, 0x25U, 0x2BU, 0x39U,
0x00U, 0x01U, 0x03U, 0x10U, 0x00U, 0x01U, 0x03U, 0x10U,

View File

@ -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_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 * @brief TFT
* @param dev: [] 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); 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 * @brief
* @param dev: [] TFT * @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); 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 #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 #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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,3 +1,4 @@
#include <valarray>
#include "tft.h" #include "tft.h"
#include "ascii_font.h" #include "ascii_font.h"
@ -201,11 +202,11 @@ void TFT_FillColor(TFT_T *dev,TFT_Color_t color){
dev->sendData(color.u8, 2); 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) { void TFT_DrawLine(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
uint16_t i, k, k1, k2; uint16_t i;
if ((x1 < 0) || (x2 > dev->width) || (y1 < 0) || (y2 > dev->height) || (x1 > x2) || (y1 > y2))return; if ((x1 < 0) || (x2 > dev->width) || (y1 < 0) || (y2 > dev->height))return;
if (x1 == x2) //画竖线 if (x1 == x2) //画竖线
{ {
for (i = 0; i < (y2 - y1); i++) { 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); TFT_SetPixel(dev, x1 + i, y1,POINT_COLOR);
} }
} else //画斜线 } else //画斜线
{ {//Bresenham算法
k1 = y2 - y1; int p, twoDy, twoDyMinusDx, s1, s2;
k2 = x2 - x1; int dx = abs(x2 - x1), dy = abs(y2 - y1);
k = k1 * 10 / k2; if (dy > dx) //斜率大于1
for (i = 0; i < (x2 - x1); i++) { {
TFT_SetPixel(dev, x1 + i, y1 + i * k / 10,POINT_COLOR); 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 TFT_DrawLine(dev, x1, y2, x2, y2); // Bottom side
} }
void TFT_DrawCircle(TFT_T *dev, uint16_t x, uint16_t y, uint16_t r) { void TFT_DrawCircle(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t radius) {
int a, b, num; int x = radius;
a = 0; int y = 0;
b = r; int decision = 1 - x;
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);
a++; while (y <= x) {
num = (a * a + b * b) - r * r;//计算画的点离圆心的距离 TFT_SetPixel(dev, x0 + x, y0 + y, POINT_COLOR);
if (num > 0) { TFT_SetPixel(dev, x0 + y, y0 + x, POINT_COLOR);
b--; TFT_SetPixel(dev, x0 - y, y0 + x, POINT_COLOR);
a--; 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) { 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 i, m, temp, size2, chr1;
uint16_t ys = y; 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); 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) { uint16_t invertRGB565(uint16_t color) {
// 分离颜色分量 // 分离颜色分量
uint8_t r = (color >> 11) & 0x1F; // 取出红色分量 uint8_t r = (color >> 11) & 0x1F; // 取出红色分量

View File

@ -42,11 +42,11 @@
//////////////////////// ////////////////////////
#ifdef LOG_WITH_RUN_TIMER #ifdef LOG_WITH_RUN_TIMER
#define LOG_RUN_TIMER_FUN GetSysCnt32() #define LOG_RUN_TIMER_FUN GetTickCount64()
#define LOG_RUN_TIMER_FMT "-T(%lums)" #define LOG_RUN_TIMER_FMT "-T(%lums)"
#else #else
#define LOG_RUN_TIMER_FUN 0 #define LOG_RUN_TIMER_FUN GetTickCount64()
#define LOG_RUN_TIMER_FMT "-T(%lu)" #define LOG_RUN_TIMER_FMT "(%llums)"
#endif #endif
#ifdef LOG_LINE_END_CRLF #ifdef LOG_LINE_END_CRLF
@ -65,6 +65,9 @@
#endif #endif
#endif #endif
#define LOG_OUT_FUNC printf
#define LOG_BASE_FILENAME \ #define LOG_BASE_FILENAME \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \
strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
@ -101,9 +104,9 @@
// 带时钟输出 // 带时钟输出
#if defined(LOG_TIMER) #if defined(LOG_TIMER)
#ifdef LOG_WITH_RUN_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 #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 #endif
#else #else
#define LOGT(fmt, ...) ((void)0) #define LOGT(fmt, ...) ((void)0)
@ -112,9 +115,9 @@
// 等级输出 // 等级输出
#if LOG_OUTPUT_LVL >= LOG_LVL_FATAL #if LOG_OUTPUT_LVL >= LOG_LVL_FATAL
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGF(fmt, ...) ((void)0) #define LOGF(fmt, ...) ((void)0)
@ -122,9 +125,9 @@
#if LOG_OUTPUT_LVL >= LOG_LVL_ERROR #if LOG_OUTPUT_LVL >= LOG_LVL_ERROR
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGE(fmt, ...) ((void)0) #define LOGE(fmt, ...) ((void)0)
@ -132,9 +135,9 @@
#if LOG_OUTPUT_LVL >= LOG_LVL_WARN #if LOG_OUTPUT_LVL >= LOG_LVL_WARN
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGW(fmt, ...) ((void)0) #define LOGW(fmt, ...) ((void)0)
@ -142,9 +145,9 @@
#if LOG_OUTPUT_LVL >= LOG_LVL_INFO #if LOG_OUTPUT_LVL >= LOG_LVL_INFO
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGI(fmt, ...) ((void)0) #define LOGI(fmt, ...) ((void)0)
@ -152,9 +155,9 @@
#if LOG_OUTPUT_LVL >= LOG_LVL_DEBUG #if LOG_OUTPUT_LVL >= LOG_LVL_DEBUG
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGD(fmt, ...) ((void)0) #define LOGD(fmt, ...) ((void)0)
@ -162,11 +165,164 @@
#if LOG_OUTPUT_LVL >= LOG_LVL_VERBOSE #if LOG_OUTPUT_LVL >= LOG_LVL_VERBOSE
#ifdef LOG_WITH_RUN_TIMER #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 #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 #endif
#else #else
#define LOGV(fmt, ...) ((void)0) #define LOGV(fmt, ...) ((void)0)
#endif #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

806
lib/utils/inc/ticks.h Normal file
View File

@ -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

View File

@ -48,9 +48,9 @@ typedef enum { // 定义枚举类型Type_t包含不同数据类型
default: ((void)0)) default: ((void)0))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[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宏遍历数组ae为当前元素下标 #define _foreach(e, a) for(size_t e = 0; e < ARRAY_SIZE(a); e++) // 实现foreach宏遍历数组ae为当前元素下标
#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(_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) #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_cat(a, b) a ## b
#define _range_n(n) _range_n_cat(_range_, n) #define _range_n(n) _range_n_cat(_range_, n)
#define _range(...) _range_n(VA_ARGS_N(__VA_ARGS__)) // 根据传入参数个数选择对应的范围循环宏 #define _range(...) _range_n(VA_ARGS_N(__VA_ARGS__)) // 根据传入参数个数选择对应的范围循环宏
/** /**
* @Name * @Name
* @brief * @brief
@ -125,7 +126,7 @@ float Str2Float(char *str);
* @param fmt: [] * @param fmt: []
* @param frame: [] * @param frame: []
* @return void * @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 { \ #define PRINT_ARRAY(arr, fmt, frame) do { \
printf("\n"#arr ":\n"); \ printf("\n"#arr ":\n"); \
@ -143,9 +144,41 @@ int :"[int]-> "#v"=%d" END, \
float :"[float]-> "#v"=%.2f" END , \ float :"[float]-> "#v"=%.2f" END , \
double :"[double]-> "#v"=%.2f" END, \ double :"[double]-> "#v"=%.2f" END, \
default: "[err]-> "#v"=%p" END) default: "[err]-> "#v"=%p" END)
#define POUT(s) printf(TYPE_F(s) ,s) #define POUT(s) printf(TYPE_F(s) ,s)
#ifndef GET_BIT
#define GET_BIT(x, bit) ((x & (1 << bit)) >> 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 #ifdef __cplusplus
} }

631
lib/utils/ticks.cpp Normal file
View File

@ -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
View File

@ -76,14 +76,14 @@ int main(int argc, char *argv[]) {
// return -1; // return -1;
// } // }
// SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); // 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_RenderFillRect(renderer, &rect1);
// //
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE); // SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
// //
// SDL_RenderLines(renderer, points, POINTS_COUNT); // 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_RenderRect(renderer, &rect);
// //
// SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255); // SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
@ -166,9 +166,9 @@ int main(int argc, char *argv[]) {
// Test_Run("List", Test_List,NULL); // Test_Run("List", Test_List,NULL);
// Test_RunTime("Key", Test_Key); // Test_RunTime("Key", Test_Key);
// Test_RunTime("Queue", Test_Queue); // Test_RunTime("Queue", Test_Queue);
// Test_RunTime("Task", Test_task); Test_RunTime("Task", Test_task);
// Test_RunTime("OLED", Test_OLED); // Test_RunTime("OLED", Test_OLED);
Test_RunTime("LVGL", Test_lvgl); // Test_RunTime("LVGL", Test_lvgl);
// Test_RunTime("TFT", Test_tft); // Test_RunTime("TFT", Test_tft);
return 0; return 0;
} }

View File

@ -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) { 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); 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_) { SDL_FRect rect1 = {(x * display->scale) * 1.0f, (y * display->scale) * 1.0f, display->scale * 1.0f,
for (int x_ = x * display->scale; x_ < (x * display->scale) + display->scale; ++x_) { display->scale * 1.0f};
SDL_RenderPoint(display->renderer, x_, y_); 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) { void SIM_OneColor_DrawFromBuffer(SIM_Display_t *display, uint8_t *buf, uint16_t width, uint16_t height) {

View File

@ -1,6 +1,7 @@
#include "sim_key.h" #include "sim_key.h"
#include "log.h" #include "log.h"
#ifndef USER_SDL3
#include<easyx.h> #include<easyx.h>
#include<conio.h> #include<conio.h>
@ -80,4 +81,31 @@ uint8_t SIM_Key_SET(uint8_t) {
uint8_t SIM_Key_RESET(uint8_t) { uint8_t SIM_Key_RESET(uint8_t) {
return GetAsyncKeyState(VK_END); 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

View File

@ -5,6 +5,9 @@ extern "C" {
#endif #endif
#include "stdint.h" #include "stdint.h"
//是否启用SDL3获取按键事件
#define USER_SDL3
typedef enum Key_map { typedef enum Key_map {
SIM_KEY_UP = 1, SIM_KEY_UP = 1,
SIM_KEY_DOWN, SIM_KEY_DOWN,

View File

@ -736,7 +736,7 @@
====================*/ ====================*/
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ /*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 #if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW 0 #define LV_DEMO_WIDGETS_SLIDESHOW 0
#endif #endif

View File

@ -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*/ // lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
// /* Example for 2) */ // /* Example for 2) */
// static lv_disp_draw_buf_t draw_buf_dsc_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_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*/ 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*/ 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*/ /* Example for 3) also set disp_drv.full_refresh = 1 below*/
static lv_disp_draw_buf_t draw_buf_dsc_3; // 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_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*/ // 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, // 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*/ // MY_DISP_VER_RES * MY_DISP_HOR_RES); /*Initialize the display buffer*/
/*----------------------------------- /*-----------------------------------
* Register the display in LVGL * Register the display in LVGL
@ -120,7 +120,7 @@ void lv_port_disp_init(void)
disp_drv.flush_cb = disp_flush; disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/ /*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_3; disp_drv.draw_buf = &draw_buf_dsc_2;
/*Required for Example 3)*/ /*Required for Example 3)*/
//disp_drv.full_refresh = 1; //disp_drv.full_refresh = 1;

View File

@ -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();
}

View File

@ -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