CARPLAY版本整理

This commit is contained in:
2025-01-21 16:49:37 +08:00
commit f0fb64e4e6
26542 changed files with 13719676 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
#ifndef _CRC32_H
#define _CRC32_H
unsigned int
xcrc32(const unsigned char *buf, int len, unsigned int init);
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 = &reg;
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

View File

@ -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 &gt1x_chip_data;
case 911:
case 9271:
case 9110:
case 927:
case 928:
return &gt911_chip_data;
case 912:
case 967:
return &gt967_chip_data;
case 6571:
return &gt6571_chip_data;
default:
return &gt9x_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

View File

@ -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 &gt1x_chip_data;
case 911:
case 9271:
case 9110:
case 927:
case 928:
return &gt911_chip_data;
case 912:
case 967:
return &gt967_chip_data;
default:
return &gt9x_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

View File

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

View File

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