CARPLAY版本整理
This commit is contained in:
@ -0,0 +1,656 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
|
||||
#include "sfud.h"
|
||||
#include "updatefile.h"
|
||||
#include "mfcapi.h"
|
||||
#include "dwl.h"
|
||||
#include "animation.h"
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
#include "mmcsd_core.h"
|
||||
#endif
|
||||
|
||||
static TaskHandle_t animation_task = NULL;
|
||||
static SemaphoreHandle_t animation_mutex;
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
static BANIHEADER ani_header;
|
||||
static BANIHEADER *aniheader = &ani_header;
|
||||
#else
|
||||
static BANIHEADER *aniheader;
|
||||
#endif
|
||||
static unsigned int anioffset;
|
||||
static unsigned int anisize;
|
||||
static int ani_playing = 0;
|
||||
static int ani_replay = 0;
|
||||
static int ani_stop = 0;
|
||||
static int ani_frames = 0;
|
||||
static int ani_display_index = 0;
|
||||
static int ani_take_vdisbuf = 0;
|
||||
static unsigned int ani_frame_addr;
|
||||
static uint32_t first_show_done = 0;
|
||||
|
||||
|
||||
#if 0
|
||||
#include "ff_stdio.h"
|
||||
|
||||
static int get_h264_single_file_from_sd(void *buf, int *len)
|
||||
{
|
||||
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
char path_name[64] = "/sd/000.h264";
|
||||
static int count = 0;
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
sprintf(path_name, "/sd/%.3d.h264", count++);
|
||||
*len = 0;
|
||||
|
||||
fp = ff_fopen(path_name, "rb");
|
||||
if (fp) {
|
||||
ret = ff_fread(buf, 1, READ_SIZE, fp);
|
||||
if (ret <= 0) {
|
||||
printf("read sdmmc file:%s failed, maybe read done\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
*len = ret;
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
count = 0;
|
||||
return -1;
|
||||
}
|
||||
if(fp)
|
||||
ff_fclose(fp);
|
||||
|
||||
//printf("###read %s len:%d.\n", path_name, *len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void h264_decode_test_thread(void *param)
|
||||
{
|
||||
#define H264DEC_SEMIPLANAR_YUV420 0x020001
|
||||
#define H264DEC_INBUF_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
#define H264DEC_DISP_COUNTS 2
|
||||
|
||||
DWLLinearMem_t inBuf;
|
||||
OutFrameBuffer outBuf = {0};
|
||||
uint32_t h264SrcSize = 0;
|
||||
MFCHandle *handle = NULL;
|
||||
uint32_t display_addr[H264DEC_DISP_COUNTS] = {0};
|
||||
uint32_t display_addr_index = 0;
|
||||
uint32_t first_show_done = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
void *h264SrcBuf = pvPortMalloc(H264DEC_INBUF_SIZE);
|
||||
if(!h264SrcBuf) {
|
||||
printf("%s, h264SrcBuf pvPortMalloc failed.\n", __func__);
|
||||
return ;
|
||||
}
|
||||
|
||||
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
|
||||
display_addr[i] = (uint32_t)pvPortMalloc(H264DEC_INBUF_SIZE);
|
||||
if(!display_addr[i] ) {
|
||||
printf("%s, display_addr[%d] pvPortMalloc failed.\n", __func__, i);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
mmcsd_wait_cd_changed(portMAX_DELAY);
|
||||
|
||||
handle = mfc_init(RAW_STRM_TYPE_H264);
|
||||
if(!handle) {
|
||||
printf("%s, mfc_init failed.\n", __func__);
|
||||
return ;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
//memset(&outBuf, 0, sizeof(OutFrameBuffer));
|
||||
//memset(h264SrcBuf, 0, H264DEC_INBUF_SIZE);
|
||||
mdelay(30);
|
||||
#if 1 //get h264 info form sdcard.
|
||||
ret = get_h264_single_file_from_sd(h264SrcBuf, &h264SrcSize);
|
||||
if(ret != 0) {
|
||||
printf("%s, get_h264_single_file_from_sd failed.\n", __func__);
|
||||
continue;
|
||||
}
|
||||
inBuf.busAddress = (u32)h264SrcBuf;
|
||||
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
|
||||
inBuf.size = h264SrcSize;
|
||||
CP15_clean_dcache_for_dma(inBuf.busAddress, inBuf.busAddress + inBuf.size);
|
||||
#else
|
||||
//1. copy your h264 data to h264SrcBuf;
|
||||
//2. set your h264 data size to h264SrcSize;
|
||||
|
||||
inBuf.busAddress = (u32)h264SrcBuf;
|
||||
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
|
||||
inBuf.size = h264SrcSize;
|
||||
#endif
|
||||
|
||||
ret = mfc_decode(handle, &inBuf, &outBuf);
|
||||
if (ret < 0) {
|
||||
printf("animation decode fail.\n");
|
||||
} else {
|
||||
uint32_t align_width, align_height;
|
||||
uint32_t yaddr, uaddr, vaddr;
|
||||
|
||||
for(i=0; i<outBuf.num; i++) {
|
||||
align_width = outBuf.frameWidth;
|
||||
align_height = outBuf.frameHeight;
|
||||
if(1/*outBuf.outputFormat == H264DEC_SEMIPLANAR_YUV420*/ && align_width && align_height)
|
||||
{
|
||||
memcpy((void *)display_addr[display_addr_index], outBuf.buffer[i].pyVirAddress, align_width * align_height * 3 / 2);
|
||||
// ret = dma_m2mcpy(display_addr[display_addr_index], (uint32_t)outBuf.buffer[i].yBusAddress, align_width * align_height * 3 / 2);
|
||||
// if(ret) {
|
||||
// printf("%s() dma_m2m_memcpy failed.\n", __func__);
|
||||
// continue;
|
||||
// }
|
||||
yaddr = display_addr[display_addr_index];
|
||||
uaddr = yaddr + align_width * align_height;
|
||||
vaddr = yaddr + align_width * align_height * 5/4;
|
||||
|
||||
display_addr_index++;
|
||||
if(display_addr_index >= H264DEC_DISP_COUNTS) {
|
||||
display_addr_index = 0;
|
||||
}
|
||||
|
||||
if(!first_show_done) {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, /*outBuf.codedWidth, outBuf.codedHeight*/LCD_WIDTH, LCD_HEIGHT);
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
|
||||
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
|
||||
first_show_done = 1;
|
||||
}
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, yaddr);
|
||||
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, uaddr);
|
||||
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, vaddr);
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_wait_for_vsync();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(handle)
|
||||
mfc_uninit(handle);
|
||||
|
||||
if(h264SrcBuf)
|
||||
vPortFree(h264SrcBuf);
|
||||
|
||||
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
|
||||
if(!display_addr[i]) {
|
||||
vPortFree((void *)display_addr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int save_nv12_file_to_sd(void *buf, int len)
|
||||
{
|
||||
char path_name[64] = "/sd/000.bin";
|
||||
static int count = 0;
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
sprintf(path_name, "/sd/%.3d.bin", count++);
|
||||
|
||||
fp = ff_fopen(path_name, "w+");
|
||||
if (fp) {
|
||||
ret = ff_fwrite(buf, 1, len, fp);
|
||||
if (ret != len) {
|
||||
printf("read sdmmc file:%s failed.\n", path_name);
|
||||
ff_fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
ff_fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_file_from_sd(void *buf, int *len)
|
||||
{
|
||||
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
#if LCD_BPP == 32
|
||||
char path_name[64] = "/sd/480x1280_rgb888.rgb";
|
||||
#else
|
||||
char path_name[64] = "/sd/480x1280_rgb565.rgb";
|
||||
#endif
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
*len = 0;
|
||||
fp = ff_fopen(path_name, "rb");
|
||||
if (fp) {
|
||||
ret = ff_fread(buf, 1, READ_SIZE, fp);
|
||||
if (ret <= 0) {
|
||||
printf("read sdmmc file:%s failed.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
*len = ret;
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
if(fp)
|
||||
ff_fclose(fp);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mipi_disp_test(void)
|
||||
{
|
||||
u32 len;
|
||||
int ret;
|
||||
u32 *disp_addr = (u32 *)pvPortMalloc(LCD_WIDTH*LCD_HEIGHT*2);
|
||||
if(!disp_addr) {
|
||||
printf("disp_addr pvPortMalloc failed.\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
mmcsd_wait_cd_changed(portMAX_DELAY);
|
||||
get_file_from_sd(disp_addr, &len);
|
||||
if(!len) {
|
||||
printf("get_file_from_sd failed.\n");
|
||||
return ;
|
||||
}
|
||||
CP15_clean_dcache_for_dma((uint32_t)disp_addr, (uint32_t)disp_addr + LCD_WIDTH*LCD_HEIGHT*2);
|
||||
|
||||
u32 layer = LCD_OSD0;
|
||||
u32 width = VIDEO_DISPLAY_WIDTH;
|
||||
u32 height = VIDEO_DISPLAY_HEIGHT;
|
||||
u32 format;
|
||||
#if LCD_BPP == 32
|
||||
format = LCD_OSD_FORAMT_ARGB888;
|
||||
#else
|
||||
format = LCD_OSD_FORAMT_RGB565;
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
ark_lcd_osd_enable(LCD_OSD0, 0);
|
||||
ark_lcd_osd_enable(LCD_OSD1, 0);
|
||||
ark_lcd_set_osd_sync(LCD_OSD0);
|
||||
ark_lcd_set_osd_sync(LCD_OSD1);
|
||||
|
||||
ark_lcd_set_osd_size(layer, width, height);
|
||||
ark_lcd_set_osd_format(layer, format);
|
||||
ark_lcd_osd_enable(layer, 1);
|
||||
ark_lcd_set_osd_yaddr(layer, (u32)disp_addr);
|
||||
ark_lcd_set_osd_sync(layer);
|
||||
ark_lcd_wait_for_vsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#define PLAY_SHUTDOWN_ANIMATION
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
static int shutdown_anim = 0;
|
||||
#endif
|
||||
uint16_t animo_flag = 0;
|
||||
static void animation_thread(void *param)
|
||||
{
|
||||
MFCHandle *mfc_handle = NULL;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash;
|
||||
#endif
|
||||
uint32_t size;
|
||||
uint32_t stick, etick, delaytick;
|
||||
uint32_t display_addr;
|
||||
uint32_t *tmp_addr = NULL;
|
||||
uint8_t power=1;
|
||||
|
||||
anioffset = GetUpFileOffset(MKTAG('B', 'A', 'N', 'I'));
|
||||
anisize = GetUpFileSize(MKTAG('B', 'A', 'N', 'I'));
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(shutdown_anim){
|
||||
anioffset = GetUpFileOffset(MKTAG('S', 'A', 'N', 'I'));
|
||||
anisize = GetUpFileSize(MKTAG('S', 'A', 'N', 'I'));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (anisize > 0) {
|
||||
void *anibuf = pvPortMalloc(anisize);
|
||||
if (anibuf) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, anioffset, anisize, anibuf);
|
||||
#else
|
||||
emmc_read(anioffset, anisize, anibuf);
|
||||
#endif
|
||||
aniheader = (BANIHEADER*)anibuf;
|
||||
|
||||
if (aniheader->magic != MKTAG('B', 'A', 'N', 'I')
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
&& aniheader->magic != MKTAG('S', 'A', 'N', 'I')
|
||||
#endif
|
||||
) {
|
||||
printf("Read animation file error!\n");
|
||||
vPortFree(anibuf);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
CP15_clean_dcache_for_dma((uint32_t)anibuf, (uint32_t)anibuf + anisize);
|
||||
} else {
|
||||
printf("Error! No enough memory for animation file.\n");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
printf("Warning! Not found animation in update file.\n");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
if (ani_replay) {
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
ani_frames = 0;
|
||||
ani_replay = 0;
|
||||
}
|
||||
stick = xTaskGetTickCount();
|
||||
ani_playing = 1;
|
||||
|
||||
size = *(uint32_t*)ani_frame_addr;
|
||||
|
||||
if (xVideoDisplayBufTake(pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
if(!mfc_handle)
|
||||
mfc_handle = mfc_init(RAW_STRM_TYPE_JPEG);
|
||||
if(!mfc_handle) {
|
||||
printf("%s, mfc_init failed.\n", __func__);
|
||||
continue ;
|
||||
}
|
||||
|
||||
display_addr = ulVideoDisplayBufGet();
|
||||
|
||||
JpegHeaderInfo jpegInfo = {0};
|
||||
jpegInfo.handle = mfc_handle;
|
||||
jpegInfo.jpg_addr = ani_frame_addr + 8;
|
||||
jpegInfo.jpg_size = size;
|
||||
jpegInfo.dec_addry = display_addr;
|
||||
|
||||
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
|
||||
if(!tmp_addr) {
|
||||
uint32_t tmp_size = ulVideoDisplayBufGetSize();
|
||||
tmp_addr = (u32 *)pvPortMalloc(tmp_size);
|
||||
if(!tmp_addr) {
|
||||
printf("tmp_addr pvPortMalloc failed.\n");
|
||||
}
|
||||
}
|
||||
if(tmp_addr) {
|
||||
jpegInfo.dec_addry = VIRT_TO_PHY((u32)tmp_addr);
|
||||
}
|
||||
#endif
|
||||
if (mfc_jpegdec(&jpegInfo) != 0) {
|
||||
printf("animation decode %d frame fail.\n", ani_frames);
|
||||
vVideoDisplayBufFree(display_addr);
|
||||
} else {
|
||||
if(!first_show_done) {
|
||||
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
|
||||
int align_width = (LCD_WIDTH + 0xF) & (~0xF);
|
||||
int align_height = (LCD_HEIGHT + 0xF) & (~0xF);
|
||||
if((align_width == jpegInfo.dec_width) && (align_height == jpegInfo.dec_height)) {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
|
||||
} else {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, jpegInfo.dec_width, jpegInfo.dec_height);
|
||||
}
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
|
||||
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
|
||||
#else
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_RGB565);
|
||||
#endif
|
||||
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
|
||||
first_show_done = 1;
|
||||
}
|
||||
animo_flag++;
|
||||
if(animo_flag == 3){
|
||||
BrightnessPowerOnSetting();
|
||||
pwm_enable(2);
|
||||
pwm_enable(3);
|
||||
}
|
||||
// printf("animo_flag------------ %d .\r\n",animo_flag);
|
||||
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addry);
|
||||
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addru);
|
||||
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addrv);
|
||||
#else
|
||||
pxp_scaler_rotate(jpegInfo.dec_addry, jpegInfo.dec_addru, jpegInfo.dec_addrv,
|
||||
PXP_SRC_FMT_YUV2P420, jpegInfo.dec_width, jpegInfo.dec_height,
|
||||
display_addr, 0, PXP_OUT_FMT_RGB565, LCD_WIDTH, LCD_HEIGHT, LCD_ROTATE_ANGLE);
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, display_addr);
|
||||
#endif
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_wait_for_vsync();
|
||||
vVideoDisplayBufRender(display_addr);
|
||||
ani_take_vdisbuf = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ani_frame_addr += size;
|
||||
ani_display_index = !ani_display_index;
|
||||
|
||||
if (ani_stop || (++ani_frames >= aniheader->aniCount + aniheader->hasBootlogo ? 1 : 0)
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
|| (ani_frame_addr > anioffset + anisize))
|
||||
#else
|
||||
|| (ani_frame_addr > (uint32_t)aniheader + anisize))
|
||||
#endif
|
||||
{
|
||||
|
||||
printf("animation end.\n");
|
||||
extern void Set_sys_power_on_self_test(uint8_t value);
|
||||
Set_sys_power_on_self_test(50);
|
||||
ani_stop = 0;
|
||||
if (aniheader->aniCount > 0)
|
||||
vTaskDelay(aniheader->aniDelayHideTime);
|
||||
else if (aniheader->hasBootlogo)
|
||||
vTaskDelay(aniheader->bootlogoDisplayTime);
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(shutdown_anim)
|
||||
ani_take_vdisbuf = 0;
|
||||
#endif
|
||||
if (ani_take_vdisbuf) {
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
}
|
||||
vVideoDisplayBufFree(display_addr);
|
||||
vVideoDisplayBufGive();
|
||||
ani_playing = 0;
|
||||
if (ani_replay)
|
||||
xTaskNotifyGive(animation_task);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
if(mfc_handle) {
|
||||
mfc_uninit(mfc_handle);
|
||||
mfc_handle = NULL;
|
||||
}
|
||||
if(tmp_addr) {
|
||||
vPortFree(tmp_addr);
|
||||
tmp_addr = NULL;
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
break;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
vVideoDisplayBufGive();
|
||||
xSemaphoreGive(animation_mutex);
|
||||
etick = xTaskGetTickCount();
|
||||
|
||||
if (aniheader->hasBootlogo && ani_frames == 1)
|
||||
delaytick = pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) > (etick - stick) ?
|
||||
pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) - (etick - stick) : 0;
|
||||
else
|
||||
delaytick = pdMS_TO_TICKS(1000 / aniheader->aniFps) > (etick - stick) ?
|
||||
pdMS_TO_TICKS(1000 / aniheader->aniFps) - (etick - stick) : 0;
|
||||
|
||||
if (delaytick)
|
||||
vTaskDelay(delaytick);
|
||||
|
||||
xTaskNotifyGive(animation_task);
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(aniheader) {
|
||||
vPortFree(aniheader);
|
||||
aniheader = NULL;
|
||||
}
|
||||
|
||||
animation_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int animation_init(void)
|
||||
{
|
||||
if (animation_task) {
|
||||
printf("animation is already inited.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
animation_mutex = xSemaphoreCreateMutex();
|
||||
|
||||
/* Create a task to play animation */
|
||||
//if (xTaskCreate(h264_decode_test_thread, "h264_decode_test", configMINIMAL_STACK_SIZE*2, NULL,
|
||||
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES - 1, &animation_task) != pdPASS) {
|
||||
printf("create animation task fail.\n");
|
||||
animation_task = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void animation_start(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
first_show_done=0;
|
||||
if (ani_playing) {
|
||||
printf("animation is already playing.\n");
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
ani_frame_addr = anioffset + sizeof(BANIHEADER);
|
||||
#else
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
#endif
|
||||
ani_frames = 0;
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
/* replay animation even if animation is already playing */
|
||||
void animation_restart(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
first_show_done=0;
|
||||
ani_stop=0;
|
||||
if (ani_playing) {
|
||||
ani_replay = 1;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
ani_frame_addr = anioffset + sizeof(BANIHEADER);
|
||||
#else
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
#endif
|
||||
ani_frames = 0;
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
int play_shutdown_animation(void)
|
||||
{
|
||||
#define TIMEOUT_SEC 10
|
||||
uint32_t wait_tick;
|
||||
|
||||
if (animation_task) {
|
||||
printf("%s, animation is already inited.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
shutdown_anim = 1;
|
||||
ani_frames = 0;
|
||||
first_show_done = 0;
|
||||
ani_stop = 0;
|
||||
ani_take_vdisbuf = 0;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES - 2, &animation_task) != pdPASS) {
|
||||
printf("%s, create animation task fail.\n", __func__);
|
||||
animation_task = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
|
||||
if (ani_playing) {
|
||||
printf("%s, animation is already playing.\n", __func__);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return -1;
|
||||
}
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
//wait for animation_thread exit.
|
||||
wait_tick = xTaskGetTickCount();
|
||||
while(xTaskGetTickCount() - wait_tick < configTICK_RATE_HZ * TIMEOUT_SEC) {
|
||||
if(ani_stop)
|
||||
break;
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void animation_stop(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
ani_stop = 1;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
int get_animation_status(void)
|
||||
{
|
||||
return ani_playing;
|
||||
}
|
@ -0,0 +1,653 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
|
||||
#include "sfud.h"
|
||||
#include "updatefile.h"
|
||||
#include "mfcapi.h"
|
||||
#include "dwl.h"
|
||||
#include "animation.h"
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
#include "mmcsd_core.h"
|
||||
#endif
|
||||
|
||||
static TaskHandle_t animation_task = NULL;
|
||||
static SemaphoreHandle_t animation_mutex;
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
static BANIHEADER ani_header;
|
||||
static BANIHEADER *aniheader = &ani_header;
|
||||
#else
|
||||
static BANIHEADER *aniheader;
|
||||
#endif
|
||||
static unsigned int anioffset;
|
||||
static unsigned int anisize;
|
||||
static int ani_playing = 0;
|
||||
static int ani_replay = 0;
|
||||
static int ani_stop = 0;
|
||||
static int ani_frames = 0;
|
||||
static int ani_display_index = 0;
|
||||
static int ani_take_vdisbuf = 0;
|
||||
static unsigned int ani_frame_addr;
|
||||
static uint32_t first_show_done = 0;
|
||||
|
||||
|
||||
#if 0
|
||||
#include "ff_stdio.h"
|
||||
|
||||
static int get_h264_single_file_from_sd(void *buf, int *len)
|
||||
{
|
||||
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
char path_name[64] = "/sd/000.h264";
|
||||
static int count = 0;
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
sprintf(path_name, "/sd/%.3d.h264", count++);
|
||||
*len = 0;
|
||||
|
||||
fp = ff_fopen(path_name, "rb");
|
||||
if (fp) {
|
||||
ret = ff_fread(buf, 1, READ_SIZE, fp);
|
||||
if (ret <= 0) {
|
||||
printf("read sdmmc file:%s failed, maybe read done\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
*len = ret;
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
count = 0;
|
||||
return -1;
|
||||
}
|
||||
if(fp)
|
||||
ff_fclose(fp);
|
||||
|
||||
//printf("###read %s len:%d.\n", path_name, *len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void h264_decode_test_thread(void *param)
|
||||
{
|
||||
#define H264DEC_SEMIPLANAR_YUV420 0x020001
|
||||
#define H264DEC_INBUF_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
#define H264DEC_DISP_COUNTS 2
|
||||
|
||||
DWLLinearMem_t inBuf;
|
||||
OutFrameBuffer outBuf = {0};
|
||||
uint32_t h264SrcSize = 0;
|
||||
MFCHandle *handle = NULL;
|
||||
uint32_t display_addr[H264DEC_DISP_COUNTS] = {0};
|
||||
uint32_t display_addr_index = 0;
|
||||
uint32_t first_show_done = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
void *h264SrcBuf = pvPortMalloc(H264DEC_INBUF_SIZE);
|
||||
if(!h264SrcBuf) {
|
||||
printf("%s, h264SrcBuf pvPortMalloc failed.\n", __func__);
|
||||
return ;
|
||||
}
|
||||
|
||||
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
|
||||
display_addr[i] = (uint32_t)pvPortMalloc(H264DEC_INBUF_SIZE);
|
||||
if(!display_addr[i] ) {
|
||||
printf("%s, display_addr[%d] pvPortMalloc failed.\n", __func__, i);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
mmcsd_wait_cd_changed(portMAX_DELAY);
|
||||
|
||||
handle = mfc_init(RAW_STRM_TYPE_H264);
|
||||
if(!handle) {
|
||||
printf("%s, mfc_init failed.\n", __func__);
|
||||
return ;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
//memset(&outBuf, 0, sizeof(OutFrameBuffer));
|
||||
//memset(h264SrcBuf, 0, H264DEC_INBUF_SIZE);
|
||||
mdelay(30);
|
||||
#if 1 //get h264 info form sdcard.
|
||||
ret = get_h264_single_file_from_sd(h264SrcBuf, &h264SrcSize);
|
||||
if(ret != 0) {
|
||||
printf("%s, get_h264_single_file_from_sd failed.\n", __func__);
|
||||
continue;
|
||||
}
|
||||
inBuf.busAddress = (u32)h264SrcBuf;
|
||||
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
|
||||
inBuf.size = h264SrcSize;
|
||||
CP15_clean_dcache_for_dma(inBuf.busAddress, inBuf.busAddress + inBuf.size);
|
||||
#else
|
||||
//1. copy your h264 data to h264SrcBuf;
|
||||
//2. set your h264 data size to h264SrcSize;
|
||||
|
||||
inBuf.busAddress = (u32)h264SrcBuf;
|
||||
inBuf.virtualAddress = (u32 *)inBuf.busAddress;
|
||||
inBuf.size = h264SrcSize;
|
||||
#endif
|
||||
|
||||
ret = mfc_decode(handle, &inBuf, &outBuf);
|
||||
if (ret < 0) {
|
||||
printf("animation decode fail.\n");
|
||||
} else {
|
||||
uint32_t align_width, align_height;
|
||||
uint32_t yaddr, uaddr, vaddr;
|
||||
|
||||
for(i=0; i<outBuf.num; i++) {
|
||||
align_width = outBuf.frameWidth;
|
||||
align_height = outBuf.frameHeight;
|
||||
if(1/*outBuf.outputFormat == H264DEC_SEMIPLANAR_YUV420*/ && align_width && align_height)
|
||||
{
|
||||
memcpy((void *)display_addr[display_addr_index], outBuf.buffer[i].pyVirAddress, align_width * align_height * 3 / 2);
|
||||
// ret = dma_m2mcpy(display_addr[display_addr_index], (uint32_t)outBuf.buffer[i].yBusAddress, align_width * align_height * 3 / 2);
|
||||
// if(ret) {
|
||||
// printf("%s() dma_m2m_memcpy failed.\n", __func__);
|
||||
// continue;
|
||||
// }
|
||||
yaddr = display_addr[display_addr_index];
|
||||
uaddr = yaddr + align_width * align_height;
|
||||
vaddr = yaddr + align_width * align_height * 5/4;
|
||||
|
||||
display_addr_index++;
|
||||
if(display_addr_index >= H264DEC_DISP_COUNTS) {
|
||||
display_addr_index = 0;
|
||||
}
|
||||
|
||||
if(!first_show_done) {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, /*outBuf.codedWidth, outBuf.codedHeight*/LCD_WIDTH, LCD_HEIGHT);
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
|
||||
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
|
||||
first_show_done = 1;
|
||||
}
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, yaddr);
|
||||
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, uaddr);
|
||||
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, vaddr);
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_wait_for_vsync();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(handle)
|
||||
mfc_uninit(handle);
|
||||
|
||||
if(h264SrcBuf)
|
||||
vPortFree(h264SrcBuf);
|
||||
|
||||
for(i=0; i<H264DEC_DISP_COUNTS; i++) {
|
||||
if(!display_addr[i]) {
|
||||
vPortFree((void *)display_addr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int save_nv12_file_to_sd(void *buf, int len)
|
||||
{
|
||||
char path_name[64] = "/sd/000.bin";
|
||||
static int count = 0;
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
sprintf(path_name, "/sd/%.3d.bin", count++);
|
||||
|
||||
fp = ff_fopen(path_name, "w+");
|
||||
if (fp) {
|
||||
ret = ff_fwrite(buf, 1, len, fp);
|
||||
if (ret != len) {
|
||||
printf("read sdmmc file:%s failed.\n", path_name);
|
||||
ff_fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
ff_fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_file_from_sd(void *buf, int *len)
|
||||
{
|
||||
#define READ_SIZE (LCD_WIDTH*LCD_HEIGHT*2)
|
||||
#if LCD_BPP == 32
|
||||
char path_name[64] = "/sd/480x1280_rgb888.rgb";
|
||||
#else
|
||||
char path_name[64] = "/sd/480x1280_rgb565.rgb";
|
||||
#endif
|
||||
FF_FILE *fp;
|
||||
int ret = -1;
|
||||
|
||||
*len = 0;
|
||||
fp = ff_fopen(path_name, "rb");
|
||||
if (fp) {
|
||||
ret = ff_fread(buf, 1, READ_SIZE, fp);
|
||||
if (ret <= 0) {
|
||||
printf("read sdmmc file:%s failed.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
*len = ret;
|
||||
} else {
|
||||
printf("### open %s fail.\n", path_name);
|
||||
return -1;
|
||||
}
|
||||
if(fp)
|
||||
ff_fclose(fp);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mipi_disp_test(void)
|
||||
{
|
||||
u32 len;
|
||||
int ret;
|
||||
u32 *disp_addr = (u32 *)pvPortMalloc(LCD_WIDTH*LCD_HEIGHT*2);
|
||||
if(!disp_addr) {
|
||||
printf("disp_addr pvPortMalloc failed.\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
mmcsd_wait_cd_changed(portMAX_DELAY);
|
||||
get_file_from_sd(disp_addr, &len);
|
||||
if(!len) {
|
||||
printf("get_file_from_sd failed.\n");
|
||||
return ;
|
||||
}
|
||||
CP15_clean_dcache_for_dma((uint32_t)disp_addr, (uint32_t)disp_addr + LCD_WIDTH*LCD_HEIGHT*2);
|
||||
|
||||
u32 layer = LCD_OSD0;
|
||||
u32 width = VIDEO_DISPLAY_WIDTH;
|
||||
u32 height = VIDEO_DISPLAY_HEIGHT;
|
||||
u32 format;
|
||||
#if LCD_BPP == 32
|
||||
format = LCD_OSD_FORAMT_ARGB888;
|
||||
#else
|
||||
format = LCD_OSD_FORAMT_RGB565;
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
ark_lcd_osd_enable(LCD_OSD0, 0);
|
||||
ark_lcd_osd_enable(LCD_OSD1, 0);
|
||||
ark_lcd_set_osd_sync(LCD_OSD0);
|
||||
ark_lcd_set_osd_sync(LCD_OSD1);
|
||||
|
||||
ark_lcd_set_osd_size(layer, width, height);
|
||||
ark_lcd_set_osd_format(layer, format);
|
||||
ark_lcd_osd_enable(layer, 1);
|
||||
ark_lcd_set_osd_yaddr(layer, (u32)disp_addr);
|
||||
ark_lcd_set_osd_sync(layer);
|
||||
ark_lcd_wait_for_vsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//#define PLAY_SHUTDOWN_ANIMATION
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
static int shutdown_anim = 0;
|
||||
#endif
|
||||
|
||||
static void animation_thread(void *param)
|
||||
{
|
||||
MFCHandle *mfc_handle = NULL;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash;
|
||||
#endif
|
||||
uint32_t size;
|
||||
uint32_t stick, etick, delaytick;
|
||||
uint32_t display_addr;
|
||||
uint32_t *tmp_addr = NULL;
|
||||
uint8_t power=1;
|
||||
|
||||
anioffset = GetUpFileOffset(MKTAG('B', 'A', 'N', 'I'));
|
||||
anisize = GetUpFileSize(MKTAG('B', 'A', 'N', 'I'));
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(shutdown_anim){
|
||||
anioffset = GetUpFileOffset(MKTAG('S', 'A', 'N', 'I'));
|
||||
anisize = GetUpFileSize(MKTAG('S', 'A', 'N', 'I'));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (anisize > 0) {
|
||||
void *anibuf = pvPortMalloc(anisize);
|
||||
if (anibuf) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, anioffset, anisize, anibuf);
|
||||
#else
|
||||
emmc_read(anioffset, anisize, anibuf);
|
||||
#endif
|
||||
aniheader = (BANIHEADER*)anibuf;
|
||||
|
||||
if (aniheader->magic != MKTAG('B', 'A', 'N', 'I')
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
&& aniheader->magic != MKTAG('S', 'A', 'N', 'I')
|
||||
#endif
|
||||
) {
|
||||
printf("Read animation file error!\n");
|
||||
vPortFree(anibuf);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
CP15_clean_dcache_for_dma((uint32_t)anibuf, (uint32_t)anibuf + anisize);
|
||||
} else {
|
||||
printf("Error! No enough memory for animation file.\n");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
printf("Warning! Not found animation in update file.\n");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
if (ani_replay) {
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
ani_frames = 0;
|
||||
ani_replay = 0;
|
||||
}
|
||||
stick = xTaskGetTickCount();
|
||||
ani_playing = 1;
|
||||
|
||||
size = *(uint32_t*)ani_frame_addr;
|
||||
|
||||
if (xVideoDisplayBufTake(pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||
if(!mfc_handle)
|
||||
mfc_handle = mfc_init(RAW_STRM_TYPE_JPEG);
|
||||
if(!mfc_handle) {
|
||||
printf("%s, mfc_init failed.\n", __func__);
|
||||
continue ;
|
||||
}
|
||||
|
||||
display_addr = ulVideoDisplayBufGet();
|
||||
|
||||
JpegHeaderInfo jpegInfo = {0};
|
||||
jpegInfo.handle = mfc_handle;
|
||||
jpegInfo.jpg_addr = ani_frame_addr + 8;
|
||||
jpegInfo.jpg_size = size;
|
||||
jpegInfo.dec_addry = display_addr;
|
||||
|
||||
#if LCD_ROTATE_ANGLE != LCD_ROTATE_ANGLE_0
|
||||
if(!tmp_addr) {
|
||||
uint32_t tmp_size = ulVideoDisplayBufGetSize();
|
||||
tmp_addr = (u32 *)pvPortMalloc(tmp_size);
|
||||
if(!tmp_addr) {
|
||||
printf("tmp_addr pvPortMalloc failed.\n");
|
||||
}
|
||||
}
|
||||
if(tmp_addr) {
|
||||
jpegInfo.dec_addry = VIRT_TO_PHY((u32)tmp_addr);
|
||||
}
|
||||
#endif
|
||||
if (mfc_jpegdec(&jpegInfo) != 0) {
|
||||
printf("animation decode %d frame fail.\n", ani_frames);
|
||||
vVideoDisplayBufFree(display_addr);
|
||||
} else {
|
||||
if(!first_show_done) {
|
||||
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
|
||||
int align_width = (LCD_WIDTH + 0xF) & (~0xF);
|
||||
int align_height = (LCD_HEIGHT + 0xF) & (~0xF);
|
||||
if((align_width == jpegInfo.dec_width) && (align_height == jpegInfo.dec_height)) {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
|
||||
} else {
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, jpegInfo.dec_width, jpegInfo.dec_height);
|
||||
}
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_YUV420);
|
||||
ark_lcd_set_osd_yuv420_mode(LCD_VIDEO_LAYER, LCD_OSD_Y_UV420);
|
||||
#else
|
||||
ark_lcd_set_osd_size(LCD_VIDEO_LAYER, LCD_WIDTH, LCD_HEIGHT);
|
||||
ark_lcd_set_osd_format(LCD_VIDEO_LAYER, LCD_OSD_FORAMT_RGB565);
|
||||
#endif
|
||||
if(power){
|
||||
BrightnessPowerOnSetting();
|
||||
pwm_enable(2);
|
||||
pwm_enable(3);
|
||||
}
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
|
||||
first_show_done = 1;
|
||||
}
|
||||
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addry);
|
||||
ark_lcd_set_osd_uaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addru);
|
||||
ark_lcd_set_osd_vaddr(LCD_VIDEO_LAYER, jpegInfo.dec_addrv);
|
||||
#else
|
||||
pxp_scaler_rotate(jpegInfo.dec_addry, jpegInfo.dec_addru, jpegInfo.dec_addrv,
|
||||
PXP_SRC_FMT_YUV2P420, jpegInfo.dec_width, jpegInfo.dec_height,
|
||||
display_addr, 0, PXP_OUT_FMT_RGB565, LCD_WIDTH, LCD_HEIGHT, LCD_ROTATE_ANGLE);
|
||||
ark_lcd_set_osd_yaddr(LCD_VIDEO_LAYER, display_addr);
|
||||
#endif
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_wait_for_vsync();
|
||||
vVideoDisplayBufRender(display_addr);
|
||||
ani_take_vdisbuf = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ani_frame_addr += size;
|
||||
ani_display_index = !ani_display_index;
|
||||
|
||||
if (ani_stop || (++ani_frames >= aniheader->aniCount + aniheader->hasBootlogo ? 1 : 0)
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
|| (ani_frame_addr > anioffset + anisize))
|
||||
#else
|
||||
|| (ani_frame_addr > (uint32_t)aniheader + anisize))
|
||||
#endif
|
||||
{
|
||||
|
||||
printf("animation end.\n");
|
||||
extern void Set_sys_power_on_self_test(uint8_t value);
|
||||
Set_sys_power_on_self_test(50);
|
||||
ani_stop = 0;
|
||||
if (aniheader->aniCount > 0)
|
||||
vTaskDelay(aniheader->aniDelayHideTime);
|
||||
else if (aniheader->hasBootlogo)
|
||||
vTaskDelay(aniheader->bootlogoDisplayTime);
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(shutdown_anim)
|
||||
ani_take_vdisbuf = 0;
|
||||
#endif
|
||||
if (ani_take_vdisbuf) {
|
||||
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
|
||||
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
|
||||
ark_lcd_set_osd_sync(LCD_UI_LAYER);
|
||||
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
|
||||
}
|
||||
vVideoDisplayBufFree(display_addr);
|
||||
vVideoDisplayBufGive();
|
||||
ani_playing = 0;
|
||||
if (ani_replay)
|
||||
xTaskNotifyGive(animation_task);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
if(mfc_handle) {
|
||||
mfc_uninit(mfc_handle);
|
||||
mfc_handle = NULL;
|
||||
}
|
||||
if(tmp_addr) {
|
||||
vPortFree(tmp_addr);
|
||||
tmp_addr = NULL;
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
break;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
vVideoDisplayBufGive();
|
||||
xSemaphoreGive(animation_mutex);
|
||||
etick = xTaskGetTickCount();
|
||||
|
||||
if (aniheader->hasBootlogo && ani_frames == 1)
|
||||
delaytick = pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) > (etick - stick) ?
|
||||
pdMS_TO_TICKS(aniheader->bootlogoDisplayTime) - (etick - stick) : 0;
|
||||
else
|
||||
delaytick = pdMS_TO_TICKS(1000 / aniheader->aniFps) > (etick - stick) ?
|
||||
pdMS_TO_TICKS(1000 / aniheader->aniFps) - (etick - stick) : 0;
|
||||
|
||||
if (delaytick)
|
||||
vTaskDelay(delaytick);
|
||||
|
||||
xTaskNotifyGive(animation_task);
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
if(aniheader) {
|
||||
vPortFree(aniheader);
|
||||
aniheader = NULL;
|
||||
}
|
||||
|
||||
animation_task = NULL;
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int animation_init(void)
|
||||
{
|
||||
if (animation_task) {
|
||||
printf("animation is already inited.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
animation_mutex = xSemaphoreCreateMutex();
|
||||
|
||||
/* Create a task to play animation */
|
||||
//if (xTaskCreate(h264_decode_test_thread, "h264_decode_test", configMINIMAL_STACK_SIZE*2, NULL,
|
||||
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES - 1, &animation_task) != pdPASS) {
|
||||
printf("create animation task fail.\n");
|
||||
animation_task = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void animation_start(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
first_show_done=0;
|
||||
if (ani_playing) {
|
||||
printf("animation is already playing.\n");
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
ani_frame_addr = anioffset + sizeof(BANIHEADER);
|
||||
#else
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
#endif
|
||||
ani_frames = 0;
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
/* replay animation even if animation is already playing */
|
||||
void animation_restart(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
first_show_done=0;
|
||||
ani_stop=0;
|
||||
if (ani_playing) {
|
||||
ani_replay = 1;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#if ANIMATION_POLICY == ANIMATION_USE_SMALL_MEM
|
||||
ani_frame_addr = anioffset + sizeof(BANIHEADER);
|
||||
#else
|
||||
ani_frame_addr = (uint32_t)aniheader + sizeof(BANIHEADER);
|
||||
#endif
|
||||
ani_frames = 0;
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
#ifdef PLAY_SHUTDOWN_ANIMATION
|
||||
int play_shutdown_animation(void)
|
||||
{
|
||||
#define TIMEOUT_SEC 10
|
||||
uint32_t wait_tick;
|
||||
|
||||
if (animation_task) {
|
||||
printf("%s, animation is already inited.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
shutdown_anim = 1;
|
||||
ani_frames = 0;
|
||||
first_show_done = 0;
|
||||
ani_stop = 0;
|
||||
ani_take_vdisbuf = 0;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
if (xTaskCreate(animation_thread, "animation", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES - 2, &animation_task) != pdPASS) {
|
||||
printf("%s, create animation task fail.\n", __func__);
|
||||
animation_task = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
|
||||
if (ani_playing) {
|
||||
printf("%s, animation is already playing.\n", __func__);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
return -1;
|
||||
}
|
||||
if (animation_task)
|
||||
xTaskNotifyGive(animation_task);
|
||||
xSemaphoreGive(animation_mutex);
|
||||
|
||||
//wait for animation_thread exit.
|
||||
wait_tick = xTaskGetTickCount();
|
||||
while(xTaskGetTickCount() - wait_tick < configTICK_RATE_HZ * TIMEOUT_SEC) {
|
||||
if(ani_stop)
|
||||
break;
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void animation_stop(void)
|
||||
{
|
||||
xSemaphoreTake(animation_mutex, portMAX_DELAY);
|
||||
ani_stop = 1;
|
||||
xSemaphoreGive(animation_mutex);
|
||||
}
|
||||
|
||||
int get_animation_status(void)
|
||||
{
|
||||
return ani_playing;
|
||||
}
|
@ -0,0 +1,603 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
#include "ark7116.h"
|
||||
|
||||
#ifdef VIDEO_DECODER_ARK7116
|
||||
|
||||
#define ARK7116_RST_GPIO 7
|
||||
|
||||
PanlstaticPara AV1_staticPara[]=
|
||||
{
|
||||
//GLOBAL
|
||||
{0XFD02,0X00},
|
||||
{0XFD0A,0X48},
|
||||
{0XFD0B,0X1D},
|
||||
{0XFD0C,0X33},
|
||||
{0XFD0D,0X20},
|
||||
{0XFD0E,0X2C},
|
||||
{0XFD0F,0X09},
|
||||
{0XFD10,0X01},
|
||||
{0XFD11,0XFF},
|
||||
{0XFD12,0XFF},
|
||||
{0XFD13,0XFF},
|
||||
{0XFD14,0X02},
|
||||
{0XFD15,0X02},
|
||||
{0XFD16,0X02},
|
||||
{0XFD1A,0X45},
|
||||
{0XFD19,0X0A},
|
||||
//PWM
|
||||
//DECODER
|
||||
{0XFE01,0X06},
|
||||
{0XFE02,0X00},
|
||||
{0XFE06,0X07},
|
||||
{0XFE07,0X80},
|
||||
{0XFE08,0X0E},
|
||||
{0XFE0C,0X10},
|
||||
{0XFE0F,0X07},
|
||||
{0XFE13,0X16},
|
||||
{0XFE14,0X22},
|
||||
{0XFE15,0X05},
|
||||
{0XFE26,0X0E},
|
||||
{0XFE27,0X00},
|
||||
{0XFE48,0X87},
|
||||
{0XFE54,0X00},
|
||||
{0XFE55,0X01},
|
||||
{0XFE63,0XC0},
|
||||
{0XFE83,0XFF},
|
||||
{0XFED5,0X81},
|
||||
{0XFED7,0XF7},
|
||||
{0XFEDC,0X00},
|
||||
{0XFE44,0X20},
|
||||
{0XFE45,0X80},
|
||||
{0XFE43,0X80},
|
||||
{0XFECB,0X00},
|
||||
{0XFE56,0X07},
|
||||
{0XFEC9,0X01},
|
||||
{0XFE46,0X00},
|
||||
{0XFE42,0X00},
|
||||
{0XFE19,0X82},
|
||||
{0XFE1A,0X50},
|
||||
{0XFE1B,0X22},
|
||||
{0XFE1C,0X61},
|
||||
{0XFE1D,0X70},
|
||||
//VP
|
||||
{0XFFB0,0X67},
|
||||
{0XFFB1,0X0F},
|
||||
{0XFFB2,0X10},
|
||||
{0XFFB3,0X10},
|
||||
{0XFFB4,0X10},
|
||||
{0XFFB7,0X10},
|
||||
{0XFFB8,0X10},
|
||||
{0XFFB9,0X22},
|
||||
{0XFFBA,0X20},
|
||||
{0XFFBB,0XFF},
|
||||
{0XFFBC,0X10},
|
||||
{0XFFC7,0X31},
|
||||
{0XFFC8,0X03},
|
||||
{0XFFC9,0X10},
|
||||
{0XFFCB,0X80},
|
||||
{0XFFCC,0X80},
|
||||
{0XFFCD,0X00},
|
||||
{0XFFCE,0X10},
|
||||
{0XFFCF,0X80},
|
||||
{0XFFD0,0X80},
|
||||
{0XFFD2,0X4F},
|
||||
{0XFFD3,0X80},
|
||||
{0XFFD4,0X80},
|
||||
{0XFFD7,0X05},
|
||||
{0XFFD8,0X80},
|
||||
{0XFFE7,0X50},
|
||||
{0XFFE8,0X10},
|
||||
{0XFFE9,0X22},
|
||||
{0XFFEA,0X20},
|
||||
{0XFFF0,0X2F},
|
||||
{0XFFF1,0XE1},
|
||||
{0XFFF2,0XEE},
|
||||
{0XFFF3,0XDC},
|
||||
{0XFFF4,0XFD},
|
||||
{0XFFF5,0X29},
|
||||
{0XFFF6,0XF7},
|
||||
{0XFFF7,0X9E},
|
||||
{0XFFF8,0X10},
|
||||
{0XFFF9,0X3D},
|
||||
{0XFFFA,0X4E},
|
||||
{0XFFFB,0X81},
|
||||
{0XFFD5,0X00},
|
||||
{0XFFD6,0X35},
|
||||
//TCON
|
||||
{0XFC00,0X48},
|
||||
{0XFC01,0X00},
|
||||
{0XFC02,0X00},
|
||||
{0XFC09,0X06},
|
||||
{0XFC0A,0X33},
|
||||
//SCALE
|
||||
{0XFC90,0X42},
|
||||
{0XFC91,0X00},
|
||||
{0XFC92,0X00},
|
||||
{0XFC93,0X0C},
|
||||
{0XFC94,0X00},
|
||||
{0XFC95,0X00},
|
||||
{0XFC96,0XE0},
|
||||
{0XFC97,0X03},
|
||||
{0XFC98,0X00},
|
||||
{0XFC99,0X04},
|
||||
{0XFC9A,0X57},
|
||||
{0XFC9B,0X03},
|
||||
{0XFC9C,0X02},
|
||||
{0XFC9D,0X00},
|
||||
{0XFC9E,0X06},
|
||||
{0XFC9F,0X00},
|
||||
{0XFCA0,0X23},
|
||||
{0XFCA1,0X00},
|
||||
{0XFCA2,0X1D},
|
||||
{0XFCA3,0X04},
|
||||
{0XFCA4,0X06},
|
||||
{0XFCA5,0X00},
|
||||
{0XFCA6,0X08},
|
||||
{0XFCA7,0X00},
|
||||
{0XFCA8,0X0A},
|
||||
{0XFCA9,0X00},
|
||||
{0XFCAA,0X09},
|
||||
{0XFCAB,0X01},
|
||||
{0XFCAC,0X12},
|
||||
{0XFCAD,0X00},
|
||||
{0XFCAE,0X00},
|
||||
{0XFCAF,0X00},
|
||||
{0XFCB0,0X00},
|
||||
{0XFCB1,0X00},
|
||||
{0XFCB2,0X00},
|
||||
{0XFCB3,0X00},
|
||||
{0XFCB4,0X00},
|
||||
{0XFCB5,0X00},
|
||||
{0XFCB7,0X0E},
|
||||
{0XFCB8,0X02},
|
||||
{0XFCBB,0X3B},
|
||||
{0XFCBC,0X01},
|
||||
{0XFCBD,0X00},
|
||||
{0XFCBE,0X00},
|
||||
{0XFCBF,0X0C},
|
||||
{0XFCC0,0X00},
|
||||
{0XFCC1,0X00},
|
||||
{0XFCC2,0X00},
|
||||
{0XFCC3,0X04},
|
||||
{0XFCC4,0X00},
|
||||
{0XFCC5,0X04},
|
||||
{0XFCC6,0X60},
|
||||
{0XFCC7,0X03},
|
||||
{0XFCC8,0X02},
|
||||
{0XFCC9,0X00},
|
||||
{0XFCCA,0X06},
|
||||
{0XFCCB,0X00},
|
||||
{0XFCCC,0X28},
|
||||
{0XFCCD,0X00},
|
||||
{0XFCCE,0XF8},
|
||||
{0XFCCF,0X02},
|
||||
{0XFCD1,0X00},
|
||||
{0XFCD2,0X15},
|
||||
{0XFCD3,0X00},
|
||||
{0XFCD4,0X0A},
|
||||
{0XFCD5,0X00},
|
||||
{0XFCD6,0X2F},
|
||||
{0XFCD7,0X01},
|
||||
{0XFCD8,0X00},
|
||||
{0XFCD9,0X07},
|
||||
{0XFCDA,0X00},
|
||||
{0XFCDB,0X00},
|
||||
{0XFCDC,0X00},
|
||||
{0XFCDD,0X14},
|
||||
{0XFCDE,0X00},
|
||||
{0XFCDF,0X00},
|
||||
{0XFCE0,0X00},
|
||||
{0XFCE1,0X02},
|
||||
{0XFCE3,0X01},
|
||||
{0XFCE4,0X02},
|
||||
{0XFCE7,0X03},
|
||||
{0XFCD0,0X0A},
|
||||
{0XFCE2,0X00},
|
||||
{0XFCB6,0X00},
|
||||
{0XFB35,0X00},
|
||||
{0XFB89,0X00},
|
||||
//GAMMA
|
||||
{0XFF00,0X03},
|
||||
{0XFF01,0X0F},
|
||||
{0XFF02,0X1E},
|
||||
{0XFF03,0X2B},
|
||||
{0XFF04,0X36},
|
||||
{0XFF05,0X40},
|
||||
{0XFF06,0X4B},
|
||||
{0XFF07,0X55},
|
||||
{0XFF08,0X5F},
|
||||
{0XFF09,0X69},
|
||||
{0XFF0A,0X73},
|
||||
{0XFF0B,0X7D},
|
||||
{0XFF0C,0X85},
|
||||
{0XFF0D,0X8E},
|
||||
{0XFF0E,0X96},
|
||||
{0XFF0F,0X9F},
|
||||
{0XFF10,0XA7},
|
||||
{0XFF11,0XAE},
|
||||
{0XFF12,0XB6},
|
||||
{0XFF13,0XBD},
|
||||
{0XFF14,0XC4},
|
||||
{0XFF15,0XCA},
|
||||
{0XFF16,0XD1},
|
||||
{0XFF17,0XD7},
|
||||
{0XFF18,0XDD},
|
||||
{0XFF19,0XE3},
|
||||
{0XFF1A,0XE8},
|
||||
{0XFF1B,0XED},
|
||||
{0XFF1C,0XF1},
|
||||
{0XFF1D,0XF5},
|
||||
{0XFF1E,0XF8},
|
||||
{0XFF1F,0XFC},
|
||||
{0XFF20,0X0F},
|
||||
{0XFF21,0X1E},
|
||||
{0XFF22,0X2B},
|
||||
{0XFF23,0X36},
|
||||
{0XFF24,0X40},
|
||||
{0XFF25,0X4B},
|
||||
{0XFF26,0X55},
|
||||
{0XFF27,0X5F},
|
||||
{0XFF28,0X69},
|
||||
{0XFF29,0X73},
|
||||
{0XFF2A,0X7D},
|
||||
{0XFF2B,0X85},
|
||||
{0XFF2C,0X8E},
|
||||
{0XFF2D,0X96},
|
||||
{0XFF2E,0X9F},
|
||||
{0XFF2F,0XA7},
|
||||
{0XFF30,0XAE},
|
||||
{0XFF31,0XB6},
|
||||
{0XFF32,0XBD},
|
||||
{0XFF33,0XC4},
|
||||
{0XFF34,0XCA},
|
||||
{0XFF35,0XD1},
|
||||
{0XFF36,0XD7},
|
||||
{0XFF37,0XDD},
|
||||
{0XFF38,0XE3},
|
||||
{0XFF39,0XE8},
|
||||
{0XFF3A,0XED},
|
||||
{0XFF3B,0XF1},
|
||||
{0XFF3C,0XF5},
|
||||
{0XFF3D,0XF8},
|
||||
{0XFF3E,0XFC},
|
||||
{0XFF3F,0X0F},
|
||||
{0XFF40,0X1E},
|
||||
{0XFF41,0X2B},
|
||||
{0XFF42,0X36},
|
||||
{0XFF43,0X40},
|
||||
{0XFF44,0X4B},
|
||||
{0XFF45,0X55},
|
||||
{0XFF46,0X5F},
|
||||
{0XFF47,0X69},
|
||||
{0XFF48,0X73},
|
||||
{0XFF49,0X7D},
|
||||
{0XFF4A,0X85},
|
||||
{0XFF4B,0X8E},
|
||||
{0XFF4C,0X96},
|
||||
{0XFF4D,0X9F},
|
||||
{0XFF4E,0XA7},
|
||||
{0XFF4F,0XAE},
|
||||
{0XFF50,0XB6},
|
||||
{0XFF51,0XBD},
|
||||
{0XFF52,0XC4},
|
||||
{0XFF53,0XCA},
|
||||
{0XFF54,0XD1},
|
||||
{0XFF55,0XD7},
|
||||
{0XFF56,0XDD},
|
||||
{0XFF57,0XE3},
|
||||
{0XFF58,0XE8},
|
||||
{0XFF59,0XED},
|
||||
{0XFF5A,0XF1},
|
||||
{0XFF5B,0XF5},
|
||||
{0XFF5C,0XF8},
|
||||
{0XFF5D,0XFC},
|
||||
{0XFF5E,0XFF},
|
||||
{0XFF5F,0XFF},
|
||||
{0XFF60,0XFF},
|
||||
};
|
||||
|
||||
/*点屏 PAD MUX 参数*/
|
||||
PanlstaticPara AMT_PadMuxStaticPara[]=
|
||||
{
|
||||
//PAD MUX
|
||||
{0XFD30,0X22},
|
||||
{0XFD32,0X11},
|
||||
{0XFD33,0X11},
|
||||
{0XFD34,0X55},
|
||||
{0XFD35,0X55},
|
||||
{0XFD36,0X55},
|
||||
{0XFD37,0X55},
|
||||
{0XFD38,0X55},
|
||||
{0XFD39,0X55},
|
||||
{0XFD3A,0X11},
|
||||
{0XFD3B,0X11},
|
||||
{0XFD3C,0X44},
|
||||
{0XFD3D,0X44},
|
||||
{0XFD3E,0X44},
|
||||
{0XFD3F,0X44},
|
||||
{0XFD40,0X44},
|
||||
{0XFD41,0X44},
|
||||
{0XFD44,0X01},
|
||||
{0XFD45,0X00},
|
||||
{0XFD46,0X00},
|
||||
{0XFD47,0X00},
|
||||
{0XFD48,0X00},
|
||||
{0XFD49,0X00},
|
||||
{0XFD4A,0X00},
|
||||
{0XFD4B,0X00},
|
||||
{0XFD50,0X0B},
|
||||
{0XFD51,0X55},
|
||||
{0XFD52,0X55},
|
||||
{0XFD53,0X57},
|
||||
{0XFD54,0X57},
|
||||
{0XFD55,0X55},
|
||||
{0XFD56,0X55},
|
||||
{0XFD57,0X55},
|
||||
{0XFD58,0X55},
|
||||
{0XFD59,0X5D},
|
||||
{0XFD5A,0X55},
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static int ark7116_i2c_write (struct i2c_adapter *adap, UINT16 RegAddr, unsigned int data)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret = -1;
|
||||
u8 retries = 0;
|
||||
u8 buf[2];
|
||||
UINT8 ucDeviceAddr;
|
||||
UINT8 uctmpDeviceAddr;
|
||||
UINT8 ucSubAddr;
|
||||
|
||||
uctmpDeviceAddr = (unsigned char)((RegAddr>>8)&0XFF);
|
||||
ucSubAddr = (UINT8)(RegAddr&0XFF);
|
||||
|
||||
switch(uctmpDeviceAddr)
|
||||
{
|
||||
case 0XF9:
|
||||
case 0XFD:
|
||||
ucDeviceAddr= 0XB0;
|
||||
break;
|
||||
|
||||
case 0XFA:
|
||||
ucDeviceAddr= 0XBE;
|
||||
break;
|
||||
|
||||
case 0XFB:
|
||||
ucDeviceAddr= 0XB6;
|
||||
break;
|
||||
|
||||
case 0XFC:
|
||||
ucDeviceAddr= 0XB8;
|
||||
break;
|
||||
|
||||
case 0XFE:
|
||||
ucDeviceAddr= 0XB2;
|
||||
break;
|
||||
|
||||
case 0XFF:
|
||||
ucDeviceAddr= 0XB4;
|
||||
break;
|
||||
|
||||
case 0X00:
|
||||
ucDeviceAddr = 0XBE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ucDeviceAddr= 0XB0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
buf[0] = (ucSubAddr);
|
||||
buf[1] = (data & 0xFF);
|
||||
|
||||
msg.flags = !I2C_M_RD;
|
||||
msg.addr = (ucDeviceAddr>>1);
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
//printf("msg.addr is %x\n", msg.addr);
|
||||
//printf("msg.ucSubAddr is %x\n",buf[0]);
|
||||
//printf("msg.data is %x\n", buf[1]);
|
||||
while(retries < 10)
|
||||
{
|
||||
//printf("retries is %x\n", retries);
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
//printf("ret is %x\n", ret);
|
||||
if (ret == 1)
|
||||
break;
|
||||
retries++;
|
||||
vTaskDelay (20);
|
||||
}
|
||||
|
||||
if (retries >= 10)
|
||||
{
|
||||
printf("%s timeout11\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ARK7116_reset(void)
|
||||
{
|
||||
gpio_direction_output(ARK7116_RST_GPIO, 0);
|
||||
vTaskDelay(10);
|
||||
gpio_direction_output(ARK7116_RST_GPIO, 1);
|
||||
vTaskDelay(10);
|
||||
gpio_direction_output(ARK7116_RST_GPIO, 0);
|
||||
vTaskDelay(10);
|
||||
}
|
||||
|
||||
int ConfigSlaveMode(struct i2c_adapter *adap)
|
||||
{
|
||||
unsigned char AddrBuff[6] = {0xa1,0xa2,0xa3,0xa4,0xa5,0xa6};
|
||||
unsigned char DataBuff[6] = {0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
unsigned char i;
|
||||
|
||||
DataBuff[0] = 0X55;
|
||||
DataBuff[1] = 0xAA;
|
||||
DataBuff[2] = 0X03;
|
||||
DataBuff[3] = 0X50; //slave mode
|
||||
DataBuff[4] = 0; // crc val
|
||||
DataBuff[5] = DataBuff[2]^DataBuff[3]^DataBuff[4];
|
||||
|
||||
printf("ConfigSlaveMode\n");
|
||||
ark7116_i2c_write(adap,MCU_CFG_ADDR,0X40);
|
||||
ark7116_i2c_write(adap,RSTN,0X00);
|
||||
ark7116_i2c_write(adap,RSTN,0X5A);
|
||||
|
||||
if(ark7116_i2c_write(adap,BUS_STATUS_ADDR, 0x00) < 0) //I2c Write Start
|
||||
return -1;
|
||||
|
||||
for(i =0;i < 6;i++)
|
||||
{
|
||||
if(ark7116_i2c_write(adap,AddrBuff[i], DataBuff[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ark7116_i2c_write(adap,BUS_STATUS_ADDR, 0x11) < 0) //I2c Write End
|
||||
return -1;
|
||||
|
||||
vTaskDelay (200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AMT_WriteStaticPara(struct i2c_adapter *adap,PanlstaticPara * dataPt,UINT16 num)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret = -1;
|
||||
u8 retries = 0;
|
||||
u8 buf[2];
|
||||
u8 ucDeviceAddr;
|
||||
u8 uctmpDeviceAddr;
|
||||
u8 ucSubAddr;
|
||||
u8 ucRegVal;
|
||||
|
||||
while(num--)
|
||||
{
|
||||
uctmpDeviceAddr = (unsigned char)(((*dataPt).addr>>8)&0XFF);
|
||||
ucSubAddr = (unsigned char)(((*dataPt).addr)&0XFF);
|
||||
ucRegVal = (*dataPt).dat;
|
||||
|
||||
switch(uctmpDeviceAddr)
|
||||
{
|
||||
case 0XF9:
|
||||
case 0XFD:
|
||||
ucDeviceAddr= 0XB0;
|
||||
break;
|
||||
|
||||
case 0XFA:
|
||||
ucDeviceAddr= 0XBE;
|
||||
break;
|
||||
|
||||
case 0XFB:
|
||||
ucDeviceAddr= 0XB6;
|
||||
break;
|
||||
|
||||
case 0XFC:
|
||||
ucDeviceAddr= 0XB8;
|
||||
break;
|
||||
|
||||
case 0XFE:
|
||||
ucDeviceAddr= 0XB2;
|
||||
break;
|
||||
|
||||
case 0XFF:
|
||||
ucDeviceAddr= 0XB4;
|
||||
break;
|
||||
|
||||
case 0X00:
|
||||
ucDeviceAddr = 0XBE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ucDeviceAddr= 0XB0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
buf[0] = (ucSubAddr);
|
||||
buf[1] = (ucRegVal & 0xFF);
|
||||
|
||||
msg.flags = !I2C_M_RD;
|
||||
msg.addr = (ucDeviceAddr>>1);
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
while(retries < 10)
|
||||
{
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
if (ret == 1)
|
||||
break;
|
||||
retries++;
|
||||
vTaskDelay (20);
|
||||
}
|
||||
|
||||
if (retries >= 10)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
dataPt++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConfigStaticPara(struct i2c_adapter *adap)
|
||||
{
|
||||
//CurretSource = CurretSource;
|
||||
AMT_WriteStaticPara(adap,AV1_staticPara,sizeof(AV1_staticPara)/sizeof(AV1_staticPara[0]));
|
||||
}
|
||||
void ConfigPadMuxPara(struct i2c_adapter *adap)
|
||||
{
|
||||
AMT_WriteStaticPara(adap,AMT_PadMuxStaticPara,
|
||||
sizeof(AMT_PadMuxStaticPara)/sizeof(AMT_PadMuxStaticPara[0]));
|
||||
}
|
||||
|
||||
void InitGlobalPara(struct i2c_adapter *adap) //165
|
||||
{
|
||||
printf("InitGlobalPara\n");
|
||||
ark7116_i2c_write(adap,ENH_PLL,0X20);
|
||||
ConfigStaticPara(adap);
|
||||
ConfigPadMuxPara(adap);
|
||||
|
||||
ark7116_i2c_write(adap,0xFD0C,0X33);
|
||||
ark7116_i2c_write(adap,0xFD14,0X02);
|
||||
//黑屏
|
||||
ark7116_i2c_write(adap,0xFFCE,0X00);
|
||||
ark7116_i2c_write(adap,0xFFCF,0X80);
|
||||
ark7116_i2c_write(adap,0xFFD0,0X80);
|
||||
ark7116_i2c_write(adap,ENH_PLL,0X2C);
|
||||
#if 1 //20190117 增加每次上电初始化完之后复位decoder
|
||||
//复位Decoder
|
||||
vTaskDelay (200);
|
||||
ark7116_i2c_write(adap,DECODER_RST,0X03);
|
||||
vTaskDelay (10);
|
||||
ark7116_i2c_write(adap,DECODER_RST,0X02);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ark7116_init(void)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if (!(adap = i2c_open("i2c1"))) {
|
||||
printf("open i2c1 fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ARK7116_reset();
|
||||
|
||||
if(ConfigSlaveMode(adap) < 0)
|
||||
return -1;
|
||||
|
||||
InitGlobalPara(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,190 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "board.h"
|
||||
#include "sysinfo.h"
|
||||
#include "chip.h"
|
||||
|
||||
static const char* abort_status[][2]=
|
||||
{
|
||||
// IFSR status , DFSR status
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//0
|
||||
{"Unknown(reserved status)", "Alignment Fault" },//1
|
||||
{"Debug Event", "Debug Event" },//2
|
||||
{"Access flag - section", "Access flag - section" },//3
|
||||
{"Unknown(reserved status)", "Instruction cache maintenance" },//4
|
||||
{"Translation fault - section", "Translation fault - section" },//5
|
||||
{"Access flag - Page", "Access flag - Page" },//6
|
||||
{"Translation fault -Page", "Translation fault -Page" },//7
|
||||
{"Synchronous external abort", "Synchronous external abort, nontranslation" },//8
|
||||
{"Domain fault - Section", "Domain fault - Section" },//9
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//10
|
||||
{"Domain fault - Page", "Domain fault - Page" },//11
|
||||
{"Synchronous external abort - L1 Translation", "Synchronous external abort - L1 Translation" },//12
|
||||
{"Permission fault - Section", "Permission fault - Section" },//13
|
||||
{"Synchronous external abort - L2 Translation", "Synchronous external abort - L2 Translation" },//14
|
||||
{"Permission fault - Page", "Permission fault - Page" },//15
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//16
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//17
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//18
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//19
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//20
|
||||
{"Unknown(reserved status)", "Unknown(reserved status)" },//21
|
||||
{"Unknown(reserved status)", "Asynchronous external abort"}
|
||||
|
||||
};
|
||||
|
||||
void LowLevelInit( void )
|
||||
{
|
||||
}
|
||||
|
||||
void Abort_C_Handler( void)
|
||||
{
|
||||
uint32_t v1,v2, dfsr;
|
||||
v1= 0;
|
||||
v2= 0;
|
||||
asm("mrc p15, 0, %0, c5, c0, 0" : : "r"(v1));
|
||||
asm("mrc p15, 0, %0, c6, c0, 0" : : "r"(v2));
|
||||
|
||||
dfsr = ((v1 >> 4) & 0x0F);
|
||||
printf("\n\r######################################################################\n\r");
|
||||
printf("Data Abort occured in %x domain\n\r", (unsigned int)dfsr);
|
||||
dfsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
|
||||
printf("Data abort fault reason is: %s\n\r", (char*)abort_status[dfsr][1]);
|
||||
printf("Data fault occured at Address = 0x%08x\n\n\r",(unsigned int)v2);
|
||||
|
||||
|
||||
printf("-[Info]-Data fault status register value = 0x%x\n\r",(unsigned int)v1);
|
||||
|
||||
while(1);
|
||||
|
||||
}
|
||||
|
||||
void Prefetch_C_Handler( void)
|
||||
{
|
||||
uint32_t v1,v2, ifsr;
|
||||
v1= 0;
|
||||
v2= 0;
|
||||
|
||||
asm("mrc p15, 0, %0, c5, c0, 1" : : "r"(v1));
|
||||
asm("mrc p15, 0, %0, c6, c0, 2" : : "r"(v2));
|
||||
|
||||
ifsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
|
||||
printf("\n\r######################################################################\n\r");
|
||||
printf("Instruction prefetch abort reason is: %s\n\r", (char*)abort_status[ifsr][0]);
|
||||
printf("Instruction prefetch Fault occured at Address = 0x%08x\n\n\r",(unsigned int)v2);
|
||||
|
||||
printf("-[INFO]- Prefetch Fault status register value by = 0x%x\n\r",(unsigned int)v1);
|
||||
|
||||
while(1);
|
||||
|
||||
}
|
||||
|
||||
void Undefined_C_Handler( void)
|
||||
{
|
||||
printf("Undefined abort \n\r");
|
||||
while(1);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
VBUF_STATUS_FREE = 0,
|
||||
VBUF_STATUS_USED,
|
||||
VBUF_STATUS_RENDERED,
|
||||
} VIDEO_BUFFER_STATUS;
|
||||
|
||||
typedef struct {
|
||||
uint32_t addr;
|
||||
int status;
|
||||
}VideoBufInfo;
|
||||
|
||||
static SemaphoreHandle_t vdisbuf_mutex = NULL;
|
||||
static VideoBufInfo vdisbufs[VIDEO_DISPLAY_BUF_NUM] = {0};
|
||||
|
||||
void VideoDisplayBufInit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
vdisbuf_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
|
||||
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
|
||||
vdisbufs[i].addr = (uint32_t)pvPortMalloc(VIDEO_DISPLAY_WIDTH * VIDEO_DISPLAY_HEIGHT * 2);
|
||||
vdisbufs[i].status = VBUF_STATUS_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
int xVideoDisplayBufTake(uint32_t xTicksToWait)
|
||||
{
|
||||
return xSemaphoreTakeRecursive(vdisbuf_mutex, xTicksToWait);
|
||||
}
|
||||
|
||||
void vVideoDisplayBufGive(void)
|
||||
{
|
||||
xSemaphoreGiveRecursive(vdisbuf_mutex);
|
||||
}
|
||||
|
||||
uint32_t ulVideoDisplayBufGet(void)
|
||||
{
|
||||
uint32_t bufaddr = 0;
|
||||
int i;
|
||||
|
||||
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
|
||||
|
||||
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
|
||||
if (vdisbufs[i].status == VBUF_STATUS_FREE) {
|
||||
bufaddr = vdisbufs[i].addr;
|
||||
vdisbufs[i].status = VBUF_STATUS_USED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGiveRecursive(vdisbuf_mutex);
|
||||
|
||||
configASSERT(bufaddr != 0);
|
||||
|
||||
return bufaddr;
|
||||
}
|
||||
|
||||
uint32_t ulVideoDisplayBufGetSize(void)
|
||||
{
|
||||
return VIDEO_DISPLAY_WIDTH * VIDEO_DISPLAY_HEIGHT * 2;
|
||||
}
|
||||
|
||||
void vVideoDisplayBufRender(uint32_t buf_addr)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
|
||||
|
||||
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
|
||||
if (vdisbufs[i].addr == buf_addr) {
|
||||
for (j = 0; j < VIDEO_DISPLAY_BUF_NUM; j++) {
|
||||
if (vdisbufs[j].status == VBUF_STATUS_RENDERED)
|
||||
vdisbufs[j].status = VBUF_STATUS_FREE;
|
||||
}
|
||||
vdisbufs[i].status = VBUF_STATUS_RENDERED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGiveRecursive(vdisbuf_mutex);
|
||||
}
|
||||
|
||||
void vVideoDisplayBufFree(uint32_t buf_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
xSemaphoreTakeRecursive(vdisbuf_mutex, portMAX_DELAY);
|
||||
|
||||
for (i = 0; i < VIDEO_DISPLAY_BUF_NUM; i++) {
|
||||
if (vdisbufs[i].addr == buf_addr) {
|
||||
vdisbufs[i].status = VBUF_STATUS_FREE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGiveRecursive(vdisbuf_mutex);
|
||||
}
|
||||
|
||||
unsigned int ulVideoDisplayGetBufferAddr(int index)
|
||||
{
|
||||
configASSERT(index < VIDEO_DISPLAY_BUF_NUM);
|
||||
return vdisbufs[index].addr;
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
|
||||
static TaskHandle_t carback_task = NULL;
|
||||
//static SemaphoreHandle_t carback_mutex;
|
||||
static int carback_status = 0;
|
||||
|
||||
void notify_enter_carback(void)
|
||||
{
|
||||
if (carback_task)
|
||||
xTaskNotify(carback_task, 1, eSetValueWithOverwrite);
|
||||
}
|
||||
|
||||
void notify_exit_carback(void)
|
||||
{
|
||||
if (carback_task)
|
||||
xTaskNotify(carback_task, 0, eSetValueWithOverwrite);
|
||||
}
|
||||
|
||||
int get_carback_status(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
status = carback_status;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void carback_thread(void *param)
|
||||
{
|
||||
uint32_t ulNotifiedValue;
|
||||
|
||||
//carback_mutex = xSemaphoreCreateMutex();
|
||||
|
||||
#if defined(VIDEO_DECODER_RN6752)
|
||||
rn6752_init();
|
||||
#elif defined(VIDEO_DECODER_ARK7116)
|
||||
ark7116_init();
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
|
||||
0xffffffff, /* Reset the notification value to 0 on exit. */
|
||||
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
|
||||
portMAX_DELAY);
|
||||
|
||||
if (ulNotifiedValue && !carback_status) {
|
||||
printf("enter carback.\n");
|
||||
ItuConfigPara para = {0};
|
||||
|
||||
para.itu601 = 1;
|
||||
para.out_format = ITU_YUV420;
|
||||
para.yuv_type = ITU_Y_UV;
|
||||
para.in_width = VIN_WIDTH;
|
||||
para.in_height = VIN_HEIGHT;
|
||||
para.in_height = VIN_HEIGHT - 2;
|
||||
|
||||
#ifdef REVERSE_TRACK
|
||||
para.out_width = 704;
|
||||
para.out_height = 440;
|
||||
#else
|
||||
para.out_width = LCD_WIDTH;
|
||||
para.out_height = LCD_HEIGHT;
|
||||
#endif
|
||||
itu_config(¶);
|
||||
itu_start();
|
||||
carback_status = 1;
|
||||
} else if (!ulNotifiedValue && carback_status) {
|
||||
printf("exit carback.\n");
|
||||
itu_stop();
|
||||
carback_status = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void carback_test_thread(void *param)
|
||||
{
|
||||
for (;;) {
|
||||
vTaskDelay(pdMS_TO_TICKS(30000));
|
||||
notify_enter_carback();
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
notify_exit_carback();
|
||||
}
|
||||
}
|
||||
|
||||
int carback_init(void)
|
||||
{
|
||||
/* Create a task to play animation */
|
||||
if (xTaskCreate(carback_thread, "carback", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES - 3, &carback_task) != pdPASS) {
|
||||
printf("create carback task fail.\n");
|
||||
carback_task = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
xTaskCreate(carback_test_thread, "ctest", configMINIMAL_STACK_SIZE, NULL,
|
||||
configMAX_PRIORITIES / 2, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const unsigned int crc32_table[] =
|
||||
{
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
|
||||
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
|
||||
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
|
||||
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
|
||||
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
|
||||
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
|
||||
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
|
||||
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
|
||||
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
|
||||
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
|
||||
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
|
||||
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
|
||||
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
|
||||
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
|
||||
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
|
||||
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
|
||||
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
|
||||
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
|
||||
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
|
||||
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
|
||||
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
|
||||
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
|
||||
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
|
||||
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
|
||||
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
|
||||
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
|
||||
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
|
||||
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
|
||||
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
|
||||
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
|
||||
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
|
||||
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
|
||||
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
|
||||
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
|
||||
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
|
||||
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
|
||||
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
|
||||
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
|
||||
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
|
||||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
|
||||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
|
||||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
|
||||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
unsigned int
|
||||
xcrc32(const unsigned char *buf, int len, unsigned int init)
|
||||
{
|
||||
unsigned int crc = init;
|
||||
while (len--)
|
||||
{
|
||||
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
|
||||
buf++;
|
||||
}
|
||||
return crc;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#ifndef _CRC32_H
|
||||
#define _CRC32_H
|
||||
|
||||
unsigned int
|
||||
xcrc32(const unsigned char *buf, int len, unsigned int init);
|
||||
|
||||
#endif
|
@ -0,0 +1,723 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "soc-dai.h"
|
||||
|
||||
#if AUDIO_CODEC_ADC_IC == AUDIO_CODEC_ADC_ES7243E
|
||||
|
||||
/* Slave device address */
|
||||
#define ES7243E_SLAVE_ADDR 0x10
|
||||
|
||||
typedef enum adc_data_select {
|
||||
ADC_OUTPUT_L_R,
|
||||
ADC_OUTPUT_L_L,
|
||||
ADC_OUTPUT_R_R,
|
||||
ADC_OUTPUT_R_L
|
||||
} adc_data_sel;
|
||||
|
||||
typedef enum adc_polarity_invert {
|
||||
ADC_INV_NORMAL,
|
||||
ADC_R_INV,
|
||||
ADC_L_INV,
|
||||
ADC_LR_INV
|
||||
} adc_pol_inv;
|
||||
|
||||
|
||||
struct _coeff_div {
|
||||
u32 mclk; //mclk frequency
|
||||
u32 sr_rate; //sample rate
|
||||
u8 osr; //adc over sample rate
|
||||
u8 prediv_premulti; //adcclk and dacclk divider
|
||||
u8 cf_dsp_div; //adclrck divider and daclrck divider
|
||||
u8 scale;
|
||||
u8 lrckdiv_h;
|
||||
u8 lrckdiv_l;
|
||||
u8 bclkdiv; //sclk divider
|
||||
};
|
||||
|
||||
typedef struct _adc_private {
|
||||
adc_data_sel adc_data_sel;
|
||||
adc_pol_inv adc_inv;
|
||||
} adc_private;
|
||||
|
||||
typedef struct es7243e_private_data {
|
||||
struct i2c_adapter *adap;
|
||||
unsigned short slave_addr;
|
||||
int rates;
|
||||
int channels;
|
||||
int bits;
|
||||
int master;
|
||||
int mclk;
|
||||
int fmt;
|
||||
int mute;
|
||||
adc_private adc_priv;
|
||||
} es7243e_client;
|
||||
|
||||
static int es7243e_mute(int mute);
|
||||
|
||||
static es7243e_client *g_es7243e_client = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* es7243e_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to read from.
|
||||
* @buf: raw write data buffer.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int es7243e_i2c_read(es7243e_client *client, uint8_t reg)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
uint8_t wbuf[2];
|
||||
uint8_t rbuf = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
wbuf[0] = reg;
|
||||
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].addr = client->slave_addr;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = wbuf;
|
||||
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = client->slave_addr;
|
||||
msgs[1].len = 1;
|
||||
msgs[1].buf = &rbuf;
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
ret = i2c_transfer(client->adap, msgs, 2);
|
||||
if(ret == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret==ARRAY_SIZE(msgs)) ? rbuf : -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* es7243e_i2c_write - write data to a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to write to.
|
||||
* @buf: raw data buffer to write.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int es7243e_i2c_write(es7243e_client *client, uint8_t reg, uint8_t val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
uint8_t addr_buf[2];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
addr_buf[0] = reg;
|
||||
addr_buf[1] = val;
|
||||
|
||||
msg.flags = 0;
|
||||
msg.addr = client->slave_addr;
|
||||
msg.buf = addr_buf;
|
||||
msg.len = 2;
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
ret = i2c_transfer(client->adap, &msg, 1);
|
||||
if(ret == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("reg[0x%x], val:0x%x, read:0x%x\n", reg, val, es7243e_i2c_read(client, reg));
|
||||
|
||||
return (ret != 1 ? -EIO : 0);
|
||||
}
|
||||
|
||||
int es7243e_i2c_write_bits(es7243e_client *client, u8 reg, u8 mask, u8 offset, u8 val)
|
||||
{
|
||||
int value = es7243e_i2c_read(client, reg);
|
||||
if(value < 0)
|
||||
{
|
||||
printf("%s read failed, reg:0x%x, val:0x%x\n", __func__, reg, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
value &= ~(mask << offset);
|
||||
value |= (val << offset);
|
||||
if(es7243e_i2c_write(client, reg, value&0xFF))
|
||||
{
|
||||
printf("%s write failed, reg:0x%x, val:0x%x\n", __func__, reg, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* codec mclk clock divider coefficients */
|
||||
static const struct _coeff_div coeff_div[] = {
|
||||
//mclk lrck, osr, pre, div ,scale, lrckdiv_h, lrckdiv_l, bclkdiv
|
||||
/* 24.576MHZ */
|
||||
{24576000, 8000 , 0x20, 0x50, 0x00, 0x00, 0x0b, 0xff, 0x2f},
|
||||
{24576000, 12000, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
|
||||
{24576000, 16000, 0x20, 0x20, 0x00, 0x00, 0x05, 0xff, 0x17},
|
||||
{24576000, 24000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{24576000, 32000, 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
|
||||
{24576000, 48000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
/* 12.288MHZ */
|
||||
{12288000, 8000 , 0x20, 0x20, 0x00, 0x00, 0x05, 0xff, 0x17},
|
||||
{12288000, 12000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{12288000, 16000, 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
|
||||
{12288000, 24000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{12288000, 32000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
|
||||
{12288000, 48000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
/* 6.144MHZ */
|
||||
{6144000 , 8000 , 0x20, 0x21, 0x00, 0x00, 0x02, 0xff, 0x0b},
|
||||
{6144000 , 12000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{6144000 , 16000, 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
|
||||
{6144000 , 24000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{6144000 , 32000, 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
|
||||
{6144000 , 48000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
/* 3.072MHZ */
|
||||
{3072000 , 8000 , 0x20, 0x22, 0x00, 0x00, 0x01, 0x7f, 0x05},
|
||||
{3072000 , 12000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{3072000 , 16000, 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
|
||||
{3072000 , 24000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{3072000 , 32000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x5f, 0x02},
|
||||
{3072000 , 48000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
/* 1.536MHZ */
|
||||
{1536000 , 8000 , 0x20, 0x23, 0x00, 0x00, 0x00, 0xbf, 0x02},
|
||||
{1536000 , 12000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{1536000 , 16000, 0x10, 0x03, 0x20, 0x04, 0x00, 0x5f, 0x00},
|
||||
{1536000 , 24000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
|
||||
/* 32.768MHZ */
|
||||
{32768000, 8000 , 0x20, 0x70, 0x00, 0x00, 0x0f, 0xff, 0x3f},
|
||||
{32768000, 16000, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
|
||||
{32768000, 32000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
/* 16.384MHZ */
|
||||
{16384000, 8000 , 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
|
||||
{16384000, 16000, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{16384000, 32000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
/* 8.192MHZ */
|
||||
{8192000 , 8000 , 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{8192000 , 16000, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{8192000 , 32000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
/* 4.096MHZ */
|
||||
{4096000 , 8000 , 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{4096000 , 16000, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{4096000 , 32000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
/* 2.048MHZ */
|
||||
{2048000 , 8000 , 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{2048000 , 16000, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{2048000 , 32000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
/* 1.024MHZ */
|
||||
{1024000 , 8000 , 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{1024000 , 16000, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
|
||||
/* 22.5792MHz */
|
||||
{22579200, 11025, 0x20, 0x30, 0x00, 0x00, 0x07, 0xff, 0x1f},
|
||||
{22579200, 22050, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{22579200, 44100, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
/* 11.2896MHz */
|
||||
{11289600, 11025, 0x20, 0x10, 0x00, 0x00, 0x03, 0xff, 0x0f},
|
||||
{11289600, 22050, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{11289600, 44100, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
/* 5.6448MHz */
|
||||
{56448000, 11025, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0x07},
|
||||
{56448000, 22050, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{56448000, 44100, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
/* 2.8224MHz */
|
||||
{28224000, 11025, 0x20, 0x01, 0x00, 0x00, 0x00, 0xff, 0x03},
|
||||
{28224000, 22050, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{28224000, 44100, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
/* 1.4112MHz */
|
||||
{14112000, 11025, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x01},
|
||||
{14112000, 22050, 0x20, 0x03, 0x00, 0x00, 0x00, 0x3f, 0x00},
|
||||
};
|
||||
|
||||
static inline int get_coeff(int mclk, int rate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
|
||||
if (coeff_div[i].sr_rate == rate && coeff_div[i].mclk == mclk) {
|
||||
printf("%s() get_coeff find index:%d\n", __func__, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
printf("%s() get_coeff not find\n", __func__);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int es7243e_pcm_hw_params(es7243e_client *client)
|
||||
{
|
||||
u8 regv;
|
||||
int coeff;
|
||||
|
||||
#if 1
|
||||
coeff = get_coeff(client->mclk, client->rates);
|
||||
|
||||
if(coeff < 0)
|
||||
{
|
||||
printf("Unable to configure sample rate %dHz with %dHz MCLK", client->rates, client->mclk);
|
||||
return coeff;
|
||||
}
|
||||
|
||||
/*
|
||||
* set clock parameters
|
||||
*/
|
||||
//printf("%s():coeff = %d\n",__func__, coeff);
|
||||
if(coeff >= 0)
|
||||
{
|
||||
es7243e_i2c_write(client, 0x03, coeff_div[coeff].osr);
|
||||
es7243e_i2c_write(client, 0x04, coeff_div[coeff].prediv_premulti);
|
||||
es7243e_i2c_write(client, 0x05, coeff_div[coeff].cf_dsp_div);
|
||||
es7243e_i2c_write_bits(client, 0x0D, 0x07, 0, coeff_div[coeff].scale);
|
||||
es7243e_i2c_write(client, 0x03, coeff_div[coeff].osr);
|
||||
es7243e_i2c_write_bits(client, 0x07, 0x0F, 0, coeff_div[coeff].lrckdiv_h & 0x0f);
|
||||
es7243e_i2c_write(client, 0x06, coeff_div[coeff].bclkdiv);
|
||||
//es7243e_i2c_write(client, 0x06, 0x07);//BCLK:1.536
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1//add-
|
||||
regv = es7243e_i2c_read(client, 0x0B);
|
||||
regv &= 0xe3;
|
||||
|
||||
switch (client->bits)
|
||||
{
|
||||
case 16:
|
||||
regv |= 0x0c;
|
||||
break;
|
||||
case 20:
|
||||
regv |= 0x04;
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
case 32:
|
||||
regv |= 0x10;
|
||||
break;
|
||||
default:
|
||||
regv |= 0x0c;
|
||||
break;
|
||||
}
|
||||
es7243e_i2c_write(client, 0x0B, regv);
|
||||
|
||||
/*
|
||||
* unmute SDP for MT8516 and MT8167 platform
|
||||
*/
|
||||
msleep(500);
|
||||
es7243e_mute(1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_set_bias_level(es7243e_client *client, enum snd_soc_bias_level level)
|
||||
{
|
||||
u8 regv;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
printf("%s on\n", __func__);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
printf("%s prepare\n", __func__);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
printf("%s standby\n", __func__);
|
||||
/*
|
||||
* enable clock
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x01);
|
||||
regv |= 0x0A;
|
||||
es7243e_i2c_write(client, 0x01, regv);
|
||||
es7243e_i2c_write(client, 0x16, 0x00); //power up analog
|
||||
/*
|
||||
* enable mic input 1
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x20);
|
||||
regv |= 0x10;
|
||||
es7243e_i2c_write(client, 0x20, regv);
|
||||
/*
|
||||
* enable mic input 2
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x21);
|
||||
regv |= 0x10;
|
||||
es7243e_i2c_write(client, 0x21, regv);
|
||||
msleep(100);
|
||||
es7243e_mute(0);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
printf("%s off\n", __func__);
|
||||
es7243e_mute(1);
|
||||
/*
|
||||
* disable mic input 1
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x20);
|
||||
regv &= 0xef;
|
||||
es7243e_i2c_write(client, 0x20, regv);
|
||||
/*
|
||||
* disable mic input 2
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x21);
|
||||
regv &= 0xef;
|
||||
es7243e_i2c_write(client, 0x21, regv);
|
||||
|
||||
es7243e_i2c_write(client, 0x16, 0xff); //power down analog
|
||||
|
||||
/*
|
||||
* disable clock
|
||||
*/
|
||||
regv = es7243e_i2c_read(client, 0x01);
|
||||
regv &= 0xf5;
|
||||
es7243e_i2c_write(client, 0x01, regv);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int es7243e_init_regs(es7243e_client *client)
|
||||
{
|
||||
if(client->master)
|
||||
{
|
||||
//ES7243e master mode
|
||||
es7243e_i2c_write(client, 0x01, 0x3A);
|
||||
es7243e_i2c_write(client, 0x00, 0x80);
|
||||
es7243e_i2c_write(client, 0x04, 0x02);
|
||||
es7243e_i2c_write(client, 0x04, 0x01);
|
||||
es7243e_i2c_write(client, 0xF9, 0x01);
|
||||
|
||||
es7243e_i2c_write(client, 0x00, 0x1E);
|
||||
es7243e_i2c_write(client, 0x01, 0x00);
|
||||
es7243e_i2c_write(client, 0x02, 0x00); //default:0x00 (0x01 :BCLK invert)
|
||||
es7243e_i2c_write(client, 0x03, 0x20);
|
||||
//es7243e_i2c_write(client, 0x0D, 0x40);//default:0x00 (settable:0x40 0x80)
|
||||
es7243e_i2c_write_bits(client, 0x0D, 0x0f, 4, (client->adc_priv.adc_data_sel<<2) | client->adc_priv.adc_inv);
|
||||
es7243e_i2c_write(client, 0xF9, 0x00);
|
||||
es7243e_i2c_write(client, 0x04, 0x02);
|
||||
es7243e_i2c_write(client, 0x04, 0x01);
|
||||
es7243e_i2c_write(client, 0x05, 0x00);
|
||||
//es7243e_i2c_write(client, 0x06, 0x07);//test: set BCLK 1.536M
|
||||
es7243e_i2c_write(client, 0x07, 0x00);//default:0x00 0x02
|
||||
es7243e_i2c_write(client, 0x08, 0xFF);//default:0xFF
|
||||
es7243e_i2c_write(client, 0x09, 0xC5);
|
||||
es7243e_i2c_write(client, 0x0A, 0x81);
|
||||
es7243e_i2c_write(client, 0x0B, 0x0C);//default:0x00(24bit) 0x0c(16 bit) add:0x0d 20210722
|
||||
es7243e_i2c_write(client, 0x0E, 0xBF);
|
||||
es7243e_i2c_write(client, 0x0F, 0x80);
|
||||
es7243e_i2c_write(client, 0x14, 0x0C);
|
||||
es7243e_i2c_write(client, 0x15, 0x0C);
|
||||
es7243e_i2c_write(client, 0x17, 0x02);
|
||||
es7243e_i2c_write(client, 0x18, 0x26);
|
||||
es7243e_i2c_write(client, 0x19, 0x77);
|
||||
es7243e_i2c_write(client, 0x1A, 0xF4);
|
||||
es7243e_i2c_write(client, 0x1B, 0x66);
|
||||
es7243e_i2c_write(client, 0x1C, 0x44);
|
||||
es7243e_i2c_write(client, 0x1E, 0x00);
|
||||
es7243e_i2c_write(client, 0x1F, 0x0C);
|
||||
es7243e_i2c_write(client, 0x20, 0x1c);//default:0x19 Analog gain(min:0x01 max:0x1e)
|
||||
es7243e_i2c_write(client, 0x21, 0x1c);//default:0x19 Analog gain(min:0x01 max:0x1e)
|
||||
es7243e_i2c_write(client, 0x00, 0xC0);
|
||||
es7243e_i2c_write(client, 0x01, 0x3A);
|
||||
es7243e_i2c_write(client, 0x16, 0x3F);
|
||||
es7243e_i2c_write(client, 0x16, 0x00);
|
||||
es7243e_i2c_write(client, 0x13, 0x3f);//add
|
||||
es7243e_i2c_write(client, 0x0f, 0x40);//add
|
||||
}
|
||||
else
|
||||
{
|
||||
//ES7243e slave mode
|
||||
es7243e_i2c_write(client, 0x01, 0x3A);
|
||||
es7243e_i2c_write(client, 0x00, 0x80);
|
||||
es7243e_i2c_write(client, 0x04, 0x02);
|
||||
es7243e_i2c_write(client, 0x04, 0x01);
|
||||
es7243e_i2c_write(client, 0xF9, 0x01);
|
||||
|
||||
es7243e_i2c_write(client, 0x00, 0x1E);
|
||||
es7243e_i2c_write(client, 0x01, 0x00);
|
||||
es7243e_i2c_write(client, 0x02, 0x00);
|
||||
es7243e_i2c_write(client, 0x03, 0x20);
|
||||
//es7243e_i2c_write(client, 0x0D, 0x00);
|
||||
es7243e_i2c_write_bits(client, 0x0D, 0x0f, 4, (client->adc_priv.adc_data_sel<<2) | client->adc_priv.adc_inv);
|
||||
es7243e_i2c_write(client, 0xF9, 0x00);
|
||||
es7243e_i2c_write(client, 0x04, 0x02);
|
||||
es7243e_i2c_write(client, 0x04, 0x01);
|
||||
es7243e_i2c_write(client, 0x05, 0x00);
|
||||
es7243e_i2c_write(client, 0x07, 0x00);//add
|
||||
es7243e_i2c_write(client, 0x09, 0xC5);
|
||||
es7243e_i2c_write(client, 0x0A, 0x81);
|
||||
es7243e_i2c_write(client, 0x0b, 0x00);
|
||||
es7243e_i2c_write(client, 0x0E, 0xBF);
|
||||
es7243e_i2c_write(client, 0x0F, 0x80);
|
||||
es7243e_i2c_write(client, 0x14, 0x0C);
|
||||
es7243e_i2c_write(client, 0x15, 0x0C);
|
||||
es7243e_i2c_write(client, 0x17, 0x02);//add
|
||||
es7243e_i2c_write(client, 0x18, 0x26);
|
||||
es7243e_i2c_write(client, 0x19, 0x77);
|
||||
es7243e_i2c_write(client, 0x1A, 0xF4);
|
||||
es7243e_i2c_write(client, 0x1B, 0x66);
|
||||
es7243e_i2c_write(client, 0x1C, 0x44);
|
||||
es7243e_i2c_write(client, 0x1E, 0x00);
|
||||
es7243e_i2c_write(client, 0x1F, 0x0C);
|
||||
es7243e_i2c_write(client, 0x20, 0x19);
|
||||
es7243e_i2c_write(client, 0x21, 0x19);
|
||||
es7243e_i2c_write(client, 0x00, 0x80);
|
||||
es7243e_i2c_write(client, 0x01, 0x3A);
|
||||
es7243e_i2c_write(client, 0x16, 0x3F);
|
||||
es7243e_i2c_write(client, 0x16, 0x00);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_set_fmt(unsigned int fmt)
|
||||
{
|
||||
u8 iface = 0;
|
||||
u8 adciface = 0;
|
||||
u8 clksel = 0;
|
||||
|
||||
es7243e_client *client = g_es7243e_client;
|
||||
if(!client)
|
||||
{
|
||||
printf("%s(), Invalid client\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
adciface = es7243e_i2c_read(client, 0x0B); //get interface format
|
||||
iface = es7243e_i2c_read(client, 0x00); //get spd interface
|
||||
clksel = es7243e_i2c_read(client, 0x02); //get spd interface
|
||||
|
||||
/* set master/slave audio interface */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)
|
||||
{
|
||||
case SND_SOC_DAIFMT_CBM_CFM: // MASTER MODE
|
||||
printf("Enter into %s(), I2S master\n", __func__);
|
||||
iface |= 0x40;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS: // SLAVE MODE
|
||||
printf("Enter into %s(), I2S slave\n", __func__);
|
||||
iface &= 0xbf;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* interface format */
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
|
||||
{
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
printf("Enter into %s(), I2S format \n", __func__);
|
||||
adciface &= 0xFC;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
return -EINVAL;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
printf("Enter into %s(), LJ format \n", __func__);
|
||||
adciface &= 0xFC;
|
||||
adciface |= 0x01;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
printf("Enter into %s(), DSP-A format \n", __func__);
|
||||
adciface &= 0xDC;
|
||||
adciface |= 0x03;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
printf("Enter into %s(), DSP-B format \n", __func__);
|
||||
adciface &= 0xDC;
|
||||
adciface |= 0x23;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clock inversion */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK)
|
||||
{
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
printf("Enter into %s(), BCLK noinvert, MCLK noinvert \n", __func__);
|
||||
adciface &= 0xdf;
|
||||
clksel &= 0xfe;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
printf("Enter into %s(), BCLK invert, MCLK invert \n", __func__);
|
||||
adciface |= 0x20;
|
||||
clksel |= 0x01;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
printf("Enter into %s(), BCLK invert, MCLK noinvert \n", __func__);
|
||||
adciface &= 0xdf;
|
||||
clksel |= 0x01;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
printf("Enter into %s(), BCLK noinvert, MCLK invert \n", __func__);
|
||||
adciface |= 0x20;
|
||||
clksel &= 0xfe;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
es7243e_i2c_write(client, 0x00, iface);
|
||||
es7243e_i2c_write(client, 0x02, clksel);
|
||||
es7243e_i2c_write(client, 0x0B, adciface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_mute(int mute)
|
||||
{
|
||||
es7243e_client *client = g_es7243e_client;
|
||||
if(!client)
|
||||
{
|
||||
printf("%s(), Invalid client\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%s %d\n", __func__, mute);
|
||||
if (mute)
|
||||
{
|
||||
es7243e_i2c_write_bits(client, 0x0B, 0x3, 6, 0x3);
|
||||
client->mute = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
es7243e_i2c_write_bits(client, 0x0B, 0x3, 6, 0x0);
|
||||
client->mute = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_set_mclk(int freq, int dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_hw_params(struct snd_soc_hw_params *params)
|
||||
{
|
||||
es7243e_client *client = g_es7243e_client;
|
||||
if(!client)
|
||||
{
|
||||
printf("%s(), Invalid client\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!params)
|
||||
{
|
||||
printf("%s(), Invalid params\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->rates = params->rates;
|
||||
client->channels = params->channels;
|
||||
client->bits = params->bits;
|
||||
client->mclk = client->rates * 256;
|
||||
|
||||
es7243e_set_bias_level(client, SND_SOC_BIAS_OFF);
|
||||
|
||||
es7243e_pcm_hw_params(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_startup(int start)
|
||||
{
|
||||
es7243e_client *client = g_es7243e_client;
|
||||
if(!client)
|
||||
{
|
||||
printf("%s(), Invalid client\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(start)
|
||||
es7243e_set_bias_level(client, SND_SOC_BIAS_STANDBY);
|
||||
else
|
||||
es7243e_set_bias_level(client, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_hw_init(int master)
|
||||
{
|
||||
es7243e_client *client = g_es7243e_client;
|
||||
if(!client)
|
||||
{
|
||||
printf("%s(), Invalid client\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->master = !!master;
|
||||
client->fmt = SND_SOC_DAIFMT_I2S; //interface type.
|
||||
client->fmt |= SND_SOC_DAIFMT_NB_NF; //normal bclk + normal frame.
|
||||
client->fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
|
||||
if(client->master)
|
||||
client->fmt |= SND_SOC_DAIFMT_CBM_CFM; //master
|
||||
else
|
||||
client->fmt |= SND_SOC_DAIFMT_CBS_CFS; //slave
|
||||
|
||||
client->adc_priv.adc_data_sel = ADC_OUTPUT_L_R;
|
||||
client->adc_priv.adc_inv = ADC_INV_NORMAL;
|
||||
|
||||
es7243e_init_regs(client);
|
||||
|
||||
es7243e_set_fmt(client->fmt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es7243e_reset(es7243e_client *client)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int es7243e_probe(struct i2c_adapter *adap, struct snd_soc_dai_ops *ops)
|
||||
{
|
||||
es7243e_client *client;
|
||||
|
||||
client = pvPortMalloc(sizeof(es7243e_client));
|
||||
if (!client)
|
||||
{
|
||||
printf("%s, pvPortMalloc fail.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(client, 0, sizeof(es7243e_client));
|
||||
g_es7243e_client = client;
|
||||
|
||||
client->adap = adap;
|
||||
client->slave_addr = ES7243E_SLAVE_ADDR;
|
||||
|
||||
if(ops)
|
||||
{
|
||||
ops->init = es7243e_hw_init;
|
||||
ops->hw_params = es7243e_hw_params;
|
||||
ops->startup = es7243e_startup;
|
||||
ops->set_fmt = es7243e_set_fmt;
|
||||
ops->set_mute = es7243e_mute;
|
||||
ops->set_mclk = es7243e_set_mclk;
|
||||
}
|
||||
|
||||
es7243e_reset(client);
|
||||
|
||||
es7243e_mute(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_codec_adc_init(struct snd_soc_dai_ops *ops)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if (!(adap = i2c_open("i2c0"))) {
|
||||
printf("%s, open i2c0 fail.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return es7243e_probe(adap, ops);
|
||||
}
|
||||
#endif
|
@ -0,0 +1,229 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "soc-dai.h"
|
||||
|
||||
|
||||
#if AUDIO_CODEC_DAC_IC == AUDIO_CODEC_DAC_ES8156
|
||||
/* Reset Control */
|
||||
#define ES8156_RESET_REG00 0x00
|
||||
/* Clock Managerment */
|
||||
#define ES8156_MAINCLOCK_CTL_REG01 0x01
|
||||
#define ES8156_SCLK_MODE_REG02 0x02
|
||||
#define ES8156_LRCLK_DIV_H_REG03 0x03
|
||||
#define ES8156_LRCLK_DIV_L_REG04 0x04
|
||||
#define ES8156_SCLK_DIV_REG05 0x05
|
||||
#define ES8156_NFS_CONFIG_REG06 0x06
|
||||
#define ES8156_MISC_CONTROL1_REG07 0x07
|
||||
#define ES8156_CLOCK_ON_OFF_REG08 0x08
|
||||
#define ES8156_MISC_CONTROL2_REG09 0x09
|
||||
#define ES8156_TIME_CONTROL1_REG0A 0x0a
|
||||
#define ES8156_TIME_CONTROL2_REG0B 0x0b
|
||||
/* System Control */
|
||||
#define ES8156_CHIP_STATUS_REG0C 0x0c
|
||||
#define ES8156_P2S_CONTROL_REG0D 0x0d
|
||||
#define ES8156_DAC_OSR_COUNTER_REG10 0x10
|
||||
/* SDP Control */
|
||||
#define ES8156_DAC_SDP_REG11 0x11
|
||||
#define ES8156_AUTOMUTE_SET_REG12 0x12
|
||||
#define ES8156_DAC_MUTE_REG13 0x13
|
||||
#define ES8156_VOLUME_CONTROL_REG14 0x14
|
||||
|
||||
/* ALC Control */
|
||||
#define ES8156_ALC_CONFIG1_REG15 0x15
|
||||
#define ES8156_ALC_CONFIG2_REG16 0x16
|
||||
#define ES8156_ALC_CONFIG3_REG17 0x17
|
||||
#define ES8156_MISC_CONTROL3_REG18 0x18
|
||||
#define ES8156_EQ_CONTROL1_REG19 0x19
|
||||
#define ES8156_EQ_CONTROL2_REG1A 0x1a
|
||||
/* Analog System Control */
|
||||
#define ES8156_ANALOG_SYS1_REG20 0x20
|
||||
#define ES8156_ANALOG_SYS2_REG21 0x21
|
||||
#define ES8156_ANALOG_SYS3_REG22 0x22
|
||||
#define ES8156_ANALOG_SYS4_REG23 0x23
|
||||
#define ES8156_ANALOG_LP_REG24 0x24
|
||||
#define ES8156_ANALOG_SYS5_REG25 0x25
|
||||
/* Chip Information */
|
||||
#define ES8156_I2C_PAGESEL_REGFC 0xFC
|
||||
#define ES8156_CHIPID1_REGFD 0xFD
|
||||
#define ES8156_CHIPID0_REGFE 0xFE
|
||||
#define ES8156_CHIP_VERSION_REGFF 0xFF
|
||||
|
||||
/* Slave device address */
|
||||
#define ES8156_SLAVE_ADDR 0x09
|
||||
|
||||
|
||||
typedef struct es8156_private_data {
|
||||
struct i2c_adapter *adap;
|
||||
unsigned short slave_addr;
|
||||
int rates;
|
||||
int channels;
|
||||
int bits;
|
||||
int master;
|
||||
int mclk;
|
||||
int fmt;
|
||||
int mute;
|
||||
} es8156_client;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* es8156_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to read from.
|
||||
* @buf: raw write data buffer.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int es8156_i2c_read(es8156_client *client, uint8_t reg)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
uint8_t wbuf[2];
|
||||
uint8_t rbuf = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
wbuf[0] = reg;
|
||||
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].addr = client->slave_addr;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = wbuf;
|
||||
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = client->slave_addr;
|
||||
msgs[1].len = 1;
|
||||
msgs[1].buf = &rbuf;
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
ret = i2c_transfer(client->adap, msgs, 2);
|
||||
if(ret == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret==ARRAY_SIZE(msgs)) ? rbuf : -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* es8156_i2c_write - write data to a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to write to.
|
||||
* @buf: raw data buffer to write.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int es8156_i2c_write(es8156_client *client, uint8_t reg, uint8_t val)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
uint8_t addr_buf[2];
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
addr_buf[0] = reg;
|
||||
addr_buf[1] = val;
|
||||
|
||||
msg.flags = 0;
|
||||
msg.addr = client->slave_addr;
|
||||
msg.buf = addr_buf;
|
||||
msg.len = 2;
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
ret = i2c_transfer(client->adap, &msg, 1);
|
||||
if(ret == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
printf("reg[0x%x], val:0x%x, read:0x%x\n", reg, val, es8156_i2c_read(client, reg));
|
||||
|
||||
return (ret != 1 ? -EIO : 0);
|
||||
}
|
||||
|
||||
int es8156_i2c_write_bits(es8156_client *client, u8 reg, u8 mask, u8 offset, u8 value)
|
||||
{
|
||||
int val = es8156_i2c_read(client, reg);
|
||||
if(val < 0)
|
||||
{
|
||||
printf("%s read failed, reg:0x%x, val:0x%x\n", __func__, reg, val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
val &= ~(mask << offset);
|
||||
val |= (value << offset);
|
||||
if(es8156_i2c_write(client, reg, val))
|
||||
{
|
||||
printf("%s write failed, reg:0x%x, val:0x%x\n", __func__, reg, val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8156_reset(es8156_client *client)
|
||||
{
|
||||
es8156_i2c_write(client, ES8156_RESET_REG00, 0x1c);
|
||||
mdelay(5);
|
||||
es8156_i2c_write(client, ES8156_RESET_REG00, 0x03);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8156_probe(struct i2c_adapter *adap, struct snd_soc_dai_ops *ops)
|
||||
{
|
||||
es8156_client *client;
|
||||
|
||||
client = pvPortMalloc(sizeof(es8156_client));
|
||||
if (!client)
|
||||
{
|
||||
printf("%s, pvPortMalloc fail.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(client, 0, sizeof(es8156_client));
|
||||
|
||||
#if 0 //set default value;
|
||||
client->rates = 44100;
|
||||
client->channels = 2;
|
||||
client->bits = 16;
|
||||
client->mute = 0;
|
||||
client->master = 1;
|
||||
client->mclk = client->rates * 256;
|
||||
client->fmt = SND_SOC_DAIFMT_I2S; //interface type.
|
||||
#endif
|
||||
|
||||
if(ops)
|
||||
{
|
||||
//es8156 Free Driver(免驱).
|
||||
//ops->init =;
|
||||
//ops->hw_params =;
|
||||
//ops->startup =;
|
||||
//ops->set_fmt =;
|
||||
//ops->set_mute =;
|
||||
//ops->set_mclk =;
|
||||
}
|
||||
|
||||
//es8156_reset(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int audio_codec_dac_init(struct snd_soc_dai_ops *ops)
|
||||
{
|
||||
(void)ops;
|
||||
#if 0 //es8156 no need driver.
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if (!(adap = i2c_open("i2c0"))) {
|
||||
printf("%s, open i2c0 fail.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
es8156_probe(adap, ops);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,102 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
|
||||
#ifdef I2C_EEPROM_SLAVE_DEMO
|
||||
#if !defined(I2C0_SLAVE_MODE) && !defined(I2C1_SLAVE_MODE)
|
||||
#error "i2c eeprom slave demo needs a slave mode i2c dev"
|
||||
#endif
|
||||
|
||||
#define I2C_EEPROM_24C02_ADDR 0x50
|
||||
#define I2C_EEPROM_24C02_SIZE 256
|
||||
|
||||
struct eeprom_data {
|
||||
bool first_write;
|
||||
u8 buffer_idx;
|
||||
u8 buffer[];
|
||||
};
|
||||
|
||||
static struct eeprom_data *g_eeprom = NULL;
|
||||
static struct i2c_adapter *g_adap = NULL;
|
||||
|
||||
static int i2c_slave_eeprom_slave_cb(struct i2c_adapter *adap,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
{
|
||||
struct eeprom_data *eeprom = g_eeprom;
|
||||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_WRITE_RECEIVED:
|
||||
if (eeprom->first_write) {
|
||||
eeprom->buffer_idx = *val;
|
||||
eeprom->first_write = false;
|
||||
} else {
|
||||
eeprom->buffer[eeprom->buffer_idx++] = *val;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_READ_REQUESTED:
|
||||
*val = eeprom->buffer[eeprom->buffer_idx++];
|
||||
/*
|
||||
* Do not increment buffer_idx here, because we don't know if
|
||||
* this byte will be actually used. Read Linux I2C slave docs
|
||||
* for details.
|
||||
*/
|
||||
break;
|
||||
|
||||
case I2C_SLAVE_STOP:
|
||||
case I2C_SLAVE_WRITE_REQUESTED:
|
||||
eeprom->first_write = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_slave_eeprom_init(void)
|
||||
{
|
||||
struct eeprom_data *eeprom;
|
||||
int ret;
|
||||
unsigned size = I2C_EEPROM_24C02_SIZE;
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
eeprom = pvPortMalloc(sizeof(struct eeprom_data) + size);
|
||||
if (!eeprom)
|
||||
return -ENOMEM;
|
||||
g_eeprom = eeprom;
|
||||
|
||||
eeprom->first_write = true;
|
||||
#ifdef I2C0_SLAVE_MODE
|
||||
adap = i2c_open("i2c0");
|
||||
#else
|
||||
adap = i2c_open("i2c1");
|
||||
#endif
|
||||
if (!adap) {
|
||||
printf("%s open i2c fail.\n", __func__);
|
||||
vPortFree(eeprom);
|
||||
return -1;
|
||||
}
|
||||
g_adap = adap;
|
||||
|
||||
ret = i2c_slave_register(adap, I2C_EEPROM_24C02_ADDR, i2c_slave_eeprom_slave_cb);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
int i2c_slave_eeprom_uninit(void)
|
||||
{
|
||||
if (g_adap)
|
||||
i2c_slave_unregister(g_adap);
|
||||
|
||||
if (g_eeprom)
|
||||
vPortFree(g_eeprom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,251 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "keypad.h"
|
||||
|
||||
#if !defined(VG_ONLY) && !defined(AWTK)
|
||||
#include "lvgl/lvgl.h"
|
||||
#else
|
||||
typedef int16_t lv_coord_t;
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
typedef struct {
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
|
||||
|
||||
enum {
|
||||
LV_KEY_UP = 17, /*0x11*/
|
||||
LV_KEY_DOWN = 18, /*0x12*/
|
||||
LV_KEY_RIGHT = 19, /*0x13*/
|
||||
LV_KEY_LEFT = 20, /*0x14*/
|
||||
LV_KEY_ESC = 27, /*0x1B*/
|
||||
LV_KEY_DEL = 127, /*0x7F*/
|
||||
LV_KEY_BACKSPACE = 8, /*0x08*/
|
||||
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
|
||||
LV_KEY_NEXT = 9, /*0x09, '\t'*/
|
||||
LV_KEY_PREV = 11, /*0x0B, '*/
|
||||
LV_KEY_HOME = 2, /*0x02, STX*/
|
||||
LV_KEY_END = 3, /*0x03, ETX*/
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
} lv_indev_data_t;
|
||||
#endif
|
||||
|
||||
#define KEYAD_1 10
|
||||
#define KEYAD_2 530
|
||||
#define KEYAD_3 1150
|
||||
#define KEYAD_4 1665
|
||||
#define KEYAD_5 2278
|
||||
#define KEYAD_6 2845
|
||||
#define KEYAD_7 3372
|
||||
#define KEYAD_NUM 7
|
||||
|
||||
#define KEYAD_RANGE 10
|
||||
|
||||
|
||||
static int KeyAdcValue[KEYAD_NUM] =
|
||||
{
|
||||
KEYAD_1,
|
||||
KEYAD_2,
|
||||
KEYAD_3,
|
||||
KEYAD_4,
|
||||
KEYAD_5,
|
||||
KEYAD_6,
|
||||
KEYAD_7,
|
||||
};
|
||||
|
||||
static unsigned int KeypadMap[KEYAD_NUM] =
|
||||
{
|
||||
LV_KEY_HOME,
|
||||
LV_KEY_ENTER,
|
||||
LV_KEY_ESC,
|
||||
LV_KEY_UP,
|
||||
LV_KEY_DOWN,
|
||||
LV_KEY_LEFT,
|
||||
LV_KEY_RIGHT,
|
||||
};
|
||||
|
||||
#define NULL_KEY 0xFFFF
|
||||
#define KEY_STATE_IDLE 0
|
||||
#define KEY_STATE_START 1
|
||||
#define KEY_STATE_PRESS 2
|
||||
|
||||
static UINT32 lg_ulKeyMachineState = KEY_STATE_IDLE;
|
||||
static UINT32 lg_ulLastKey = NULL_KEY;
|
||||
|
||||
#define KEY_POOL_SIZE 8
|
||||
static UINT32 lg_arrKeyAvgPool[KEY_POOL_SIZE];
|
||||
static UINT32 lg_ulKeyIndex = 0;
|
||||
|
||||
extern void SendKeypadInputEventFromISR(lv_indev_data_t *indata);
|
||||
|
||||
static void PushKeyToAVGPool(UINT32 ulKeyValue)
|
||||
{
|
||||
if(lg_ulKeyIndex < KEY_POOL_SIZE)
|
||||
{
|
||||
lg_arrKeyAvgPool[lg_ulKeyIndex] = ulKeyValue;
|
||||
lg_ulKeyIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
static UINT32 AVGPoolIsFull(void)
|
||||
{
|
||||
return lg_ulKeyIndex == KEY_POOL_SIZE;
|
||||
}
|
||||
|
||||
static UINT32 GetKeyAVGValue(void)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 ulSum;
|
||||
|
||||
ulSum = 0;
|
||||
for(i=0;i<lg_ulKeyIndex;i++)
|
||||
{
|
||||
ulSum += lg_arrKeyAvgPool[i];
|
||||
}
|
||||
|
||||
return ulSum/lg_ulKeyIndex;
|
||||
}
|
||||
|
||||
|
||||
static void ResetKeyAVGPool(void)
|
||||
{
|
||||
lg_ulKeyIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
static UINT32 CheckKey(UINT32 ulSampleValue)
|
||||
{
|
||||
UINT32 i;
|
||||
|
||||
for(i = 0; i < (sizeof(KeyAdcValue) / sizeof(KeyAdcValue[0])); i++ )
|
||||
{
|
||||
if((ulSampleValue >= KeyAdcValue[i] - KEYAD_RANGE) && (ulSampleValue <= KeyAdcValue[i] + KEYAD_RANGE))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_KEY;
|
||||
}
|
||||
|
||||
static void SendKeyPress(UINT32 key)
|
||||
{
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.key = key;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendKeypadInputEventFromISR(&indata);
|
||||
}
|
||||
|
||||
static void SendKeyRelease(UINT32 key)
|
||||
{
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.key = key;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendKeypadInputEventFromISR(&indata);
|
||||
}
|
||||
extern char key_value;
|
||||
void KeyEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
|
||||
{
|
||||
switch(lg_ulKeyMachineState)
|
||||
{
|
||||
case KEY_STATE_IDLE:
|
||||
if(ulEvent == KEY_START_EVENT)
|
||||
{
|
||||
lg_ulKeyMachineState = KEY_STATE_START;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_STATE_START:
|
||||
key_value = !key_value;
|
||||
if(ulEvent == KEY_SAMPLE_EVENT)
|
||||
{
|
||||
ResetKeyAVGPool();
|
||||
PushKeyToAVGPool(lpParam);
|
||||
lg_ulKeyMachineState = KEY_STATE_PRESS;
|
||||
}
|
||||
else if(ulEvent == KEY_STOP_EVENT)
|
||||
{
|
||||
lg_ulKeyMachineState = KEY_STATE_IDLE;
|
||||
lg_ulLastKey = NULL_KEY;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_STATE_PRESS:
|
||||
if(ulEvent == KEY_SAMPLE_EVENT)
|
||||
{
|
||||
PushKeyToAVGPool(lpParam);
|
||||
if(AVGPoolIsFull())
|
||||
{
|
||||
UINT32 ulKeySampleValue;
|
||||
UINT32 ulNewKeyCode;
|
||||
|
||||
ulKeySampleValue = GetKeyAVGValue();
|
||||
ulNewKeyCode = CheckKey(ulKeySampleValue);
|
||||
ResetKeyAVGPool();
|
||||
|
||||
if(ulNewKeyCode != NULL_KEY)
|
||||
{
|
||||
if(lg_ulLastKey != ulNewKeyCode && lg_ulLastKey != NULL_KEY)
|
||||
{
|
||||
lg_ulKeyMachineState = KEY_STATE_IDLE;
|
||||
//send key release event;
|
||||
SendKeyRelease(KeypadMap[lg_ulLastKey]);
|
||||
lg_ulLastKey = NULL_KEY;
|
||||
}
|
||||
else if (lg_ulLastKey == ulNewKeyCode)
|
||||
{
|
||||
//Send repeat key event;
|
||||
SendKeyPress(KeypadMap[lg_ulLastKey]);
|
||||
}
|
||||
else if (lg_ulLastKey == NULL_KEY)
|
||||
{
|
||||
//Send key press event;
|
||||
SendKeyPress(KeypadMap[ulNewKeyCode]);
|
||||
}
|
||||
lg_ulLastKey = ulNewKeyCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
lg_ulKeyMachineState = KEY_STATE_IDLE;
|
||||
if(lg_ulLastKey != NULL_KEY)
|
||||
{
|
||||
//send key release event
|
||||
SendKeyRelease(KeypadMap[lg_ulLastKey]);
|
||||
lg_ulLastKey = NULL_KEY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ulEvent == KEY_STOP_EVENT)
|
||||
{
|
||||
lg_ulKeyMachineState = KEY_STATE_IDLE;
|
||||
if(lg_ulLastKey != NULL_KEY)
|
||||
{
|
||||
//send key release event
|
||||
SendKeyRelease(KeypadMap[lg_ulLastKey]);
|
||||
lg_ulLastKey = NULL_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KeypadInit(void)
|
||||
{
|
||||
adc_channel_enable(ADC_CH_AUX0);
|
||||
}
|
@ -0,0 +1,715 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
#include "sfud.h"
|
||||
#include "romfile.h"
|
||||
#include "updatefile.h"
|
||||
#include "animation.h"
|
||||
#include "sysinfo.h"
|
||||
#include "mmcsd_core.h"
|
||||
#include "ff_stdio.h"
|
||||
#include "source/crc32.h"
|
||||
|
||||
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
#include "ff_sfdisk.h"
|
||||
#endif
|
||||
|
||||
#ifdef OTA_UPDATE_SUPPORT
|
||||
#include "ota_update.h"
|
||||
|
||||
|
||||
/* 获取已升级文件位置, toburn不为0时获取升级文件要烧录的位置 */
|
||||
static unsigned int get_upfile_offset(int filetype, int toburn)
|
||||
{
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
if (!toburn) return sysinfo->image_offset;
|
||||
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
|
||||
return UPDATEFILE_MEDIA_B_OFFSET;
|
||||
else
|
||||
return UPDATEFILE_MEDIA_OFFSET;
|
||||
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
if (!toburn) return sysinfo->loader_offset;
|
||||
if (sysinfo->loader_offset == LOADER_OFFSET)
|
||||
return LOADERB_OFFSET;
|
||||
else
|
||||
return LOADER_OFFSET;
|
||||
#else
|
||||
return LOADER_OFFSET;
|
||||
#endif
|
||||
} else if (filetype == UPFILE_TYPE_STEPLDR) {
|
||||
if (!toburn) return sysinfo->stepldr_offset;
|
||||
if (sysinfo->stepldr_offset == STEPLDRA_OFFSET)
|
||||
return STEPLDRB_OFFSET;
|
||||
else
|
||||
return STEPLDRA_OFFSET;
|
||||
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
|
||||
return 0;
|
||||
} else {
|
||||
uint8_t buf[512];
|
||||
UpFileHeader *header;
|
||||
UpFileInfo *appfile;
|
||||
unsigned int image_offset;
|
||||
int i;
|
||||
|
||||
if (toburn) {
|
||||
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
|
||||
image_offset = UPDATEFILE_MEDIA_B_OFFSET;
|
||||
else
|
||||
image_offset = UPDATEFILE_MEDIA_OFFSET;
|
||||
} else {
|
||||
image_offset = sysinfo->image_offset;
|
||||
}
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(image_offset, 512, buf);
|
||||
#else
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, image_offset, 512, buf);
|
||||
#endif
|
||||
header = (UpFileHeader *)buf;
|
||||
if (header->magic != MKTAG('U', 'P', 'D', 'F')) {
|
||||
printf("update file isn't found, can't support module update.\n");
|
||||
return 0xffffffff;
|
||||
}
|
||||
for (i = 0; i < header->filenum; i++) {
|
||||
appfile = &header->files[i];
|
||||
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
|
||||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
|
||||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
|
||||
if (appfile->offset & (64 - 1)) {
|
||||
printf("offset isn't align to sector erase size, can't support module update.\n");
|
||||
return 0xffffffff;
|
||||
}
|
||||
return appfile->offset + image_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
static void set_upfile_offset(SysInfo *sysinfo, int filetype, uint32_t offset)
|
||||
{
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
sysinfo->image_offset = offset;
|
||||
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
sysinfo->loader_offset = offset;
|
||||
#endif
|
||||
} else if (filetype == UPFILE_TYPE_STEPLDR) {
|
||||
sysinfo->stepldr_offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_upfile_size(int filetype)
|
||||
{
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
uint32_t offset;
|
||||
uint8_t buf[512];
|
||||
|
||||
if (filetype <= UPFILE_TYPE_ANIMATION) {
|
||||
offset = get_upfile_offset(filetype, 0);
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(offset, 512, buf);
|
||||
#else
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, offset, 512, buf);
|
||||
#endif
|
||||
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
UpFileHeader *header = (UpFileHeader *)buf;
|
||||
return header->size;
|
||||
} else if (filetype == UPFILE_TYPE_RESOURCE) {
|
||||
RomHeader *header = (RomHeader *)buf;
|
||||
return header->romsize;
|
||||
} else if (filetype == UPFILE_TYPE_ANIMATION) {
|
||||
BANIHEADER *header = (BANIHEADER *)buf;
|
||||
return header->aniSize;
|
||||
}
|
||||
} else if (filetype >= UPFILE_TYPE_APP) {
|
||||
return sysinfo->app_size;
|
||||
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
|
||||
return sysinfo->loader_size;
|
||||
} else if (filetype == UPFILE_TYPE_STEPLDR) {
|
||||
return sysinfo->stepldr_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 获取已升级文件校验和
|
||||
filesize 0:从已升级的文件中读取该文件大小
|
||||
toburn 0:获取当运行文件的校验和 1:获取要烧录位置的旧升级文件的校验和
|
||||
checkmode 0:不校验 1:进行校验,校验错误返回0 2:进行校验,校验出错也返回校验值 */
|
||||
static uint32_t get_upfile_checksum(int filetype, size_t filesize, int checkmode, int toburn)
|
||||
{
|
||||
uint32_t checksum, calc_checksum = 0xffffffff;
|
||||
uint8_t *buf;
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
uint32_t fileoffset;
|
||||
int off, size, leftsize;
|
||||
|
||||
buf = pvPortMalloc(IMAGE_RW_SIZE);
|
||||
if (!buf) {
|
||||
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!filesize) {
|
||||
filesize = get_upfile_size(filetype);
|
||||
if (!filesize) {
|
||||
if (!checkmode) {
|
||||
filesize = IMAGE_RW_SIZE;
|
||||
} else {
|
||||
printf("Error, filesize is zero when needing chekced.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileoffset = get_upfile_offset(filetype, toburn);
|
||||
size = filesize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : filesize;
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
if (filetype == UPFILE_TYPE_LNCHEMMC) {
|
||||
if (!sflash->init_ok)
|
||||
sfud_init();
|
||||
sfud_read(sflash, fileoffset, size, buf);
|
||||
} else emmc_read(fileoffset, size, buf);
|
||||
#else
|
||||
sfud_read(sflash, fileoffset, size, buf);
|
||||
#endif
|
||||
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
UpFileHeader *header = (UpFileHeader *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (checkmode)
|
||||
calc_checksum = xcrc32(buf, size, calc_checksum);
|
||||
} else if (filetype == UPFILE_TYPE_RESOURCE) {
|
||||
RomHeader *header = (RomHeader *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (checkmode)
|
||||
calc_checksum = xcrc32(buf, size, calc_checksum);
|
||||
} else if (filetype == UPFILE_TYPE_ANIMATION) {
|
||||
BANIHEADER *header = (BANIHEADER *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (checkmode)
|
||||
calc_checksum = xcrc32(buf, size, calc_checksum);
|
||||
} else if (filetype >= UPFILE_TYPE_APP) {
|
||||
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
|
||||
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
|
||||
if (checkmode)
|
||||
calc_checksum = xcrc32(buf, size, calc_checksum);
|
||||
}
|
||||
|
||||
if (!checkmode) {
|
||||
vPortFree(buf);
|
||||
return checksum;
|
||||
}
|
||||
|
||||
off = fileoffset + IMAGE_RW_SIZE;
|
||||
leftsize = filesize - size;
|
||||
while (leftsize > 0) {
|
||||
size = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
if (filetype == UPFILE_TYPE_LNCHEMMC)
|
||||
sfud_read(sflash, off, size, buf);
|
||||
else
|
||||
emmc_read(off, size, buf);
|
||||
#else
|
||||
sfud_read(sflash, off, size, buf);
|
||||
#endif
|
||||
calc_checksum = xcrc32(buf, size, calc_checksum);
|
||||
off += size;
|
||||
leftsize -= size;
|
||||
}
|
||||
vPortFree(buf);
|
||||
if (calc_checksum == checksum || checkmode > 1)
|
||||
return calc_checksum;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 获取升级文件的校验和,bchecked不为0时表示需要校验,校验错误返回0 */
|
||||
static uint32_t get_mediafile_checksum(const char *ufile, int filetype, int bchecked)
|
||||
{
|
||||
uint32_t checksum, calc_checksum = 0xffffffff;
|
||||
FF_FILE *fp;
|
||||
uint8_t *buf;
|
||||
int rlen;
|
||||
|
||||
fp = ff_fopen(ufile, "rb");
|
||||
if (!fp) {
|
||||
printf("open %s fail.\n", ufile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = pvPortMalloc(IMAGE_RW_SIZE);
|
||||
if (!buf) {
|
||||
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
|
||||
ff_fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
|
||||
if (rlen <= 0) {
|
||||
printf("read %s data fail.\n", ufile);
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
UpFileHeader *header = (UpFileHeader *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (bchecked)
|
||||
calc_checksum = xcrc32(buf, rlen, calc_checksum);
|
||||
} else if (filetype == UPFILE_TYPE_RESOURCE) {
|
||||
RomHeader *header = (RomHeader *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (bchecked)
|
||||
calc_checksum = xcrc32(buf, rlen, calc_checksum);
|
||||
} else if (filetype == UPFILE_TYPE_ANIMATION) {
|
||||
BANIHEADER *header = (BANIHEADER *)buf;
|
||||
checksum = header->checksum;
|
||||
header->checksum = 0;
|
||||
if (bchecked)
|
||||
calc_checksum = xcrc32(buf, rlen, calc_checksum);
|
||||
} else if (filetype >= UPFILE_TYPE_APP) {
|
||||
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
|
||||
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
|
||||
if (bchecked)
|
||||
calc_checksum = xcrc32(buf, rlen, calc_checksum);
|
||||
}
|
||||
|
||||
if (!bchecked) {
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
return checksum;
|
||||
}
|
||||
|
||||
while ((rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) > 0)
|
||||
calc_checksum = xcrc32(buf, rlen, calc_checksum);
|
||||
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
|
||||
if (calc_checksum == checksum)
|
||||
return checksum;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int backup_whole_image(void)
|
||||
{
|
||||
uint8_t *buf;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
uint32_t imagechecksum, imagesize, imageoff, roff, woff;
|
||||
UpFileHeader *header = NULL;
|
||||
int leftsize, rwsize;
|
||||
int retimes = 3;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
#endif
|
||||
|
||||
buf = pvPortMalloc(IMAGE_RW_SIZE);
|
||||
if (!buf) {
|
||||
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
|
||||
imageoff = UPDATEFILE_MEDIA_B_OFFSET;
|
||||
else
|
||||
imageoff = UPDATEFILE_MEDIA_OFFSET;
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(imageoff, IMAGE_RW_SIZE, buf);
|
||||
#else
|
||||
sfud_read(sflash, imageoff, IMAGE_RW_SIZE, buf);
|
||||
#endif
|
||||
header = (UpFileHeader*)buf;
|
||||
if (header->checksum == sysinfo->app_checksum) {
|
||||
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 1, 1) == sysinfo->app_checksum) {
|
||||
printf("the whole images are same, no need to backup.\n");
|
||||
vPortFree(buf);
|
||||
return 0;
|
||||
}
|
||||
} else if (sysinfo->app_checksum == 0) {
|
||||
uint32_t checksum = get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 1);
|
||||
if (checksum && checksum == get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 0)) {
|
||||
printf("the whole images are same, no need to backup.\n");
|
||||
vPortFree(buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("start backup the whole image...\n");
|
||||
rewrite:
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
|
||||
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
|
||||
#else
|
||||
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
|
||||
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
|
||||
#endif
|
||||
imagesize = header->size;
|
||||
leftsize = imagesize - IMAGE_RW_SIZE;
|
||||
woff = imageoff + IMAGE_RW_SIZE;
|
||||
roff = sysinfo->image_offset + IMAGE_RW_SIZE;
|
||||
/* 如果串口单独升级过update.bin内某一种文件的话可能导致header->checksum并不是真实的校验和 */
|
||||
header->checksum = 0;
|
||||
imagechecksum = xcrc32(buf, IMAGE_RW_SIZE, 0xffffffff);
|
||||
while (leftsize > 0) {
|
||||
rwsize = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(roff, rwsize, buf);
|
||||
emmc_write(woff, rwsize, buf);
|
||||
#else
|
||||
sfud_read(sflash, roff, rwsize, buf);
|
||||
sfud_erase_write(sflash, woff, rwsize, buf);
|
||||
#endif
|
||||
leftsize -= rwsize;
|
||||
roff += rwsize;
|
||||
woff += rwsize;
|
||||
imagechecksum = xcrc32(buf, rwsize, imagechecksum);
|
||||
}
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
|
||||
header->checksum = imagechecksum;
|
||||
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
|
||||
#else
|
||||
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
|
||||
header->checksum = imagechecksum;
|
||||
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
|
||||
#endif
|
||||
|
||||
printf("checksum after backup...\n");
|
||||
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, imagesize, 1, 1) == imagechecksum) {
|
||||
printf("backup the whole image ok.\n");
|
||||
vPortFree(buf);
|
||||
return 0;
|
||||
} else if (retimes-- > 0) {
|
||||
printf("checksum fail, retry...\n");
|
||||
goto rewrite;
|
||||
} else {
|
||||
printf("backup the whole image fail.\n");
|
||||
}
|
||||
|
||||
vPortFree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 获取app, resource, rom升级文件单独升级时能支持的最大文件大小 */
|
||||
static unsigned int get_subfile_maxsize(int filetype)
|
||||
{
|
||||
uint8_t buf[512];
|
||||
UpFileHeader *header;
|
||||
UpFileInfo *appfile;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
int i;
|
||||
|
||||
if (filetype < UPFILE_TYPE_RESOURCE || filetype > UPFILE_TYPE_APP)
|
||||
return 0;
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
emmc_read(sysinfo->image_offset, 512, buf);
|
||||
#else
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, sysinfo->image_offset, 512, buf);
|
||||
#endif
|
||||
header = (UpFileHeader *)buf;
|
||||
if (header->magic != MKTAG('U', 'P', 'D', 'F'))
|
||||
return 0;
|
||||
for (i = 0; i < header->filenum; i++) {
|
||||
appfile = &header->files[i];
|
||||
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
|
||||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
|
||||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
|
||||
if (i < header->filenum - 1) {
|
||||
UpFileInfo *nextfile = &header->files[i + 1];
|
||||
return nextfile->offset - appfile->offset;
|
||||
} else {
|
||||
return UPDATEFILE_MAX_SIZE - appfile->offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int update_from_media(char *mpath, int filetype)
|
||||
{
|
||||
char update_file[32];
|
||||
FF_FILE *fp;
|
||||
size_t filesize;
|
||||
uint8_t *buf;
|
||||
size_t file_offset;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
int leftsize, rwoffset, rwsize;
|
||||
int rlen;
|
||||
uint32_t checksum;
|
||||
SysInfo bak_sysinfo;
|
||||
|
||||
memcpy(&bak_sysinfo, sysinfo, sizeof(SysInfo));
|
||||
|
||||
strcpy(update_file, mpath);
|
||||
strcat(update_file, "/");
|
||||
strcat(update_file, g_upfilename[filetype]);
|
||||
|
||||
printf("%s checksum...\n", update_file);
|
||||
if (!(checksum = get_mediafile_checksum(update_file, filetype, 1))) {
|
||||
printf("checksum fail, don't update.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (checksum == get_upfile_checksum(filetype, 0, 0, 0)) {
|
||||
if (!(filetype == UPFILE_TYPE_WHOLE && sysinfo->app_checksum == 0)) {
|
||||
printf("checksum is the same as now, don't update.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fp = ff_fopen(update_file, "rb");
|
||||
if (!fp) {
|
||||
printf("open %s fail.\n", update_file);
|
||||
return -1;
|
||||
}
|
||||
filesize = ff_filelength(fp);
|
||||
|
||||
buf = pvPortMalloc(IMAGE_RW_SIZE);
|
||||
if (!buf) {
|
||||
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
|
||||
ff_fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
|
||||
if (rlen <= 0) {
|
||||
printf("read %s data fail.\n", update_file);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (filetype == UPFILE_TYPE_WHOLE) {
|
||||
UpFileHeader *header = (UpFileHeader *)buf;
|
||||
bak_sysinfo.app_checksum = header->checksum;
|
||||
bak_sysinfo.app_size = header->files[0].size;
|
||||
} else if (filetype == UPFILE_TYPE_APP) {
|
||||
bak_sysinfo.app_size = filesize;
|
||||
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
|
||||
bak_sysinfo.loader_size = filesize;
|
||||
} else if (filetype == UPFILE_TYPE_STEPLDR) {
|
||||
bak_sysinfo.stepldr_size = filesize;
|
||||
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
|
||||
if (!sflash->init_ok)
|
||||
sfud_init();
|
||||
}
|
||||
|
||||
/* 这三种文件没有备份,需要先备份整个update.bin镜像再升级备份区域 */
|
||||
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP) {
|
||||
if (filesize > get_subfile_maxsize(filetype)) {
|
||||
printf("Not have enough space to update subfile %s.\n", update_file);
|
||||
goto end;
|
||||
}
|
||||
if (backup_whole_image()) {
|
||||
printf("backup_whole_image fail.\n");
|
||||
goto end;
|
||||
}
|
||||
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
|
||||
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_B_OFFSET;
|
||||
else
|
||||
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_OFFSET;
|
||||
}
|
||||
|
||||
file_offset = get_upfile_offset(filetype, 1);
|
||||
if (file_offset == 0xffffffff) {
|
||||
printf("get_upfile_offset fail.\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
leftsize = filesize;
|
||||
rwoffset = file_offset;
|
||||
while (leftsize > 0) {
|
||||
rwsize = leftsize > rlen ? rlen : leftsize;
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
if (filetype == UPFILE_TYPE_LNCHEMMC) {
|
||||
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
|
||||
{
|
||||
printf("burn %s data fail.\n", update_file);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (emmc_write(rwoffset, rwsize, buf))
|
||||
#else
|
||||
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
|
||||
#endif
|
||||
{
|
||||
printf("burn %s data fail.\n", update_file);
|
||||
goto end;
|
||||
}
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
}
|
||||
#endif
|
||||
rwoffset += rwsize;
|
||||
leftsize -= rwsize;
|
||||
printf("burn %d/%d.\n", filesize - leftsize, filesize);
|
||||
|
||||
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
|
||||
if (rlen < 0) {
|
||||
printf("read %s data fail.\n", update_file);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
printf("checksum after burn...\n");
|
||||
if (checksum == get_upfile_checksum(filetype, filesize, 1, 1)) {
|
||||
/* 升级这三个文件app_checksum后不准确,不能再用来判断版本 */
|
||||
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP)
|
||||
bak_sysinfo.app_checksum = 0;
|
||||
set_upfile_offset(&bak_sysinfo, filetype, file_offset);
|
||||
memcpy(sysinfo, &bak_sysinfo, sizeof(SysInfo));
|
||||
SaveSysInfo();
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
printf("burn %s ok.\n", update_file);
|
||||
return 0;
|
||||
} else {
|
||||
printf("checksum after burn fail.\n");
|
||||
}
|
||||
|
||||
end:
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int save_file_to_ota(int filetype)
|
||||
{
|
||||
char update_file[32];
|
||||
char ota_file[32];
|
||||
FF_FILE *fp, *fota;
|
||||
size_t filesize;
|
||||
int leftsize;
|
||||
uint8_t *buf = NULL;
|
||||
size_t readlen;
|
||||
|
||||
strcpy(update_file,"/usb/");
|
||||
strcat(update_file, g_upfilename[filetype]);
|
||||
strcpy(ota_file, OTA_MOUNT_PATH "/");
|
||||
strcat(ota_file, g_upfilename[filetype]);
|
||||
|
||||
if (get_mediafile_checksum(update_file, filetype, 0) ==
|
||||
get_mediafile_checksum(ota_file, filetype, 0)) {
|
||||
if (get_mediafile_checksum(ota_file, filetype, 1)) {
|
||||
printf("%s is same with ota, not save.\n", g_upfilename[filetype]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
fp = ff_fopen(update_file, "rb");
|
||||
if (!fp) {
|
||||
printf("open %s fail.\n", update_file);
|
||||
return -1;
|
||||
}
|
||||
filesize = ff_filelength(fp);
|
||||
fota = ff_fopen(ota_file, "wb");
|
||||
if (!fota) {
|
||||
printf("create %s in ota partition fail.\n", ota_file);
|
||||
ff_fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
buf = pvPortMalloc(IMAGE_RW_SIZE);
|
||||
if (!buf) {
|
||||
printf("malloc IMAGE_RW_SIZE fail.\n");
|
||||
ff_fclose(fota);
|
||||
ff_fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
leftsize = filesize;
|
||||
while (leftsize > 0) {
|
||||
if (readlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) {
|
||||
if (ff_fwrite(buf, 1, readlen, fota) != readlen) {
|
||||
printf("write ota data fail.\n");
|
||||
break;
|
||||
} else {
|
||||
printf("write ota data %d/%d.\n", filesize - leftsize + readlen, filesize);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
leftsize -= readlen;
|
||||
}
|
||||
ff_fclose(fota);
|
||||
ff_fclose(fp);
|
||||
vPortFree(buf);
|
||||
if (leftsize == 0) {
|
||||
printf("save file ok.\n");
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WIFI_UPDATE_SUPPORT
|
||||
#define USB_DEV_PLUGED 0
|
||||
#define USB_DEV_UNPLUGED 1
|
||||
extern int usb_wait_stor_dev_pluged(uint32_t timeout);
|
||||
extern void hub_usb_dev_reset(void);
|
||||
|
||||
/* 用从usb读取数据来模拟wifi接收升级数据,真实的wifi接收升级文件
|
||||
需要和端app适配,需要客户自己实现 */
|
||||
static void wifi_update_demo_thread(void *para)
|
||||
{
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
FF_Disk_t *sfdisk = FF_SFDiskInit(SF_MOUNT_PATH);
|
||||
if (sfdisk)
|
||||
#endif
|
||||
{
|
||||
unsigned int status;
|
||||
int filetype;
|
||||
|
||||
for (;;) {
|
||||
status = usb_wait_stor_dev_pluged(portMAX_DELAY);
|
||||
if (status == USB_DEV_PLUGED) {
|
||||
printf("usb dev inserted.\n");
|
||||
for (filetype = UPFILE_TYPE_WHOLE; filetype <= UPFILE_TYPE_LNCHEMMC; filetype++) {
|
||||
if (save_file_to_ota(filetype)) {
|
||||
printf("save_file_to_ota fail.\n");
|
||||
} else {
|
||||
printf("start to update from ota...\n");
|
||||
update_from_media(OTA_MOUNT_PATH, filetype);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("usb removed.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
vTaskDelay(portMAX_DELAY);
|
||||
}
|
||||
|
||||
void wifi_update_demo(void)
|
||||
{
|
||||
if (xTaskCreate(wifi_update_demo_thread, "wifiupdate", configMINIMAL_STACK_SIZE * 16, NULL,
|
||||
1, NULL) != pdPASS) {
|
||||
printf("create wifi update demo task fail.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,536 @@
|
||||
#include <FreeRTOS.h>
|
||||
#include "list.h"
|
||||
#include "ringblk_buf.h"
|
||||
|
||||
/**
|
||||
* ring block buffer object initialization
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param buf buffer
|
||||
* @param buf_size buffer size
|
||||
* @param block_set block set
|
||||
* @param blk_max_num max block number
|
||||
*
|
||||
* @note When your application need align access, please make the buffer address is aligned.
|
||||
*/
|
||||
void rbb_init(rbb_t rbb, uint8_t *buf, size_t buf_size, rbb_blk_t block_set, size_t blk_max_num)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
configASSERT(rbb);
|
||||
configASSERT(buf);
|
||||
configASSERT(block_set);
|
||||
|
||||
rbb->buf = buf;
|
||||
rbb->buf_size = buf_size;
|
||||
rbb->blk_set = block_set;
|
||||
rbb->blk_max_num = blk_max_num;
|
||||
vListInitialise(&rbb->blk_list);
|
||||
/* initialize block status */
|
||||
for (i = 0; i < blk_max_num; i++)
|
||||
{
|
||||
block_set[i].status = RBB_BLK_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ring block buffer object create
|
||||
*
|
||||
* @param buf_size buffer size
|
||||
* @param blk_max_num max block number
|
||||
*
|
||||
* @return != NULL: ring block buffer object
|
||||
* NULL: create failed
|
||||
*/
|
||||
rbb_t rbb_create(size_t buf_size, size_t blk_max_num)
|
||||
{
|
||||
rbb_t rbb = NULL;
|
||||
uint8_t *buf;
|
||||
rbb_blk_t blk_set;
|
||||
|
||||
rbb = (rbb_t)pvPortMalloc(sizeof(struct rbb));
|
||||
if (!rbb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (uint8_t *)pvPortMalloc(buf_size);
|
||||
if (!buf)
|
||||
{
|
||||
vPortFree(rbb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk_set = (rbb_blk_t)pvPortMalloc(sizeof(struct rbb_blk) * blk_max_num);
|
||||
if (!blk_set)
|
||||
{
|
||||
vPortFree(buf);
|
||||
vPortFree(rbb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rbb_init(rbb, buf, buf_size, blk_set, blk_max_num);
|
||||
|
||||
return rbb;
|
||||
}
|
||||
|
||||
/**
|
||||
* ring block buffer object destroy
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*/
|
||||
void rbb_destroy(rbb_t rbb)
|
||||
{
|
||||
configASSERT(rbb);
|
||||
|
||||
vPortFree(rbb->buf);
|
||||
vPortFree(rbb->blk_set);
|
||||
vPortFree(rbb);
|
||||
|
||||
}
|
||||
|
||||
static rbb_blk_t find_empty_blk_in_set(rbb_t rbb)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
configASSERT(rbb);
|
||||
|
||||
for (i = 0; i < rbb->blk_max_num; i ++)
|
||||
{
|
||||
if (rbb->blk_set[i].status == RBB_BLK_UNUSED)
|
||||
{
|
||||
return &rbb->blk_set[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a block by given size. The block will add to blk_list when allocate success.
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param blk_size block size
|
||||
*
|
||||
* @note When your application need align access, please make the blk_szie is aligned.
|
||||
*
|
||||
* @return != NULL: allocated block
|
||||
* NULL: allocate failed
|
||||
*/
|
||||
rbb_blk_t rbb_blk_alloc(rbb_t rbb, size_t blk_size)
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
size_t empty1 = 0, empty2 = 0;
|
||||
rbb_blk_t head, tail, new_rbb = NULL;
|
||||
|
||||
configASSERT(rbb);
|
||||
configASSERT(blk_size < (1L << 24));
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
|
||||
new_rbb = find_empty_blk_in_set(rbb);
|
||||
|
||||
if (listCURRENT_LIST_LENGTH(&rbb->blk_list) < rbb->blk_max_num && new_rbb)
|
||||
{
|
||||
if (listCURRENT_LIST_LENGTH(&rbb->blk_list) > 0)
|
||||
{
|
||||
head = listGET_OWNER_OF_HEAD_ENTRY(&rbb->blk_list);
|
||||
tail = listGET_LIST_ITEM_OWNER(rbb->blk_list.xListEnd.pxPrevious);
|
||||
if (head->buf <= tail->buf)
|
||||
{
|
||||
/**
|
||||
* head tail
|
||||
* +--------------------------------------+-----------------+------------------+
|
||||
* | empty2 | block1 | block2 | block3 | empty1 |
|
||||
* +--------------------------------------+-----------------+------------------+
|
||||
* rbb->buf
|
||||
*/
|
||||
empty1 = (rbb->buf + rbb->buf_size) - (tail->buf + tail->size);
|
||||
empty2 = head->buf - rbb->buf;
|
||||
|
||||
if (empty1 >= blk_size)
|
||||
{
|
||||
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
|
||||
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
|
||||
new_rbb->status = RBB_BLK_INITED;
|
||||
new_rbb->buf = tail->buf + tail->size;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else if (empty2 >= blk_size)
|
||||
{
|
||||
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
|
||||
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
|
||||
new_rbb->status = RBB_BLK_INITED;
|
||||
new_rbb->buf = rbb->buf;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no space */
|
||||
new_rbb = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* tail head
|
||||
* +----------------+-------------------------------------+--------+-----------+
|
||||
* | block3 | empty1 | block1 | block2 |
|
||||
* +----------------+-------------------------------------+--------+-----------+
|
||||
* rbb->buf
|
||||
*/
|
||||
empty1 = head->buf - (tail->buf + tail->size);
|
||||
|
||||
if (empty1 >= blk_size)
|
||||
{
|
||||
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
|
||||
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
|
||||
new_rbb->status = RBB_BLK_INITED;
|
||||
new_rbb->buf = tail->buf + tail->size;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no space */
|
||||
new_rbb = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the list is empty */
|
||||
listSET_LIST_ITEM_OWNER(&new_rbb->list, new_rbb);
|
||||
vListInsertEnd(&rbb->blk_list, &new_rbb->list);
|
||||
new_rbb->status = RBB_BLK_INITED;
|
||||
new_rbb->buf = rbb->buf;
|
||||
new_rbb->size = blk_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_rbb = NULL;
|
||||
}
|
||||
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
|
||||
|
||||
return new_rbb;
|
||||
}
|
||||
|
||||
/**
|
||||
* put a block to ring block buffer object
|
||||
*
|
||||
* @param block the block
|
||||
*/
|
||||
void rbb_blk_put(rbb_blk_t block)
|
||||
{
|
||||
configASSERT(block);
|
||||
configASSERT(block->status == RBB_BLK_INITED);
|
||||
|
||||
block->status = RBB_BLK_PUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a block from the ring block buffer object
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return != NULL: block
|
||||
* NULL: get failed
|
||||
*/
|
||||
rbb_blk_t rbb_blk_get(rbb_t rbb)
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
rbb_blk_t block = NULL;
|
||||
ListItem_t *node;
|
||||
|
||||
configASSERT(rbb);
|
||||
|
||||
if (listLIST_IS_EMPTY(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
|
||||
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
|
||||
node = listGET_NEXT(node))
|
||||
{
|
||||
block = listGET_LIST_ITEM_OWNER(node);
|
||||
if (block->status == RBB_BLK_PUT)
|
||||
{
|
||||
block->status = RBB_BLK_GET;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
/* not found */
|
||||
block = NULL;
|
||||
|
||||
__exit:
|
||||
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size
|
||||
*
|
||||
* @param block the block
|
||||
*
|
||||
* @return block size
|
||||
*/
|
||||
size_t rbb_blk_size(rbb_blk_t block)
|
||||
{
|
||||
configASSERT(block);
|
||||
|
||||
return block->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block buffer
|
||||
*
|
||||
* @param block the block
|
||||
*
|
||||
* @return block buffer
|
||||
*/
|
||||
uint8_t *rbb_blk_buf(rbb_blk_t block)
|
||||
{
|
||||
configASSERT(block);
|
||||
|
||||
return block->buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* free the block
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param block the block
|
||||
*/
|
||||
void rbb_blk_free(rbb_t rbb, rbb_blk_t block)
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
|
||||
configASSERT(rbb);
|
||||
configASSERT(block);
|
||||
configASSERT(block->status != RBB_BLK_UNUSED);
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
|
||||
/* remove it on rbb block list */
|
||||
uxListRemove(&block->list);
|
||||
|
||||
block->status = RBB_BLK_UNUSED;
|
||||
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a continuous block to queue by given size
|
||||
*
|
||||
* tail head
|
||||
* +------------------+---------------+--------+----------+--------+
|
||||
* | block3 | empty1 | block1 | block2 |fragment|
|
||||
* +------------------+------------------------+----------+--------+
|
||||
* |<-- return_size -->| |
|
||||
* |<--- queue_data_len --->|
|
||||
*
|
||||
* tail head
|
||||
* +------------------+---------------+--------+----------+--------+
|
||||
* | block3 | empty1 | block1 | block2 |fragment|
|
||||
* +------------------+------------------------+----------+--------+
|
||||
* |<-- return_size -->| out of len(b1+b2+b3) |
|
||||
* |<-------------------- queue_data_len -------------------->|
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param queue_data_len The max queue data size, and the return size must less then it.
|
||||
* @param queue continuous block queue
|
||||
*
|
||||
* @return the block queue data total size
|
||||
*/
|
||||
size_t rbb_blk_queue_get(rbb_t rbb, size_t queue_data_len, rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
size_t data_total_size = 0;
|
||||
ListItem_t *node;
|
||||
rbb_blk_t last_block = NULL, block;
|
||||
|
||||
configASSERT(rbb);
|
||||
configASSERT(blk_queue);
|
||||
|
||||
if (listLIST_IS_EMPTY(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
|
||||
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
|
||||
node = listGET_NEXT(node))
|
||||
{
|
||||
if (!last_block)
|
||||
{
|
||||
last_block = listGET_LIST_ITEM_OWNER(node);
|
||||
if (last_block->status == RBB_BLK_PUT)
|
||||
{
|
||||
/* save the first put status block to queue */
|
||||
blk_queue->blocks = last_block;
|
||||
blk_queue->blk_num = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the first block must be put status */
|
||||
last_block = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
block = listGET_LIST_ITEM_OWNER(node);
|
||||
/*
|
||||
* these following conditions will break the loop:
|
||||
* 1. the current block is not put status
|
||||
* 2. the last block and current block is not continuous
|
||||
* 3. the data_total_size will out of range
|
||||
*/
|
||||
if (block->status != RBB_BLK_PUT ||
|
||||
last_block->buf > block->buf ||
|
||||
data_total_size + block->size > queue_data_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* backup last block */
|
||||
last_block = block;
|
||||
}
|
||||
/* remove current block */
|
||||
uxListRemove(&last_block->list);
|
||||
data_total_size += last_block->size;
|
||||
last_block->status = RBB_BLK_GET;
|
||||
blk_queue->blk_num++;
|
||||
}
|
||||
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
|
||||
|
||||
return data_total_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all block length on block queue
|
||||
*
|
||||
* @param blk_queue the block queue
|
||||
*
|
||||
* @return total length
|
||||
*/
|
||||
size_t rbb_blk_queue_len(rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
size_t i, data_total_size = 0;
|
||||
|
||||
configASSERT(blk_queue);
|
||||
|
||||
for (i = 0; i < blk_queue->blk_num; i++)
|
||||
{
|
||||
data_total_size += blk_queue->blocks[i].size;
|
||||
}
|
||||
|
||||
return data_total_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block queue buffer
|
||||
*
|
||||
* @param blk_queue the block queue
|
||||
*
|
||||
* @return block queue buffer
|
||||
*/
|
||||
uint8_t *rbb_blk_queue_buf(rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
configASSERT(blk_queue);
|
||||
|
||||
return blk_queue->blocks[0].buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* free the block queue
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
* @param blk_queue the block queue
|
||||
*/
|
||||
void rbb_blk_queue_free(rbb_t rbb, rbb_blk_queue_t blk_queue)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
configASSERT(rbb);
|
||||
configASSERT(blk_queue);
|
||||
|
||||
for (i = 0; i < blk_queue->blk_num; i++)
|
||||
{
|
||||
rbb_blk_free(rbb, &blk_queue->blocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The put status and buffer continuous blocks can be make a block queue.
|
||||
* This function will return the length which from next can be make block queue.
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return the next can be make block queue's length
|
||||
*/
|
||||
size_t rbb_next_blk_queue_len(rbb_t rbb)
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
size_t data_len = 0;
|
||||
ListItem_t *node;
|
||||
rbb_blk_t last_block = NULL, block;
|
||||
|
||||
configASSERT(rbb);
|
||||
|
||||
if (listLIST_IS_EMPTY(&rbb->blk_list))
|
||||
return 0;
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
|
||||
for (node = listGET_HEAD_ENTRY(&rbb->blk_list); node != listGET_END_MARKER(&rbb->blk_list);
|
||||
node = listGET_NEXT(node))
|
||||
{
|
||||
if (!last_block)
|
||||
{
|
||||
last_block = listGET_LIST_ITEM_OWNER(node);
|
||||
if (last_block->status != RBB_BLK_PUT)
|
||||
{
|
||||
/* the first block must be put status */
|
||||
last_block = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
block = listGET_LIST_ITEM_OWNER(node);
|
||||
/*
|
||||
* these following conditions will break the loop:
|
||||
* 1. the current block is not put status
|
||||
* 2. the last block and current block is not continuous
|
||||
*/
|
||||
if (block->status != RBB_BLK_PUT || last_block->buf > block->buf)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* backup last block */
|
||||
last_block = block;
|
||||
}
|
||||
data_len += last_block->size;
|
||||
}
|
||||
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the ring block buffer object buffer size
|
||||
*
|
||||
* @param rbb ring block buffer object
|
||||
*
|
||||
* @return buffer size
|
||||
*/
|
||||
size_t rbb_get_buf_size(rbb_t rbb)
|
||||
{
|
||||
configASSERT(rbb);
|
||||
|
||||
return rbb->buf_size;
|
||||
}
|
@ -0,0 +1,465 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
|
||||
#ifdef VIDEO_DECODER_RN6752
|
||||
|
||||
#define RN6752_RST_GPIO 7
|
||||
#define RN6752_SLAVE_ADDR (0x58 >> 1)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static int rn6752_i2c_write (struct i2c_adapter *adap, unsigned int addr, unsigned int data)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret = -1;
|
||||
u8 retries = 0;
|
||||
u8 buf[2];
|
||||
|
||||
buf[0] = (addr & 0xFF);
|
||||
buf[1] = (data & 0xFF);
|
||||
|
||||
msg.flags = !I2C_M_RD;
|
||||
msg.addr = RN6752_SLAVE_ADDR;
|
||||
msg.len = sizeof(buf);
|
||||
msg.buf = buf;
|
||||
|
||||
while(retries < 5)
|
||||
{
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
if (ret == 1)
|
||||
break;
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (retries >= 5)
|
||||
{
|
||||
printf("%s timeout\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* static unsigned int rn6752_i2c_read(struct i2c_adapter *adap, unsigned int addr)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
int retries = 0;
|
||||
int ret = -1;
|
||||
u8 buf;
|
||||
|
||||
buf = addr & 0xFF;
|
||||
|
||||
msgs[0].flags = !I2C_M_RD;
|
||||
msgs[0].addr = RN6752_SLAVE_ADDR;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = &buf;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = RN6752_SLAVE_ADDR;
|
||||
msgs[1].len = 1;
|
||||
msgs[1].buf = &buf;
|
||||
|
||||
while(retries < 5)
|
||||
{
|
||||
ret = i2c_transfer(adap, msgs, 2);
|
||||
if(ret == 2)
|
||||
break;
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (retries >= 5)
|
||||
{
|
||||
printf( "%s timeout\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
} */
|
||||
|
||||
static void rn6752_reset(void)
|
||||
{
|
||||
gpio_direction_output(RN6752_RST_GPIO, 1);
|
||||
vTaskDelay(10);
|
||||
gpio_direction_output(RN6752_RST_GPIO, 0);
|
||||
vTaskDelay(10);
|
||||
gpio_direction_output(RN6752_RST_GPIO, 1);
|
||||
vTaskDelay(100);
|
||||
|
||||
}
|
||||
|
||||
typedef struct _RXCCHIPstaticPara
|
||||
{
|
||||
unsigned int addr;
|
||||
unsigned int dat;
|
||||
} RXCHIPstaticPara;
|
||||
|
||||
#if VIDEO_IN_FORMAT == VIN_AHD_720P_25
|
||||
const RXCHIPstaticPara rn6752m_720p_25_staticPara[]=
|
||||
{
|
||||
//RN6752M-601-720P(°üÀ¨Í¬Öá¿ØÖÆ)
|
||||
// 720P@25 BT601
|
||||
// Slave address is 0x58
|
||||
// Register, data
|
||||
|
||||
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
|
||||
//0xD2, 0x85, // disable auto clock detect
|
||||
//0xD6, 0x37, // 27MHz default
|
||||
//0xD8, 0x18, // switch to 26MHz clock
|
||||
//delay(100), // delay 100ms
|
||||
|
||||
{0x81, 0x01}, // turn on video decoder
|
||||
{0xA3, 0x04},
|
||||
{0xDF, 0xFE}, // enable HD format
|
||||
{0x88, 0x40}, // disable SCLK0B out
|
||||
{0xF6, 0x40}, // disable SCLK3A out
|
||||
|
||||
// ch0
|
||||
{0xFF, 0x00}, // switch to ch0 (default; optional)
|
||||
{0x2C, 0x30},
|
||||
{0x2D, 0xF0},
|
||||
{0x00, 0x20}, // internal use*
|
||||
{0x06, 0x08}, // internal use*
|
||||
{0x07, 0x63}, // HD format
|
||||
{0x2A, 0x01}, // filter control
|
||||
{0x3A, 0x00}, // No Insert Channel ID in SAV/EAV code
|
||||
{0x3F, 0x10}, // channel ID
|
||||
{0x4C, 0x37}, // equalizer
|
||||
{0x4F, 0x03}, // sync control
|
||||
{0x50, 0x02}, // 720p resolution
|
||||
{0x56, 0x05}, // BT 72M mode and BT601 mode
|
||||
{0x5F, 0x40}, // blank level
|
||||
{0x63, 0xF5}, // filter control
|
||||
{0x59, 0x00}, // extended register access
|
||||
{0x5A, 0x42}, // data for extended register
|
||||
{0x58, 0x01}, // enable extended register write
|
||||
{0x59, 0x33}, // extended register access
|
||||
{0x5A, 0x23}, // data for extended register
|
||||
{0x58, 0x01}, // enable extended register write
|
||||
{0x51, 0xE1}, // scale factor1
|
||||
{0x52, 0x88}, // scale factor2
|
||||
{0x53, 0x12}, // scale factor3
|
||||
{0x5B, 0x07}, // H-scaling control
|
||||
{0x5E, 0x08}, // enable H-scaling control
|
||||
{0x6A, 0x82}, // H-scaling control
|
||||
{0x28, 0x92}, // cropping
|
||||
{0x01, 0x08}, // brightness
|
||||
{0x02, 0x80}, // contrast
|
||||
{0x03, 0x80}, // saturation
|
||||
{0x04, 0x80}, // hue
|
||||
{0x05, 0x03}, // sharpness
|
||||
{0x09, 0xC8}, // EQ
|
||||
{0x34, 0x02}, // OB
|
||||
{0x57, 0x15}, // black/white stretch
|
||||
{0x68, 0x32}, // coring
|
||||
|
||||
{0x00, 0x20}, // internal use*
|
||||
{0x0D, 0x20}, // cagc initial value
|
||||
//{0x2D, 0xF2}, // cagc adjust
|
||||
{0x37, 0X33},
|
||||
{0x61, 0X6C},
|
||||
|
||||
//{0x30, 0X30},// V30H_0836_NEW
|
||||
//{0x0d, 0X50},
|
||||
|
||||
//{0x3A, 0x04},
|
||||
//{0x3E, 0x32},
|
||||
{0x3A, 0x02},//P-MOS
|
||||
{0x3E, 0xf6},//ͬÖáÓ³Éäµ½AVID½Å
|
||||
|
||||
{0x40, 0x04},
|
||||
{0x46, 0x23},
|
||||
|
||||
{0x47, 0x30},
|
||||
|
||||
//{0x49, 0x84},//85
|
||||
{0x6d, 0x00},
|
||||
|
||||
{0x8E, 0x00}, // single channel output for VP
|
||||
{0x8F, 0x80}, // 720p mode for VP
|
||||
{0x8D, 0x31}, // enable VP out
|
||||
{0x89, 0x09}, // select 72MHz for SCLK
|
||||
{0x88, 0x41}, // enable SCLK out
|
||||
|
||||
{0x96, 0x00}, // select AVID & VBLK as status indicator
|
||||
{0x97, 0x0B}, // enable status indicator out on AVID,VBLK & VSYNC
|
||||
{0x98, 0x00}, // video timing pin status
|
||||
{0x9A, 0x40}, // select AVID & VBLK as status indicator
|
||||
{0x9B, 0xE1}, // enable status indicator out on HSYNC
|
||||
{0x9C, 0x00}, // video timing pin status
|
||||
|
||||
//{0x00, 0xC0},//test bar color
|
||||
};
|
||||
#endif
|
||||
|
||||
#if VIDEO_IN_FORMAT == VIN_AHD_720P_30
|
||||
const RXCHIPstaticPara rn6752m_720p_30_staticPara[]=
|
||||
{
|
||||
// 720P@30 BT601
|
||||
// Slave address is 0x58
|
||||
// Register, data
|
||||
|
||||
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
|
||||
//0xD2, 0x85, // disable auto clock detect
|
||||
//0xD6, 0x37, // 27MHz default
|
||||
//0xD8, 0x18, // switch to 26MHz clock
|
||||
//delay(100), // delay 100ms
|
||||
0x49,0x01,
|
||||
0x19,0x07,
|
||||
0x81, 0x01, // turn on video decoder
|
||||
0xA3, 0x04,
|
||||
0xDF, 0xFE, // enable HD format
|
||||
0x88, 0x40, // disable SCLK0B out
|
||||
0xF6, 0x40, // disable SCLK3A out
|
||||
|
||||
// ch0
|
||||
0xFF, 0x00, // switch to ch0 (default; optional)
|
||||
0x00, 0x20, // internal use*
|
||||
0x06, 0x08, // internal use*
|
||||
0x07, 0x63, // HD format
|
||||
0x2A, 0x01, // filter control
|
||||
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
|
||||
0x3F, 0x10, // channel ID
|
||||
0x4C, 0x37, // equalizer
|
||||
0x4F, 0x03, // sync control
|
||||
0x50, 0x02, // 720p resolution
|
||||
0x56, 0x05, // BT 72M mode and BT601 mode
|
||||
0x5F, 0x40, // blank level
|
||||
0x63, 0xF5, // filter control
|
||||
0x59, 0x00, // extended register access
|
||||
0x5A, 0x44, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x59, 0x33, // extended register access
|
||||
0x5A, 0x23, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x51, 0xE1, // scale factor1
|
||||
0x52, 0x88, // scale factor2
|
||||
0x53, 0x12, // scale factor3
|
||||
0x5B, 0x07, // H-scaling control
|
||||
0x5E, 0x0B, // enable H-scaling control
|
||||
0x6A, 0x82, // H-scaling control
|
||||
0x28, 0x92, // cropping
|
||||
0x03, 0x80, // saturation
|
||||
0x04, 0x80, // hue
|
||||
0x05, 0x00, // sharpness
|
||||
0x57, 0x23, // black/white stretch
|
||||
0x68, 0x32, // coring
|
||||
0x3A, 0x04,
|
||||
0x3E, 0x32,
|
||||
0x40, 0x04,
|
||||
0x46, 0x23,
|
||||
|
||||
0x8E, 0x00, // single channel output for VP
|
||||
0x8F, 0x80, // 720p mode for VP
|
||||
0x8D, 0x31, // enable VP out
|
||||
0x89, 0x09, // select 72MHz for SCLK
|
||||
0x88, 0x41, // enable SCLK out
|
||||
|
||||
0XD3,0X00,//channel 0 0x00 channel 1 0X01
|
||||
|
||||
0x96, 0x00, // select AVID & VBLK as status indicator
|
||||
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
|
||||
0x98, 0x00, // video timing pin status
|
||||
0x9A, 0x40, // select AVID & VBLK as status indicator
|
||||
0x9B, 0xE1, // enable status indicator out on HSYNC
|
||||
0x9C, 0x00, // video timing pin status
|
||||
};
|
||||
#endif
|
||||
|
||||
#if VIDEO_IN_FORMAT == VIN_CVBS_NTSC
|
||||
const RXCHIPstaticPara rn6752m_cvbs_ntsc_staticPara[]=
|
||||
{
|
||||
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
|
||||
//0xD2, 0x85, // disable auto clock detect
|
||||
//0xD6, 0x37, // 27MHz default
|
||||
//0xD8, 0x18, // switch to 26MHz clock
|
||||
//delay(100), // delay 100ms
|
||||
|
||||
0x81, 0x01, // turn on video decoder
|
||||
0xA3, 0x00,
|
||||
0xDF, 0xFF, // enable CVBS format
|
||||
|
||||
// ch0
|
||||
0xFF, 0x00, // switch to ch0 (default; optional)
|
||||
0x00, 0x00, // internal use*
|
||||
0x06, 0x08, // internal use*
|
||||
0x07, 0x63, // HD format
|
||||
0x2A, 0x81, // filter control
|
||||
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
|
||||
0x3F, 0x10, // channel ID
|
||||
0x4C, 0x37, // equalizer
|
||||
0x4F, 0x00, // sync control
|
||||
0x50, 0x00, // D1 resolution
|
||||
0x56, 0x04, // 27M mode and BT601 mode
|
||||
0x5F, 0x00, // blank level
|
||||
0x63, 0x75, // filter control
|
||||
0x59, 0x00, // extended register access
|
||||
0x5A, 0x00, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x59, 0x33, // extended register access
|
||||
0x5A, 0x02, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x5B, 0x00, // H-scaling control
|
||||
0x5E, 0x01, // enable H-scaling control
|
||||
0x6A, 0x00, // H-scaling control
|
||||
0x28, 0xB2, // cropping
|
||||
0x20, 0x24,
|
||||
0x23, 0x11,
|
||||
0x24, 0x05,
|
||||
0x25, 0x11,
|
||||
0x26, 0x00,
|
||||
0x42, 0x00,
|
||||
0x03, 0x80, // saturation
|
||||
0x04, 0x80, // hue
|
||||
0x05, 0x03, // sharpness
|
||||
0x57, 0x20, // black/white stretch
|
||||
0x68, 0x32, // coring
|
||||
0x3A, 0x04,
|
||||
0x3E, 0x32,
|
||||
0x40, 0x04,
|
||||
0x46, 0x23,
|
||||
|
||||
|
||||
0x8E, 0x00, // single channel output for VP
|
||||
0x8F, 0x00, // D1 mode for VP
|
||||
0x8D, 0x31, // enable VP out
|
||||
0x89, 0x00, // select 27MHz for SCLK
|
||||
0x88, 0x41, // enable SCLK out
|
||||
|
||||
0x96, 0x00, // select AVID & VBLK as status indicator
|
||||
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
|
||||
0x98, 0x00, // video timing pin status
|
||||
0x9A, 0x40, // select AVID & VBLK as status indicator
|
||||
0x9B, 0xE1, // enable status indicator out on HSYNC
|
||||
0x9C, 0x00, // video timing pin status
|
||||
};
|
||||
#endif
|
||||
|
||||
#if VIDEO_IN_FORMAT == VIN_CVBS_PAL
|
||||
const RXCHIPstaticPara rn6752m_cvbs_pal_staticPara[]=
|
||||
{
|
||||
// cvbs@25 BT601
|
||||
// Slave address is 0x58
|
||||
// Register, data
|
||||
|
||||
// if clock source(Xin) of RN6752 is 26MHz, please add these procedures marked first
|
||||
//0xD2, 0x85, // disable auto clock detect
|
||||
//0xD6, 0x37, // 27MHz default
|
||||
//0xD8, 0x18, // switch to 26MHz clock
|
||||
//delay(100), // delay 100ms
|
||||
0x49,0x01,
|
||||
0x19,0x07,
|
||||
0x81, 0x01, // turn on video decoder
|
||||
0xA3, 0x04,
|
||||
0xDF, 0x0F, // enable CVBS format
|
||||
|
||||
0x88, 0x40, // disable SCLK0B out
|
||||
0xF6, 0x40, // disable SCLK3A out
|
||||
|
||||
// ch0
|
||||
0xFF, 0x00, // switch to ch0 (default; optional)
|
||||
0x00, 0x00, // internal use*
|
||||
0x06, 0x08, // internal use*
|
||||
0x07, 0x62, // HD format
|
||||
0x2A, 0x81, // filter control
|
||||
0x3A, 0x00, // No Insert Channel ID in SAV/EAV code
|
||||
0x3F, 0x10, // channel ID
|
||||
0x4C, 0x37, // equalizer
|
||||
0x4F, 0x00, // sync control
|
||||
0x50, 0x00, // 720p resolution
|
||||
0x56, 0x05, // 72M mode and BT601 mode
|
||||
0x5F, 0x00, // blank level
|
||||
0x63, 0x75, // filter control
|
||||
0x59, 0x00, // extended register access
|
||||
0x5A, 0x00, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x59, 0x33, // extended register access
|
||||
0x5A, 0x02, // data for extended register
|
||||
0x58, 0x01, // enable extended register write
|
||||
0x5B, 0x00, // H-scaling control
|
||||
0x5E, 0x01, // enable H-scaling control
|
||||
0x6A, 0x00, // H-scaling control
|
||||
0x28, 0xB2, // cropping
|
||||
0x20, 0x24,
|
||||
0x23, 0x17,
|
||||
0x24, 0x37,
|
||||
0x25, 0x17,
|
||||
0x26, 0x00,
|
||||
0x42, 0x00,
|
||||
0x03, 0x80, // saturation
|
||||
0x04, 0x80, // hue
|
||||
0x05, 0x03, // sharpness
|
||||
0x57, 0x20, // black/white stretch
|
||||
0x68, 0x32, // coring
|
||||
0x3A, 0x04,
|
||||
0x3E, 0x32,
|
||||
0x40, 0x04,
|
||||
0x46, 0x23,
|
||||
|
||||
0x8E, 0x00, // single channel output for VP
|
||||
0x8F, 0x80, // 720p mode for VP
|
||||
0x8D, 0x31, // enable VP out
|
||||
0x89, 0x09, // select 72MHz for SCLK
|
||||
0x88, 0x41, // enable SCLK out
|
||||
|
||||
0x96, 0x00, // select AVID & VBLK as status indicator
|
||||
0x97, 0x0B, // enable status indicator out on AVID,VBLK & VSYNC
|
||||
0x98, 0x00, // video timing pin status
|
||||
0x9A, 0x40, // select AVID & VBLK as status indicator
|
||||
0x9B, 0xE1, // enable status indicator out on HSYNC
|
||||
0x9C, 0x00, // video timing pin status
|
||||
};
|
||||
#endif
|
||||
|
||||
static void rn6752_config(struct i2c_adapter *adap)
|
||||
{
|
||||
int i;
|
||||
//int val;
|
||||
#if VIDEO_IN_FORMAT == VIN_CVBS_PAL
|
||||
for (i = 0; i < sizeof(rn6752m_cvbs_pal_staticPara) / sizeof(RXCHIPstaticPara); i++)
|
||||
{
|
||||
rn6752_i2c_write(adap, rn6752m_cvbs_pal_staticPara[i].addr,
|
||||
rn6752m_cvbs_pal_staticPara[i].dat);
|
||||
|
||||
}
|
||||
#elif VIDEO_IN_FORMAT == VIN_CVBS_NTSC
|
||||
for (i = 0; i < sizeof(rn6752m_cvbs_ntsc_staticPara) / sizeof(RXCHIPstaticPara); i++)
|
||||
{
|
||||
rn6752_i2c_write(adap, rn6752m_cvbs_ntsc_staticPara[i].addr,
|
||||
rn6752m_cvbs_ntsc_staticPara[i].dat);
|
||||
|
||||
}
|
||||
#elif VIDEO_IN_FORMAT == VIN_AHD_720P_25
|
||||
for (i = 0; i < sizeof(rn6752m_720p_25_staticPara) / sizeof(RXCHIPstaticPara); i++)
|
||||
{
|
||||
rn6752_i2c_write(adap, rn6752m_720p_25_staticPara[i].addr,
|
||||
rn6752m_720p_25_staticPara[i].dat);
|
||||
|
||||
}
|
||||
#elif VIDEO_IN_FORMAT == VIN_AHD_720P_30
|
||||
for (i = 0; i < sizeof(rn6752m_720p_30_staticPara) / sizeof(RXCHIPstaticPara); i++)
|
||||
{
|
||||
rn6752_i2c_write(adap, rn6752m_720p_30_staticPara[i].addr,
|
||||
rn6752m_720p_30_staticPara[i].dat);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int rn6752_init(void)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
rn6752_reset();
|
||||
|
||||
if (!(adap = i2c_open("i2c1"))) {
|
||||
printf("open i2c1 fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rn6752_config(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,426 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "sfud.h"
|
||||
#include "updatefile.h"
|
||||
#include "romfile.h"
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
#include "mmcsd_core.h"
|
||||
#endif
|
||||
|
||||
static RomHeader *romheader = NULL;
|
||||
static SemaphoreHandle_t romfileMutex;
|
||||
|
||||
#ifndef ROMFILE_USE_SMALL_MEM
|
||||
#ifndef READ_ROMFILE_ONCE
|
||||
static unsigned char *filestatus;
|
||||
static uint32_t romoffset;
|
||||
#endif
|
||||
#else
|
||||
static uint32_t romoffset;
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
#define ROMFILE_CACHE_LIFE_LIMIT 1000000
|
||||
static RomFileCache *romfilecache;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int ReadRomFile(void)
|
||||
{
|
||||
uint32_t offset = GetUpFileOffset(MKTAG('R', 'O', 'M', 'A'));
|
||||
uint32_t size = GetUpFileSize(MKTAG('R', 'O', 'M', 'A'));
|
||||
|
||||
romfileMutex = xSemaphoreCreateMutex();
|
||||
|
||||
xSemaphoreTake(romfileMutex, portMAX_DELAY);
|
||||
|
||||
if (size > 0) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
#endif
|
||||
#ifndef ROMFILE_USE_SMALL_MEM
|
||||
void *rombuf = pvPortMalloc(size);
|
||||
if (rombuf) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
#ifdef READ_ROMFILE_ONCE
|
||||
sfud_read(sflash, offset, size, rombuf);
|
||||
#else
|
||||
sfud_read(sflash, offset, sizeof(RomHeader), rombuf);
|
||||
romoffset = offset;
|
||||
#endif
|
||||
#else
|
||||
#ifdef READ_ROMFILE_ONCE
|
||||
emmc_read(offset, size, rombuf);
|
||||
#else
|
||||
emmc_read(offset, sizeof(RomHeader), rombuf);
|
||||
romoffset = offset;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
romheader = rombuf;
|
||||
if (romheader->magic != MKTAG('R', 'O', 'M', 'A')) {
|
||||
printf("Read rom file error!\n");
|
||||
vPortFree(rombuf);
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
#ifdef READ_ROMFILE_ONCE
|
||||
CP15_clean_dcache_for_dma((uint32_t)rombuf, (uint32_t)rombuf + size);
|
||||
#else
|
||||
int files = romheader->filenum;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, offset + sizeof(RomHeader), sizeof(RomFileInfo) * files,
|
||||
(unsigned char*)rombuf + sizeof(RomHeader));
|
||||
#else
|
||||
emmc_read(offset + sizeof(RomHeader), sizeof(RomFileInfo) * files,
|
||||
(unsigned char*)rombuf + sizeof(RomHeader));
|
||||
#endif
|
||||
filestatus = pvPortMalloc(files * sizeof(*filestatus));
|
||||
if (!filestatus) {
|
||||
printf("filestatus malloc fail.\n");
|
||||
vPortFree(rombuf);
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
memset(filestatus, 0, files * sizeof(*filestatus));
|
||||
CP15_clean_dcache_for_dma((uint32_t)rombuf, (uint32_t)rombuf + sizeof(RomHeader) +
|
||||
sizeof(RomFileInfo) * files);
|
||||
#endif
|
||||
} else {
|
||||
printf("Error! No enough memory for romfile.\n");
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
RomHeader header;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, offset, sizeof(RomHeader), (void*)&header);
|
||||
#else
|
||||
emmc_read(offset, sizeof(RomHeader), (void*)&header);
|
||||
#endif
|
||||
romoffset = offset;
|
||||
romheader = pvPortMalloc(sizeof(RomHeader) + sizeof(RomFileInfo) * header.filenum);
|
||||
if (romheader == NULL) {
|
||||
printf("Error! No enough memory for romheader.\n");
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
memcpy(romheader, &header, sizeof(RomHeader));
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, offset + sizeof(RomHeader), sizeof(RomFileInfo) * header.filenum,
|
||||
(unsigned char*)romheader + sizeof(RomHeader));
|
||||
#else
|
||||
emmc_read(offset + sizeof(RomHeader), sizeof(RomFileInfo) * header.filenum,
|
||||
(unsigned char*)romheader + sizeof(RomHeader));
|
||||
#endif
|
||||
CP15_clean_dcache_for_dma((uint32_t)romheader, (uint32_t)romheader + sizeof(RomHeader) +
|
||||
sizeof(RomFileInfo) * header.filenum);
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
romfilecache = pvPortMalloc(sizeof(RomFileCache) * ROMFILE_CACHE_DEF_SIZE);
|
||||
if (romfilecache == NULL) {
|
||||
printf("Error! No enough memory for romfile cache.\n");
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
memset(romfilecache, 0, sizeof(RomFileCache) * ROMFILE_CACHE_DEF_SIZE);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
printf("Warning! Not found romfile in update file.\n");
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xSemaphoreGive(romfileMutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RomFile *RomFileOpen(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
xSemaphoreTake(romfileMutex, portMAX_DELAY);
|
||||
|
||||
for (i = 0; i < romheader->filenum; i++) {
|
||||
if (!strcmp(romheader->files[i].name, name)) {
|
||||
RomFile *file = pvPortMalloc(sizeof(RomFile));
|
||||
if (!file) {
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return NULL;
|
||||
}
|
||||
memset(file, 0, sizeof(RomFile));
|
||||
file->index = i;
|
||||
#ifndef ROMFILE_USE_SMALL_MEM
|
||||
file->buf = (void*)((uint32_t)romheader + romheader->files[i].offset);
|
||||
#endif
|
||||
file->size = romheader->files[i].size;
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGive(romfileMutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t RomFileRead(RomFile *file, void *buf, size_t size)
|
||||
{
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if (!file) return 0;
|
||||
|
||||
if (size > file->size - file->pos)
|
||||
size = file->size - file->pos;
|
||||
|
||||
if(size == 0)
|
||||
return 0;
|
||||
|
||||
xSemaphoreTake(romfileMutex, portMAX_DELAY);
|
||||
|
||||
#ifndef ROMFILE_USE_SMALL_MEM
|
||||
#ifndef READ_ROMFILE_ONCE
|
||||
if (!filestatus[file->index]) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
sfud_read(sflash, romoffset + romheader->files[file->index].offset, file->size, file->buf);
|
||||
#else
|
||||
emmc_read(romoffset + romheader->files[file->index].offset, file->size, file->buf);
|
||||
#endif
|
||||
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + file->size);
|
||||
filestatus[file->index] = 1;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
if (!file->cache) {
|
||||
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
|
||||
if(!strcmp(romfilecache[i].name, romheader->files[file->index].name)) {
|
||||
configASSERT(romfilecache[i].buf);
|
||||
file->buf = romfilecache[i].buf;
|
||||
file->cache = &romfilecache[i];
|
||||
romfilecache[i].cached_filenum++;
|
||||
romfilecache[i].life++;
|
||||
if (romfilecache[i].life > ROMFILE_CACHE_LIFE_LIMIT)
|
||||
romfilecache[i].life = ROMFILE_CACHE_LIFE_LIMIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
|
||||
if(romfilecache[i].life > INT32_MIN + 1)
|
||||
romfilecache[i].life -= 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!file->cache) {
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
#endif
|
||||
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
RomFileCache *cachefile = NULL;
|
||||
uint32_t stime;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
|
||||
if (romfilecache[i].name[0] == 0) {
|
||||
cachefile = &romfilecache[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cachefile) {
|
||||
for (i = 0; i < ROMFILE_CACHE_DEF_SIZE; i++) {
|
||||
if (romfilecache[i].cached_filenum == 0) {
|
||||
cachefile = &romfilecache[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cachefile) {
|
||||
for(i = i + 1; i < ROMFILE_CACHE_DEF_SIZE; i++) {
|
||||
if (romfilecache[i].cached_filenum == 0 &&
|
||||
romfilecache[i].life < cachefile->life)
|
||||
cachefile = &romfilecache[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cachefile) {
|
||||
int filelife;
|
||||
|
||||
file->buf = pvPortMalloc(romheader->files[file->index].size);
|
||||
if (!file->buf) {
|
||||
printf("ERROR! No enough memory for opening romfile.\n");
|
||||
vPortFree(file);
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return 0;
|
||||
}
|
||||
stime = get_timer(0);
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, romoffset + romheader->files[file->index].offset, file->size, file->buf);
|
||||
#else
|
||||
emmc_read(romoffset + romheader->files[file->index].offset, file->size, file->buf);
|
||||
#endif
|
||||
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + file->size);
|
||||
filelife = get_timer(stime);
|
||||
if (cachefile->buf)
|
||||
vPortFree(cachefile->buf);
|
||||
strncpy(cachefile->name, romheader->files[file->index].name, ROMFILE_NAME_MAX_LEN);
|
||||
cachefile->buf = file->buf;
|
||||
cachefile->cached_filenum = 1;
|
||||
cachefile->life = filelife;
|
||||
if (cachefile->life > ROMFILE_CACHE_LIFE_LIMIT)
|
||||
cachefile->life = ROMFILE_CACHE_LIFE_LIMIT;
|
||||
file->cache = cachefile;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
file->buf = pvPortMalloc(size);
|
||||
if (!file->buf) {
|
||||
printf("ERROR! No enough memory for opening romfile.\n");
|
||||
vPortFree(file);
|
||||
xSemaphoreGive(romfileMutex);
|
||||
return 0;
|
||||
}
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, romoffset + romheader->files[file->index].offset + file->pos,
|
||||
size, file->buf);
|
||||
#else
|
||||
emmc_read(romoffset + romheader->files[file->index].offset + file->pos,
|
||||
size, file->buf);
|
||||
#endif
|
||||
CP15_clean_dcache_for_dma((uint32_t)file->buf, (uint32_t)file->buf + size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (buf) {
|
||||
#ifdef ROMFILE_USE_SMALL_MEM
|
||||
if (!file->cache) {
|
||||
memcpy(buf, (char *)file->buf, size);
|
||||
vPortFree(file->buf);
|
||||
file->buf = NULL;
|
||||
} else {
|
||||
#endif
|
||||
memcpy(buf, (char *)file->buf + file->pos, size);
|
||||
#ifdef ROMFILE_USE_SMALL_MEM
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
file->pos += size;
|
||||
|
||||
xSemaphoreGive(romfileMutex);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int RomFileSeek(RomFile *file, int offset, int whence)
|
||||
{
|
||||
if (!file) return -1;
|
||||
|
||||
xSemaphoreTake(romfileMutex, portMAX_DELAY);
|
||||
|
||||
if (whence == SEEK_SET)
|
||||
file->pos = offset;
|
||||
else if (whence == SEEK_CUR)
|
||||
file->pos += offset;
|
||||
else if (whence == SEEK_END)
|
||||
file->pos = file->size - 1 + offset;
|
||||
|
||||
if (file->pos >= file->size)
|
||||
file->pos = file->size - 1;
|
||||
else if (file->pos < 0)
|
||||
file->pos = 0;
|
||||
|
||||
xSemaphoreGive(romfileMutex);
|
||||
|
||||
return file->pos;
|
||||
}
|
||||
|
||||
void RomFileClose(RomFile *file)
|
||||
{
|
||||
xSemaphoreTake(romfileMutex, portMAX_DELAY);
|
||||
|
||||
if (file) {
|
||||
#ifdef ROMFILE_USE_SMALL_MEM
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
if (file->cache) {
|
||||
file->cache->cached_filenum--;
|
||||
} else {
|
||||
#endif
|
||||
if (file->buf)
|
||||
vPortFree(file->buf);
|
||||
#if ROMFILE_CACHE_DEF_SIZE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
vPortFree(file);
|
||||
}
|
||||
|
||||
xSemaphoreGive(romfileMutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return with the extension of the filename
|
||||
* @param fn string with a filename
|
||||
* @return pointer to the beginning extension or empty string if no extension
|
||||
*/
|
||||
const char * RomFileGetExt(const char * path)
|
||||
{
|
||||
size_t i;
|
||||
for(i = strlen(path); i > 0; i--) {
|
||||
if(path[i] == '.') {
|
||||
return &path[i + 1];
|
||||
}
|
||||
else if(path[i] == '/' || path[i] == '\\') {
|
||||
return ""; /*No extension if a '\' or '/' found*/
|
||||
}
|
||||
}
|
||||
|
||||
return ""; /*Empty string if no '.' in the file name. */
|
||||
}
|
||||
|
||||
int RomFileTell(RomFile *file)
|
||||
{
|
||||
return file->pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int RomFileGetSize(RomFile *file)
|
||||
{
|
||||
return file->size;
|
||||
}
|
||||
|
||||
int RomFileExist(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < romheader->filenum; i++) {
|
||||
if (!strcmp(romheader->files[i].name, name)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RomFileDirExist(const char *name)
|
||||
{
|
||||
int i;
|
||||
int len = strlen(name);
|
||||
|
||||
for (i = 0; i < romheader->filenum; i++) {
|
||||
if (!strncmp(romheader->files[i].name, name, len) &&
|
||||
romheader->files[i].name[len] == '/') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* ST7701S LCD Display.
|
||||
*
|
||||
* LCD Type: AMT TFT
|
||||
* Display Format: 320(RGB)*960
|
||||
* Input Data: RGB 16bits(RGB565)
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "board.h"
|
||||
#include "chip.h"
|
||||
|
||||
|
||||
//3 lines mode spi.
|
||||
#define ST7701S_GPIO_SPI_CS 23
|
||||
#define ST7701S_GPIO_SPI_SCL 24
|
||||
#define ST7701S_GPIO_SPI_SDA 25
|
||||
#define ST7701S_GPIO_SPI_RST 26
|
||||
|
||||
#define ST7701S_DELAY udelay(5)
|
||||
|
||||
|
||||
static void SPI_SendData(unsigned char value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
if(value & 0x80)
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
|
||||
else
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
|
||||
|
||||
value<<= 1;
|
||||
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
|
||||
ST7701S_DELAY;
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
|
||||
ST7701S_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
static void SPI_WriteComm(unsigned char value)
|
||||
{
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
|
||||
|
||||
//D/CX = 0
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
|
||||
ST7701S_DELAY;
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
|
||||
ST7701S_DELAY;
|
||||
|
||||
//Command data.
|
||||
SPI_SendData(value);
|
||||
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
|
||||
ST7701S_DELAY;
|
||||
}
|
||||
|
||||
static void SPI_WriteData(unsigned char value)
|
||||
{
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_CS, 0); //CS=0
|
||||
|
||||
//D/CX = 1
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 1); //SDA=1
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 0); //SCL=0
|
||||
ST7701S_DELAY;
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
|
||||
ST7701S_DELAY;
|
||||
|
||||
//Parameter data.
|
||||
SPI_SendData(value);
|
||||
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
|
||||
ST7701S_DELAY;
|
||||
}
|
||||
|
||||
static void st7701s_reg_init(void)
|
||||
{
|
||||
SPI_WriteComm (0xFF);
|
||||
SPI_WriteData (0x77);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x13);
|
||||
|
||||
SPI_WriteComm (0xEF);
|
||||
SPI_WriteData (0x08);
|
||||
|
||||
SPI_WriteComm (0xFF);
|
||||
SPI_WriteData (0x77);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x10);
|
||||
|
||||
SPI_WriteComm (0xC0);
|
||||
SPI_WriteData (0x77);
|
||||
SPI_WriteData (0x00);
|
||||
|
||||
SPI_WriteComm (0xC1); //proch control.
|
||||
SPI_WriteData (0x09); //vbp
|
||||
SPI_WriteData (0x08); //vfp
|
||||
|
||||
SPI_WriteComm (0xC2); //inv
|
||||
#if 0
|
||||
SPI_WriteData (0x01);
|
||||
#else
|
||||
SPI_WriteData (0x07);
|
||||
#endif
|
||||
SPI_WriteData (0x02);
|
||||
|
||||
//default:0x00, DE mode.
|
||||
SPI_WriteComm (0xC3); //RGB control.
|
||||
SPI_WriteData (0x02); //82 HVmode 02 DEmode
|
||||
|
||||
#if 0 //default:0x00
|
||||
SPI_WriteComm (0xC7); //add. Source direction control.
|
||||
SPI_WriteData (0x04); //0x00:Source form 0 to 479, 0x04:from 479 to 0.
|
||||
#endif
|
||||
|
||||
SPI_WriteComm (0xCC);
|
||||
SPI_WriteData (0x10);
|
||||
|
||||
SPI_WriteComm (0xB0);
|
||||
SPI_WriteData (0x40);
|
||||
SPI_WriteData (0x14);
|
||||
SPI_WriteData (0x59);
|
||||
SPI_WriteData (0x10);
|
||||
SPI_WriteData (0x12);
|
||||
SPI_WriteData (0x08);
|
||||
SPI_WriteData (0x03);
|
||||
SPI_WriteData (0x09);
|
||||
SPI_WriteData (0x05);
|
||||
SPI_WriteData (0x1E);
|
||||
SPI_WriteData (0x05);
|
||||
SPI_WriteData (0x14);
|
||||
SPI_WriteData (0x10);
|
||||
SPI_WriteData (0x68);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x15);
|
||||
|
||||
SPI_WriteComm (0xB1);
|
||||
SPI_WriteData (0x40);
|
||||
SPI_WriteData (0x08);
|
||||
SPI_WriteData (0x53);
|
||||
SPI_WriteData (0x09);
|
||||
SPI_WriteData (0x11);
|
||||
SPI_WriteData (0x09);
|
||||
SPI_WriteData (0x02);
|
||||
SPI_WriteData (0x07);
|
||||
SPI_WriteData (0x09);
|
||||
SPI_WriteData (0x1A);
|
||||
SPI_WriteData (0x04);
|
||||
SPI_WriteData (0x12);
|
||||
SPI_WriteData (0x12);
|
||||
SPI_WriteData (0x64);
|
||||
SPI_WriteData (0x29);
|
||||
SPI_WriteData (0x29);
|
||||
|
||||
SPI_WriteComm (0xFF);
|
||||
SPI_WriteData (0x77);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x11);
|
||||
|
||||
SPI_WriteComm (0xB0);
|
||||
SPI_WriteData (0x6D); //6D
|
||||
|
||||
SPI_WriteComm (0xB1); //vcom
|
||||
SPI_WriteData (0x1D);
|
||||
|
||||
SPI_WriteComm (0xB2);
|
||||
SPI_WriteData (0x87);
|
||||
|
||||
SPI_WriteComm (0xB3);
|
||||
SPI_WriteData (0x80);
|
||||
|
||||
SPI_WriteComm (0xB5);
|
||||
SPI_WriteData (0x49);
|
||||
|
||||
SPI_WriteComm (0xB7);
|
||||
SPI_WriteData (0x85);
|
||||
|
||||
SPI_WriteComm (0xB8);
|
||||
SPI_WriteData (0x20);
|
||||
|
||||
SPI_WriteComm (0xC1);
|
||||
SPI_WriteData (0x78);
|
||||
|
||||
SPI_WriteComm (0xC2);
|
||||
SPI_WriteData (0x78);
|
||||
|
||||
SPI_WriteComm (0xD0);
|
||||
SPI_WriteData (0x88);
|
||||
|
||||
SPI_WriteComm (0xE0);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x02);
|
||||
|
||||
SPI_WriteComm (0xE1);
|
||||
SPI_WriteData (0x02);
|
||||
SPI_WriteData (0x8C);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x03);
|
||||
SPI_WriteData (0x8C);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
|
||||
SPI_WriteComm (0xE2);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0xC9);
|
||||
SPI_WriteData (0x3C);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0xCA);
|
||||
SPI_WriteData (0x3C);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
|
||||
SPI_WriteComm (0xE3);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
|
||||
SPI_WriteComm (0xE4);
|
||||
SPI_WriteData (0x44);
|
||||
SPI_WriteData (0x44);
|
||||
|
||||
SPI_WriteComm (0xE5);
|
||||
SPI_WriteData (0x05);
|
||||
SPI_WriteData (0xCD);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0xC9);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x07);
|
||||
SPI_WriteData (0xCF);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x03);
|
||||
SPI_WriteData (0xCB);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
|
||||
SPI_WriteComm (0xE6);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x33);
|
||||
SPI_WriteData (0x33);
|
||||
|
||||
SPI_WriteComm (0xE7);
|
||||
SPI_WriteData (0x44);
|
||||
SPI_WriteData (0x44);
|
||||
|
||||
SPI_WriteComm (0xE8);
|
||||
SPI_WriteData (0x06);
|
||||
SPI_WriteData (0xCE);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x02);
|
||||
SPI_WriteData (0xCA);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x08);
|
||||
SPI_WriteData (0xD0);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x04);
|
||||
SPI_WriteData (0xCC);
|
||||
SPI_WriteData (0x82);
|
||||
SPI_WriteData (0x82);
|
||||
|
||||
SPI_WriteComm (0xEB);
|
||||
SPI_WriteData (0x08);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0xE4);
|
||||
SPI_WriteData (0xE4);
|
||||
SPI_WriteData (0x88);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x40);
|
||||
|
||||
SPI_WriteComm (0xEC);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
|
||||
SPI_WriteComm (0xED);
|
||||
SPI_WriteData (0xFF);
|
||||
SPI_WriteData (0xF0);
|
||||
SPI_WriteData (0x07);
|
||||
SPI_WriteData (0x65);
|
||||
SPI_WriteData (0x4F);
|
||||
SPI_WriteData (0xFC);
|
||||
SPI_WriteData (0xC2);
|
||||
SPI_WriteData (0x2F);
|
||||
SPI_WriteData (0xF2);
|
||||
SPI_WriteData (0x2C);
|
||||
SPI_WriteData (0xCF);
|
||||
SPI_WriteData (0xF4);
|
||||
SPI_WriteData (0x56);
|
||||
SPI_WriteData (0x70);
|
||||
SPI_WriteData (0x0F);
|
||||
SPI_WriteData (0xFF);
|
||||
|
||||
SPI_WriteComm (0xEF);
|
||||
SPI_WriteData (0x10);
|
||||
SPI_WriteData (0x0D);
|
||||
SPI_WriteData (0x04);
|
||||
SPI_WriteData (0x08);
|
||||
SPI_WriteData (0x3F);
|
||||
SPI_WriteData (0x1F);
|
||||
|
||||
SPI_WriteComm (0xFF);
|
||||
SPI_WriteData (0x77);
|
||||
SPI_WriteData (0x01);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
SPI_WriteData (0x00);
|
||||
|
||||
mdelay(114); //Sleep out cmd cannot be send after hw-reset for 120ms.
|
||||
SPI_WriteComm (0x11); //sleep out.
|
||||
|
||||
SPI_WriteComm (0x35);
|
||||
SPI_WriteData (0x00);
|
||||
|
||||
#if 0
|
||||
SPI_WriteComm (0x36); //
|
||||
SPI_WriteData (0x10); //bit4(0:normal scan, 1:inverse scan); bit3(0:RGB, 1:BGR), default:0x00
|
||||
#endif
|
||||
|
||||
SPI_WriteComm (0x3A); //RGB Interface pixel format.
|
||||
SPI_WriteData (0x77); //bit[4-6](101:16-bit/pixel; 110:18-bit/pixel;111:24-bit/pixel), default:0x70
|
||||
|
||||
//SPI_WriteComm (0x11);
|
||||
//Delay(120);
|
||||
|
||||
SPI_WriteComm (0x29); //display on.
|
||||
}
|
||||
|
||||
static void st7701s_hw_reset(void)
|
||||
{
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
|
||||
mdelay(10);
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_RST, 0);
|
||||
mdelay(1); //>=9us
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_RST, 1);
|
||||
mdelay(6); //>=5ms
|
||||
}
|
||||
|
||||
int st7701s_init(void)
|
||||
{
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_CS, 1); //CS=1
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SCL, 1); //SCL=1
|
||||
gpio_direction_output(ST7701S_GPIO_SPI_SDA, 0); //SDA=0
|
||||
|
||||
st7701s_hw_reset();
|
||||
|
||||
st7701s_reg_init();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "sfud.h"
|
||||
#include "sysinfo.h"
|
||||
#include "crc32.h"
|
||||
|
||||
#if DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
#include "mmcsd_core.h"
|
||||
#endif
|
||||
|
||||
#pragma data_alignment=4
|
||||
static SysInfo amt630h_sysinfo;
|
||||
|
||||
int ReadSysInfo(void)
|
||||
{
|
||||
unsigned int checksum;
|
||||
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
|
||||
sfud_read(sflash, SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
#else
|
||||
emmc_read(SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
#endif
|
||||
checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
|
||||
if (checksum == amt630h_sysinfo.checksum)
|
||||
return 0;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_read(sflash, SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
#else
|
||||
emmc_read(SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
#endif
|
||||
checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
|
||||
if (checksum == amt630h_sysinfo.checksum)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
SysInfo *GetSysInfo(void)
|
||||
{
|
||||
return &amt630h_sysinfo;
|
||||
}
|
||||
|
||||
void SaveSysInfo(void)
|
||||
{
|
||||
amt630h_sysinfo.checksum = xcrc32((unsigned char*)&amt630h_sysinfo, sizeof(SysInfo) - 4, 0xffffffff);
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
sfud_flash *sflash = sfud_get_device(0);
|
||||
if(sflash) {
|
||||
sfud_erase_write(sflash, SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
sfud_erase_write(sflash, SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
}
|
||||
#else
|
||||
emmc_write(SYSINFOB_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
emmc_write(SYSINFOA_MEDIA_OFFSET, sizeof(SysInfo), (void*)&amt630h_sysinfo);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,997 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "touch.h"
|
||||
|
||||
#if !defined(VG_ONLY) && !defined(AWTK)
|
||||
#include "lvgl/lvgl.h"
|
||||
#else
|
||||
typedef int16_t lv_coord_t;
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
typedef struct {
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
|
||||
|
||||
enum {
|
||||
LV_KEY_UP = 17, /*0x11*/
|
||||
LV_KEY_DOWN = 18, /*0x12*/
|
||||
LV_KEY_RIGHT = 19, /*0x13*/
|
||||
LV_KEY_LEFT = 20, /*0x14*/
|
||||
LV_KEY_ESC = 27, /*0x1B*/
|
||||
LV_KEY_DEL = 127, /*0x7F*/
|
||||
LV_KEY_BACKSPACE = 8, /*0x08*/
|
||||
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
|
||||
LV_KEY_NEXT = 9, /*0x09, '\t'*/
|
||||
LV_KEY_PREV = 11, /*0x0B, '*/
|
||||
LV_KEY_HOME = 2, /*0x02, STX*/
|
||||
LV_KEY_END = 3, /*0x03, ETX*/
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
} lv_indev_data_t;
|
||||
#endif
|
||||
|
||||
#ifdef ADC_TOUCH
|
||||
|
||||
#define TOUCH_STATE_IDLE 0
|
||||
#define TOUCH_STATE_START 1
|
||||
#define TOUCH_STATE_SAMPLE 2
|
||||
#define TOUCH_STATE_STOP 3
|
||||
|
||||
#define MAX_POINT_POOL_SIZE 2
|
||||
#define FILTER_MAX 3
|
||||
|
||||
#define MAXPANADCLEN 20
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} POINT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 adcX;
|
||||
UINT16 adcY;
|
||||
} PAN_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 *pValue;
|
||||
UINT32 header;
|
||||
UINT32 trail;
|
||||
UINT32 quelen;
|
||||
} ADCValueQueue;
|
||||
|
||||
static calibration cal;
|
||||
static UINT32 lg_ulTouchMachineState = TOUCH_STATE_IDLE;
|
||||
static POINT lg_stLastMovePoint;
|
||||
ADCValueQueue panADCXQueue;
|
||||
ADCValueQueue panADCYQueue;
|
||||
UINT32 PANADC_X[MAXPANADCLEN];
|
||||
UINT32 PANADC_Y[MAXPANADCLEN];
|
||||
|
||||
static INT32 Queue_ADCValue_Init(ADCValueQueue *pQueue, UINT32 *pValue, UINT32 quelen)
|
||||
{
|
||||
INT32 ret=0;
|
||||
|
||||
if((pQueue != 0) && (pValue != 0) && (quelen > 0))
|
||||
{
|
||||
pQueue->pValue = pValue;
|
||||
pQueue->quelen = quelen;
|
||||
pQueue->header = 0;
|
||||
pQueue->trail = 0;
|
||||
ret =1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static INT32 Queue_ADCValue_Length(ADCValueQueue *pQueue)
|
||||
{
|
||||
INT32 queuelen=0;
|
||||
|
||||
if(pQueue != 0)
|
||||
{
|
||||
if(pQueue->trail < pQueue->header)
|
||||
{
|
||||
queuelen = pQueue->quelen +(pQueue->trail- pQueue->header);
|
||||
}
|
||||
else
|
||||
queuelen = pQueue->trail- pQueue->header;
|
||||
}
|
||||
|
||||
return queuelen;
|
||||
}
|
||||
|
||||
static INT32 Queue_ADCValue_Add(ADCValueQueue *pQueue,unsigned int value)
|
||||
{
|
||||
INT32 ret=0;
|
||||
UINT32 *pValue=0;
|
||||
|
||||
if(pQueue != 0)
|
||||
{
|
||||
pValue = pQueue->pValue + pQueue->trail;
|
||||
*pValue = value;
|
||||
|
||||
pQueue->trail++;
|
||||
if(pQueue->trail >= pQueue->quelen)
|
||||
{
|
||||
pQueue->trail = 0;
|
||||
}
|
||||
|
||||
if(pQueue->trail == pQueue->header)
|
||||
{
|
||||
pQueue->header++;
|
||||
if(pQueue->header >= pQueue->quelen)
|
||||
{
|
||||
pQueue->header = 1;
|
||||
pQueue->trail=0;
|
||||
}
|
||||
}
|
||||
|
||||
ret=1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static INT32 Queue_ADCValue_Read(ADCValueQueue *pQueue, UINT32 *pValue)
|
||||
{
|
||||
INT32 ret=0;
|
||||
UINT32 *pHeaderValue=0;
|
||||
|
||||
if((pQueue != 0) && (pValue != 0))
|
||||
{
|
||||
if(Queue_ADCValue_Length(pQueue) > 0)
|
||||
{
|
||||
pHeaderValue = pQueue->pValue + pQueue->header;
|
||||
*pValue = *pHeaderValue;
|
||||
|
||||
pQueue->header++;
|
||||
if(pQueue->header >= pQueue->quelen)
|
||||
{
|
||||
pQueue->header = 0;
|
||||
}
|
||||
|
||||
ret=1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
static UINT32 GetADCTouch(PAN_DATA *pPan)
|
||||
{
|
||||
UINT32 panX;
|
||||
UINT32 panY;
|
||||
|
||||
INT32 ret=0;
|
||||
|
||||
if(pPan != 0)
|
||||
{
|
||||
ret = Queue_ADCValue_Read(&panADCXQueue,&panX);
|
||||
if(ret==1)
|
||||
{
|
||||
ret = Queue_ADCValue_Read(&panADCYQueue,&panY);
|
||||
if(ret == 1)
|
||||
{
|
||||
pPan->adcX = panX;
|
||||
pPan->adcY = panY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void CalcCoord(PAN_DATA *pPan, POINT *pPT);
|
||||
|
||||
#define TOUCH_DOT_REGION 10
|
||||
|
||||
extern void SendTouchInputEventFromISR(lv_indev_data_t *indata);
|
||||
|
||||
/***********************************************************************************************
|
||||
通过大量试验发现触摸屏存在的问题有
|
||||
1: 触摸刚开始的几个点可能任意哪个点或者哪几个点会有较大偏差;
|
||||
2: 释放前的采样点很大几率不准确。
|
||||
|
||||
为了应对各种错误情况,采取的措施有
|
||||
1: 首先简单地丢弃掉最后一个采样点
|
||||
2: 提高采样频率,保证最开始的几个采样点都在一个比较小的范围
|
||||
内(即使快速滑动,刚开始不会有很大速度,因此也能保证起始点
|
||||
比较聚集)。在这种前提下提取开始采样时的若干个点进行分析,
|
||||
找出坐标值比较接近的点数最多的点,其他点则认为是错误点丢
|
||||
弃掉,如果找不到的话则认为所有点都不稳定,重新再提取之后
|
||||
的若干个点进行分析。
|
||||
*************************************************************************************************/
|
||||
#define SCOPE_ADJUST 8
|
||||
|
||||
#define ANALYSIS_POINT_SUCCESS 3
|
||||
#define ANALYSIS_POINT_COUNT 5
|
||||
#define DISCARD_POINT_COUNT 2
|
||||
#define POINT_POOL_SIZE (ANALYSIS_POINT_COUNT+DISCARD_POINT_COUNT)
|
||||
|
||||
#define MYABS(x) (((x)>=0) ? (x) : (-(x)))
|
||||
/*
|
||||
*********************************************************************************************************
|
||||
* Description: 分析采样最开始的若干点,丢弃错误点
|
||||
*
|
||||
* Arguments : point[] : 采样点坐标值数组
|
||||
num : 用于分析的采样点个数
|
||||
*
|
||||
* Returns : 有效点的个数,返回0表示所有点都无效
|
||||
|
||||
* Notes : 剩余的有效点重新从原数组起始位置开始依次放置
|
||||
*********************************************************************************************************
|
||||
*/
|
||||
static int Touch_Start_Analyse(POINT point[], int num)
|
||||
{
|
||||
int i, j;
|
||||
int key[ANALYSIS_POINT_COUNT] = {0};
|
||||
int near_by_point[ANALYSIS_POINT_COUNT] = {0};
|
||||
int effective_near_by_points[ANALYSIS_POINT_COUNT] = {0};
|
||||
int max = -1;
|
||||
int samplecnt = 0;
|
||||
|
||||
if(num > ANALYSIS_POINT_COUNT)
|
||||
num = ANALYSIS_POINT_COUNT;
|
||||
|
||||
for(i=0; i<num; i++)
|
||||
{
|
||||
//计算每个点和其接近的点的个数并记录下距离最近的点
|
||||
near_by_point[i] = 1;
|
||||
for(j=0; j<num; j++)
|
||||
{
|
||||
if(j == i)
|
||||
continue;
|
||||
|
||||
if(MYABS(point[i].x - point[j].x)<SCOPE_ADJUST && MYABS(point[i].y - point[j].y)<SCOPE_ADJUST)
|
||||
{
|
||||
key[i]++;
|
||||
near_by_point[j] = 1;
|
||||
}
|
||||
else
|
||||
near_by_point[j] = 0;
|
||||
}
|
||||
|
||||
//筛选出相近点数最多的点并记录下与其距离最近的点位置
|
||||
if(key[i] > max)
|
||||
{
|
||||
max = key[i];
|
||||
for(j=0;j<num;j++)
|
||||
{
|
||||
effective_near_by_points[j] = near_by_point[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//有效点个数不够,判定所有点都不稳定全部丢弃
|
||||
if(max < ANALYSIS_POINT_SUCCESS-1)
|
||||
return 0;
|
||||
|
||||
//移除所有无效点,有效点从原数组位置0开始依次放置
|
||||
for(i=0; i<num; i++)
|
||||
{
|
||||
if(effective_near_by_points[i])
|
||||
{
|
||||
point[samplecnt] = point[i];
|
||||
samplecnt++;
|
||||
}
|
||||
}
|
||||
|
||||
return samplecnt;
|
||||
}
|
||||
|
||||
static void Handler_Touch_IntEvent(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
|
||||
{
|
||||
static int s_SampleCnt;
|
||||
static int s_PoolIndex;
|
||||
static POINT s_PointPool[POINT_POOL_SIZE];
|
||||
|
||||
switch(lg_ulTouchMachineState)
|
||||
{
|
||||
case TOUCH_STATE_IDLE:
|
||||
if(ulEvent == TOUCH_START_EVENT)
|
||||
{
|
||||
lg_ulTouchMachineState = TOUCH_STATE_START;
|
||||
s_SampleCnt = 0;
|
||||
s_PoolIndex = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_START:
|
||||
if(ulEvent == TOUCH_STOP_EVENT)
|
||||
{
|
||||
lg_ulTouchMachineState = TOUCH_STATE_IDLE;
|
||||
}
|
||||
else if(ulEvent == TOUCH_SAMPLE_EVENT)
|
||||
{
|
||||
POINT pt;
|
||||
PAN_DATA stPanData;
|
||||
lv_indev_data_t indata = {0};
|
||||
int i;
|
||||
|
||||
//get cordinate
|
||||
stPanData.adcX = lpParam;
|
||||
stPanData.adcY = wParam;
|
||||
CalcCoord(&stPanData, &pt);
|
||||
if(pt.x < 0 || pt.y < 0)
|
||||
return;
|
||||
|
||||
if(pt.x < 0 || pt.x >= LCD_WIDTH || pt.y < 0 || pt.y >= LCD_HEIGHT)
|
||||
return;
|
||||
|
||||
//防止ANALYSIS_POINT_START个点内包含最后要丢弃的点,刚开始要暂存
|
||||
//ANALYSIS_POINT_START + DISCARD_POINT_END个点
|
||||
if(s_SampleCnt < ANALYSIS_POINT_COUNT + DISCARD_POINT_COUNT)
|
||||
{
|
||||
s_PointPool[s_SampleCnt++] = pt;
|
||||
if(s_SampleCnt < ANALYSIS_POINT_COUNT + DISCARD_POINT_COUNT)
|
||||
return;
|
||||
}
|
||||
|
||||
s_SampleCnt = Touch_Start_Analyse(s_PointPool, ANALYSIS_POINT_COUNT);
|
||||
if(s_SampleCnt == 0)
|
||||
{
|
||||
for(i=0; i<DISCARD_POINT_COUNT; i++)
|
||||
s_PointPool[i] = s_PointPool[ANALYSIS_POINT_COUNT+i];
|
||||
s_SampleCnt = DISCARD_POINT_COUNT;
|
||||
return;
|
||||
}
|
||||
//send press event
|
||||
indata.point.x = s_PointPool[0].x;
|
||||
indata.point.y = s_PointPool[0].y;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendTouchInputEventFromISR(&indata);
|
||||
|
||||
lg_ulTouchMachineState = TOUCH_STATE_SAMPLE;
|
||||
|
||||
//将为满足最后丢弃任务而暂存的点复制到分析后剩余点之后
|
||||
for(i=0; i<DISCARD_POINT_COUNT; i++)
|
||||
s_PointPool[s_SampleCnt + i] = s_PointPool[ANALYSIS_POINT_COUNT+i];
|
||||
s_PoolIndex = 1;
|
||||
//计算此时剩余的未操作的有效点数
|
||||
s_SampleCnt = s_SampleCnt - 1 + DISCARD_POINT_COUNT;
|
||||
//send move event in the pool
|
||||
while(s_SampleCnt > DISCARD_POINT_COUNT)
|
||||
{
|
||||
int xdiff, ydiff;
|
||||
unsigned int totaldiff;
|
||||
|
||||
xdiff = s_PointPool[s_PoolIndex].x - lg_stLastMovePoint.x;
|
||||
ydiff = s_PointPool[s_PoolIndex].y - lg_stLastMovePoint.y;
|
||||
totaldiff = xdiff * xdiff + ydiff * ydiff;
|
||||
if(totaldiff > 4)
|
||||
{
|
||||
indata.point.x = s_PointPool[s_PoolIndex].x;
|
||||
indata.point.y = s_PointPool[s_PoolIndex].y;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendTouchInputEventFromISR(&indata);
|
||||
lg_stLastMovePoint.x = s_PointPool[s_PoolIndex].x;
|
||||
lg_stLastMovePoint.y = s_PointPool[s_PoolIndex].y;
|
||||
}
|
||||
s_PoolIndex++;
|
||||
s_SampleCnt--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_SAMPLE:
|
||||
if(ulEvent == TOUCH_SAMPLE_EVENT)
|
||||
{
|
||||
//caculate move center cordinate
|
||||
//if move, then send move event
|
||||
PAN_DATA stPanData;
|
||||
POINT pt;
|
||||
int xDiff = 0, yDiff = 0;
|
||||
unsigned int totalDiff = 0;
|
||||
|
||||
//get cordinate
|
||||
stPanData.adcX = lpParam;
|
||||
stPanData.adcY = wParam;
|
||||
CalcCoord(&stPanData, &pt);
|
||||
if(pt.x < 0 || pt.y < 0)
|
||||
return;
|
||||
|
||||
if(pt.x < 0 || pt.x >= LCD_WIDTH || pt.y < 0 || pt.y >= LCD_HEIGHT)
|
||||
return;
|
||||
|
||||
if(s_SampleCnt < DISCARD_POINT_COUNT)
|
||||
{
|
||||
int index = (s_PoolIndex+s_SampleCnt++) % POINT_POOL_SIZE;
|
||||
|
||||
s_PointPool[index] = pt;
|
||||
return;
|
||||
}
|
||||
|
||||
xDiff = s_PointPool[s_PoolIndex].x - lg_stLastMovePoint.x;
|
||||
yDiff = s_PointPool[s_PoolIndex].y - lg_stLastMovePoint.y;
|
||||
totalDiff = xDiff * xDiff + yDiff * yDiff;
|
||||
if(totalDiff > 4)
|
||||
{
|
||||
lv_indev_data_t indata = {0};
|
||||
|
||||
indata.point.x = s_PointPool[s_PoolIndex].x;
|
||||
indata.point.y = s_PointPool[s_PoolIndex].y;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendTouchInputEventFromISR(&indata);
|
||||
lg_stLastMovePoint.x = s_PointPool[s_PoolIndex].x;
|
||||
lg_stLastMovePoint.y = s_PointPool[s_PoolIndex].y;
|
||||
}
|
||||
s_PointPool[(s_PoolIndex+DISCARD_POINT_COUNT)%POINT_POOL_SIZE] = pt;
|
||||
s_PoolIndex = (s_PoolIndex+1)%POINT_POOL_SIZE;
|
||||
}
|
||||
else if(ulEvent == TOUCH_STOP_EVENT)
|
||||
{
|
||||
lv_indev_data_t indata = {0};
|
||||
|
||||
//send release event
|
||||
indata.point.x = lg_stLastMovePoint.x;
|
||||
indata.point.y = lg_stLastMovePoint.y;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendTouchInputEventFromISR(&indata);
|
||||
lg_ulTouchMachineState = TOUCH_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOUCH_STATE_STOP:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static volatile UINT32 lg_bTouchStart = 0;
|
||||
static UINT32 CheckTouchStart()
|
||||
{
|
||||
return lg_bTouchStart == 1;
|
||||
}
|
||||
|
||||
static UINT32 CheckTouchStop()
|
||||
{
|
||||
return lg_bTouchStart == 0;
|
||||
}
|
||||
|
||||
static UINT32 GetTouchSampleCounter()
|
||||
{
|
||||
return Queue_ADCValue_Length(&panADCXQueue);
|
||||
}
|
||||
|
||||
static UINT32 lg_bTouchAdjusted = 0;
|
||||
void TouchEventHandler(UINT32 ulEvent, UINT32 lpParam, UINT32 wParam)
|
||||
{
|
||||
if(lg_bTouchAdjusted)
|
||||
{
|
||||
Handler_Touch_IntEvent(ulEvent, lpParam, wParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if(ulEvent == TOUCH_START_EVENT)
|
||||
{
|
||||
lg_bTouchStart = 1;
|
||||
Queue_ADCValue_Init(&panADCXQueue, PANADC_X, MAXPANADCLEN);
|
||||
Queue_ADCValue_Init(&panADCYQueue, PANADC_Y, MAXPANADCLEN);
|
||||
}
|
||||
else if(ulEvent == TOUCH_SAMPLE_EVENT)
|
||||
{
|
||||
Queue_ADCValue_Add(&panADCXQueue,lpParam);
|
||||
Queue_ADCValue_Add(&panADCYQueue,wParam);
|
||||
}
|
||||
else if(ulEvent == TOUCH_STOP_EVENT)
|
||||
{
|
||||
lg_bTouchStart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
触摸屏坐标校验代码
|
||||
***************************************************************************************/
|
||||
|
||||
|
||||
#define GRID_RANGE 12
|
||||
#define HIT_RANGE 2
|
||||
#define ABS_HIT ((GRID_RANGE+HIT_RANGE)*2)
|
||||
|
||||
#define TOUCH_HIGH_EXACTION 0
|
||||
#define TOUCH_MID_EXACTION 0
|
||||
#define TOUCH_LOW_EXACTION 1
|
||||
|
||||
|
||||
#define TOUCH_REVISE_DEBUG 1
|
||||
|
||||
#if TOUCH_REVISE_DEBUG
|
||||
#define TOUCH_DEBUG_MSG(fmt, args...) printf(fmt, ##args)
|
||||
#else
|
||||
#define TOUCH_DEBUG_MSG(fmt, args...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define SYSTEM_ERROR 100.0
|
||||
|
||||
#define SCALE_AERROR 2// 3 这里考虑触摸屏的差异修改20130618
|
||||
#define SCALE_DERROR 5
|
||||
static double abs_ax,abs_dx,abs_ly,abs_ry;
|
||||
static double abs_lx,abs_rx;
|
||||
static double abs_err1,abs_err2,abs_err3,abs_err4,abs_err5;
|
||||
static double abs_cx,abs_cy;
|
||||
static int lg_direction = 0;
|
||||
|
||||
#if TOUCH_HIGH_EXACTION
|
||||
#define SYSTEM_ERROR1 100.0
|
||||
#elif TOUCH_MID_EXACTION
|
||||
#define SYSTEM_ERROR1 150.0
|
||||
#elif TOUCH_LOW_EXACTION
|
||||
#define SYSTEM_ERROR1 200.0
|
||||
#else
|
||||
#define SYSTEM_ERROR1 150.0
|
||||
#endif
|
||||
|
||||
/* static void InitializeCalibration(int a0, int a1, int a2, int a3, int a4, int a5, int a6)
|
||||
{
|
||||
cal.a[0] = a0;
|
||||
cal.a[1] = a1;
|
||||
cal.a[2] = a2;
|
||||
cal.a[3] = a3;
|
||||
cal.a[4] = a4;
|
||||
cal.a[5] = a5;
|
||||
cal.a[6] = a6;
|
||||
} */
|
||||
|
||||
static void SaveCalibration(calibration *pCalibration)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int perform_calibration(calibration *cal) {
|
||||
int j;
|
||||
float n, x, y, x2, y2, xy, z, zx, zy;
|
||||
float det, a, b, c, e, f, i;
|
||||
float scaling = 65536.0;
|
||||
|
||||
// Get sums for matrix
|
||||
n = x = y = x2 = y2 = xy = 0;
|
||||
for(j=0;j<5;j++) {
|
||||
n += 1.0;
|
||||
x += (float)cal->x[j];
|
||||
y += (float)cal->y[j];
|
||||
x2 += (float)(cal->x[j]*cal->x[j]);
|
||||
y2 += (float)(cal->y[j]*cal->y[j]);
|
||||
xy += (float)(cal->x[j]*cal->y[j]);
|
||||
}
|
||||
|
||||
// Get determinant of matrix -- check if determinant is too small
|
||||
det = n*(x2*y2 - xy*xy) + x*(xy*y - x*y2) + y*(x*xy - y*x2);
|
||||
if(det < 0.1 && det > -0.1) {
|
||||
printf("ts_calibrate: determinant is too small -- %f\n",det);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get elements of inverse matrix
|
||||
a = (x2*y2 - xy*xy)/det;
|
||||
b = (xy*y - x*y2)/det;
|
||||
c = (x*xy - y*x2)/det;
|
||||
e = (n*y2 - y*y)/det;
|
||||
f = (x*y - n*xy)/det;
|
||||
i = (n*x2 - x*x)/det;
|
||||
|
||||
// Get sums for x calibration
|
||||
z = zx = zy = 0;
|
||||
for(j=0;j<5;j++) {
|
||||
z += (float)cal->xfb[j];
|
||||
zx += (float)(cal->xfb[j]*cal->x[j]);
|
||||
zy += (float)(cal->xfb[j]*cal->y[j]);
|
||||
}
|
||||
|
||||
// Now multiply out to get the calibration for framebuffer x coord
|
||||
cal->a[0] = (int)((a*z + b*zx + c*zy)*(scaling));
|
||||
cal->a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
|
||||
cal->a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
|
||||
|
||||
// Get sums for y calibration
|
||||
z = zx = zy = 0;
|
||||
for(j=0;j<5;j++) {
|
||||
z += (float)cal->yfb[j];
|
||||
zx += (float)(cal->yfb[j]*cal->x[j]);
|
||||
zy += (float)(cal->yfb[j]*cal->y[j]);
|
||||
}
|
||||
|
||||
// Now multiply out to get the calibration for framebuffer y coord
|
||||
cal->a[3] = (int)((a*z + b*zx + c*zy)*(scaling));
|
||||
cal->a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
|
||||
cal->a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
|
||||
|
||||
// If we got here, we're OK, so assign scaling to a[6] and return
|
||||
cal->a[6] = (int)scaling;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CleanTouchAdjustParameter(void)
|
||||
{
|
||||
Queue_ADCValue_Init(&panADCXQueue, PANADC_X, MAXPANADCLEN);
|
||||
Queue_ADCValue_Init(&panADCYQueue, PANADC_Y, MAXPANADCLEN);
|
||||
lg_bTouchAdjusted = 0;
|
||||
}
|
||||
|
||||
void TouchInit(void)
|
||||
{
|
||||
CleanTouchAdjustParameter();
|
||||
}
|
||||
|
||||
static void CalcCoord(PAN_DATA *pPan, POINT *pPT)
|
||||
{
|
||||
pPT->x = (pPan->adcX * cal.a[1] + pPan->adcY * cal.a[2] + cal.a[0])/cal.a[6];
|
||||
pPT->y = (pPan->adcX * cal.a[4] + pPan->adcY * cal.a[5] + cal.a[3])/cal.a[6];
|
||||
}
|
||||
|
||||
static unsigned int GetTouchHit(PAN_DATA *pPan)
|
||||
{
|
||||
unsigned int PanReq;
|
||||
PAN_DATA Pan[50];
|
||||
unsigned int i, Count;
|
||||
|
||||
for(i = 0; i < 50; i++)
|
||||
{
|
||||
Pan[i].adcX = 0xFFFF;
|
||||
Pan[i].adcY = 0xFFFF;
|
||||
}
|
||||
|
||||
ReStartCheck:
|
||||
while(!CheckTouchStart());
|
||||
while(!CheckTouchStop());
|
||||
if(GetTouchSampleCounter() < 16)
|
||||
goto ReStartCheck;
|
||||
|
||||
AIC_DisableIT(ADC_IRQn);
|
||||
while(1)
|
||||
{
|
||||
PanReq = GetADCTouch(&Pan[49]);
|
||||
|
||||
if(PanReq==0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
for(i = 0; i < 49; i++)
|
||||
{
|
||||
Pan[i].adcX = Pan[i+1].adcX;
|
||||
Pan[i].adcY = Pan[i+1].adcY;
|
||||
}
|
||||
}
|
||||
AIC_EnableIT(ADC_IRQn);
|
||||
|
||||
Count = 0;
|
||||
|
||||
for(i = 0; i < 49; i++)
|
||||
{
|
||||
if(Pan[i].adcY < 0xFFF)
|
||||
{
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
|
||||
pPan->adcX = Pan[49-Count/2].adcX;
|
||||
pPan->adcY = Pan[49-Count/2].adcY;
|
||||
|
||||
|
||||
TOUCH_DEBUG_MSG("Hit Count = %d\n", Count);
|
||||
TOUCH_DEBUG_MSG("pPan->adcX=%d\n",pPan->adcX);
|
||||
TOUCH_DEBUG_MSG("pPan->adcY=%d\n",pPan->adcY);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ClearBitmap(lv_color_t color, const lv_area_t * area, lv_color_t * color_p)
|
||||
{
|
||||
/*Truncate the area to the screen*/
|
||||
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
|
||||
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
|
||||
int32_t act_x2 = area->x2 > LCD_WIDTH - 1 ? LCD_WIDTH - 1 : area->x2;
|
||||
int32_t act_y2 = area->y2 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1 : area->y2;
|
||||
|
||||
/*32 or 24 bit per pixel*/
|
||||
if(LCD_BPP == 32) {
|
||||
uint32_t * fbp32 = (uint32_t *)color_p;
|
||||
int32_t x, y;
|
||||
for(y = act_y1; y <= act_y2; y++) {
|
||||
fbp32 = (uint32_t *)color_p + y * LCD_WIDTH;
|
||||
for (x = act_x1; x <= act_x2; x++)
|
||||
fbp32[x] = color.full;
|
||||
}
|
||||
}
|
||||
/*16 bit per pixel*/
|
||||
else if(LCD_BPP == 16) {
|
||||
uint16_t * fbp16 = (uint16_t *)color_p;
|
||||
int32_t x, y;
|
||||
for(y = act_y1; y <= act_y2; y++) {
|
||||
fbp16 = (uint16_t *)color_p + y * LCD_WIDTH;
|
||||
for (x = act_x1; x <= act_x2; x++)
|
||||
fbp16[x] = color.full;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PutHitCursor(int x, int y)
|
||||
{
|
||||
lv_area_t area;
|
||||
area.x1 = x - GRID_RANGE;
|
||||
area.y1 = y;
|
||||
area.x2 = x + GRID_RANGE + HIT_RANGE - 1;
|
||||
area.y2 = y + HIT_RANGE - 1;
|
||||
ClearBitmap(LV_COLOR_WHITE, &area, (lv_color_t*)ark_lcd_get_virt_addr());
|
||||
area.x1 = x;
|
||||
area.y1 = y - GRID_RANGE;
|
||||
area.x2 = x + HIT_RANGE - 1;
|
||||
area.y2 = y + GRID_RANGE + HIT_RANGE - 1;
|
||||
ClearBitmap(LV_COLOR_WHITE, &area, (lv_color_t*)ark_lcd_get_virt_addr());
|
||||
area.x1 = x;
|
||||
area.y1 = y;
|
||||
area.x2 = x + HIT_RANGE - 1;
|
||||
area.y2 = y + HIT_RANGE - 1;
|
||||
ClearBitmap(LV_COLOR_BLACK, &area, (lv_color_t*)ark_lcd_get_virt_addr());
|
||||
CP15_clean_dcache_for_dma((uint32_t)(lv_color_t*)ark_lcd_get_virt_addr(),
|
||||
(uint32_t)(lv_color_t*)ark_lcd_get_virt_addr() + FB_SIZE);
|
||||
}
|
||||
|
||||
static void ClrHitCursor(int x, int y)
|
||||
{
|
||||
lv_area_t area;
|
||||
area.x1 = x - GRID_RANGE;
|
||||
area.y1 = y - GRID_RANGE;
|
||||
area.x2 = x + GRID_RANGE + HIT_RANGE - 1;
|
||||
area.y2 = y + GRID_RANGE + HIT_RANGE - 1;
|
||||
ClearBitmap(LV_COLOR_BLACK, &area, (lv_color_t*)ark_lcd_get_virt_addr());
|
||||
CP15_clean_dcache_for_dma((uint32_t)(lv_color_t*)ark_lcd_get_virt_addr(),
|
||||
(uint32_t)(lv_color_t*)ark_lcd_get_virt_addr() + FB_SIZE);
|
||||
}
|
||||
|
||||
static int compare_data(calibration *cal)
|
||||
{
|
||||
int ret=0;
|
||||
int diff_x;
|
||||
int diff_y;
|
||||
|
||||
diff_x = (int)fabs(cal->x[0] - cal->x[1]);
|
||||
diff_y = (int)fabs(cal->y[0] - cal->y[1]);
|
||||
|
||||
if(diff_x > diff_y)
|
||||
lg_direction = 0;
|
||||
else
|
||||
lg_direction = 1;
|
||||
|
||||
TOUCH_DEBUG_MSG("lg_direction = %d\r\n", lg_direction);
|
||||
|
||||
if(lg_direction == 0)
|
||||
{
|
||||
if((cal->x [0]<cal->x [1])&&(cal->x [3]<cal->x [2]))
|
||||
ret=1;
|
||||
if((cal->x [0]>cal->x [1])&&(cal->x [3]>cal->x [2]))
|
||||
ret=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((cal->y[0]<cal->y[1])&&(cal->y[3]<cal->y[2]))
|
||||
ret=1;
|
||||
if((cal->y[0]>cal->y[1])&&(cal->y[3]>cal->y[2]))
|
||||
ret=1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int square_judge(calibration *cal)
|
||||
{
|
||||
int ret=0;
|
||||
|
||||
if(lg_direction == 0)
|
||||
{
|
||||
abs_ax=fabs(cal->x [0] - cal->x [1]);
|
||||
abs_dx=fabs(cal->x [2]-cal->x [3]);
|
||||
abs_err1=fabs(abs_ax -abs_dx);
|
||||
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_dx=%d, abs_err1=%d, SYSTEM_ERROR1=%d*******\n", (int)abs_ax, (int)abs_dx, (int)abs_err1, (int)SYSTEM_ERROR1);
|
||||
|
||||
|
||||
abs_lx=fabs(cal->x [0]-cal->x [4]);
|
||||
abs_rx=fabs(cal->x[3]-cal->x [4]);
|
||||
abs_err2=fabs(abs_lx -abs_rx);
|
||||
TOUCH_DEBUG_MSG("***abs_lx=%d,abs_rx=%d,abs_err2=%d****2\n", (int)abs_lx, (int)abs_rx, (int)abs_err2);
|
||||
|
||||
|
||||
abs_ly=fabs(cal->y [0]-cal->y [3]);
|
||||
abs_ry=fabs(cal->y [1]-cal->y [2]);
|
||||
abs_err3=fabs(abs_ly -abs_ry);
|
||||
TOUCH_DEBUG_MSG("***abs_ly=%d, abs_ry=%d, abs_err3=%d****2\n", (int)abs_ly, (int)abs_ry, (int)abs_err3);
|
||||
|
||||
|
||||
if(abs_err1<SYSTEM_ERROR1&&abs_err2<SYSTEM_ERROR1&&abs_err3<SYSTEM_ERROR1)
|
||||
ret=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_ax=fabs(cal->y[0] - cal->y[1]);
|
||||
abs_dx=fabs(cal->y[2]-cal->y[3]);
|
||||
abs_err1=fabs(abs_ax -abs_dx);
|
||||
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_dx=%d, abs_err1=%d, SYSTEM_ERROR1=%d*******\n", (int)abs_ax, (int)abs_dx, (int)abs_err1, (int)SYSTEM_ERROR1);
|
||||
|
||||
|
||||
abs_lx=fabs(cal->y[0]-cal->y[4]);
|
||||
abs_rx=fabs(cal->y[3]-cal->y[4]);
|
||||
abs_err2=fabs(abs_lx -abs_rx);
|
||||
TOUCH_DEBUG_MSG("***abs_lx=%d, abs_rx=%d, abs_err2=%d****2\n", (int)abs_lx, (int)abs_rx, (int)abs_err2);
|
||||
|
||||
|
||||
abs_ly=fabs(cal->x[0]-cal->x[3]);
|
||||
abs_ry=fabs(cal->x[1]-cal->x[2]);
|
||||
abs_err3=fabs(abs_ly -abs_ry);
|
||||
TOUCH_DEBUG_MSG("***abs_ly=%d, abs_ry=%d, abs_err3=%d****2\n", (int)abs_ly, (int)abs_ry, (int)abs_err3);
|
||||
|
||||
|
||||
if(abs_err1<SYSTEM_ERROR1&&abs_err2<SYSTEM_ERROR1&&abs_err3<SYSTEM_ERROR1)
|
||||
ret=1;
|
||||
}
|
||||
|
||||
TOUCH_DEBUG_MSG("***ret=%d****4\n",ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int judge_center(calibration *cal)
|
||||
{
|
||||
int ret=0;
|
||||
|
||||
if(lg_direction == 0)
|
||||
{
|
||||
abs_cx=fabs(cal->x [4]-cal->x [0])*2;
|
||||
abs_cy=fabs(cal->y [4]-cal->y [0])*2;
|
||||
abs_err4=fabs(abs_cx -abs_ax);
|
||||
abs_err5=fabs(abs_cy -abs_ly);
|
||||
TOUCH_DEBUG_MSG("***abs_cx=%d, abs_cy=%d, abs_err4=%d, abs_err5=%d****2\n", (int)abs_cx, (int)abs_cy, (int)abs_err4, (int)abs_err5);
|
||||
|
||||
if(abs_err4<SYSTEM_ERROR1&&abs_err5<SYSTEM_ERROR1)
|
||||
ret=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_cx=fabs(cal->y[4]-cal->y[0])*2;
|
||||
abs_cy=fabs(cal->x[4]-cal->x[0])*2;
|
||||
abs_err4=fabs(abs_cx -abs_ax);
|
||||
abs_err5=fabs(abs_cy -abs_ly);
|
||||
TOUCH_DEBUG_MSG("***abs_cx=%d, abs_cy=%d, abs_err4=%d, abs_err5=%d****2\n", (int)abs_cx, (int)abs_cy, (int)abs_err4, (int)abs_err5);
|
||||
|
||||
if(abs_err4<SYSTEM_ERROR1&&abs_err5<SYSTEM_ERROR1)
|
||||
ret=1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int filter_data(calibration *cal)
|
||||
{
|
||||
int ret=0;
|
||||
float abs_lcd;
|
||||
int scale;
|
||||
int i;
|
||||
|
||||
TOUCH_DEBUG_MSG("***filter_data****1\n");
|
||||
for(i=0;i<5;i++)
|
||||
{
|
||||
TOUCH_DEBUG_MSG("cal->x[%d] = %d, cal->y[%d] = %d\r\n", i, (int)cal->x[i], i, (int)cal->y[i]);
|
||||
}
|
||||
|
||||
if(compare_data( cal))
|
||||
{
|
||||
TOUCH_DEBUG_MSG("*** Pass compare_data ****\n");
|
||||
|
||||
if(square_judge(cal))
|
||||
{
|
||||
TOUCH_DEBUG_MSG("*** Pass square_judge ****\n");
|
||||
|
||||
abs_lcd=fabs(cal->xfb[1] -cal->xfb[0]);
|
||||
TOUCH_DEBUG_MSG("***abs_ax=%d, abs_lcd=%d****\n", (int)abs_ax, (int)abs_lcd);
|
||||
scale=(int)(abs_ax/abs_lcd);
|
||||
TOUCH_DEBUG_MSG("***scale=%d****4\n",scale);
|
||||
if(SCALE_AERROR<scale&&SCALE_DERROR>scale)
|
||||
{
|
||||
TOUCH_DEBUG_MSG("*** Scale check ok ****\n");
|
||||
if(judge_center(cal))
|
||||
{
|
||||
ret=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
TOUCH_DEBUG_MSG("*** Failed at judge_center****\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
TOUCH_DEBUG_MSG("*** filter_data ret=%d****\n",ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void get_sample (calibration *cal,
|
||||
int index, int x, int y, char *name)
|
||||
{
|
||||
PAN_DATA ts_cord;
|
||||
|
||||
PutHitCursor(x, y);
|
||||
// getxy (ts, &cal->x [index], &cal->y [index]);
|
||||
GetTouchHit(&ts_cord);
|
||||
cal->x [index] = ts_cord.adcX;
|
||||
cal->y [index] = ts_cord.adcY;
|
||||
|
||||
ClrHitCursor(x, y);
|
||||
|
||||
cal->xfb [index] = x;
|
||||
cal->yfb [index] = y;
|
||||
|
||||
TOUCH_DEBUG_MSG("get_sample %s : X = %4d Y = %4d\n", name, cal->x [index], cal->y [index]);
|
||||
}
|
||||
|
||||
unsigned int AdjustTouch(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
||||
#if 0
|
||||
cal.a[0]=56822272;
|
||||
cal.a[1]=-14948;
|
||||
cal.a[2]=36;
|
||||
cal.a[3]=38820672;
|
||||
cal.a[4]=-59;
|
||||
cal.a[5]=-11704;
|
||||
cal.a[6]=65536;
|
||||
|
||||
lg_bTouchAdjusted = 1;
|
||||
#else
|
||||
while(1)
|
||||
{
|
||||
get_sample (&cal, 0, 50, 50, "Top left");
|
||||
get_sample (&cal, 1, LCD_WIDTH - 50, 50, "Top right");
|
||||
get_sample (&cal, 2, LCD_WIDTH - 50, LCD_HEIGHT - 50, "Bot right");
|
||||
get_sample (&cal, 3, 50, LCD_HEIGHT - 50, "Bot left");
|
||||
get_sample (&cal, 4, LCD_WIDTH / 2, LCD_HEIGHT / 2, "Center");
|
||||
|
||||
if(filter_data(&cal))
|
||||
{
|
||||
perform_calibration (&cal);
|
||||
for(i=0;i<7;i++)
|
||||
{
|
||||
printf("the result cal->a[%d]=%d\n", i, cal.a[i]);
|
||||
}
|
||||
SaveCalibration(&cal);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lg_bTouchAdjusted = 1;
|
||||
|
||||
return 0; // 5次均无效, 取默认值
|
||||
}
|
||||
|
||||
int LoadTouchConfigure(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,471 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
#include "timers.h"
|
||||
|
||||
|
||||
#ifdef TP_USE_FT6336U
|
||||
#define FT6336U_STAT_ADDR 0x02
|
||||
#define FT6336U_TOUCH1_ADDR 0x03
|
||||
#define FT6336U_TOUCH2_ADDR 0x09
|
||||
#define FT6336U_TOUCH3_ADDR 0x0F
|
||||
#define FT6336U_TOUCH4_ADDR 0x15
|
||||
#define FT6336U_TOUCH5_ADDR 0x1B
|
||||
#define FT6336U_CHIP_ID 0xA3
|
||||
|
||||
#define FT6336U_CONFIG_X_MAX 960
|
||||
#define FT6336U_CONFIG_Y_MAX 320
|
||||
|
||||
#define FT6336U_SLAVE_ADDR 0x38
|
||||
#define FT6336U_GPIO_INT TP_GPIO_INT
|
||||
#define FT6336U_GPIO_RST TP_GPIO_RST
|
||||
#define FT6336U_INVERTED_X TP_INV_X
|
||||
#define FT6336U_INVERTED_Y TP_INV_Y
|
||||
#if TP_MT_TOUCH
|
||||
#define FT6336U_MAX_CONTACTS 5
|
||||
#else
|
||||
#define FT6336U_MAX_CONTACTS 1
|
||||
#endif
|
||||
//#define FT6336U_USE_RELEASE_TIMER
|
||||
//#define FT6336U_REPEAT_FILTER
|
||||
|
||||
#define GPIO_IS_VALID(n) ((n >= 0) && (n < 128) ? 1 : 0)
|
||||
#define FT6336U_ERR(fmt, args...) printf("###ERR:[%s]"fmt, __func__, ##args)
|
||||
#define FT6336U_DBG(fmt, args...) //printf("DBG:[%s]"fmt, __func__, ##args)
|
||||
|
||||
enum {
|
||||
FT6336U_INDEV_STATE_DOWN,
|
||||
FT6336U_INDEV_STATE_UP,
|
||||
FT6336U_INDEV_STATE_CONTACT
|
||||
};
|
||||
|
||||
struct ft6336u_ts_data {
|
||||
struct i2c_adapter *adap;
|
||||
unsigned int max_touch_num;
|
||||
unsigned int x_max;
|
||||
unsigned int y_max;
|
||||
int last_input_x;
|
||||
int last_input_y;
|
||||
int last_input_state;
|
||||
int gpio_int;
|
||||
int gpio_rst;
|
||||
uint8_t id;
|
||||
unsigned long irq_flags;
|
||||
TaskHandle_t irq_task;
|
||||
#ifdef FT6336U_USE_RELEASE_TIMER
|
||||
TimerHandle_t release_timer;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct _ft6336u_point{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
uint8_t state;
|
||||
} ft6336u_point_t;
|
||||
|
||||
#if !defined(VG_ONLY) && !defined(AWTK)
|
||||
#include "lvgl/lvgl.h"
|
||||
#else
|
||||
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
|
||||
|
||||
typedef int16_t lv_coord_t;
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
|
||||
typedef struct {
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
} lv_indev_data_t;
|
||||
#endif
|
||||
|
||||
extern void SendTouchInputEvent(lv_indev_data_t *indata);
|
||||
extern void SendTouchInputEventFromISR(lv_indev_data_t *indata);
|
||||
|
||||
static int ft6336u_i2c_read(struct i2c_adapter *adap, uint8_t reg, uint8_t *buf, int len)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
int ret;
|
||||
|
||||
msgs[0].flags = !I2C_M_RD;
|
||||
msgs[0].addr = adap->addr;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = ®
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = adap->addr;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = buf;
|
||||
ret = i2c_transfer(adap, msgs, 2);
|
||||
|
||||
return ((ret != 2) ? -EIO : 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int ft6336u_i2c_write(struct i2c_adapter *adap, const uint8_t *buf, int len)
|
||||
{
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
msg.flags = !I2C_M_RD;
|
||||
msg.addr = adap->addr;
|
||||
msg.buf = buf;
|
||||
msg.len = len + 1;
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
|
||||
return ((ret != 1) ? -EIO : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ft6336u_ts_read_input_report(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
uint8_t counter = 0;
|
||||
uint8_t lvalue;
|
||||
uint8_t ts_num;
|
||||
|
||||
do {
|
||||
//make sure data in buffer is valid
|
||||
ft6336u_i2c_read(ts->adap, FT6336U_STAT_ADDR, &lvalue, 1);
|
||||
if(counter++ == 0x30)
|
||||
return 0;
|
||||
} while(lvalue & 0x08);
|
||||
|
||||
ts_num = (uint8_t)(lvalue & 0x0F);
|
||||
|
||||
if(ts_num > FT6336U_MAX_CONTACTS)
|
||||
ts_num = FT6336U_MAX_CONTACTS;
|
||||
|
||||
// FT6336U_DBG("points num:%d\n", ts_num);
|
||||
|
||||
return ts_num;
|
||||
}
|
||||
|
||||
static int ft6336u_ts_report_touch(struct ft6336u_ts_data *ts, int id)
|
||||
{
|
||||
ft6336u_point_t point;
|
||||
uint8_t values[4];
|
||||
const uint8_t x_base[] = {
|
||||
FT6336U_TOUCH1_ADDR,
|
||||
FT6336U_TOUCH2_ADDR,
|
||||
FT6336U_TOUCH3_ADDR,
|
||||
FT6336U_TOUCH4_ADDR,
|
||||
FT6336U_TOUCH5_ADDR
|
||||
};
|
||||
|
||||
if(ft6336u_i2c_read(ts->adap, x_base[id], values, 4) != 0) {
|
||||
FT6336U_ERR("i2c read coordinate failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
point.state = (values[0]>>6) & 0x3;
|
||||
point.x = (((uint16_t)(values[0]&0x0f)) << 8) | values[1];
|
||||
point.y = (((uint16_t)(values[2]&0x0f)) << 8) | values[3];
|
||||
|
||||
/*invalid point val*/
|
||||
if((point.x > ts->x_max) || (point.y > ts->y_max) || (point.state > FT6336U_INDEV_STATE_CONTACT)) {
|
||||
FT6336U_ERR("Coordinate out of range: x:%d, y:%d\n", point.x, point.y);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if FT6336U_INVERTED_X
|
||||
point.x = ts->x_max - point.x;
|
||||
#endif
|
||||
#if FT6336U_INVERTED_Y
|
||||
point.y = ts->y_max - point.y;
|
||||
#endif
|
||||
|
||||
#ifdef FT6336U_REPEAT_FILTER
|
||||
if(point.state == FT6336U_INDEV_STATE_CONTACT) {
|
||||
if((ts->last_input_x == point.x) && (ts->last_input_y == point.y)) {
|
||||
return 0;
|
||||
} else {
|
||||
//move event.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//send press event
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHDOWN, point.x, point.y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = point.x;
|
||||
indata.point.y = point.y;
|
||||
|
||||
if(point.state == FT6336U_INDEV_STATE_CONTACT) {
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
} else if(point.state == FT6336U_INDEV_STATE_DOWN) {
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
//printf("++++++ id[%d]: x:%d, y:%d\n", id, point.x, point.y);
|
||||
} else /*if(point.state == FT6336U_INDEV_STATE_UP)*/ {
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
//printf("------ id[%d]: x:%d, y:%d\n", id, point.x, point.y);
|
||||
}
|
||||
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
|
||||
ts->last_input_x = point.x;
|
||||
ts->last_input_y = point.y;
|
||||
ts->last_input_state = point.state;
|
||||
|
||||
// FT6336U_DBG("id[%d]:x:%d, y:%d, state:0x%x\n", id, point.x, point.y, point.state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ft6336u_process_events(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
uint8_t ts_num, i;
|
||||
|
||||
ts_num = ft6336u_ts_read_input_report(ts);
|
||||
|
||||
for(i=0; i<ts_num; i++) {
|
||||
ft6336u_ts_report_touch(ts, i);
|
||||
}
|
||||
|
||||
if(ts_num == 0) { /* report the last point release event */
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHUP, ts->last_input_x, ts->last_input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = ts->last_input_x;
|
||||
indata.point.y = ts->last_input_y;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FT6336U_USE_RELEASE_TIMER
|
||||
static void ft6336_timeout_callback(TimerHandle_t timer)
|
||||
{
|
||||
struct ft6336u_ts_data *ts = (struct ft6336u_ts_data *)pvTimerGetTimerID(timer);
|
||||
if(!ts) {
|
||||
FT6336U_ERR("Invalid ts.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ts->last_input_state != FT6336U_INDEV_STATE_UP) { //drop release event.
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHUP, ts->last_input_x, ts->last_input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = ts->last_input_x;
|
||||
indata.point.y = ts->last_input_y;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendTouchInputEventFromISR(&indata);
|
||||
#endif
|
||||
FT6336U_ERR("Force report release event\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ft6336u_ts_irq_task(void *param)
|
||||
{
|
||||
uint32_t ulNotifiedValue;
|
||||
struct ft6336u_ts_data *ts;
|
||||
|
||||
for(;;) {
|
||||
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
|
||||
0xffffffff, /* Reset the notification value to 0 on exit. */
|
||||
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
|
||||
portMAX_DELAY);
|
||||
|
||||
ts = (struct ft6336u_ts_data *)ulNotifiedValue;
|
||||
if(!ts) {
|
||||
FT6336U_ERR("Invalid ts.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef FT6336U_USE_RELEASE_TIMER
|
||||
if(ts->release_timer)
|
||||
xTimerStop(ts->release_timer, 0);
|
||||
#endif
|
||||
ft6336u_process_events(ts);
|
||||
|
||||
#ifdef FT6336U_USE_RELEASE_TIMER
|
||||
if(ts->release_timer)
|
||||
{
|
||||
xTimerReset(ts->release_timer, 0);
|
||||
xTimerStart(ts->release_timer, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void ft6336u_ts_irq_handler(void *param)
|
||||
{
|
||||
struct ft6336u_ts_data *ts = (struct ft6336u_ts_data *)param;
|
||||
|
||||
if(ts)
|
||||
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
|
||||
}
|
||||
|
||||
static int ft6336u_request_irq(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if(GPIO_IS_VALID(ts->gpio_int)) {
|
||||
gpio_direction_input(ts->gpio_int);
|
||||
if(gpio_irq_request(ts->gpio_int, ts->irq_flags, ft6336u_ts_irq_handler, ts)) {
|
||||
FT6336U_ERR("gpio irq request failed\n");
|
||||
return -1;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ft6336u_configure_dev(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xTaskCreate(ft6336u_ts_irq_task, "ft6336u irq task", 1024, ts, 10, &ts->irq_task);
|
||||
if(ret != pdPASS) {
|
||||
FT6336U_ERR("create ft6336u irq task fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ft6336u_request_irq(ts);
|
||||
if(ret) {
|
||||
FT6336U_ERR("request IRQ failed\n");
|
||||
if(ts->irq_task)
|
||||
vTaskDelete(ts->irq_task);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ft6336u_read_chip_id(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
int retry = 3;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = ft6336u_i2c_read(ts->adap, FT6336U_CHIP_ID, &ts->id, 1);
|
||||
if(ret == 0) {
|
||||
FT6336U_DBG("FT6336U ID %d\n", ts->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
} while(retry--);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ft6336u_get_chip_para(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ft6336u_read_chip_id(ts);
|
||||
if(ret) {
|
||||
FT6336U_ERR("read chip id failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(ts->id != 0x64) {
|
||||
FT6336U_ERR("Invalid chip ID:0x%2x\n", ts->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ts->irq_flags = IRQ_TYPE_EDGE_FALLING;
|
||||
ts->max_touch_num = FT6336U_MAX_CONTACTS;
|
||||
ts->x_max = FT6336U_CONFIG_X_MAX;
|
||||
ts->y_max = FT6336U_CONFIG_Y_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ft6336u_reset(struct ft6336u_ts_data *ts)
|
||||
{
|
||||
if(GPIO_IS_VALID(ts->gpio_rst)) {
|
||||
gpio_direction_output(ts->gpio_rst, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(10)); /* Trst: > 5ms */
|
||||
gpio_direction_output(ts->gpio_rst, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(200)); /* tpon: 200ms */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ft6336u_ts_probe(struct i2c_adapter *adap)
|
||||
{
|
||||
struct ft6336u_ts_data *ts;
|
||||
int ret;
|
||||
|
||||
ts = pvPortMalloc(sizeof(*ts));
|
||||
if(!ts) {
|
||||
FT6336U_ERR("malloc failed.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
|
||||
ts->adap = adap;
|
||||
ts->adap->addr = FT6336U_SLAVE_ADDR;
|
||||
ts->gpio_int = FT6336U_GPIO_INT;
|
||||
ts->gpio_rst = FT6336U_GPIO_RST;
|
||||
|
||||
ret = ft6336u_reset(ts);
|
||||
if(ret) {
|
||||
FT6336U_ERR("Controller reset failed.\n");
|
||||
// goto exit;
|
||||
}
|
||||
|
||||
ret = ft6336u_get_chip_para(ts);
|
||||
if(ret) {
|
||||
FT6336U_ERR("version id unmatches.\n");
|
||||
goto exit;
|
||||
}
|
||||
#ifdef FT6336U_USE_RELEASE_TIMER
|
||||
ts->release_timer = xTimerCreate("FT6336 Release Timer",
|
||||
pdMS_TO_TICKS(200),
|
||||
pdFALSE,
|
||||
ts,
|
||||
ft6336_timeout_callback
|
||||
);
|
||||
#endif
|
||||
ret = ft6336u_configure_dev(ts);
|
||||
if(ret) {
|
||||
FT6336U_ERR("ft6336u_configure_dev failed.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
vPortFree(ts);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ft6336u_init(void)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if(!(adap = i2c_open("i2c0"))) {
|
||||
FT6336U_ERR("open i2c0 fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ft6336u_ts_probe(adap)) {
|
||||
FT6336U_ERR("ft6336u probe fail\n");
|
||||
i2c_close(adap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,695 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
|
||||
|
||||
#ifdef TP_USE_GA657X
|
||||
#if !defined(VG_ONLY) && !defined(AWTK)
|
||||
#include "lvgl/lvgl.h"
|
||||
#else
|
||||
typedef int16_t lv_coord_t;
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
typedef struct {
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
|
||||
|
||||
enum {
|
||||
LV_KEY_UP = 17, /*0x11*/
|
||||
LV_KEY_DOWN = 18, /*0x12*/
|
||||
LV_KEY_RIGHT = 19, /*0x13*/
|
||||
LV_KEY_LEFT = 20, /*0x14*/
|
||||
LV_KEY_ESC = 27, /*0x1B*/
|
||||
LV_KEY_DEL = 127, /*0x7F*/
|
||||
LV_KEY_BACKSPACE = 8, /*0x08*/
|
||||
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
|
||||
LV_KEY_NEXT = 9, /*0x09, '\t'*/
|
||||
LV_KEY_PREV = 11, /*0x0B, '*/
|
||||
LV_KEY_HOME = 2, /*0x02, STX*/
|
||||
LV_KEY_END = 3, /*0x03, ETX*/
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
} lv_indev_data_t;
|
||||
#endif
|
||||
|
||||
#define GOODIX_GPIO_INT_NAME "irq"
|
||||
#define GOODIX_GPIO_RST_NAME "reset"
|
||||
|
||||
#define GOODIX_MAX_HEIGHT 4096
|
||||
#define GOODIX_MAX_WIDTH 4096
|
||||
#define GOODIX_INT_TRIGGER 1// 1//<2F>½<EFBFBD><C2BD><EFBFBD> 0 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define GOODIX_CONTACT_SIZE 8
|
||||
#define GOODIX_MAX_CONTACTS 10
|
||||
|
||||
#define GOODIX_CONFIG_MAX_LENGTH 240
|
||||
#define GOODIX_CONFIG_911_LENGTH 186
|
||||
#define GOODIX_CONFIG_967_LENGTH 228
|
||||
|
||||
/* Register defines */
|
||||
#define GOODIX_REG_COMMAND 0x8040
|
||||
#define GOODIX_CMD_SCREEN_OFF 0x05
|
||||
|
||||
#define GOODIX_READ_COOR_ADDR 0x814E
|
||||
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
|
||||
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
|
||||
#define GOODIX_GT6571_REG_CONFIG_DATA 0x814E
|
||||
#define GOODIX_REG_ID 0x8140
|
||||
|
||||
#define GOODIX_BUFFER_STATUS_READY BIT(7)
|
||||
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
|
||||
|
||||
#define RESOLUTION_LOC 1
|
||||
#define MAX_CONTACTS_LOC 5
|
||||
#define TRIGGER_LOC 6
|
||||
|
||||
#define GT657X_SLAVE_ADDR 0x5d
|
||||
#define GT657X_GPIO_INT TP_GPIO_INT
|
||||
#define GT657X_GPIO_RST TP_GPIO_RST
|
||||
#define GT657X_INVERTED_X TP_INV_Y
|
||||
#define GT657X_INVERTED_Y TP_INV_Y
|
||||
#define GT657X_MT_TOUCH TP_MT_TOUCH
|
||||
|
||||
struct goodix_ts_data;
|
||||
|
||||
struct goodix_chip_data {
|
||||
u16 config_addr;
|
||||
int config_len;
|
||||
};
|
||||
|
||||
struct goodix_ts_data {
|
||||
struct i2c_adapter *adap;
|
||||
const struct goodix_chip_data *chip;
|
||||
unsigned int max_touch_num;
|
||||
unsigned int x_max;
|
||||
unsigned int y_max;
|
||||
unsigned int int_trigger_type;
|
||||
int gpio_int;
|
||||
int gpio_rst;
|
||||
u16 id;
|
||||
u16 version;
|
||||
const char cfg_name[32];
|
||||
unsigned long irq_flags;
|
||||
TaskHandle_t irq_task;
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt1x_chip_data = {
|
||||
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt911_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_911_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt967_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_967_LENGTH,
|
||||
};
|
||||
static const struct goodix_chip_data gt6571_chip_data = {
|
||||
.config_addr = GOODIX_GT6571_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_967_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt9x_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
};
|
||||
|
||||
static const unsigned long goodix_irq_flags[] = {
|
||||
IRQ_TYPE_EDGE_RISING,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
IRQ_TYPE_LEVEL_LOW,
|
||||
IRQ_TYPE_LEVEL_HIGH,
|
||||
};
|
||||
|
||||
static int last_input_x, last_input_y;
|
||||
|
||||
extern void SendTouchInputEvent(lv_indev_data_t *indata);
|
||||
|
||||
#ifdef AWTK
|
||||
#include <xm_base.h>
|
||||
#include <xm_event.h>
|
||||
#endif
|
||||
|
||||
static inline int get_unaligned_le16(void *p)
|
||||
{
|
||||
u8 *tmp = (u8*)p;
|
||||
|
||||
return (tmp[1] << 8) | tmp[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to read from.
|
||||
* @buf: raw write data buffer.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int goodix_i2c_read(struct i2c_adapter *adap,
|
||||
u16 reg, u8 *buf, int len)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
u8 wbuf[2];
|
||||
int ret;
|
||||
|
||||
wbuf[0] = reg >> 8;
|
||||
wbuf[1] = reg & 0xFF;
|
||||
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].addr = GT657X_SLAVE_ADDR;
|
||||
msgs[0].len = 2;
|
||||
msgs[0].buf = (u8 *)&wbuf;
|
||||
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = GT657X_SLAVE_ADDR;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = buf;
|
||||
|
||||
ret = i2c_transfer(adap, msgs, 2);
|
||||
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_write - write data to a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to write to.
|
||||
* @buf: raw data buffer to write.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int goodix_i2c_write(struct i2c_adapter *adap, u16 reg, const u8 *buf,
|
||||
unsigned len)
|
||||
{
|
||||
u8 *addr_buf;
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
addr_buf = pvPortMalloc(len + 2);
|
||||
if (!addr_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
addr_buf[0] = reg >> 8;
|
||||
addr_buf[1] = reg & 0xFF;
|
||||
memcpy(&addr_buf[2], buf, len);
|
||||
|
||||
msg.flags = 0;
|
||||
msg.addr = GT657X_SLAVE_ADDR;
|
||||
msg.buf = addr_buf;
|
||||
msg.len = len + 2;
|
||||
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
vPortFree(addr_buf);
|
||||
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
|
||||
}
|
||||
|
||||
static int goodix_i2c_write_u8(struct i2c_adapter *adap, u16 reg, u8 value)
|
||||
{
|
||||
return goodix_i2c_write(adap, reg, &value, sizeof(value));
|
||||
}
|
||||
|
||||
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
|
||||
{
|
||||
|
||||
|
||||
|
||||
switch (id) {
|
||||
case 1151:
|
||||
return >1x_chip_data;
|
||||
|
||||
case 911:
|
||||
case 9271:
|
||||
case 9110:
|
||||
case 927:
|
||||
case 928:
|
||||
return >911_chip_data;
|
||||
|
||||
case 912:
|
||||
case 967:
|
||||
return >967_chip_data;
|
||||
case 6571:
|
||||
|
||||
return >6571_chip_data;
|
||||
default:
|
||||
return >9x_chip_data;
|
||||
}
|
||||
}
|
||||
|
||||
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
||||
{
|
||||
unsigned long max_timeout;
|
||||
int touch_num;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* The 'buffer status' bit, which indicates that the data is valid, is
|
||||
* not set as soon as the interrupt is raised, but slightly after.
|
||||
* This takes around 10 ms to happen, so we poll for 20 ms.
|
||||
*/
|
||||
|
||||
max_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(GOODIX_BUFFER_STATUS_TIMEOUT);
|
||||
do {
|
||||
error = goodix_i2c_read(ts->adap, GOODIX_READ_COOR_ADDR,
|
||||
data, GOODIX_CONTACT_SIZE + 1);
|
||||
if (error) {
|
||||
printf("I2C transfer error: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
|
||||
touch_num = data[0] & 0x0f;
|
||||
|
||||
if (touch_num > ts->max_touch_num)
|
||||
return -EPROTO;
|
||||
#ifdef GT9XX_MT_TOUCH
|
||||
if (touch_num > 1) {
|
||||
data += 1 + GOODIX_CONTACT_SIZE;
|
||||
error = goodix_i2c_read(ts->adap,
|
||||
GOODIX_READ_COOR_ADDR +
|
||||
1 + GOODIX_CONTACT_SIZE,
|
||||
data,
|
||||
GOODIX_CONTACT_SIZE *
|
||||
(touch_num - 1));
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return touch_num;
|
||||
#else
|
||||
|
||||
return touch_num > 0 ? 1 : 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); /* Poll every 1 - 2 ms */
|
||||
} while (xTaskGetTickCount() < max_timeout);
|
||||
|
||||
/*
|
||||
* The Goodix panel will send spurious interrupts after a
|
||||
* 'finger up' event, which will always cause a timeout.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
{
|
||||
int id = coor_data[0] & 0x0F;
|
||||
int input_x = get_unaligned_le16(&coor_data[1]);
|
||||
int input_y = get_unaligned_le16(&coor_data[3]);
|
||||
int input_w = get_unaligned_le16(&coor_data[5]);
|
||||
|
||||
printf("id=0x%x, input_x=%d, input_y=%d, input_w=%d.\n", id, input_x,
|
||||
input_y, input_w);
|
||||
|
||||
#if GT657X_INVERTED_X
|
||||
input_x = ts->x_max - input_x;
|
||||
#endif
|
||||
|
||||
#if GT657X_INVERTED_Y
|
||||
input_y = ts->y_max - input_y;
|
||||
#endif
|
||||
|
||||
//send press event
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHDOWN, input_x, input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = input_x;
|
||||
indata.point.y = input_y;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
|
||||
last_input_x = input_x;
|
||||
last_input_y = input_y;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_process_events - Process incoming events
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Called when the IRQ is triggered. Read the current device state, and push
|
||||
* the input events to the user space.
|
||||
*/
|
||||
static void goodix_process_events(struct goodix_ts_data *ts)
|
||||
{
|
||||
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
|
||||
int touch_num;
|
||||
int i;
|
||||
|
||||
touch_num = goodix_ts_read_input_report(ts, point_data);
|
||||
if (touch_num < 0)
|
||||
return;
|
||||
|
||||
|
||||
/*
|
||||
* Bit 4 of the first byte reports the status of the capacitive
|
||||
* Windows/Home button.
|
||||
*/
|
||||
//input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
|
||||
|
||||
for (i = 0; i < touch_num; i++)
|
||||
goodix_ts_report_touch(ts,
|
||||
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
|
||||
|
||||
if (touch_num == 0) {
|
||||
//send release event
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHUP, last_input_x, last_input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = last_input_x;
|
||||
indata.point.y = last_input_y;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* input_mt_sync_frame(ts->input_dev);
|
||||
input_sync(ts->input_dev); */
|
||||
}
|
||||
|
||||
static void goodix_ts_irq_task(void *param)
|
||||
{
|
||||
uint32_t ulNotifiedValue;
|
||||
struct goodix_ts_data *ts;
|
||||
|
||||
for (;;) {
|
||||
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
|
||||
0xffffffff, /* Reset the notification value to 0 on exit. */
|
||||
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
|
||||
portMAX_DELAY);
|
||||
|
||||
ts = (struct goodix_ts_data *)ulNotifiedValue;
|
||||
|
||||
goodix_process_events(ts);
|
||||
if (goodix_i2c_write_u8(ts->adap, GOODIX_READ_COOR_ADDR, 0) < 0)
|
||||
TRACE_ERROR("I2C write end_cmd error.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_ts_irq_handler - The IRQ handler
|
||||
*
|
||||
* @param: private data pointer.
|
||||
*/
|
||||
static void goodix_ts_irq_handler(void *param)
|
||||
{
|
||||
struct goodix_ts_data *ts = param;
|
||||
|
||||
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int goodix_request_irq(struct goodix_ts_data *ts)
|
||||
{
|
||||
if (xTaskCreate(goodix_ts_irq_task, "gt9xx", 1024, ts,
|
||||
10, &ts->irq_task) != pdPASS) {
|
||||
printf("create gt9xx irq task fail.\n");
|
||||
}
|
||||
|
||||
return gpio_irq_request(ts->gpio_int, ts->irq_flags, goodix_ts_irq_handler, ts);
|
||||
}
|
||||
|
||||
static int goodix_int_sync(struct goodix_ts_data *ts)
|
||||
{
|
||||
gpio_direction_output(ts->gpio_int, 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); /* T5: 50ms */
|
||||
|
||||
gpio_direction_input(ts->gpio_int);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_reset - Reset device during power on
|
||||
*
|
||||
* @ts: goodix_ts_data pointer
|
||||
*/
|
||||
static int goodix_reset(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* begin select I2C slave addr */
|
||||
gpio_direction_output(ts->gpio_rst, 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); /* T2: > 10ms */
|
||||
|
||||
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
|
||||
gpio_direction_output(ts->gpio_int, GT657X_SLAVE_ADDR == 0x14);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); /* T3: > 100us */
|
||||
|
||||
gpio_direction_output(ts->gpio_rst, 1);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(30)); /* T4: > 5ms */
|
||||
|
||||
/* end select I2C slave addr */
|
||||
gpio_direction_input(ts->gpio_rst);
|
||||
|
||||
error = goodix_int_sync(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_read_config - Read the embedded configuration of the panel
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Must be called during probe
|
||||
*/
|
||||
static void goodix_read_config(struct goodix_ts_data *ts)
|
||||
{
|
||||
u8 config[GOODIX_CONFIG_MAX_LENGTH];
|
||||
int error;
|
||||
|
||||
error = goodix_i2c_read(ts->adap, ts->chip->config_addr,
|
||||
config, ts->chip->config_len);
|
||||
if (error) {
|
||||
printf("Error reading config: %d\n", error);
|
||||
ts->int_trigger_type = GOODIX_INT_TRIGGER;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;
|
||||
return;
|
||||
}
|
||||
|
||||
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;//config[MAX_CONTACTS_LOC] & 0x0f;
|
||||
|
||||
ts->x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
|
||||
ts->y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_read_version - Read goodix touchscreen version
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*/
|
||||
static int goodix_read_version(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
u8 buf[6];
|
||||
char id_str[5];
|
||||
|
||||
error = goodix_i2c_read(ts->adap, GOODIX_REG_ID, buf, sizeof(buf));
|
||||
if (error) {
|
||||
TRACE_INFO("read version failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
memcpy(id_str, buf, 4);
|
||||
id_str[4] = 0;
|
||||
char *ptr;
|
||||
ts->id = strtoul(id_str, &ptr, 10);
|
||||
if (ts->id == 0xffff)
|
||||
ts->id = 0x1001;
|
||||
|
||||
ts->version = get_unaligned_le16(&buf[4]);
|
||||
|
||||
TRACE_INFO("ID %d, version: %04x\n", ts->id, ts->version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_test - I2C test function to check if the device answers.
|
||||
*
|
||||
* @adap: the i2c adapter
|
||||
*/
|
||||
static int goodix_i2c_test(struct i2c_adapter *adap)
|
||||
{
|
||||
int retry = 0;
|
||||
int error;
|
||||
u8 test;
|
||||
|
||||
while (retry++ < 5) {
|
||||
error = goodix_i2c_read(adap, GOODIX_REG_ID,
|
||||
&test, 1);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
TRACE_ERROR("i2c test failed attempt %d: %d\n",
|
||||
retry, error);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_configure_dev - Finish device initialization
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Must be called from probe to finish initialization of the device.
|
||||
* Contains the common initialization code for both devices that
|
||||
* declare gpio pins and devices that do not. It is either called
|
||||
* directly from probe or from request_firmware_wait callback.
|
||||
*/
|
||||
static int goodix_configure_dev(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
ts->int_trigger_type = GOODIX_INT_TRIGGER;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;
|
||||
|
||||
/* Read configuration and apply touchscreen parameters */
|
||||
goodix_read_config(ts);
|
||||
|
||||
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type];
|
||||
error = goodix_request_irq(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("request IRQ failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const unsigned char zero[2] = {0,0};
|
||||
static const unsigned char cmd[186] = {
|
||||
0x43,0x61,0x1C,0x1E,0x73,0x13,0x00,0x1B,0x52,0x9C,0x85,0x00,0xFF,0x5A,0x4B,0x00,0x00,0x16,0x1A,0x20,0x14,
|
||||
0x00,0x00,0xFF,0xFF,0x00,0x00,0x3F,0x01,0x94,0x50,0x05,0x42,0x00,0x00,0x00,0xF0,0x00,0x05,0xD0,0x02,0x10,0x10,0xBB,0x15,
|
||||
0x14,0x13,0x12,0x11,0x10,0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0E,0x0F,0x10,0x11,0x12,0x13,0x19,0x1B,0x1C,
|
||||
0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
|
||||
0x0F,0x32,0x8C,0xE3,0x81,0x14,0x04,0x00,0xD6,0x12,0x00,0xBF,0x18,0x00,0xAE,0x20,0x00,0x9E,0x2A,0x00,0x92,0x39,0x00,0x92,
|
||||
0x00,0x00,0x00,0x6A,0x00,0xAC,0x64,0x32,0x00,0xAA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x14,0x03,0x32,0x23,0xAF,0x00,0x0F,0x32,0x09,0x01,0x3C,0xC8,0x33,0x64,0x50,0x8F,0x55,0xC8,0x00,0x00,0x30,0x01
|
||||
};
|
||||
//static const unsigned char buff[186] = {0};
|
||||
int goodix_ts_probe(struct i2c_adapter *adap)
|
||||
{
|
||||
struct goodix_ts_data *ts;
|
||||
int error;
|
||||
//u8 i=0;
|
||||
TRACE_DEBUG("I2C Address: 0x%02x\n", GT657X_SLAVE_ADDR);
|
||||
|
||||
ts = pvPortMalloc(sizeof(*ts));
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
|
||||
ts->adap = adap;
|
||||
ts->gpio_int = GT657X_GPIO_INT;
|
||||
ts->gpio_rst = GT657X_GPIO_RST;
|
||||
|
||||
if (ts->gpio_int && ts->gpio_rst) {
|
||||
/* reset the controller */
|
||||
error = goodix_reset(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("Controller reset failed.\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
error = goodix_i2c_test(adap);
|
||||
if (error) {
|
||||
TRACE_ERROR("I2C communication failure: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = goodix_read_version(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("Read version failed.\n");
|
||||
return error;
|
||||
}
|
||||
printf("ts->id is %x \n ",ts->id);
|
||||
ts->chip = goodix_get_chip_data(ts->id);
|
||||
|
||||
|
||||
do{
|
||||
printf("goodix_i2c_write \n ");
|
||||
error= goodix_i2c_write(ts->adap, GOODIX_READ_COOR_ADDR, (unsigned char *)&zero[0],2);
|
||||
}while(error!=0);
|
||||
|
||||
error= goodix_i2c_write(ts->adap, 0x8047, (unsigned char *)&cmd[0],sizeof(cmd));
|
||||
if (error)
|
||||
{
|
||||
printf("goodix_i2c_write error\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
error = goodix_i2c_read(ts->adap, 0x8047,
|
||||
(unsigned char *)&buff[0], 186);
|
||||
for(i=0;i<186;i++)
|
||||
{
|
||||
if(buff[i]!=cmd[i])
|
||||
{
|
||||
printf("i is %x \n",i);
|
||||
printf("buff is %x \n",buff[i]);
|
||||
printf("cmd is %x \n",cmd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
error = goodix_configure_dev(ts);
|
||||
if (error)
|
||||
{
|
||||
printf("goodix_configure_dev error \n ");
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gt675x_init(void)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if (!(adap = i2c_open("i2c0"))) {
|
||||
printf("open i2c0 fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
goodix_ts_probe(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,635 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
|
||||
|
||||
#ifdef TP_USE_GT9XX
|
||||
#if !defined(VG_ONLY) && !defined(AWTK)
|
||||
#include "lvgl/lvgl.h"
|
||||
#else
|
||||
typedef int16_t lv_coord_t;
|
||||
typedef uint8_t lv_indev_state_t;
|
||||
typedef struct {
|
||||
lv_coord_t x;
|
||||
lv_coord_t y;
|
||||
} lv_point_t;
|
||||
|
||||
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
|
||||
|
||||
enum {
|
||||
LV_KEY_UP = 17, /*0x11*/
|
||||
LV_KEY_DOWN = 18, /*0x12*/
|
||||
LV_KEY_RIGHT = 19, /*0x13*/
|
||||
LV_KEY_LEFT = 20, /*0x14*/
|
||||
LV_KEY_ESC = 27, /*0x1B*/
|
||||
LV_KEY_DEL = 127, /*0x7F*/
|
||||
LV_KEY_BACKSPACE = 8, /*0x08*/
|
||||
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
|
||||
LV_KEY_NEXT = 9, /*0x09, '\t'*/
|
||||
LV_KEY_PREV = 11, /*0x0B, '*/
|
||||
LV_KEY_HOME = 2, /*0x02, STX*/
|
||||
LV_KEY_END = 3, /*0x03, ETX*/
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
|
||||
uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
|
||||
uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
|
||||
int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
|
||||
|
||||
lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
|
||||
} lv_indev_data_t;
|
||||
#endif
|
||||
|
||||
#define GOODIX_GPIO_INT_NAME "irq"
|
||||
#define GOODIX_GPIO_RST_NAME "reset"
|
||||
|
||||
#define GOODIX_MAX_HEIGHT 4096
|
||||
#define GOODIX_MAX_WIDTH 4096
|
||||
#define GOODIX_INT_TRIGGER 1
|
||||
#define GOODIX_CONTACT_SIZE 8
|
||||
#define GOODIX_MAX_CONTACTS 10
|
||||
|
||||
#define GOODIX_CONFIG_MAX_LENGTH 240
|
||||
#define GOODIX_CONFIG_911_LENGTH 186
|
||||
#define GOODIX_CONFIG_967_LENGTH 228
|
||||
|
||||
/* Register defines */
|
||||
#define GOODIX_REG_COMMAND 0x8040
|
||||
#define GOODIX_CMD_SCREEN_OFF 0x05
|
||||
|
||||
#define GOODIX_READ_COOR_ADDR 0x814E
|
||||
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
|
||||
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
|
||||
#define GOODIX_REG_ID 0x8140
|
||||
|
||||
#define GOODIX_BUFFER_STATUS_READY BIT(7)
|
||||
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
|
||||
|
||||
#define RESOLUTION_LOC 1
|
||||
#define MAX_CONTACTS_LOC 5
|
||||
#define TRIGGER_LOC 6
|
||||
|
||||
#define GT9XX_SLAVE_ADDR 0x5d
|
||||
#define GT9XX_GPIO_INT TP_GPIO_INT
|
||||
#define GT9XX_GPIO_RST TP_GPIO_RST
|
||||
#define GT9XX_INVERTED_X TP_INV_X
|
||||
#define GT9XX_INVERTED_Y TP_INV_Y
|
||||
#define GT9XX_MT_TOUCH TP_MT_TOUCH//支持多点触摸
|
||||
|
||||
struct goodix_ts_data;
|
||||
|
||||
struct goodix_chip_data {
|
||||
u16 config_addr;
|
||||
int config_len;
|
||||
};
|
||||
|
||||
struct goodix_ts_data {
|
||||
struct i2c_adapter *adap;
|
||||
const struct goodix_chip_data *chip;
|
||||
unsigned int max_touch_num;
|
||||
unsigned int x_max;
|
||||
unsigned int y_max;
|
||||
unsigned int int_trigger_type;
|
||||
int gpio_int;
|
||||
int gpio_rst;
|
||||
u16 id;
|
||||
u16 version;
|
||||
const char cfg_name[32];
|
||||
unsigned long irq_flags;
|
||||
TaskHandle_t irq_task;
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt1x_chip_data = {
|
||||
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt911_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_911_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt967_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_967_LENGTH,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt9x_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
};
|
||||
|
||||
static const unsigned long goodix_irq_flags[] = {
|
||||
IRQ_TYPE_EDGE_RISING,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
IRQ_TYPE_LEVEL_LOW,
|
||||
IRQ_TYPE_LEVEL_HIGH,
|
||||
};
|
||||
|
||||
static int last_input_x, last_input_y;
|
||||
|
||||
extern void SendTouchInputEvent(lv_indev_data_t *indata);
|
||||
|
||||
#ifdef AWTK
|
||||
#include <xm_base.h>
|
||||
#include <xm_event.h>
|
||||
#endif
|
||||
|
||||
static inline int get_unaligned_le16(void *p)
|
||||
{
|
||||
u8 *tmp = (u8*)p;
|
||||
|
||||
return (tmp[1] << 8) | tmp[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to read from.
|
||||
* @buf: raw write data buffer.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int goodix_i2c_read(struct i2c_adapter *adap,
|
||||
u16 reg, u8 *buf, int len)
|
||||
{
|
||||
struct i2c_msg msgs[2];
|
||||
u8 wbuf[2];
|
||||
int ret;
|
||||
|
||||
wbuf[0] = reg >> 8;
|
||||
wbuf[1] = reg & 0xFF;
|
||||
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].addr = GT9XX_SLAVE_ADDR;
|
||||
msgs[0].len = 2;
|
||||
msgs[0].buf = (u8 *)&wbuf;
|
||||
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].addr = GT9XX_SLAVE_ADDR;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = buf;
|
||||
|
||||
ret = i2c_transfer(adap, msgs, 2);
|
||||
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_write - write data to a register of the i2c slave device.
|
||||
*
|
||||
* @adap: i2c device.
|
||||
* @reg: the register to write to.
|
||||
* @buf: raw data buffer to write.
|
||||
* @len: length of the buffer to write
|
||||
*/
|
||||
static int goodix_i2c_write(struct i2c_adapter *adap, u16 reg, const u8 *buf,
|
||||
unsigned len)
|
||||
{
|
||||
u8 *addr_buf;
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
addr_buf = pvPortMalloc(len + 2);
|
||||
if (!addr_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
addr_buf[0] = reg >> 8;
|
||||
addr_buf[1] = reg & 0xFF;
|
||||
memcpy(&addr_buf[2], buf, len);
|
||||
|
||||
msg.flags = 0;
|
||||
msg.addr = GT9XX_SLAVE_ADDR;
|
||||
msg.buf = addr_buf;
|
||||
msg.len = len + 2;
|
||||
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
vPortFree(addr_buf);
|
||||
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
|
||||
}
|
||||
|
||||
static int goodix_i2c_write_u8(struct i2c_adapter *adap, u16 reg, u8 value)
|
||||
{
|
||||
return goodix_i2c_write(adap, reg, &value, sizeof(value));
|
||||
}
|
||||
|
||||
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
|
||||
{
|
||||
switch (id) {
|
||||
case 1151:
|
||||
return >1x_chip_data;
|
||||
|
||||
case 911:
|
||||
case 9271:
|
||||
case 9110:
|
||||
case 927:
|
||||
case 928:
|
||||
return >911_chip_data;
|
||||
|
||||
case 912:
|
||||
case 967:
|
||||
return >967_chip_data;
|
||||
|
||||
default:
|
||||
return >9x_chip_data;
|
||||
}
|
||||
}
|
||||
|
||||
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
||||
{
|
||||
unsigned long max_timeout;
|
||||
int touch_num;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* The 'buffer status' bit, which indicates that the data is valid, is
|
||||
* not set as soon as the interrupt is raised, but slightly after.
|
||||
* This takes around 10 ms to happen, so we poll for 20 ms.
|
||||
*/
|
||||
max_timeout = xTaskGetTickCount() + pdMS_TO_TICKS(GOODIX_BUFFER_STATUS_TIMEOUT);
|
||||
do {
|
||||
error = goodix_i2c_read(ts->adap, GOODIX_READ_COOR_ADDR,
|
||||
data, GOODIX_CONTACT_SIZE + 1);
|
||||
if (error) {
|
||||
TRACE_ERROR("I2C transfer error: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
|
||||
touch_num = data[0] & 0x0f;
|
||||
if (touch_num > ts->max_touch_num)
|
||||
return -EPROTO;
|
||||
#if GT9XX_MT_TOUCH
|
||||
if (touch_num > 1) {
|
||||
data += 1 + GOODIX_CONTACT_SIZE;
|
||||
error = goodix_i2c_read(ts->adap,
|
||||
GOODIX_READ_COOR_ADDR +
|
||||
1 + GOODIX_CONTACT_SIZE,
|
||||
data,
|
||||
GOODIX_CONTACT_SIZE *
|
||||
(touch_num - 1));
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
return touch_num;
|
||||
#else
|
||||
return touch_num > 0 ? 1 : 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); /* Poll every 1 - 2 ms */
|
||||
} while (xTaskGetTickCount() < max_timeout);
|
||||
|
||||
/*
|
||||
* The Goodix panel will send spurious interrupts after a
|
||||
* 'finger up' event, which will always cause a timeout.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
{
|
||||
//int id = coor_data[0] & 0x0F;
|
||||
int input_x = get_unaligned_le16(&coor_data[1]);
|
||||
int input_y = get_unaligned_le16(&coor_data[3]);
|
||||
int input_w = get_unaligned_le16(&coor_data[5]);
|
||||
|
||||
/* printf("id=0x%x, input_x=%d, input_y=%d, input_w=%d.\n", id, input_x,
|
||||
input_y, input_w); */
|
||||
|
||||
#if GT9XX_INVERTED_X
|
||||
input_x = ts->x_max - input_x;
|
||||
#endif
|
||||
|
||||
#if GT9XX_INVERTED_Y
|
||||
input_y = ts->y_max - input_y;
|
||||
#endif
|
||||
|
||||
//send press event
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHDOWN, input_x, input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = input_x;
|
||||
indata.point.y = input_y;
|
||||
indata.state = LV_INDEV_STATE_PR;
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
|
||||
last_input_x = input_x;
|
||||
last_input_y = input_y;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_process_events - Process incoming events
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Called when the IRQ is triggered. Read the current device state, and push
|
||||
* the input events to the user space.
|
||||
*/
|
||||
static void goodix_process_events(struct goodix_ts_data *ts)
|
||||
{
|
||||
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
|
||||
int touch_num;
|
||||
int i;
|
||||
|
||||
touch_num = goodix_ts_read_input_report(ts, point_data);
|
||||
if (touch_num < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Bit 4 of the first byte reports the status of the capacitive
|
||||
* Windows/Home button.
|
||||
*/
|
||||
//input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
|
||||
|
||||
for (i = 0; i < touch_num; i++)
|
||||
goodix_ts_report_touch(ts,
|
||||
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
|
||||
|
||||
if (touch_num == 0) {
|
||||
//send release event
|
||||
#ifdef AWTK
|
||||
XM_TpEventProc (XM_EVENT_TOUCHUP, last_input_x, last_input_y, 0);
|
||||
#else
|
||||
lv_indev_data_t indata = {0};
|
||||
indata.point.x = last_input_x;
|
||||
indata.point.y = last_input_y;
|
||||
indata.state = LV_INDEV_STATE_REL;
|
||||
SendTouchInputEvent(&indata);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* input_mt_sync_frame(ts->input_dev);
|
||||
input_sync(ts->input_dev); */
|
||||
}
|
||||
|
||||
static void goodix_ts_irq_task(void *param)
|
||||
{
|
||||
uint32_t ulNotifiedValue;
|
||||
struct goodix_ts_data *ts;
|
||||
|
||||
for (;;) {
|
||||
xTaskNotifyWait( 0x00, /* Don't clear any notification bits on entry. */
|
||||
0xffffffff, /* Reset the notification value to 0 on exit. */
|
||||
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
|
||||
portMAX_DELAY);
|
||||
|
||||
ts = (struct goodix_ts_data *)ulNotifiedValue;
|
||||
|
||||
goodix_process_events(ts);
|
||||
|
||||
if (goodix_i2c_write_u8(ts->adap, GOODIX_READ_COOR_ADDR, 0) < 0)
|
||||
TRACE_ERROR("I2C write end_cmd error\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_ts_irq_handler - The IRQ handler
|
||||
*
|
||||
* @param: private data pointer.
|
||||
*/
|
||||
static void goodix_ts_irq_handler(void *param)
|
||||
{
|
||||
struct goodix_ts_data *ts = param;
|
||||
|
||||
xTaskNotifyFromISR(ts->irq_task, (uint32_t)ts, eSetValueWithOverwrite, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int goodix_request_irq(struct goodix_ts_data *ts)
|
||||
{
|
||||
if (xTaskCreate(goodix_ts_irq_task, "gt9xx", 1024, ts,
|
||||
10, &ts->irq_task) != pdPASS) {
|
||||
printf("create gt9xx irq task fail.\n");
|
||||
}
|
||||
|
||||
return gpio_irq_request(ts->gpio_int, ts->irq_flags, goodix_ts_irq_handler, ts);
|
||||
}
|
||||
|
||||
static int goodix_int_sync(struct goodix_ts_data *ts)
|
||||
{
|
||||
gpio_direction_output(ts->gpio_int, 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); /* T5: 50ms */
|
||||
|
||||
gpio_direction_input(ts->gpio_int);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_reset - Reset device during power on
|
||||
*
|
||||
* @ts: goodix_ts_data pointer
|
||||
*/
|
||||
static int goodix_reset(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* begin select I2C slave addr */
|
||||
gpio_direction_output(ts->gpio_rst, 0);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); /* T2: > 10ms */
|
||||
|
||||
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
|
||||
gpio_direction_output(ts->gpio_int, GT9XX_SLAVE_ADDR == 0x14);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); /* T3: > 100us */
|
||||
|
||||
gpio_direction_output(ts->gpio_rst, 1);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(6)); /* T4: > 5ms */
|
||||
|
||||
/* end select I2C slave addr */
|
||||
gpio_direction_input(ts->gpio_rst);
|
||||
|
||||
error = goodix_int_sync(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_read_config - Read the embedded configuration of the panel
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Must be called during probe
|
||||
*/
|
||||
static void goodix_read_config(struct goodix_ts_data *ts)
|
||||
{
|
||||
u8 config[GOODIX_CONFIG_MAX_LENGTH];
|
||||
int error;
|
||||
|
||||
error = goodix_i2c_read(ts->adap, ts->chip->config_addr,
|
||||
config, ts->chip->config_len);
|
||||
if (error) {
|
||||
TRACE_WARNING("Error reading config: %d\n", error);
|
||||
ts->int_trigger_type = GOODIX_INT_TRIGGER;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;
|
||||
return;
|
||||
}
|
||||
|
||||
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
|
||||
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
|
||||
|
||||
ts->x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
|
||||
ts->y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_read_version - Read goodix touchscreen version
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*/
|
||||
static int goodix_read_version(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
u8 buf[6];
|
||||
char id_str[5];
|
||||
|
||||
error = goodix_i2c_read(ts->adap, GOODIX_REG_ID, buf, sizeof(buf));
|
||||
if (error) {
|
||||
TRACE_ERROR("read version failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
memcpy(id_str, buf, 4);
|
||||
id_str[4] = 0;
|
||||
char *ptr;
|
||||
ts->id = strtoul(id_str, &ptr, 10);
|
||||
if (ts->id == 0xffff)
|
||||
ts->id = 0x1001;
|
||||
|
||||
ts->version = get_unaligned_le16(&buf[4]);
|
||||
|
||||
TRACE_INFO("ID %d, version: %04x\n", ts->id, ts->version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_i2c_test - I2C test function to check if the device answers.
|
||||
*
|
||||
* @adap: the i2c adapter
|
||||
*/
|
||||
static int goodix_i2c_test(struct i2c_adapter *adap)
|
||||
{
|
||||
int retry = 0;
|
||||
int error;
|
||||
u8 test;
|
||||
|
||||
while (retry++ < 2) {
|
||||
error = goodix_i2c_read(adap, GOODIX_REG_ID,
|
||||
&test, 1);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
TRACE_ERROR("i2c test failed attempt %d: %d\n",
|
||||
retry, error);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_configure_dev - Finish device initialization
|
||||
*
|
||||
* @ts: our goodix_ts_data pointer
|
||||
*
|
||||
* Must be called from probe to finish initialization of the device.
|
||||
* Contains the common initialization code for both devices that
|
||||
* declare gpio pins and devices that do not. It is either called
|
||||
* directly from probe or from request_firmware_wait callback.
|
||||
*/
|
||||
static int goodix_configure_dev(struct goodix_ts_data *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
ts->int_trigger_type = GOODIX_INT_TRIGGER;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;
|
||||
|
||||
/* Read configuration and apply touchscreen parameters */
|
||||
goodix_read_config(ts);
|
||||
|
||||
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type];
|
||||
error = goodix_request_irq(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("request IRQ failed: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goodix_ts_probe(struct i2c_adapter *adap)
|
||||
{
|
||||
struct goodix_ts_data *ts;
|
||||
int error;
|
||||
|
||||
TRACE_DEBUG("I2C Address: 0x%02x\n", GT9XX_SLAVE_ADDR);
|
||||
|
||||
ts = pvPortMalloc(sizeof(*ts));
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
|
||||
ts->adap = adap;
|
||||
ts->gpio_int = GT9XX_GPIO_INT;
|
||||
ts->gpio_rst = GT9XX_GPIO_RST;
|
||||
|
||||
if (ts->gpio_int && ts->gpio_rst) {
|
||||
/* reset the controller */
|
||||
error = goodix_reset(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("Controller reset failed.\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
error = goodix_i2c_test(adap);
|
||||
if (error) {
|
||||
TRACE_ERROR("I2C communication failure: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = goodix_read_version(ts);
|
||||
if (error) {
|
||||
TRACE_ERROR("Read version failed.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
ts->chip = goodix_get_chip_data(ts->id);
|
||||
|
||||
error = goodix_configure_dev(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goodix_init(void)
|
||||
{
|
||||
struct i2c_adapter *adap = NULL;
|
||||
|
||||
if (!(adap = i2c_open("i2c0"))) {
|
||||
printf("open i2c0 fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
goodix_ts_probe(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include "chip.h"
|
||||
#include "board.h"
|
||||
|
||||
|
||||
#ifdef TP_SUPPORT
|
||||
extern int goodix_init(void);
|
||||
extern int gt675x_init(void);
|
||||
extern int ft6336u_init(void);
|
||||
|
||||
int tp_init(void)
|
||||
{
|
||||
#if defined(TP_USE_GT9XX)
|
||||
printf("TP select gt9xx.\n");
|
||||
return goodix_init();
|
||||
#elif defined(TP_USE_GA657X)
|
||||
printf("TP select ga657x.\n");
|
||||
return gt675x_init();
|
||||
#elif defined(TP_USE_FT6336U)
|
||||
printf("TP select ft6336u.\n");
|
||||
return ft6336u_init();
|
||||
#else
|
||||
#error "Please select one tp IC"
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,85 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "sfud.h"
|
||||
#include "updatefile.h"
|
||||
#include "mmcsd_core.h"
|
||||
#include "sysinfo.h"
|
||||
|
||||
static UpFileHeader *upfile = NULL;
|
||||
#if DEVICE_TYPE_SELECT != EMMC_FLASH
|
||||
int GetUpFileInfo(void)
|
||||
{
|
||||
UpFileHeader header;
|
||||
uint32_t headersize;
|
||||
sfud_flash *sflash;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
|
||||
sflash = sfud_get_device(0);
|
||||
|
||||
sfud_read(sflash, sysinfo->image_offset, sizeof(header), (void*)&header);
|
||||
if (header.magic != MKTAG('U', 'P', 'D', 'F')) {
|
||||
printf("Error! Wrong update file.\n");
|
||||
return -1;
|
||||
}
|
||||
headersize = sizeof(UpFileHeader) + sizeof(UpFileInfo) * header.filenum;
|
||||
upfile = pvPortMalloc(headersize);
|
||||
if (!upfile) return -1;
|
||||
sfud_read(sflash, sysinfo->image_offset, headersize, (void*)upfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int GetUpFileInfo(void)
|
||||
{
|
||||
UpFileHeader header;
|
||||
uint32_t headersize;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
|
||||
emmc_read(sysinfo->image_offset, sizeof(header), (void*)&header);
|
||||
if (header.magic != MKTAG('U', 'P', 'D', 'F')) {
|
||||
printf("Error! Wrong update file.\n");
|
||||
return -1;
|
||||
}
|
||||
headersize = sizeof(UpFileHeader) + sizeof(UpFileInfo) * header.filenum;
|
||||
upfile = pvPortMalloc(headersize);
|
||||
if (!upfile) return -1;
|
||||
emmc_read(sysinfo->image_offset, headersize, (void*)upfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t GetUpFileOffset(uint32_t magic)
|
||||
{
|
||||
int i;
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
|
||||
if (!upfile) return 0;
|
||||
|
||||
for (i = 0; i < upfile->filenum; i++) {
|
||||
if (upfile->files[i].magic == magic) {
|
||||
return upfile->files[i].offset + sysinfo->image_offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t GetUpFileSize(uint32_t magic)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!upfile) return 0;
|
||||
|
||||
for (i = 0; i < upfile->filenum; i++) {
|
||||
if (upfile->files[i].magic == magic) {
|
||||
return upfile->files[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user