[bsp/nuvoton] Upload missing files. (#6052)
* [bsp/nuvoton] Upload missing files. Co-authored-by: Wayne Lin <wclin@nuvoton.com>
This commit is contained in:
parent
c16eaf55de
commit
2006785394
83
bsp/nuvoton/libraries/m2354/StdDriver/inc/nu_trng.h
Normal file
83
bsp/nuvoton/libraries/m2354/StdDriver/inc/nu_trng.h
Normal file
@ -0,0 +1,83 @@
|
||||
/**************************************************************************//**
|
||||
* @file nu_trng.h
|
||||
* @version V3.00
|
||||
* @brief TRNG driver header file
|
||||
*
|
||||
* @copyright SPDX-License-Identifier: Apache-2.0
|
||||
* @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
|
||||
******************************************************************************/
|
||||
#ifndef __NU_TRNG_H__
|
||||
#define __NU_TRNG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/** @addtogroup Standard_Driver Standard Driver
|
||||
@{
|
||||
*/
|
||||
|
||||
/** @addtogroup TRNG_Driver TRNG Driver
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup M460_TRNG_EXPORTED_MACROS TRNG Exported Macros
|
||||
@{
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
/* Macros */
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Let TRNG engine know the currrent PCLK frequency. The CLKPSC is the peripheral
|
||||
* clock frequency range for the selected value , the CLKPSC setting must be higher
|
||||
* than or equal to the actual peripheral clock frequency (for correct random generation).
|
||||
* @param clkpsc 0: PCLK is 80~100 MHz
|
||||
* 1: PCLK is 60~80 MHz
|
||||
* 2: PCLK is 50~60 MHz
|
||||
* 3: PCLK is 40~50 MHz
|
||||
* 4: PCLK is 30~40 MHz
|
||||
* 5: PCLK is 25~30 MHz
|
||||
* 6: PCLK is 20~25 MHz
|
||||
* 7: PCLK is 15~20 MHz
|
||||
* 8: PCLK is 12~15 MHz
|
||||
* 9: PCLK is 9~12 MHz
|
||||
*
|
||||
* @return None
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define TRNG_SET_CLKP(clkpsc) do { TRNG->CTL = (TRNG->CTL&~TRNG_CTL_CLKP_Msk)|((clkpsc & 0xf)<<TRNG_CTL_CLKP_Pos); } while(0);
|
||||
|
||||
|
||||
/*@}*/ /* end of group M460_TRNG_EXPORTED_MACROS */
|
||||
|
||||
|
||||
/** @addtogroup TRNG_EXPORTED_FUNCTIONS TRNG Exported Functions
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------------------------------------*/
|
||||
/* Functions */
|
||||
/*---------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
int32_t TRNG_Open(void);
|
||||
int32_t TRNG_GenWord(uint32_t *u32RndNum);
|
||||
int32_t TRNG_GenBignum(uint8_t u8BigNum[], int32_t i32Len);
|
||||
int32_t TRNG_GenBignumHex(char cBigNumHex[], int32_t i32Len);
|
||||
|
||||
|
||||
/*@}*/ /* end of group TRNG_EXPORTED_FUNCTIONS */
|
||||
|
||||
/*@}*/ /* end of group TRNG_Driver */
|
||||
|
||||
/*@}*/ /* end of group Standard_Driver */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NU_TRNG_H__ */
|
177
bsp/nuvoton/libraries/m2354/StdDriver/src/nu_trng.c
Normal file
177
bsp/nuvoton/libraries/m2354/StdDriver/src/nu_trng.c
Normal file
@ -0,0 +1,177 @@
|
||||
/**************************************************************************//**
|
||||
* @file trng.c
|
||||
* @version V3.00
|
||||
* @brief M460 series TRNG driver source file
|
||||
*
|
||||
* @copyright SPDX-License-Identifier: Apache-2.0
|
||||
* @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "NuMicro.h"
|
||||
|
||||
|
||||
/** @addtogroup Standard_Driver Standard Driver
|
||||
@{
|
||||
*/
|
||||
|
||||
/** @addtogroup TRNG_Driver TRNG Driver
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup TRNG_EXPORTED_FUNCTIONS TRNG Exported Functions
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize TRNG hardware.
|
||||
* @return TRNG hardware enable success or failed.
|
||||
* @retval 0 Success
|
||||
* @retval -1 Time-out. TRNG hardware may not be enabled.
|
||||
*/
|
||||
int32_t TRNG_Open(void)
|
||||
{
|
||||
uint32_t u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
||||
|
||||
SYS->IPRST1 |= SYS_IPRST1_TRNGRST_Msk;
|
||||
SYS->IPRST1 ^= SYS_IPRST1_TRNGRST_Msk;
|
||||
|
||||
TRNG->CTL |= TRNG_CTL_TRNGEN_Msk;
|
||||
|
||||
TRNG->ACT |= TRNG_ACT_ACT_Msk;
|
||||
|
||||
/* Waiting for ready */
|
||||
while ((TRNG->CTL & TRNG_CTL_READY_Msk) == 0)
|
||||
{
|
||||
if (--u32TimeOutCount == 0) return -1; /* Time-out error */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generate a 32-bits random number word.
|
||||
* @param[out] u32RndNum The output 32-bits word random number.
|
||||
*
|
||||
* @return Success or time-out.
|
||||
* @retval 0 Success
|
||||
* @retval -1 Time-out. TRNG hardware may not be enabled.
|
||||
*/
|
||||
int32_t TRNG_GenWord(uint32_t *u32RndNum)
|
||||
{
|
||||
uint32_t i, u32Reg, timeout;
|
||||
|
||||
*u32RndNum = 0;
|
||||
u32Reg = TRNG->CTL;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
TRNG->CTL = TRNG_CTL_TRNGEN_Msk | u32Reg;
|
||||
|
||||
/* TRNG should generate one byte per 125*8 us */
|
||||
for (timeout = (CLK_GetHCLKFreq() / 100); timeout > 0; timeout--)
|
||||
{
|
||||
if (TRNG->CTL & TRNG_CTL_DVIF_Msk)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return -1;
|
||||
|
||||
*u32RndNum |= ((TRNG->DATA & 0xff) << i * 8);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a big number in binary format.
|
||||
* @param[out] u8BigNum The output big number.
|
||||
* @param[in] i32Len Request bit length of the output big number. It must be multiple of 8.
|
||||
*
|
||||
* @return Success or time-out.
|
||||
* @retval 0 Success
|
||||
* @retval -1 Time-out. TRNG hardware may not be enabled.
|
||||
*/
|
||||
int32_t TRNG_GenBignum(uint8_t u8BigNum[], int32_t i32Len)
|
||||
{
|
||||
uint32_t i, u32Reg, timeout;
|
||||
|
||||
u32Reg = TRNG->CTL;
|
||||
|
||||
for (i = 0; i < i32Len / 8; i++)
|
||||
{
|
||||
TRNG->CTL = TRNG_CTL_TRNGEN_Msk | u32Reg;
|
||||
|
||||
/* TRNG should generate one byte per 125*8 us */
|
||||
for (timeout = (CLK_GetHCLKFreq() / 100); timeout > 0; timeout--)
|
||||
{
|
||||
if (TRNG->CTL & TRNG_CTL_DVIF_Msk)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return -1;
|
||||
|
||||
u8BigNum[i] = (TRNG->DATA & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate a big number in hex format.
|
||||
* @param[out] cBigNumHex The output hex format big number.
|
||||
* @param[in] i32Len Request bit length of the output big number. It must be multiple of 8.
|
||||
*
|
||||
* @return Success or time-out.
|
||||
* @retval 0 Success
|
||||
* @retval -1 Time-out. TRNG hardware may not be enabled.
|
||||
*/
|
||||
int32_t TRNG_GenBignumHex(char cBigNumHex[], int32_t i32Len)
|
||||
{
|
||||
uint32_t i, idx, u32Reg, timeout;
|
||||
uint32_t data;
|
||||
|
||||
u32Reg = TRNG->CTL;
|
||||
idx = 0;
|
||||
for (i = 0; i < i32Len / 8; i++)
|
||||
{
|
||||
TRNG->CTL = TRNG_CTL_TRNGEN_Msk | u32Reg;
|
||||
|
||||
/* TRNG should generate one byte per 125*8 us */
|
||||
for (timeout = (CLK_GetHCLKFreq() / 100); timeout > 0; timeout--)
|
||||
{
|
||||
if (TRNG->CTL & TRNG_CTL_DVIF_Msk)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return -1;
|
||||
|
||||
data = (TRNG->DATA & 0xff);
|
||||
|
||||
if (data >= 0xA0)
|
||||
cBigNumHex[idx++] = ((data >> 4) & 0xf) - 10 + 'A';
|
||||
else
|
||||
cBigNumHex[idx++] = ((data >> 4) & 0xf) + '0';
|
||||
|
||||
data &= 0xf;
|
||||
if (data >= 0xA)
|
||||
cBigNumHex[idx++] = data - 10 + 'A';
|
||||
else
|
||||
cBigNumHex[idx++] = data + '0';
|
||||
}
|
||||
cBigNumHex[idx] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*@}*/ /* end of group TRNG_EXPORTED_FUNCTIONS */
|
||||
|
||||
/*@}*/ /* end of group TRNG_Driver */
|
||||
|
||||
/*@}*/ /* end of group Standard_Driver */
|
796
bsp/nuvoton/libraries/m2354/rtt_port/drv_sdio.c
Normal file
796
bsp/nuvoton/libraries/m2354/rtt_port/drv_sdio.c
Normal file
@ -0,0 +1,796 @@
|
||||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-4-21 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "rtconfig.h"
|
||||
|
||||
#if defined(BSP_USING_SDH)
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <drivers/mmcsd_core.h>
|
||||
#include <drivers/sdio.h>
|
||||
|
||||
#include "NuMicro.h"
|
||||
|
||||
#define LOG_TAG "drv.sdh"
|
||||
#undef DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL LOG_LVL_ASSERT
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define SDH_ALIGN_LEN 4
|
||||
#define SDH_BUFF_SIZE 512
|
||||
#define SDH_BLOCK_SIZE 512
|
||||
|
||||
enum
|
||||
{
|
||||
SDH_START = -1,
|
||||
#if defined(BSP_USING_SDH0)
|
||||
SDH0_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_SDH1)
|
||||
SDH1_IDX,
|
||||
#endif
|
||||
SDH_CNT
|
||||
};
|
||||
|
||||
struct nu_sdh
|
||||
{
|
||||
struct rt_mmcsd_host *host;
|
||||
char *name;
|
||||
SDH_T *base;
|
||||
IRQn_Type irqn;
|
||||
uint32_t rstidx;
|
||||
uint32_t modid;
|
||||
|
||||
uint8_t *cachebuf;
|
||||
uint32_t u32CmdResp0;
|
||||
uint32_t u32CmdResp1;
|
||||
uint32_t u32CurClk;
|
||||
rt_tick_t LastNotice;
|
||||
};
|
||||
typedef struct nu_sdh *nu_sdh_t;
|
||||
|
||||
/* Private variables ------------------------------------------------------------*/
|
||||
static struct nu_sdh nu_sdh_arr [] =
|
||||
{
|
||||
#if defined(BSP_USING_SDH0)
|
||||
{
|
||||
.name = "sdh0",
|
||||
.base = SDH0,
|
||||
.irqn = SDH0_IRQn,
|
||||
.rstidx = SDH0_RST,
|
||||
.modid = SDH0_MODULE,
|
||||
.cachebuf = RT_NULL,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_SDH1)
|
||||
{
|
||||
.name = "sdh1",
|
||||
.base = SDH1,
|
||||
.irqn = SDH1_IRQn,
|
||||
.rstidx = SDH1_RST,
|
||||
.modid = SDH1_MODULE,
|
||||
.cachebuf = RT_NULL,
|
||||
},
|
||||
#endif
|
||||
}; /* struct nu_sdh nu_sdh_arr [] */
|
||||
|
||||
#define SDH_SetClock SDH_Set_clock
|
||||
|
||||
static int SDH_SetBusWidth(SDH_T *sdh, uint32_t bw)
|
||||
{
|
||||
if (bw == 4)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_DBW_Msk;
|
||||
}
|
||||
else if (bw == 1)
|
||||
{
|
||||
sdh->CTL &= ~SDH_CTL_DBW_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_SDH_SetBusWidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_SDH_SetBusWidth:
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int SDH_GetBusStatus(SDH_T *sdh, uint32_t mask)
|
||||
{
|
||||
int cnt = 0x100000;
|
||||
while (cnt-- > 0)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_CLK8OEN_Msk;
|
||||
while (sdh->CTL & SDH_CTL_CLK8OEN_Msk) { }
|
||||
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk))
|
||||
break;
|
||||
}
|
||||
return (cnt == 0) ? -1 : 0 ;
|
||||
}
|
||||
|
||||
static int SDH_GetCD(SDH_T *sdh)
|
||||
{
|
||||
int i32CD = 0;
|
||||
if ((sdh->GCTL & SDH_GCTL_SDEN_Msk) == SDH_GCTL_SDEN_Msk)
|
||||
{
|
||||
if ((sdh->INTEN & SDH_INTEN_CDSRC_Msk) == SDH_INTEN_CDSRC_Msk) /* Card detect pin from GPIO */
|
||||
{
|
||||
i32CD = (sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) ? 0 : 1;
|
||||
}
|
||||
else /* Card detect pin from DAT3 mode */
|
||||
{
|
||||
__IO uint32_t i;
|
||||
|
||||
sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
|
||||
for (i = 0ul; i < 5000ul; i++) { }
|
||||
|
||||
i32CD = ((sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) == SDH_INTSTS_CDSTS_Msk) ? 1 : 0;
|
||||
sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
|
||||
}
|
||||
}
|
||||
return i32CD;
|
||||
}
|
||||
|
||||
static void SDH_Enable(SDH_T *sdh)
|
||||
{
|
||||
/* Reset sdh and its DMA engine at first. */
|
||||
sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
|
||||
while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
|
||||
sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
|
||||
sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
|
||||
|
||||
sdh->GCTL = SDH_GCTL_GCTLRST_Msk;
|
||||
while ((sdh->GCTL & SDH_GCTL_GCTLRST_Msk) == SDH_GCTL_GCTLRST_Msk) { }// clear all interrupt flag
|
||||
sdh->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
|
||||
sdh->GCTL = SDH_GCTL_SDEN_Msk;
|
||||
|
||||
sdh->CTL |= SDH_CTL_CTLRST_Msk;
|
||||
while ((sdh->CTL & SDH_CTL_CTLRST_Msk) == SDH_CTL_CTLRST_Msk) { }
|
||||
|
||||
sdh->INTSTS = 0xFFFFFFFF; // clear all interrupt flag
|
||||
|
||||
sdh->INTEN |= SDH_INTEN_CDSRC_Msk;
|
||||
sdh->INTEN |= SDH_INTEN_CDIEN_Msk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function get command responding.
|
||||
* @param sdh SDH instance
|
||||
* @param cmd rt_mmcsd_cmd
|
||||
* @retval none
|
||||
*/
|
||||
static void nu_sdh_sendcmd_done(SDH_T *sdh, struct rt_mmcsd_cmd *cmd)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
uint8_t *c = (uint8_t *)&sdh->FB[0];
|
||||
int i, j, tmp[5];
|
||||
|
||||
for (i = 0, j = 0; j < 5; i += 4, j++)
|
||||
{
|
||||
tmp[j] = (*(c + i) << 24) | (*(c + i + 1) << 16) | (*(c + i + 2) << 8) | (*(c + i + 3));
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
cmd->resp[i] = ((tmp[i] & 0x00ffffff) << 8) |
|
||||
((tmp[i + 1] & 0xff000000) >> 24);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->resp[0] = (sdh->RESP0 << 8) | (sdh->RESP1 & 0xff);
|
||||
cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function wait data-sending/receiving.
|
||||
* @param sdh SDH instance
|
||||
* @param data rt_mmcsd_data
|
||||
* @retval error code
|
||||
*/
|
||||
static int nu_sdh_xfer_data(SDH_T *sdh, struct rt_mmcsd_data *data)
|
||||
{
|
||||
while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk)) { }
|
||||
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk);
|
||||
|
||||
if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
|
||||
|
||||
while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk)) { }
|
||||
|
||||
sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function send command and wait its response.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param cmd rt_mmcsd_cmd
|
||||
* @param data rt_mmcsd_data
|
||||
* @retval error code
|
||||
*/
|
||||
static int nu_sdh_sendcmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, struct rt_mmcsd_data *data)
|
||||
{
|
||||
int ret;
|
||||
nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
volatile uint32_t ctl = 0, tout = 0;
|
||||
|
||||
switch (host->io_cfg.bus_width)
|
||||
{
|
||||
case MMCSD_BUS_WIDTH_1:
|
||||
ctl &= ~SDH_CTL_DBW_Msk;
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_4:
|
||||
ctl |= SDH_CTL_DBW_Msk;
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_8:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reset sdh and its DMA engine at first. */
|
||||
sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
|
||||
while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
|
||||
sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
|
||||
sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
ctl |= SDH_CTL_R2EN_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl |= SDH_CTL_RIEN_Msk;
|
||||
}
|
||||
tout = 0xFFFF;
|
||||
}
|
||||
|
||||
/* Set SDNWR and BLK_CNT to 1 */
|
||||
ctl |= ((9 << SDH_CTL_SDNWR_Pos) | (1 << SDH_CTL_BLKCNT_Pos));
|
||||
ctl |= ((cmd->cmd_code << SDH_CTL_CMDCODE_Pos) | SDH_CTL_COEN_Msk);
|
||||
|
||||
/* Set Transfer mode regarding to data flag */
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
sdh->BLEN = data->blksize - 1;
|
||||
|
||||
if (data->blksize <= 0x200)
|
||||
{
|
||||
if (data->blks < 256)
|
||||
{
|
||||
ctl = (ctl & ~SDH_CTL_BLKCNT_Msk) | (data->blks << SDH_CTL_BLKCNT_Pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("SD Max block transfer is 255!!");
|
||||
}
|
||||
}
|
||||
|
||||
if (data->flags & DATA_DIR_READ)
|
||||
{
|
||||
tout = 0xFFFFFF;
|
||||
ctl |= SDH_CTL_DIEN_Msk; // Data-in
|
||||
sdh->DMASA = (uint32_t)data->buf; // Read from dest
|
||||
}
|
||||
else if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
ctl |= SDH_CTL_DOEN_Msk; // Data-out
|
||||
sdh->DMASA = (uint32_t)data->buf; // Write to dest
|
||||
}
|
||||
}
|
||||
else if (resp_type(cmd) == RESP_R1B)
|
||||
{
|
||||
}
|
||||
|
||||
/* Clear response-timeout flag first for safty and reset new timeout value. */
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk);
|
||||
sdh->TOUT = tout;
|
||||
|
||||
/* Set argument and start a transaction. */
|
||||
sdh->CMDARG = cmd->arg;
|
||||
sdh->CTL = ctl;
|
||||
|
||||
/* Wait a command done. */
|
||||
while ((sdh->CTL & (SDH_CTL_COEN_Msk)) == SDH_CTL_COEN_Msk) { }
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
/* Wait to receive a response R2 from SD card and store the response data into DMC's Flash buffer (exclude CRC7). */
|
||||
while (sdh->CTL & SDH_CTL_R2EN_Msk)
|
||||
{
|
||||
/* When get a Response timeout, break the polling. */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
|
||||
{
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait to receive a response from SD card. */
|
||||
while ((sdh->CTL & SDH_CTL_RIEN_Msk))
|
||||
{
|
||||
/* When get a Response timeout, break the polling. */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
|
||||
{
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
/* TOFIX: ISSUE: Sometimes, SDH's RIEN is cleared automatically by controller after host sending CMD5 to SD card. */
|
||||
/* Workaround: To check previous cmd's response with CMD's. */
|
||||
if (cmd->cmd_code == 5)
|
||||
{
|
||||
if ((NuSdh->u32CmdResp0 == sdh->RESP0) && (NuSdh->u32CmdResp1 == sdh->RESP1))
|
||||
{
|
||||
LOG_E("False CMD5-RESP issue occured.\n");
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
NuSdh->u32CmdResp0 = sdh->RESP0;
|
||||
NuSdh->u32CmdResp1 = sdh->RESP1;
|
||||
}
|
||||
|
||||
/* Get response from FB or register */
|
||||
nu_sdh_sendcmd_done(sdh, cmd);
|
||||
}
|
||||
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
/* Wait data processing done */
|
||||
nu_sdh_xfer_data(sdh, data);
|
||||
|
||||
ret = SDH_GetBusStatus(sdh, 0);
|
||||
if (ret)
|
||||
{
|
||||
LOG_E("ERROR: Busy %d\n", ret);
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle CRC flag */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk)) // Fault
|
||||
{
|
||||
uint32_t u32INTSTS = sdh->INTSTS;
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk);
|
||||
ret = __LINE__;
|
||||
|
||||
if ((resp_type(cmd) != RESP_R3) && (u32INTSTS & SDH_INTSTS_CRC7_Msk) == 0) //CRC7, Ignore R3
|
||||
{
|
||||
LOG_E("CRC7 error! (resp_type=%d)", resp_type(cmd));
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
|
||||
if ((u32INTSTS & SDH_INTSTS_CRC16_Msk) == 0) //CRC16
|
||||
{
|
||||
LOG_E("CRC16 error! (resp_type=%d)", resp_type(cmd));
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
exit_nu_sdh_sendcmd:
|
||||
|
||||
LOG_D("[%s %d] cmdid=%d error line=%d", __func__, __LINE__, cmd->cmd_code, ret);
|
||||
|
||||
cmd->resp[0] = cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
|
||||
sdh->TOUT = 0;
|
||||
SDH_Enable(sdh);
|
||||
|
||||
return -ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function send request.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param req request
|
||||
* @retval None
|
||||
*/
|
||||
static void nu_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
SDH_T *sdh;
|
||||
|
||||
RT_ASSERT(host);
|
||||
RT_ASSERT(req);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
sdh = NuSdh->base;
|
||||
|
||||
if (!SDH_GetCD(sdh)) // card is not present
|
||||
{
|
||||
LOG_E("Card is not present");
|
||||
req->cmd->err = -RT_EIO;
|
||||
goto exit_nu_sdh_request;
|
||||
}
|
||||
|
||||
if (req->cmd != RT_NULL)
|
||||
{
|
||||
struct rt_mmcsd_cmd *cmd = req->cmd;
|
||||
struct rt_mmcsd_data *data = req->data;
|
||||
|
||||
LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RESP_TYPE:%d rw:%c addr:%08x, blks:%d, blksize:%d datalen:%d",
|
||||
(host->card == RT_NULL) ? "Unknown" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
|
||||
cmd->cmd_code,
|
||||
cmd->arg,
|
||||
resp_type(cmd),
|
||||
data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
|
||||
data ? data->buf : 0,
|
||||
data ? data->blks : 0,
|
||||
data ? data->blksize : 0,
|
||||
data ? data->blks * data->blksize : 0);
|
||||
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
rt_uint32_t size;
|
||||
rt_int32_t IsNonaligned = 0;
|
||||
rt_uint32_t *org_data_buf = data->buf;
|
||||
|
||||
size = data->blksize * data->blks;
|
||||
|
||||
RT_ASSERT(org_data_buf);
|
||||
|
||||
IsNonaligned = (((rt_uint32_t)data->buf & (SDH_ALIGN_LEN - 1)) > 0) ? 1 : 0;
|
||||
if (IsNonaligned)
|
||||
{
|
||||
/* Allocate memory temp buffer on demand. */
|
||||
RT_ASSERT(size <= SDH_BUFF_SIZE);
|
||||
|
||||
if (NuSdh->cachebuf == RT_NULL)
|
||||
{
|
||||
NuSdh->cachebuf = rt_malloc_align(SDH_BUFF_SIZE, SDH_ALIGN_LEN);
|
||||
RT_ASSERT(NuSdh->cachebuf);
|
||||
}
|
||||
|
||||
data->buf = (rt_uint32_t *)NuSdh->cachebuf;
|
||||
if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
LOG_D("Un-aligned, prepare into cache buf(%d)", size);
|
||||
rt_memcpy(data->buf, org_data_buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
cmd->err = nu_sdh_sendcmd(host, cmd, data);
|
||||
|
||||
if (!cmd->err && IsNonaligned)
|
||||
{
|
||||
if (data->flags & DATA_DIR_READ)
|
||||
{
|
||||
LOG_D("Un-aligned, restore from cache buf(%d)", size);
|
||||
rt_memcpy(org_data_buf, data->buf, size);
|
||||
}
|
||||
}
|
||||
data->buf = org_data_buf;
|
||||
|
||||
LOG_HEX("data.dest", 16, (void *)data->buf, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->err = nu_sdh_sendcmd(host, cmd, NULL);
|
||||
}
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
LOG_HEX("cmd->resp", 16, (void *)&cmd->resp[0], 16);
|
||||
}
|
||||
|
||||
if (req->stop != RT_NULL)
|
||||
{
|
||||
struct rt_mmcsd_cmd *stop = req->stop;
|
||||
|
||||
stop->err = nu_sdh_sendcmd(host, stop, NULL);
|
||||
|
||||
if (resp_type(stop) != RESP_NONE)
|
||||
LOG_HEX("stop->resp", 16, (void *)&stop->resp[0], 16);
|
||||
|
||||
}
|
||||
|
||||
exit_nu_sdh_request:
|
||||
|
||||
mmcsd_req_complete(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function config.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param io_cfg rt_mmcsd_io_cfg
|
||||
* @retval None
|
||||
*/
|
||||
static void nu_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
rt_uint32_t clk;
|
||||
SDH_T *sdh;
|
||||
|
||||
RT_ASSERT(host);
|
||||
RT_ASSERT(io_cfg);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
sdh = NuSdh->base;
|
||||
clk = io_cfg->clock;
|
||||
|
||||
LOG_D("[%s]clk:%d width(%d):%s%s%s power:%s%s%s",
|
||||
NuSdh->name,
|
||||
clk,
|
||||
io_cfg->bus_width,
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_8 ? "8" : "",
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_4 ? "4" : "",
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_1 ? "1" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
|
||||
|
||||
/* Clock */
|
||||
if (clk > host->freq_max)
|
||||
clk = host->freq_max;
|
||||
|
||||
if (clk < host->freq_min)
|
||||
clk = host->freq_min;
|
||||
|
||||
LOG_D("[%s] ExceptedFreq: %d kHz", NuSdh->name, clk / 1000);
|
||||
if (NuSdh->u32CurClk != (clk / 1000))
|
||||
{
|
||||
SDH_SetClock(sdh, clk / 1000);
|
||||
NuSdh->u32CurClk = (clk / 1000);
|
||||
}
|
||||
|
||||
switch (io_cfg->power_mode)
|
||||
{
|
||||
case MMCSD_POWER_UP:
|
||||
if (clk <= 400000)
|
||||
{
|
||||
/* power ON 74 clock */
|
||||
sdh->CTL |= SDH_CTL_CLK74OEN_Msk;
|
||||
|
||||
while ((sdh->CTL & SDH_CTL_CLK74OEN_Msk) == SDH_CTL_CLK74OEN_Msk)
|
||||
{
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MMCSD_POWER_ON:
|
||||
break;
|
||||
|
||||
case MMCSD_POWER_OFF:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bus width */
|
||||
switch ((io_cfg->bus_width))
|
||||
{
|
||||
case MMCSD_BUS_WIDTH_1:
|
||||
SDH_SetBusWidth(sdh, 1);
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_4:
|
||||
SDH_SetBusWidth(sdh, 4);
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_8:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function detect sdcard.
|
||||
* @param host rt_mmcsd_host
|
||||
* @retval card detection status
|
||||
*/
|
||||
static rt_int32_t nu_sdh_card_detect(struct rt_mmcsd_host *host)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
RT_ASSERT(host);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
LOG_D("try to detect device");
|
||||
return SDH_GetCD(sdh);
|
||||
}
|
||||
|
||||
static void nu_sdh_isr(nu_sdh_t NuSdh)
|
||||
{
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
uint32_t isr = sdh->INTSTS;
|
||||
|
||||
/* card detected */
|
||||
if (isr & SDH_INTSTS_CDIF_Msk)
|
||||
{
|
||||
rt_tick_t cur_tick = rt_tick_get();
|
||||
rt_tick_t diff_tick;
|
||||
|
||||
/* ready to change */
|
||||
if (cur_tick >= NuSdh->LastNotice)
|
||||
diff_tick = (cur_tick - NuSdh->LastNotice);
|
||||
else
|
||||
diff_tick = ((rt_tick_t) -1) - NuSdh->LastNotice + cur_tick;
|
||||
|
||||
if (!NuSdh->LastNotice || (diff_tick > (RT_TICK_PER_SECOND / 5))) // Debounce 200ms
|
||||
{
|
||||
NuSdh->LastNotice = cur_tick;
|
||||
mmcsd_change(NuSdh->host);
|
||||
}
|
||||
|
||||
/* Clear CDIF interrupt flag */
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BSP_USING_SDH0)
|
||||
void SDH0_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
nu_sdh_isr(&nu_sdh_arr[SDH0_IDX]);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_SDH1)
|
||||
void SDH1_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
nu_sdh_isr(&nu_sdh_arr[SDH1_IDX]);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function update sdh interrupt.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param enable
|
||||
* @retval None
|
||||
*/
|
||||
void nu_sdh_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
|
||||
{
|
||||
nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
LOG_D("Enable %s irq", NuSdh->name);
|
||||
SDH_ENABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("Disable %s irq", NuSdh->name);
|
||||
SDH_DISABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rt_mmcsd_host_ops ops =
|
||||
{
|
||||
nu_sdh_request,
|
||||
nu_sdh_iocfg,
|
||||
nu_sdh_card_detect,
|
||||
nu_sdh_irq_update,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This function create mmcsd host.
|
||||
* @param sdh nu_sdh_t
|
||||
* @retval nuvton
|
||||
*/
|
||||
void nu_sdh_host_init(nu_sdh_t sdh)
|
||||
{
|
||||
struct rt_mmcsd_host *host = mmcsd_alloc_host();
|
||||
RT_ASSERT(host);
|
||||
|
||||
/* set host default attributes */
|
||||
host->ops = &ops;
|
||||
host->freq_min = 300 * 1000;
|
||||
host->freq_max = 48 * 1000 * 1000;
|
||||
host->valid_ocr = VDD_26_27 | VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;
|
||||
|
||||
host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
|
||||
|
||||
host->max_seg_size = SDH_BUFF_SIZE;
|
||||
host->max_dma_segs = 1;
|
||||
host->max_blk_size = SDH_BLOCK_SIZE;
|
||||
host->max_blk_count = (SDH_BUFF_SIZE / SDH_BLOCK_SIZE);
|
||||
|
||||
/* link up host and sdio */
|
||||
host->private_data = sdh;
|
||||
sdh->host = host;
|
||||
|
||||
/* Enable DMA engine at first. */
|
||||
SDH_Enable(sdh->base);
|
||||
|
||||
/* Install ISR. */
|
||||
NVIC_EnableIRQ(sdh->irqn);
|
||||
|
||||
/* ready to change */
|
||||
//mmcsd_change(host);
|
||||
}
|
||||
|
||||
static int rt_hw_sdh_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
CLK_EnableModuleClock(nu_sdh_arr[i].modid);
|
||||
SYS_ResetModule(nu_sdh_arr[i].rstidx);
|
||||
|
||||
nu_sdh_host_init(&nu_sdh_arr[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(rt_hw_sdh_init);
|
||||
|
||||
void nu_sd_attach(void)
|
||||
{
|
||||
int i;
|
||||
/* ready to change */
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
if (nu_sdh_arr[i].host)
|
||||
mmcsd_change(nu_sdh_arr[i].host);
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(nu_sd_attach, attach card);
|
||||
|
||||
void nu_sd_regdump(void)
|
||||
{
|
||||
int i;
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
if (nu_sdh_arr[i].host)
|
||||
LOG_HEX("sdh_reg", 16, (void *)nu_sdh_arr[i].base, sizeof(SDH_T));
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(nu_sd_regdump, dump sdh registers);
|
||||
|
||||
#endif
|
796
bsp/nuvoton/libraries/m480/rtt_port/drv_sdio.c
Normal file
796
bsp/nuvoton/libraries/m480/rtt_port/drv_sdio.c
Normal file
@ -0,0 +1,796 @@
|
||||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-4-21 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "rtconfig.h"
|
||||
|
||||
#if defined(BSP_USING_SDH)
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <drivers/mmcsd_core.h>
|
||||
#include <drivers/sdio.h>
|
||||
|
||||
#include "NuMicro.h"
|
||||
|
||||
#define LOG_TAG "drv.sdh"
|
||||
#undef DBG_ENABLE
|
||||
#define DBG_SECTION_NAME LOG_TAG
|
||||
#define DBG_LEVEL LOG_LVL_ASSERT
|
||||
#define DBG_COLOR
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define SDH_ALIGN_LEN 4
|
||||
#define SDH_BUFF_SIZE 512
|
||||
#define SDH_BLOCK_SIZE 512
|
||||
|
||||
enum
|
||||
{
|
||||
SDH_START = -1,
|
||||
#if defined(BSP_USING_SDH0)
|
||||
SDH0_IDX,
|
||||
#endif
|
||||
#if defined(BSP_USING_SDH1)
|
||||
SDH1_IDX,
|
||||
#endif
|
||||
SDH_CNT
|
||||
};
|
||||
|
||||
struct nu_sdh
|
||||
{
|
||||
struct rt_mmcsd_host *host;
|
||||
char *name;
|
||||
SDH_T *base;
|
||||
IRQn_Type irqn;
|
||||
uint32_t rstidx;
|
||||
uint32_t modid;
|
||||
|
||||
uint8_t *cachebuf;
|
||||
uint32_t u32CmdResp0;
|
||||
uint32_t u32CmdResp1;
|
||||
uint32_t u32CurClk;
|
||||
rt_tick_t LastNotice;
|
||||
};
|
||||
typedef struct nu_sdh *nu_sdh_t;
|
||||
|
||||
/* Private variables ------------------------------------------------------------*/
|
||||
static struct nu_sdh nu_sdh_arr [] =
|
||||
{
|
||||
#if defined(BSP_USING_SDH0)
|
||||
{
|
||||
.name = "sdh0",
|
||||
.base = SDH0,
|
||||
.irqn = SDH0_IRQn,
|
||||
.rstidx = SDH0_RST,
|
||||
.modid = SDH0_MODULE,
|
||||
.cachebuf = RT_NULL,
|
||||
},
|
||||
#endif
|
||||
#if defined(BSP_USING_SDH1)
|
||||
{
|
||||
.name = "sdh1",
|
||||
.base = SDH1,
|
||||
.irqn = SDH1_IRQn,
|
||||
.rstidx = SDH1_RST,
|
||||
.modid = SDH1_MODULE,
|
||||
.cachebuf = RT_NULL,
|
||||
},
|
||||
#endif
|
||||
}; /* struct nu_sdh nu_sdh_arr [] */
|
||||
|
||||
#define SDH_SetClock SDH_Set_clock
|
||||
|
||||
static int SDH_SetBusWidth(SDH_T *sdh, uint32_t bw)
|
||||
{
|
||||
if (bw == 4)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_DBW_Msk;
|
||||
}
|
||||
else if (bw == 1)
|
||||
{
|
||||
sdh->CTL &= ~SDH_CTL_DBW_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto exit_SDH_SetBusWidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_SDH_SetBusWidth:
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int SDH_GetBusStatus(SDH_T *sdh, uint32_t mask)
|
||||
{
|
||||
int cnt = 0x100000;
|
||||
while (cnt-- > 0)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_CLK8OEN_Msk;
|
||||
while (sdh->CTL & SDH_CTL_CLK8OEN_Msk) { }
|
||||
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk))
|
||||
break;
|
||||
}
|
||||
return (cnt == 0) ? -1 : 0 ;
|
||||
}
|
||||
|
||||
static int SDH_GetCD(SDH_T *sdh)
|
||||
{
|
||||
int i32CD = 0;
|
||||
if ((sdh->GCTL & SDH_GCTL_SDEN_Msk) == SDH_GCTL_SDEN_Msk)
|
||||
{
|
||||
if ((sdh->INTEN & SDH_INTEN_CDSRC_Msk) == SDH_INTEN_CDSRC_Msk) /* Card detect pin from GPIO */
|
||||
{
|
||||
i32CD = (sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) ? 0 : 1;
|
||||
}
|
||||
else /* Card detect pin from DAT3 mode */
|
||||
{
|
||||
__IO uint32_t i;
|
||||
|
||||
sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
|
||||
for (i = 0ul; i < 5000ul; i++) { }
|
||||
|
||||
i32CD = ((sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) == SDH_INTSTS_CDSTS_Msk) ? 1 : 0;
|
||||
sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
|
||||
}
|
||||
}
|
||||
return i32CD;
|
||||
}
|
||||
|
||||
static void SDH_Enable(SDH_T *sdh)
|
||||
{
|
||||
/* Reset sdh and its DMA engine at first. */
|
||||
sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
|
||||
while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
|
||||
sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
|
||||
sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
|
||||
|
||||
sdh->GCTL = SDH_GCTL_GCTLRST_Msk;
|
||||
while ((sdh->GCTL & SDH_GCTL_GCTLRST_Msk) == SDH_GCTL_GCTLRST_Msk) { }// clear all interrupt flag
|
||||
sdh->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
|
||||
sdh->GCTL = SDH_GCTL_SDEN_Msk;
|
||||
|
||||
sdh->CTL |= SDH_CTL_CTLRST_Msk;
|
||||
while ((sdh->CTL & SDH_CTL_CTLRST_Msk) == SDH_CTL_CTLRST_Msk) { }
|
||||
|
||||
sdh->INTSTS = 0xFFFFFFFF; // clear all interrupt flag
|
||||
|
||||
sdh->INTEN |= SDH_INTEN_CDSRC_Msk;
|
||||
sdh->INTEN |= SDH_INTEN_CDIEN_Msk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function get command responding.
|
||||
* @param sdh SDH instance
|
||||
* @param cmd rt_mmcsd_cmd
|
||||
* @retval none
|
||||
*/
|
||||
static void nu_sdh_sendcmd_done(SDH_T *sdh, struct rt_mmcsd_cmd *cmd)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
uint8_t *c = (uint8_t *)&sdh->FB[0];
|
||||
int i, j, tmp[5];
|
||||
|
||||
for (i = 0, j = 0; j < 5; i += 4, j++)
|
||||
{
|
||||
tmp[j] = (*(c + i) << 24) | (*(c + i + 1) << 16) | (*(c + i + 2) << 8) | (*(c + i + 3));
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
cmd->resp[i] = ((tmp[i] & 0x00ffffff) << 8) |
|
||||
((tmp[i + 1] & 0xff000000) >> 24);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->resp[0] = (sdh->RESP0 << 8) | (sdh->RESP1 & 0xff);
|
||||
cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function wait data-sending/receiving.
|
||||
* @param sdh SDH instance
|
||||
* @param data rt_mmcsd_data
|
||||
* @retval error code
|
||||
*/
|
||||
static int nu_sdh_xfer_data(SDH_T *sdh, struct rt_mmcsd_data *data)
|
||||
{
|
||||
while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk)) { }
|
||||
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk);
|
||||
|
||||
if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
|
||||
|
||||
while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk)) { }
|
||||
|
||||
sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function send command and wait its response.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param cmd rt_mmcsd_cmd
|
||||
* @param data rt_mmcsd_data
|
||||
* @retval error code
|
||||
*/
|
||||
static int nu_sdh_sendcmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, struct rt_mmcsd_data *data)
|
||||
{
|
||||
int ret;
|
||||
nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
volatile uint32_t ctl = 0, tout = 0;
|
||||
|
||||
switch (host->io_cfg.bus_width)
|
||||
{
|
||||
case MMCSD_BUS_WIDTH_1:
|
||||
ctl &= ~SDH_CTL_DBW_Msk;
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_4:
|
||||
ctl |= SDH_CTL_DBW_Msk;
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_8:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reset sdh and its DMA engine at first. */
|
||||
sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
|
||||
while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
|
||||
sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
|
||||
sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
ctl |= SDH_CTL_R2EN_Msk;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl |= SDH_CTL_RIEN_Msk;
|
||||
}
|
||||
tout = 0xFFFF;
|
||||
}
|
||||
|
||||
/* Set SDNWR and BLK_CNT to 1 */
|
||||
ctl |= ((9 << SDH_CTL_SDNWR_Pos) | (1 << SDH_CTL_BLKCNT_Pos));
|
||||
ctl |= ((cmd->cmd_code << SDH_CTL_CMDCODE_Pos) | SDH_CTL_COEN_Msk);
|
||||
|
||||
/* Set Transfer mode regarding to data flag */
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
sdh->BLEN = data->blksize - 1;
|
||||
|
||||
if (data->blksize <= 0x200)
|
||||
{
|
||||
if (data->blks < 256)
|
||||
{
|
||||
ctl = (ctl & ~SDH_CTL_BLKCNT_Msk) | (data->blks << SDH_CTL_BLKCNT_Pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("SD Max block transfer is 255!!");
|
||||
}
|
||||
}
|
||||
|
||||
if (data->flags & DATA_DIR_READ)
|
||||
{
|
||||
tout = 0xFFFFFF;
|
||||
ctl |= SDH_CTL_DIEN_Msk; // Data-in
|
||||
sdh->DMASA = (uint32_t)data->buf; // Read from dest
|
||||
}
|
||||
else if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
ctl |= SDH_CTL_DOEN_Msk; // Data-out
|
||||
sdh->DMASA = (uint32_t)data->buf; // Write to dest
|
||||
}
|
||||
}
|
||||
else if (resp_type(cmd) == RESP_R1B)
|
||||
{
|
||||
}
|
||||
|
||||
/* Clear response-timeout flag first for safty and reset new timeout value. */
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk);
|
||||
sdh->TOUT = tout;
|
||||
|
||||
/* Set argument and start a transaction. */
|
||||
sdh->CMDARG = cmd->arg;
|
||||
sdh->CTL = ctl;
|
||||
|
||||
/* Wait a command done. */
|
||||
while ((sdh->CTL & (SDH_CTL_COEN_Msk)) == SDH_CTL_COEN_Msk) { }
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
{
|
||||
if (resp_type(cmd) == RESP_R2)
|
||||
{
|
||||
/* Wait to receive a response R2 from SD card and store the response data into DMC's Flash buffer (exclude CRC7). */
|
||||
while (sdh->CTL & SDH_CTL_R2EN_Msk)
|
||||
{
|
||||
/* When get a Response timeout, break the polling. */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
|
||||
{
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait to receive a response from SD card. */
|
||||
while ((sdh->CTL & SDH_CTL_RIEN_Msk))
|
||||
{
|
||||
/* When get a Response timeout, break the polling. */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
|
||||
{
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
/* TOFIX: ISSUE: Sometimes, SDH's RIEN is cleared automatically by controller after host sending CMD5 to SD card. */
|
||||
/* Workaround: To check previous cmd's response with CMD's. */
|
||||
if (cmd->cmd_code == 5)
|
||||
{
|
||||
if ((NuSdh->u32CmdResp0 == sdh->RESP0) && (NuSdh->u32CmdResp1 == sdh->RESP1))
|
||||
{
|
||||
LOG_E("False CMD5-RESP issue occured.\n");
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
NuSdh->u32CmdResp0 = sdh->RESP0;
|
||||
NuSdh->u32CmdResp1 = sdh->RESP1;
|
||||
}
|
||||
|
||||
/* Get response from FB or register */
|
||||
nu_sdh_sendcmd_done(sdh, cmd);
|
||||
}
|
||||
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
/* Wait data processing done */
|
||||
nu_sdh_xfer_data(sdh, data);
|
||||
|
||||
ret = SDH_GetBusStatus(sdh, 0);
|
||||
if (ret)
|
||||
{
|
||||
LOG_E("ERROR: Busy %d\n", ret);
|
||||
ret = __LINE__;
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle CRC flag */
|
||||
if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk)) // Fault
|
||||
{
|
||||
uint32_t u32INTSTS = sdh->INTSTS;
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk);
|
||||
ret = __LINE__;
|
||||
|
||||
if ((resp_type(cmd) != RESP_R3) && (u32INTSTS & SDH_INTSTS_CRC7_Msk) == 0) //CRC7, Ignore R3
|
||||
{
|
||||
LOG_E("CRC7 error! (resp_type=%d)", resp_type(cmd));
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
|
||||
if ((u32INTSTS & SDH_INTSTS_CRC16_Msk) == 0) //CRC16
|
||||
{
|
||||
LOG_E("CRC16 error! (resp_type=%d)", resp_type(cmd));
|
||||
goto exit_nu_sdh_sendcmd;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
exit_nu_sdh_sendcmd:
|
||||
|
||||
LOG_D("[%s %d] cmdid=%d error line=%d", __func__, __LINE__, cmd->cmd_code, ret);
|
||||
|
||||
cmd->resp[0] = cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
|
||||
sdh->TOUT = 0;
|
||||
SDH_Enable(sdh);
|
||||
|
||||
return -ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function send request.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param req request
|
||||
* @retval None
|
||||
*/
|
||||
static void nu_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
SDH_T *sdh;
|
||||
|
||||
RT_ASSERT(host);
|
||||
RT_ASSERT(req);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
sdh = NuSdh->base;
|
||||
|
||||
if (!SDH_GetCD(sdh)) // card is not present
|
||||
{
|
||||
LOG_E("Card is not present");
|
||||
req->cmd->err = -RT_EIO;
|
||||
goto exit_nu_sdh_request;
|
||||
}
|
||||
|
||||
if (req->cmd != RT_NULL)
|
||||
{
|
||||
struct rt_mmcsd_cmd *cmd = req->cmd;
|
||||
struct rt_mmcsd_data *data = req->data;
|
||||
|
||||
LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RESP_TYPE:%d rw:%c addr:%08x, blks:%d, blksize:%d datalen:%d",
|
||||
(host->card == RT_NULL) ? "Unknown" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
|
||||
(host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
|
||||
cmd->cmd_code,
|
||||
cmd->arg,
|
||||
resp_type(cmd),
|
||||
data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
|
||||
data ? data->buf : 0,
|
||||
data ? data->blks : 0,
|
||||
data ? data->blksize : 0,
|
||||
data ? data->blks * data->blksize : 0);
|
||||
|
||||
if (data != RT_NULL)
|
||||
{
|
||||
rt_uint32_t size;
|
||||
rt_int32_t IsNonaligned = 0;
|
||||
rt_uint32_t *org_data_buf = data->buf;
|
||||
|
||||
size = data->blksize * data->blks;
|
||||
|
||||
RT_ASSERT(org_data_buf);
|
||||
|
||||
IsNonaligned = (((rt_uint32_t)data->buf & (SDH_ALIGN_LEN - 1)) > 0) ? 1 : 0;
|
||||
if (IsNonaligned)
|
||||
{
|
||||
/* Allocate memory temp buffer on demand. */
|
||||
RT_ASSERT(size <= SDH_BUFF_SIZE);
|
||||
|
||||
if (NuSdh->cachebuf == RT_NULL)
|
||||
{
|
||||
NuSdh->cachebuf = rt_malloc_align(SDH_BUFF_SIZE, SDH_ALIGN_LEN);
|
||||
RT_ASSERT(NuSdh->cachebuf);
|
||||
}
|
||||
|
||||
data->buf = (rt_uint32_t *)NuSdh->cachebuf;
|
||||
if (data->flags & DATA_DIR_WRITE)
|
||||
{
|
||||
LOG_D("Un-aligned, prepare into cache buf(%d)", size);
|
||||
rt_memcpy(data->buf, org_data_buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
cmd->err = nu_sdh_sendcmd(host, cmd, data);
|
||||
|
||||
if (!cmd->err && IsNonaligned)
|
||||
{
|
||||
if (data->flags & DATA_DIR_READ)
|
||||
{
|
||||
LOG_D("Un-aligned, restore from cache buf(%d)", size);
|
||||
rt_memcpy(org_data_buf, data->buf, size);
|
||||
}
|
||||
}
|
||||
data->buf = org_data_buf;
|
||||
|
||||
LOG_HEX("data.dest", 16, (void *)data->buf, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->err = nu_sdh_sendcmd(host, cmd, NULL);
|
||||
}
|
||||
|
||||
if (resp_type(cmd) != RESP_NONE)
|
||||
LOG_HEX("cmd->resp", 16, (void *)&cmd->resp[0], 16);
|
||||
}
|
||||
|
||||
if (req->stop != RT_NULL)
|
||||
{
|
||||
struct rt_mmcsd_cmd *stop = req->stop;
|
||||
|
||||
stop->err = nu_sdh_sendcmd(host, stop, NULL);
|
||||
|
||||
if (resp_type(stop) != RESP_NONE)
|
||||
LOG_HEX("stop->resp", 16, (void *)&stop->resp[0], 16);
|
||||
|
||||
}
|
||||
|
||||
exit_nu_sdh_request:
|
||||
|
||||
mmcsd_req_complete(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function config.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param io_cfg rt_mmcsd_io_cfg
|
||||
* @retval None
|
||||
*/
|
||||
static void nu_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
rt_uint32_t clk;
|
||||
SDH_T *sdh;
|
||||
|
||||
RT_ASSERT(host);
|
||||
RT_ASSERT(io_cfg);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
sdh = NuSdh->base;
|
||||
clk = io_cfg->clock;
|
||||
|
||||
LOG_D("[%s]clk:%d width(%d):%s%s%s power:%s%s%s",
|
||||
NuSdh->name,
|
||||
clk,
|
||||
io_cfg->bus_width,
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_8 ? "8" : "",
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_4 ? "4" : "",
|
||||
(io_cfg->bus_width) == MMCSD_BUS_WIDTH_1 ? "1" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
|
||||
io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
|
||||
|
||||
/* Clock */
|
||||
if (clk > host->freq_max)
|
||||
clk = host->freq_max;
|
||||
|
||||
if (clk < host->freq_min)
|
||||
clk = host->freq_min;
|
||||
|
||||
LOG_D("[%s] ExceptedFreq: %d kHz", NuSdh->name, clk / 1000);
|
||||
if (NuSdh->u32CurClk != (clk / 1000))
|
||||
{
|
||||
SDH_SetClock(sdh, clk / 1000);
|
||||
NuSdh->u32CurClk = (clk / 1000);
|
||||
}
|
||||
|
||||
switch (io_cfg->power_mode)
|
||||
{
|
||||
case MMCSD_POWER_UP:
|
||||
if (clk <= 400000)
|
||||
{
|
||||
/* power ON 74 clock */
|
||||
sdh->CTL |= SDH_CTL_CLK74OEN_Msk;
|
||||
|
||||
while ((sdh->CTL & SDH_CTL_CLK74OEN_Msk) == SDH_CTL_CLK74OEN_Msk)
|
||||
{
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MMCSD_POWER_ON:
|
||||
break;
|
||||
|
||||
case MMCSD_POWER_OFF:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bus width */
|
||||
switch ((io_cfg->bus_width))
|
||||
{
|
||||
case MMCSD_BUS_WIDTH_1:
|
||||
SDH_SetBusWidth(sdh, 1);
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_4:
|
||||
SDH_SetBusWidth(sdh, 4);
|
||||
break;
|
||||
|
||||
case MMCSD_BUS_WIDTH_8:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function detect sdcard.
|
||||
* @param host rt_mmcsd_host
|
||||
* @retval card detection status
|
||||
*/
|
||||
static rt_int32_t nu_sdh_card_detect(struct rt_mmcsd_host *host)
|
||||
{
|
||||
nu_sdh_t NuSdh;
|
||||
RT_ASSERT(host);
|
||||
|
||||
NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
LOG_D("try to detect device");
|
||||
return SDH_GetCD(sdh);
|
||||
}
|
||||
|
||||
static void nu_sdh_isr(nu_sdh_t NuSdh)
|
||||
{
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
uint32_t isr = sdh->INTSTS;
|
||||
|
||||
/* card detected */
|
||||
if (isr & SDH_INTSTS_CDIF_Msk)
|
||||
{
|
||||
rt_tick_t cur_tick = rt_tick_get();
|
||||
rt_tick_t diff_tick;
|
||||
|
||||
/* ready to change */
|
||||
if (cur_tick >= NuSdh->LastNotice)
|
||||
diff_tick = (cur_tick - NuSdh->LastNotice);
|
||||
else
|
||||
diff_tick = ((rt_tick_t) -1) - NuSdh->LastNotice + cur_tick;
|
||||
|
||||
if (!NuSdh->LastNotice || (diff_tick > (RT_TICK_PER_SECOND / 5))) // Debounce 200ms
|
||||
{
|
||||
NuSdh->LastNotice = cur_tick;
|
||||
mmcsd_change(NuSdh->host);
|
||||
}
|
||||
|
||||
/* Clear CDIF interrupt flag */
|
||||
SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BSP_USING_SDH0)
|
||||
void SDH0_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
nu_sdh_isr(&nu_sdh_arr[SDH0_IDX]);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BSP_USING_SDH1)
|
||||
void SDH1_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
nu_sdh_isr(&nu_sdh_arr[SDH1_IDX]);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function update sdh interrupt.
|
||||
* @param host rt_mmcsd_host
|
||||
* @param enable
|
||||
* @retval None
|
||||
*/
|
||||
void nu_sdh_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
|
||||
{
|
||||
nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
|
||||
SDH_T *sdh = NuSdh->base;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
LOG_D("Enable %s irq", NuSdh->name);
|
||||
SDH_ENABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("Disable %s irq", NuSdh->name);
|
||||
SDH_DISABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rt_mmcsd_host_ops ops =
|
||||
{
|
||||
nu_sdh_request,
|
||||
nu_sdh_iocfg,
|
||||
nu_sdh_card_detect,
|
||||
nu_sdh_irq_update,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This function create mmcsd host.
|
||||
* @param sdh nu_sdh_t
|
||||
* @retval nuvton
|
||||
*/
|
||||
void nu_sdh_host_init(nu_sdh_t sdh)
|
||||
{
|
||||
struct rt_mmcsd_host *host = mmcsd_alloc_host();
|
||||
RT_ASSERT(host);
|
||||
|
||||
/* set host default attributes */
|
||||
host->ops = &ops;
|
||||
host->freq_min = 300 * 1000;
|
||||
host->freq_max = 48 * 1000 * 1000;
|
||||
host->valid_ocr = VDD_26_27 | VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;
|
||||
|
||||
host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
|
||||
|
||||
host->max_seg_size = SDH_BUFF_SIZE;
|
||||
host->max_dma_segs = 1;
|
||||
host->max_blk_size = SDH_BLOCK_SIZE;
|
||||
host->max_blk_count = (SDH_BUFF_SIZE / SDH_BLOCK_SIZE);
|
||||
|
||||
/* link up host and sdio */
|
||||
host->private_data = sdh;
|
||||
sdh->host = host;
|
||||
|
||||
/* Enable DMA engine at first. */
|
||||
SDH_Enable(sdh->base);
|
||||
|
||||
/* Install ISR. */
|
||||
NVIC_EnableIRQ(sdh->irqn);
|
||||
|
||||
/* ready to change */
|
||||
//mmcsd_change(host);
|
||||
}
|
||||
|
||||
static int rt_hw_sdh_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
CLK_EnableModuleClock(nu_sdh_arr[i].modid);
|
||||
SYS_ResetModule(nu_sdh_arr[i].rstidx);
|
||||
|
||||
nu_sdh_host_init(&nu_sdh_arr[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(rt_hw_sdh_init);
|
||||
|
||||
void nu_sd_attach(void)
|
||||
{
|
||||
int i;
|
||||
/* ready to change */
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
if (nu_sdh_arr[i].host)
|
||||
mmcsd_change(nu_sdh_arr[i].host);
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(nu_sd_attach, attach card);
|
||||
|
||||
void nu_sd_regdump(void)
|
||||
{
|
||||
int i;
|
||||
for (i = (SDH_START + 1); i < SDH_CNT; i++)
|
||||
{
|
||||
if (nu_sdh_arr[i].host)
|
||||
LOG_HEX("sdh_reg", 16, (void *)nu_sdh_arr[i].base, sizeof(SDH_T));
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(nu_sd_regdump, dump sdh registers);
|
||||
|
||||
#endif
|
19
bsp/nuvoton/libraries/nu_packages/FSA506/SConscript
Normal file
19
bsp/nuvoton/libraries/nu_packages/FSA506/SConscript
Normal file
@ -0,0 +1,19 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
|
||||
src = Split("""
|
||||
lcd_fsa506.c
|
||||
""")
|
||||
CPPPATH = [cwd]
|
||||
|
||||
if GetDepend('NU_PKG_USING_FSA506_EBI'):
|
||||
src += Glob('fsa506_ebi.c')
|
||||
|
||||
if GetDepend('NU_PKG_USING_FSA506'):
|
||||
group = DefineGroup('nu_pkgs_fsa506', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
124
bsp/nuvoton/libraries/nu_packages/FSA506/fsa506_ebi.c
Normal file
124
bsp/nuvoton/libraries/nu_packages/FSA506/fsa506_ebi.c
Normal file
@ -0,0 +1,124 @@
|
||||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-2-23 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(NU_PKG_USING_FSA506_EBI)
|
||||
|
||||
#include <lcd_fsa506.h>
|
||||
#include "drv_pdma.h"
|
||||
|
||||
#define FSA506_ADDR_CMD 0x0
|
||||
#define FSA506_ADDR_DATA 0x0
|
||||
|
||||
#if defined(FSA506_EBI_16BIT)
|
||||
#define fsa506_reg_write(RegAddr) (*((volatile uint16_t *)(s_u32AccessBase+(FSA506_ADDR_CMD))) = (RegAddr))
|
||||
#define fsa506_read_data() (*((volatile uint16_t *)(s_u32AccessBase+(FSA506_ADDR_DATA))))
|
||||
#define fsa506_write_data(Data) (*((volatile uint16_t *)(s_u32AccessBase+(FSA506_ADDR_DATA))) = (Data))
|
||||
#else
|
||||
#define fsa506_reg_write(RegAddr) (*((volatile uint8_t *)(s_u32AccessBase+(FSA506_ADDR_CMD))) = (RegAddr))
|
||||
#define fsa506_read_data() (*((volatile uint8_t *)(s_u32AccessBase+(FSA506_ADDR_DATA))))
|
||||
#define fsa506_write_data(Data) (*((volatile uint8_t *)(s_u32AccessBase+(FSA506_ADDR_DATA))) = (Data))
|
||||
#endif
|
||||
|
||||
static rt_uint32_t s_u32AccessBase = 0;
|
||||
|
||||
void fsa506_send_cmd(rt_uint8_t cmd)
|
||||
{
|
||||
CLR_RS;
|
||||
fsa506_reg_write(cmd);
|
||||
SET_RS;
|
||||
}
|
||||
|
||||
void fsa506_send_cmd_parameter(rt_uint8_t data)
|
||||
{
|
||||
fsa506_write_data(data);
|
||||
}
|
||||
|
||||
void fsa506_send_cmd_done(void)
|
||||
{
|
||||
CLR_RS;
|
||||
fsa506_reg_write(0x80);
|
||||
SET_RS;
|
||||
}
|
||||
|
||||
void fsa506_write_reg(rt_uint8_t cmd, rt_uint8_t data)
|
||||
{
|
||||
fsa506_send_cmd(cmd);
|
||||
fsa506_send_cmd_parameter(data);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
|
||||
void fsa506_send_pixel_data(rt_uint16_t color)
|
||||
{
|
||||
#if 1
|
||||
// for LV_COLOR_16_SWAP
|
||||
//BGR, B is high byte
|
||||
fsa506_write_data(color & 0xffu);
|
||||
fsa506_write_data((color >> 8) & 0xffu);
|
||||
#else
|
||||
//RGB, R is high byte
|
||||
fsa506_write_data((color >> 8) & 0xffu);
|
||||
fsa506_write_data(color & 0xffu);
|
||||
#endif
|
||||
}
|
||||
|
||||
void fsa506_send_pixels(rt_uint16_t *pixels, int len)
|
||||
{
|
||||
int count = len / sizeof(rt_uint16_t);
|
||||
if (count < 512)
|
||||
{
|
||||
// CPU feed
|
||||
int i = 0;
|
||||
while (i < count)
|
||||
{
|
||||
fsa506_send_pixel_data(pixels[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// PDMA-M2M feed
|
||||
// Must enable LV_COLOR_16_SWAP definition in LVGL.
|
||||
nu_pdma_mempush((void *)(s_u32AccessBase + (FSA506_ADDR_DATA)), (void *)pixels, 8, len);
|
||||
}
|
||||
}
|
||||
|
||||
void fsa506_set_column(uint16_t StartCol, uint16_t EndCol)
|
||||
{
|
||||
fsa506_write_reg(0x0, (StartCol >> 8) & 0xFF);
|
||||
fsa506_write_reg(0x1, StartCol & 0xFF);
|
||||
fsa506_write_reg(0x2, (EndCol >> 8) & 0xFF);
|
||||
fsa506_write_reg(0x3, EndCol & 0xFF);
|
||||
}
|
||||
|
||||
void fsa506_set_page(uint16_t StartPage, uint16_t EndPage)
|
||||
{
|
||||
fsa506_write_reg(0x4, (StartPage >> 8) & 0xFF);
|
||||
fsa506_write_reg(0x5, StartPage & 0xFF);
|
||||
fsa506_write_reg(0x6, (EndPage >> 8) & 0xFF);
|
||||
fsa506_write_reg(0x7, EndPage & 0xFF);
|
||||
}
|
||||
|
||||
void fsa506_lcd_get_pixel(char *color, int x, int y)
|
||||
{
|
||||
//Not supported.
|
||||
return;
|
||||
}
|
||||
|
||||
rt_err_t rt_hw_lcd_fsa506_ebi_init(rt_uint32_t fsa506_base)
|
||||
{
|
||||
s_u32AccessBase = fsa506_base;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#endif /* if defined(NU_PKG_USING_FSA506_EBI) */
|
392
bsp/nuvoton/libraries/nu_packages/FSA506/lcd_fsa506.c
Normal file
392
bsp/nuvoton/libraries/nu_packages/FSA506/lcd_fsa506.c
Normal file
@ -0,0 +1,392 @@
|
||||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-2-23 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(NU_PKG_USING_FSA506)
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <lcd_fsa506.h>
|
||||
|
||||
#if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
|
||||
#if !defined(NU_PKG_FSA506_LINE_BUFFER_NUMBER)
|
||||
#define NU_PKG_FSA506_LINE_BUFFER_NUMBER YSIZE_PHYS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define fsa506_delay_ms(ms) rt_thread_mdelay(ms)
|
||||
static void fsa506_fillscreen(rt_uint16_t color);
|
||||
|
||||
static struct rt_device_graphic_info g_FSA506Info =
|
||||
{
|
||||
.bits_per_pixel = 16,
|
||||
.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565,
|
||||
.framebuffer = RT_NULL,
|
||||
.width = XSIZE_PHYS,
|
||||
.pitch = XSIZE_PHYS * 2,
|
||||
.height = YSIZE_PHYS
|
||||
};
|
||||
|
||||
static rt_err_t fsa506_pin_init(void)
|
||||
{
|
||||
rt_pin_mode(BOARD_USING_FSA506_PIN_DC, PIN_MODE_OUTPUT);
|
||||
rt_pin_mode(BOARD_USING_FSA506_PIN_RESET, PIN_MODE_OUTPUT);
|
||||
rt_pin_mode(BOARD_USING_FSA506_PIN_BACKLIGHT, PIN_MODE_OUTPUT);
|
||||
rt_pin_mode(BOARD_USING_FSA506_PIN_DISPLAY, PIN_MODE_OUTPUT);
|
||||
|
||||
CLR_RS;
|
||||
CLR_RST;
|
||||
SET_BACKLIGHT_OFF;
|
||||
SET_DISP_OFF;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t fsa506_lcd_init(rt_device_t dev)
|
||||
{
|
||||
/* Hardware reset */
|
||||
CLR_RST;
|
||||
fsa506_delay_ms(100); // Delay 100ms
|
||||
|
||||
SET_RST;
|
||||
fsa506_delay_ms(100); // Delay 100ms
|
||||
|
||||
fsa506_write_reg(0x40, 0x12); // Underspece
|
||||
fsa506_write_reg(0x41, 0x05); // Underspece
|
||||
fsa506_write_reg(0x42, 0x06); // Underspece
|
||||
|
||||
/* Set the panel X size */
|
||||
fsa506_write_reg(0x08, (uint8_t)(XSIZE_PHYS >> 8)); //Set the panel X size H[1.0]
|
||||
fsa506_write_reg(0x09, (uint8_t)(XSIZE_PHYS)); //Set the panel X size L[7:0]
|
||||
|
||||
/* Memory write start address */
|
||||
fsa506_write_reg(0x0a, 0x00); //[17:16] bits of memory write start address
|
||||
fsa506_write_reg(0x0b, 0x00); //[15:8] bits of memory write start address
|
||||
fsa506_write_reg(0x0c, 0x00); //[7:0] bits of memory write start address
|
||||
|
||||
/* Clock & format */
|
||||
fsa506_write_reg(0x10, 0x0D); //[0-1] : 20MHz, [2]: Parallel panel, [3]: Normal operation
|
||||
fsa506_write_reg(0x11, 0x05); //[3-5]: RGB, [0-2]BGR
|
||||
|
||||
/* For TFT output timing adjust */
|
||||
fsa506_write_reg(0x12, 0x00); //Hsync start position H-Byte
|
||||
fsa506_write_reg(0x13, 0x00); //Hsync start position L-Byte
|
||||
fsa506_write_reg(0x14, (uint8_t)(41 >> 8)); //Hsync pulse width H-Byte
|
||||
fsa506_write_reg(0x15, (uint8_t)(41)); //Hsync pulse width L-Byte
|
||||
|
||||
fsa506_write_reg(0x16, (uint8_t)(43 >> 8)); //DE pulse start position H-Byte
|
||||
fsa506_write_reg(0x17, (uint8_t)(43)); //DE pulse start position L-Byte
|
||||
fsa506_write_reg(0x18, (uint8_t)(XSIZE_PHYS >> 8)); //DE pulse width H-Byte
|
||||
fsa506_write_reg(0x19, (uint8_t)(XSIZE_PHYS)); //DE pulse width L-Byte
|
||||
fsa506_write_reg(0x1a, (uint8_t)(525 >> 8)); //Hsync total clocks H-Byte
|
||||
fsa506_write_reg(0x1b, (uint8_t)(525)); //Hsync total clocks H-Byte
|
||||
fsa506_write_reg(0x1c, 0x00); //Vsync start position H-Byte
|
||||
fsa506_write_reg(0x1d, 0x00); //Vsync start position L-Byte
|
||||
fsa506_write_reg(0x1e, (uint8_t)(10 >> 8)); //Vsync pulse width H-Byte
|
||||
fsa506_write_reg(0x1f, (uint8_t)(10)); //Vsync pulse width L-Byte
|
||||
fsa506_write_reg(0x20, (uint8_t)(12 >> 8)); //Vertical DE pulse start position H-Byte
|
||||
fsa506_write_reg(0x21, (uint8_t)(12)); //Vertical DE pulse start position L-Byte
|
||||
fsa506_write_reg(0x22, (uint8_t)(YSIZE_PHYS >> 8)); //Vertical Active width H-Byte
|
||||
fsa506_write_reg(0x23, (uint8_t)(YSIZE_PHYS)); //Vertical Active width H-Byte
|
||||
fsa506_write_reg(0x24, (uint8_t)(286 >> 8)); //Vertical total width H-Byte
|
||||
fsa506_write_reg(0x25, (uint8_t)(286)); //Vertical total width L-Byte
|
||||
|
||||
fsa506_write_reg(0x26, 0x00); //Memory read start address
|
||||
fsa506_write_reg(0x27, 0x00); //Memory read start address
|
||||
fsa506_write_reg(0x28, 0x00); //Memory read start address
|
||||
fsa506_write_reg(0x29, 0x01); //[0] Load output timing related setting (H sync., V sync. and DE) to take effect
|
||||
|
||||
//[7:4] Reserved
|
||||
//[3] Output pin X_DCON level control
|
||||
//[2] Output clock inversion 0: Normal 1: Inverse
|
||||
//[1:0] Image rotate
|
||||
// 00: 0? 01: 90? 10: 270?11: 180?
|
||||
fsa506_write_reg(0x2d, (1 << 2) | 0x08);
|
||||
|
||||
/* Set the Horizontal offset */
|
||||
fsa506_write_reg(0x30, 0x00); //_H byte H-Offset[3:0]
|
||||
fsa506_write_reg(0x31, 0x00); //_L byte H-Offset[7:0]
|
||||
fsa506_write_reg(0x32, 0x00); //_H byte V-Offset[3:0]
|
||||
fsa506_write_reg(0x33, 0x00); //_L byte V-Offset[7:0]
|
||||
fsa506_write_reg(0x34, (uint8_t)(XSIZE_PHYS >> 8)); //H byte H-def[3:0]
|
||||
fsa506_write_reg(0x35, (uint8_t)(XSIZE_PHYS)); //_L byte H-def[7:0]
|
||||
fsa506_write_reg(0x36, (uint8_t)((2 * YSIZE_PHYS) >> 8)); //[3:0] MSB of image vertical physical resolution in memory
|
||||
fsa506_write_reg(0x37, (uint8_t)(2 * YSIZE_PHYS)); //[7:0] LSB of image vertical physical resolution in memory
|
||||
|
||||
fsa506_fillscreen(0);
|
||||
|
||||
SET_DISP_ON;
|
||||
|
||||
SET_BACKLIGHT_ON;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
|
||||
static void fsa506_fillrect(uint16_t *pixels, struct rt_device_rect_info *pRectInfo)
|
||||
{
|
||||
fsa506_set_column(pRectInfo->x, pRectInfo->x + pRectInfo->width - 1);
|
||||
fsa506_set_page(pRectInfo->y, pRectInfo->y + pRectInfo->height - 1);
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
fsa506_send_pixels(pixels, pRectInfo->height * pRectInfo->width * 2);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fsa506_fillscreen(rt_uint16_t color)
|
||||
{
|
||||
#if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
|
||||
struct rt_device_rect_info rectinfo;
|
||||
int filled_line_num = 0;
|
||||
|
||||
while (filled_line_num < YSIZE_PHYS)
|
||||
{
|
||||
int pixel_count;
|
||||
rectinfo.x = 0;
|
||||
rectinfo.y = filled_line_num;
|
||||
rectinfo.width = XSIZE_PHYS;
|
||||
rectinfo.height = (NU_PKG_FSA506_LINE_BUFFER_NUMBER < YSIZE_PHYS) ? NU_PKG_FSA506_LINE_BUFFER_NUMBER : YSIZE_PHYS;
|
||||
|
||||
pixel_count = XSIZE_PHYS * NU_PKG_FSA506_LINE_BUFFER_NUMBER;
|
||||
rt_uint16_t *pu16ShadowBuf = (rt_uint16_t *)g_FSA506Info.framebuffer;
|
||||
|
||||
while (pixel_count > 0)
|
||||
{
|
||||
*pu16ShadowBuf++ = color;
|
||||
pixel_count--;
|
||||
}
|
||||
fsa506_fillrect((uint16_t *)g_FSA506Info.framebuffer, &rectinfo);
|
||||
filled_line_num += NU_PKG_FSA506_LINE_BUFFER_NUMBER;
|
||||
}
|
||||
#else
|
||||
fsa506_set_column(0, (XSIZE_PHYS - 1));
|
||||
fsa506_set_page(0, (YSIZE_PHYS - 1));
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
for (int i = 0; i < (XSIZE_PHYS * YSIZE_PHYS); i++)
|
||||
fsa506_send_pixel_data(color);
|
||||
fsa506_send_cmd_done();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fsa506_lcd_set_pixel(const char *color, int x, int y)
|
||||
{
|
||||
fsa506_set_column(x, x);
|
||||
fsa506_set_page(y, y);
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
fsa506_send_pixel_data(*(uint16_t *)color);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
|
||||
static void fsa506_lcd_draw_hline(const char *pixel, int x1, int x2, int y)
|
||||
{
|
||||
fsa506_set_column(x1, x2);
|
||||
fsa506_set_page(y, y);
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
for (; x1 < x2; x1++)
|
||||
fsa506_send_pixel_data(*(uint16_t *)pixel);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
|
||||
static void fsa506_lcd_draw_vline(const char *pixel, int x, int y1, int y2)
|
||||
{
|
||||
fsa506_set_column(x, x);
|
||||
fsa506_set_page(y1, y2);
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
for (; y1 < y2; y1++)
|
||||
fsa506_send_pixel_data(*(uint16_t *)pixel);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
|
||||
static void fsa506_lcd_blit_line(const char *pixels, int x, int y, rt_size_t size)
|
||||
{
|
||||
rt_uint16_t *ptr = (rt_uint16_t *)pixels;
|
||||
|
||||
fsa506_set_column(x, x + size);
|
||||
fsa506_set_page(y, y);
|
||||
|
||||
fsa506_send_cmd(0xC1);
|
||||
while (size--)
|
||||
fsa506_send_pixel_data(*ptr++);
|
||||
fsa506_send_cmd_done();
|
||||
}
|
||||
|
||||
static rt_err_t fsa506_lcd_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t fsa506_lcd_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t fsa506_lcd_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case RTGRAPHIC_CTRL_GET_INFO:
|
||||
{
|
||||
struct rt_device_graphic_info *info;
|
||||
|
||||
info = (struct rt_device_graphic_info *) args;
|
||||
RT_ASSERT(info != RT_NULL);
|
||||
rt_memcpy(args, (void *)&g_FSA506Info, sizeof(struct rt_device_graphic_info));
|
||||
}
|
||||
break;
|
||||
|
||||
case RTGRAPHIC_CTRL_RECT_UPDATE:
|
||||
{
|
||||
#if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
|
||||
struct rt_device_rect_info *psRectInfo = (struct rt_device_rect_info *)args;
|
||||
rt_uint16_t *pixels = (rt_uint16_t *)g_FSA506Info.framebuffer;
|
||||
RT_ASSERT(args);
|
||||
|
||||
fsa506_fillrect(pixels, psRectInfo);
|
||||
#else
|
||||
/* nothong to be done */
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_device lcd_device;
|
||||
static struct rt_device_graphic_ops fsa506_ops =
|
||||
{
|
||||
fsa506_lcd_set_pixel,
|
||||
fsa506_lcd_get_pixel,
|
||||
fsa506_lcd_draw_hline,
|
||||
fsa506_lcd_draw_vline,
|
||||
fsa506_lcd_blit_line
|
||||
};
|
||||
|
||||
int rt_hw_lcd_fsa506_init(void)
|
||||
{
|
||||
fsa506_pin_init();
|
||||
|
||||
/* register lcd device */
|
||||
lcd_device.type = RT_Device_Class_Graphic;
|
||||
lcd_device.init = fsa506_lcd_init;
|
||||
lcd_device.open = fsa506_lcd_open;
|
||||
lcd_device.close = fsa506_lcd_close;
|
||||
lcd_device.control = fsa506_lcd_control;
|
||||
lcd_device.read = RT_NULL;
|
||||
lcd_device.write = RT_NULL;
|
||||
|
||||
lcd_device.user_data = &fsa506_ops;
|
||||
|
||||
#if defined(NU_PKG_FSA506_WITH_OFFSCREEN_FRAMEBUFFER)
|
||||
g_FSA506Info.framebuffer = rt_malloc_align((g_FSA506Info.pitch * NU_PKG_FSA506_LINE_BUFFER_NUMBER) + 32, 32);
|
||||
RT_ASSERT(g_FSA506Info.framebuffer != RT_NULL);
|
||||
g_FSA506Info.smem_len = g_FSA506Info.pitch * NU_PKG_FSA506_LINE_BUFFER_NUMBER;
|
||||
#endif
|
||||
|
||||
/* register graphic device driver */
|
||||
rt_device_register(&lcd_device, "lcd", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#define LINE_LEN 32
|
||||
static void lcd_test(int argc, char *argv[])
|
||||
{
|
||||
uint16_t pixels[LINE_LEN];
|
||||
uint16_t color;
|
||||
int x, y, i;
|
||||
x = y = 100;
|
||||
|
||||
fsa506_lcd_init(NULL);
|
||||
|
||||
color = 0x0; //Black, RGB
|
||||
rt_kprintf("Brush 0x%X on screen.\n", color);
|
||||
fsa506_fillscreen(color);
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
color = 0xffff; //White, RGB
|
||||
rt_kprintf("Brush 0x%X on screen.\n", color);
|
||||
fsa506_fillscreen(color);
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
color = 0x1f; //Blue, RGB
|
||||
rt_kprintf("Brush 0x%X on screen.\n", color);
|
||||
fsa506_fillscreen(color);
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
color = 0x07e0; //Green, RGB
|
||||
rt_kprintf("Brush 0x%X on screen.\n", color);
|
||||
fsa506_fillscreen(color);
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
color = 0xf800; //Red, RGB
|
||||
rt_kprintf("Brush 0x%X on screen.\n", color);
|
||||
fsa506_fillscreen(color);
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
color = 0xffff; //White, RGB
|
||||
rt_kprintf("lcd draw hline, pixel: 0x%X, x1: %d, x2: %d, y: %d\n", color, x, x + 20, y);
|
||||
fsa506_lcd_draw_hline((const char *)&color, x, x + 20, y);
|
||||
|
||||
color = 0xffff; //White, RGB
|
||||
rt_kprintf("lcd draw vline, pixel: 0x%X, x: %d, y: %d\n", color, y, y + 20);
|
||||
fsa506_lcd_draw_vline((const char *)&color, x, y, y + 20);
|
||||
|
||||
for (i = 0; i < LINE_LEN; i++)
|
||||
pixels[i] = 20 + i * 5;
|
||||
|
||||
x = y = 50;
|
||||
rt_kprintf("lcd blit line, start: x: %d, y: %d\n", x, y);
|
||||
fsa506_lcd_blit_line((const char *)&pixels[0], x, y, LINE_LEN);
|
||||
|
||||
x = y = 200;
|
||||
color = 0x07E0; //Green, RGB
|
||||
rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
fsa506_lcd_set_pixel((const char *)&color, x, y);
|
||||
color = 0x0;
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
x = y = 200;
|
||||
color = 0x1f; //Blue, RGB
|
||||
rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
fsa506_lcd_set_pixel((const char *)&color, x, y);
|
||||
color = 0x0;
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
|
||||
x = y = 200;
|
||||
color = 0xf800; //Red, RGB
|
||||
rt_kprintf("lcd set pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
fsa506_lcd_set_pixel((const char *)&color, x, y);
|
||||
color = 0x0;
|
||||
fsa506_lcd_get_pixel((char *)&color, x, y);
|
||||
rt_kprintf("lcd get pixel, pixel: 0x%X, x: %d, y: %d\n", color, x, y);
|
||||
}
|
||||
MSH_CMD_EXPORT(lcd_test, test lcd display);
|
||||
#endif
|
||||
|
||||
#endif /* if defined(NU_PKG_USING_FSA506) */
|
57
bsp/nuvoton/libraries/nu_packages/FSA506/lcd_fsa506.h
Normal file
57
bsp/nuvoton/libraries/nu_packages/FSA506/lcd_fsa506.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**************************************************************************//**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-2-23 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __LCD_FSA506_H__
|
||||
#define __LCD_FSA506_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define SET_RS rt_pin_write(BOARD_USING_FSA506_PIN_DC, 1)
|
||||
#define CLR_RS rt_pin_write(BOARD_USING_FSA506_PIN_DC, 0)
|
||||
|
||||
#define SET_RST rt_pin_write(BOARD_USING_FSA506_PIN_RESET, 1)
|
||||
#define CLR_RST rt_pin_write(BOARD_USING_FSA506_PIN_RESET, 0)
|
||||
|
||||
#define SET_BACKLIGHT_ON rt_pin_write(BOARD_USING_FSA506_PIN_BACKLIGHT, 1)
|
||||
#define SET_BACKLIGHT_OFF rt_pin_write(BOARD_USING_FSA506_PIN_BACKLIGHT, 0)
|
||||
|
||||
#define SET_DISP_ON rt_pin_write(BOARD_USING_FSA506_PIN_DISPLAY, 1)
|
||||
#define SET_DISP_OFF rt_pin_write(BOARD_USING_FSA506_PIN_DISPLAY, 0)
|
||||
|
||||
//
|
||||
// Physical display size
|
||||
//
|
||||
//#if defined(NU_PKG_FSA506_HORIZONTAL)
|
||||
#define XSIZE_PHYS 480
|
||||
#define YSIZE_PHYS 272
|
||||
//#else
|
||||
// #define XSIZE_PHYS 272
|
||||
// #define YSIZE_PHYS 480
|
||||
//#endif
|
||||
|
||||
int rt_hw_lcd_fsa506_init(void);
|
||||
void fsa506_send_cmd(rt_uint8_t cmd);
|
||||
void fsa506_send_cmd_parameter(rt_uint8_t data);
|
||||
void fsa506_send_cmd_done(void);
|
||||
void fsa506_write_reg(rt_uint8_t cmd, rt_uint8_t data);
|
||||
void fsa506_set_column(rt_uint16_t StartCol, rt_uint16_t EndCol);
|
||||
void fsa506_set_page(rt_uint16_t StartPage, rt_uint16_t EndPage);
|
||||
void fsa506_send_pixel_data(rt_uint16_t color);
|
||||
void fsa506_lcd_get_pixel(char *color, int x, int y);
|
||||
void fsa506_send_pixels(rt_uint16_t *pixels, int len);
|
||||
|
||||
#if defined(NU_PKG_USING_FSA506_EBI)
|
||||
rt_err_t rt_hw_lcd_fsa506_ebi_init(rt_uint32_t ebi_base);
|
||||
#endif
|
||||
|
||||
#endif /* __LCD_FSA506_H__ */
|
342
bsp/nuvoton/libraries/nu_packages/TPC/ft5446.c
Normal file
342
bsp/nuvoton/libraries/nu_packages/TPC/ft5446.c
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-04-11 Wayne First version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DBG_TAG "ft5446"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "ft5446.h"
|
||||
|
||||
static struct rt_i2c_client ft5446_client;
|
||||
static void ft5446_touch_up(void *buf, rt_int8_t id);
|
||||
static rt_err_t ft5446_write_reg(struct rt_i2c_client *dev, rt_uint8_t reg, rt_uint8_t value)
|
||||
{
|
||||
struct rt_i2c_msg msgs;
|
||||
rt_uint8_t buf[2];
|
||||
|
||||
buf[0] = reg;
|
||||
buf[1] = value;
|
||||
|
||||
msgs.addr = dev->client_addr;
|
||||
msgs.flags = RT_I2C_WR;
|
||||
msgs.buf = buf;
|
||||
msgs.len = sizeof(buf);
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t ft5446_read_reg(struct rt_i2c_client *dev, rt_uint8_t reg, rt_uint8_t *data, rt_uint8_t len)
|
||||
{
|
||||
struct rt_i2c_msg msgs[2];
|
||||
|
||||
msgs[0].addr = dev->client_addr;
|
||||
msgs[0].flags = RT_I2C_WR;
|
||||
msgs[0].buf = ®
|
||||
msgs[0].len = FT_REGITER_LEN;
|
||||
|
||||
msgs[1].addr = dev->client_addr;
|
||||
msgs[1].flags = RT_I2C_RD;
|
||||
msgs[1].buf = data;
|
||||
msgs[1].len = len;
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, msgs, 2) == 2)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_int16_t pre_x[FT_MAX_TOUCH];
|
||||
static rt_int16_t pre_y[FT_MAX_TOUCH];
|
||||
static rt_int16_t pre_w[FT_MAX_TOUCH];
|
||||
static rt_uint8_t s_tp_dowm[FT_MAX_TOUCH];
|
||||
|
||||
static void ft5446_touch_up(void *buf, rt_int8_t id)
|
||||
{
|
||||
struct rt_touch_data *read_data = (struct rt_touch_data *)buf;
|
||||
|
||||
if (s_tp_dowm[id] == 1)
|
||||
{
|
||||
s_tp_dowm[id] = 0;
|
||||
read_data[id].event = RT_TOUCH_EVENT_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_NONE;
|
||||
}
|
||||
|
||||
read_data[id].timestamp = rt_touch_get_ts();
|
||||
read_data[id].width = pre_w[id];
|
||||
read_data[id].x_coordinate = pre_x[id];
|
||||
read_data[id].y_coordinate = pre_y[id];
|
||||
read_data[id].track_id = id;
|
||||
|
||||
pre_x[id] = -1; /* last point is none */
|
||||
pre_y[id] = -1;
|
||||
pre_w[id] = -1;
|
||||
|
||||
//LOG_I("%s (%d)\n", __func__, id);
|
||||
}
|
||||
|
||||
static void ft5446_touch_down(void *buf, rt_int8_t id, rt_int16_t x, rt_int16_t y, rt_int16_t w)
|
||||
{
|
||||
struct rt_touch_data *read_data = (struct rt_touch_data *)buf;
|
||||
|
||||
if (s_tp_dowm[id] == 1)
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_MOVE;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_DOWN;
|
||||
s_tp_dowm[id] = 1;
|
||||
}
|
||||
|
||||
read_data[id].timestamp = rt_touch_get_ts();
|
||||
read_data[id].width = w;
|
||||
read_data[id].x_coordinate = x;
|
||||
read_data[id].y_coordinate = y;
|
||||
read_data[id].track_id = id;
|
||||
|
||||
pre_x[id] = x; /* save last point */
|
||||
pre_y[id] = y;
|
||||
pre_w[id] = w;
|
||||
|
||||
//LOG_I("%s (%d %d %d %d)\n", __func__, id, x, y, w );
|
||||
}
|
||||
|
||||
static int8_t pre_id[FT_MAX_TOUCH];
|
||||
static S_FT_REGMAP sFtRegMap;
|
||||
static rt_uint8_t pre_touch = 0;
|
||||
|
||||
static rt_size_t ft5446_read_point(struct rt_touch_device *touch, void *buf, rt_size_t read_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
rt_err_t error = 0;
|
||||
rt_int32_t touch_event, touchid;
|
||||
|
||||
RT_ASSERT(touch);
|
||||
RT_ASSERT(buf);
|
||||
RT_ASSERT(read_num != 0);
|
||||
RT_ASSERT(read_num <= FT_MAX_TOUCH);
|
||||
|
||||
error = ft5446_read_reg(&ft5446_client, 0, (rt_uint8_t *)&sFtRegMap, sizeof(sFtRegMap));
|
||||
if (error)
|
||||
{
|
||||
LOG_E("get touch data failed, err:%d\n", error);
|
||||
goto exit_read_point;
|
||||
}
|
||||
|
||||
if (sFtRegMap.u8TDStatus > FT_MAX_TOUCH)
|
||||
{
|
||||
LOG_E("FW report max point:%d > panel info. max:%d\n", sFtRegMap.u8TDStatus, FT_MAX_TOUCH);
|
||||
goto exit_read_point;
|
||||
}
|
||||
|
||||
if (pre_touch > sFtRegMap.u8TDStatus) /* point up */
|
||||
{
|
||||
for (i = 0; i < FT_MAX_TOUCH; i++)
|
||||
{
|
||||
rt_uint8_t j;
|
||||
for (j = 0; j < sFtRegMap.u8TDStatus; j++) /* this time touch num */
|
||||
{
|
||||
touchid = sFtRegMap.m_sTP[j].u8TouchID;
|
||||
if (touchid >= 0x0f)
|
||||
continue;
|
||||
|
||||
if (pre_id[i] == touchid) /* this id is not free */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((j == sFtRegMap.u8TDStatus) && (pre_id[i] != -1)) /* free this node */
|
||||
{
|
||||
// LOG_I("free %d tid=%d\n", i, pre_id[i]);
|
||||
ft5446_touch_up(buf, pre_id[i]);
|
||||
pre_id[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < sFtRegMap.u8TDStatus; i++)
|
||||
{
|
||||
touch_event = sFtRegMap.m_sTP[i].u8EvtFlag;
|
||||
touchid = sFtRegMap.m_sTP[i].u8TouchID;
|
||||
|
||||
//LOG_I("(%d/%d) %d %d\n", i, sFtRegMap.u8TDStatus, touchid, touch_event );
|
||||
|
||||
if (touchid >= 0x0f)
|
||||
continue;
|
||||
|
||||
pre_id[i] = touchid;
|
||||
|
||||
if ((touch_event == FT_EVENTFLAG_PRESS_DOWN) || (touch_event == FT_EVENTFLAG_CONTACT))
|
||||
{
|
||||
rt_uint16_t x, y, w;
|
||||
|
||||
x = ((uint16_t)sFtRegMap.m_sTP[i].u8X_11_8 << 8) | sFtRegMap.m_sTP[i].u8X_7_0;
|
||||
y = ((uint16_t)sFtRegMap.m_sTP[i].u8Y_11_8 << 8) | sFtRegMap.m_sTP[i].u8Y_7_0;
|
||||
w = sFtRegMap.m_sTP[i].m_u8Weight;
|
||||
|
||||
//LOG_I("[%d] (%d %d %d %d)\n", touch_event, touchid, x, y, w );
|
||||
|
||||
if (x >= touch->info.range_x || y >= touch->info.range_y)
|
||||
{
|
||||
LOG_E("invalid position, X[%d,%u,%d], Y[%d,%u,%d]\n",
|
||||
0, x, touch->info.range_x,
|
||||
0, y, touch->info.range_y);
|
||||
continue;
|
||||
}
|
||||
|
||||
ft5446_touch_down(buf, touchid, x, y, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Up
|
||||
ft5446_touch_up(buf, touchid);
|
||||
}
|
||||
|
||||
} // for (i = 0; i < sFtRegMap.u8TDStatus; i++)
|
||||
|
||||
pre_touch = sFtRegMap.u8TDStatus;
|
||||
|
||||
return read_num;
|
||||
|
||||
exit_read_point:
|
||||
|
||||
pre_touch = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t ft5446_control(struct rt_touch_device *touch, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_TOUCH_CTRL_GET_INFO:
|
||||
{
|
||||
struct rt_touch_info *info = (struct rt_touch_info *)arg;
|
||||
RT_ASSERT(arg);
|
||||
|
||||
rt_memcpy(info, &touch->info, sizeof(struct rt_touch_info));
|
||||
break;
|
||||
}
|
||||
case RT_TOUCH_CTRL_GET_ID:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_X_RANGE:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_Y_RANGE:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_X_TO_Y:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_MODE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_touch_ops ft5446_touch_ops =
|
||||
{
|
||||
.touch_readpoint = ft5446_read_point,
|
||||
.touch_control = ft5446_control,
|
||||
};
|
||||
|
||||
static void ft5446_init(struct rt_i2c_client *dev)
|
||||
{
|
||||
ft5446_write_reg(dev, 0x0, 0);
|
||||
}
|
||||
|
||||
int rt_hw_ft5446_init(const char *name, struct rt_touch_config *cfg)
|
||||
{
|
||||
struct rt_touch_device *touch_device = RT_NULL;
|
||||
rt_uint32_t bus_speed = 400000;
|
||||
|
||||
touch_device = (struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));
|
||||
if (touch_device == RT_NULL)
|
||||
{
|
||||
LOG_E("touch device malloc fail");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));
|
||||
|
||||
/* hw init*/
|
||||
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
|
||||
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);
|
||||
rt_thread_delay(5);
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);
|
||||
rt_thread_delay(200);
|
||||
|
||||
rt_pin_mode(cfg->irq_pin.pin, cfg->irq_pin.mode);
|
||||
|
||||
ft5446_client.bus = (struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
|
||||
|
||||
if (ft5446_client.bus == RT_NULL)
|
||||
{
|
||||
LOG_E("Can't find %s device", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_device_open((rt_device_t)ft5446_client.bus, RT_DEVICE_FLAG_RDWR) != RT_EOK)
|
||||
{
|
||||
LOG_E("open %s device failed", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_device_control((rt_device_t)ft5446_client.bus, RT_I2C_DEV_CTRL_CLK, &bus_speed) != RT_EOK)
|
||||
{
|
||||
LOG_E("control %s device failed", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
ft5446_client.client_addr = FT5446_ADDRESS;
|
||||
|
||||
ft5446_init(&ft5446_client);
|
||||
|
||||
rt_memset(&pre_x[0], 0xff, FT_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_y[0], 0xff, FT_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_w[0], 0xff, FT_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&s_tp_dowm[0], 0, FT_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_id[0], 0xff, FT_MAX_TOUCH * sizeof(int8_t));
|
||||
|
||||
/* register touch device */
|
||||
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
|
||||
touch_device->info.vendor = RT_TOUCH_VENDOR_FT;
|
||||
touch_device->info.range_x = BSP_LCD_WIDTH;
|
||||
touch_device->info.range_y = BSP_LCD_HEIGHT;
|
||||
touch_device->info.point_num = FT_MAX_TOUCH;
|
||||
|
||||
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
|
||||
touch_device->ops = &ft5446_touch_ops;
|
||||
|
||||
rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL);
|
||||
|
||||
LOG_I("touch device ft5446 init success");
|
||||
|
||||
return RT_EOK;
|
||||
}
|
133
bsp/nuvoton/libraries/nu_packages/TPC/ft5446.h
Normal file
133
bsp/nuvoton/libraries/nu_packages/TPC/ft5446.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-04-11 Wayne the first version
|
||||
*/
|
||||
|
||||
#ifndef __FT5446_H__
|
||||
#define __FT5446_H__
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
#define FT_REGITER_LEN 1
|
||||
#define FT_MAX_TOUCH 5
|
||||
#define FT5446_ADDRESS 0x38
|
||||
|
||||
#pragma anon_unions
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//03H
|
||||
union
|
||||
{
|
||||
uint8_t m_u8XH;
|
||||
struct
|
||||
{
|
||||
uint8_t u8X_11_8: 4;
|
||||
uint8_t : 2;
|
||||
uint8_t u8EvtFlag: 2;
|
||||
#define FT_EVENTFLAG_PRESS_DOWN 0x0
|
||||
#define FT_EVENTFLAG_LIFT_UP 0x1
|
||||
#define FT_EVENTFLAG_CONTACT 0x2
|
||||
#define FT_EVENTFLAG_NONE 0x3
|
||||
};
|
||||
};
|
||||
|
||||
//04H
|
||||
union
|
||||
{
|
||||
uint8_t m_u8XL;
|
||||
struct
|
||||
{
|
||||
uint8_t u8X_7_0;
|
||||
};
|
||||
};
|
||||
|
||||
//05H
|
||||
union
|
||||
{
|
||||
uint8_t m_u8YH;
|
||||
struct
|
||||
{
|
||||
uint8_t u8Y_11_8: 4;
|
||||
uint8_t u8TouchID: 4; /* Touch ID of Touch Point, this value is 0x0F when the ID is invalid */
|
||||
};
|
||||
};
|
||||
|
||||
//06H
|
||||
union
|
||||
{
|
||||
uint8_t m_u8YL;
|
||||
struct
|
||||
{
|
||||
uint8_t u8Y_7_0;
|
||||
};
|
||||
};
|
||||
|
||||
//07H
|
||||
uint8_t m_u8Weight; /* Touch pressure value */
|
||||
|
||||
//08H
|
||||
union
|
||||
{
|
||||
uint8_t m_u8Misc;
|
||||
struct
|
||||
{
|
||||
uint8_t : 4;
|
||||
uint8_t u8TouchArea: 4; /* Touch area value */
|
||||
};
|
||||
};
|
||||
|
||||
} S_FT_TP;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(4)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8_t m_u8ModeSwitch;
|
||||
#define FT_DEVICE_MODE_WORKING 0x0
|
||||
#define FT_DEVICE_MODE_TEST 0x4
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t : 4;
|
||||
uint8_t u8DevMode: 3;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
|
||||
uint8_t m_u8Guesture;
|
||||
#define FT_GESTURE_ID_MOVE_UP 0x10
|
||||
#define FT_GESTURE_ID_MOVE_RIGHT 0x14
|
||||
#define FT_GESTURE_ID_MOVE_DOWN 0x18
|
||||
#define FT_GESTURE_ID_MOVE_LEFT 0x1C
|
||||
#define FT_GESTURE_ID_MOVE_IN 0x48
|
||||
#define FT_GESTURE_ID_MOVE_OUT 0x49
|
||||
#define FT_GESTURE_ID_MOVE_NONE 0x00
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t m_u8Status;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t u8TDStatus: 4;
|
||||
uint8_t : 4;
|
||||
};
|
||||
};
|
||||
|
||||
S_FT_TP m_sTP[FT_MAX_TOUCH];
|
||||
|
||||
} S_FT_REGMAP;
|
||||
#pragma pack(pop)
|
||||
|
||||
int rt_hw_ft5446_init(const char *name, struct rt_touch_config *cfg);
|
||||
|
||||
#endif /* __FT5446_H__ */
|
337
bsp/nuvoton/libraries/nu_packages/TPC/st1663i.c
Normal file
337
bsp/nuvoton/libraries/nu_packages/TPC/st1663i.c
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-04-11 Wayne First version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DBG_TAG "st1663i"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "st1663i.h"
|
||||
|
||||
static struct rt_i2c_client st1663i_client;
|
||||
static void st1663i_touch_up(void *buf, rt_int8_t id);
|
||||
static rt_err_t st1663i_write_reg(struct rt_i2c_client *dev, rt_uint8_t reg, rt_uint8_t value)
|
||||
{
|
||||
struct rt_i2c_msg msgs;
|
||||
rt_uint8_t buf[2];
|
||||
|
||||
buf[0] = reg;
|
||||
buf[1] = value;
|
||||
|
||||
msgs.addr = dev->client_addr;
|
||||
msgs.flags = RT_I2C_WR;
|
||||
msgs.buf = buf;
|
||||
msgs.len = sizeof(buf);
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t st1663i_read_reg(struct rt_i2c_client *dev, rt_uint8_t reg, rt_uint8_t *data, rt_uint8_t len)
|
||||
{
|
||||
struct rt_i2c_msg msgs[2];
|
||||
|
||||
msgs[0].addr = dev->client_addr;
|
||||
msgs[0].flags = RT_I2C_WR;
|
||||
msgs[0].buf = ®
|
||||
msgs[0].len = ST_REGITER_LEN;
|
||||
|
||||
msgs[1].addr = dev->client_addr;
|
||||
msgs[1].flags = RT_I2C_RD;
|
||||
msgs[1].buf = data;
|
||||
msgs[1].len = len;
|
||||
|
||||
if (rt_i2c_transfer(dev->bus, msgs, 2) == 2)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_int16_t pre_x[ST_MAX_TOUCH];
|
||||
static rt_int16_t pre_y[ST_MAX_TOUCH];
|
||||
static rt_int16_t pre_w[ST_MAX_TOUCH];
|
||||
static rt_uint8_t s_tp_dowm[ST_MAX_TOUCH];
|
||||
|
||||
static void st1663i_touch_up(void *buf, rt_int8_t id)
|
||||
{
|
||||
struct rt_touch_data *read_data = (struct rt_touch_data *)buf;
|
||||
|
||||
if (s_tp_dowm[id] == 1)
|
||||
{
|
||||
s_tp_dowm[id] = 0;
|
||||
read_data[id].event = RT_TOUCH_EVENT_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_NONE;
|
||||
}
|
||||
|
||||
read_data[id].timestamp = rt_touch_get_ts();
|
||||
read_data[id].width = pre_w[id];
|
||||
read_data[id].x_coordinate = pre_x[id];
|
||||
read_data[id].y_coordinate = pre_y[id];
|
||||
read_data[id].track_id = id;
|
||||
|
||||
pre_x[id] = -1; /* last point is none */
|
||||
pre_y[id] = -1;
|
||||
pre_w[id] = -1;
|
||||
|
||||
//LOG_I("%s (%d)\n", __func__, id);
|
||||
}
|
||||
|
||||
static void st1663i_touch_down(void *buf, rt_int8_t id, rt_int16_t x, rt_int16_t y, rt_int16_t w)
|
||||
{
|
||||
struct rt_touch_data *read_data = (struct rt_touch_data *)buf;
|
||||
|
||||
if (s_tp_dowm[id] == 1)
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_MOVE;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
read_data[id].event = RT_TOUCH_EVENT_DOWN;
|
||||
s_tp_dowm[id] = 1;
|
||||
}
|
||||
|
||||
read_data[id].timestamp = rt_touch_get_ts();
|
||||
read_data[id].width = w;
|
||||
read_data[id].x_coordinate = x;
|
||||
read_data[id].y_coordinate = y;
|
||||
read_data[id].track_id = id;
|
||||
|
||||
pre_x[id] = x; /* save last point */
|
||||
pre_y[id] = y;
|
||||
pre_w[id] = w;
|
||||
|
||||
//LOG_I("%s (%d %d %d %d)\n", __func__, id, x, y, w );
|
||||
}
|
||||
|
||||
static int8_t pre_id[ST_MAX_TOUCH];
|
||||
static S_ST_REGMAP sStRegMap;
|
||||
static rt_uint8_t pre_touch = 0;
|
||||
|
||||
static rt_size_t st1663i_read_point(struct rt_touch_device *touch, void *buf, rt_size_t read_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
rt_err_t error = 0;
|
||||
rt_int32_t touch_event, touchid;
|
||||
|
||||
RT_ASSERT(touch);
|
||||
RT_ASSERT(buf);
|
||||
RT_ASSERT(read_num != 0);
|
||||
RT_ASSERT(read_num <= ST_MAX_TOUCH);
|
||||
|
||||
error = st1663i_read_reg(&st1663i_client, 0x10, (rt_uint8_t *)&sStRegMap, sizeof(sStRegMap));
|
||||
if (error)
|
||||
{
|
||||
LOG_E("get touch data failed, err:%d\n", error);
|
||||
goto exit_read_point;
|
||||
}
|
||||
|
||||
if (sStRegMap.u8Fingers > ST_MAX_TOUCH)
|
||||
{
|
||||
LOG_E("FW report max point:%d > panel info. max:%d\n", sStRegMap.u8Fingers, ST_MAX_TOUCH);
|
||||
goto exit_read_point;
|
||||
}
|
||||
|
||||
if (pre_touch > sStRegMap.u8Fingers) /* point up */
|
||||
{
|
||||
for (i = 0; i < ST_MAX_TOUCH; i++)
|
||||
{
|
||||
rt_uint8_t j;
|
||||
for (j = 0; j < sStRegMap.u8Fingers; j++) /* this time touch num */
|
||||
{
|
||||
touchid = i;
|
||||
|
||||
if (pre_id[i] == touchid) /* this id is not free */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((j == sStRegMap.u8Fingers) && (pre_id[i] != -1)) /* free this node */
|
||||
{
|
||||
// LOG_I("free %d tid=%d\n", i, pre_id[i]);
|
||||
st1663i_touch_up(buf, pre_id[i]);
|
||||
pre_id[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < sStRegMap.u8Fingers; i++)
|
||||
{
|
||||
touch_event = sStRegMap.m_sTP[i].u8Valid;
|
||||
touchid = i;
|
||||
|
||||
//LOG_I("(%d/%d) %d %d\n", i, sStRegMap.u8Fingers, touchid, touch_event);
|
||||
|
||||
pre_id[i] = touchid;
|
||||
|
||||
if (touch_event)
|
||||
{
|
||||
rt_uint16_t x, y, w;
|
||||
|
||||
x = ((uint16_t)sStRegMap.m_sTP[i].u8X0_H << 8) | sStRegMap.m_sTP[i].m_u8X0_L;
|
||||
y = ((uint16_t)sStRegMap.m_sTP[i].u8Y0_H << 8) | sStRegMap.m_sTP[i].m_u8Y0_L;
|
||||
w = sStRegMap.m_sTP[i].m_u8Z;
|
||||
|
||||
//LOG_I("[%d] (%d %d %d %d)\n", touch_event, touchid, x, y, w);
|
||||
|
||||
if (x >= touch->info.range_x || y >= touch->info.range_y)
|
||||
{
|
||||
LOG_E("invalid position, X[%d,%u,%d], Y[%d,%u,%d]\n",
|
||||
0, x, touch->info.range_x,
|
||||
0, y, touch->info.range_y);
|
||||
continue;
|
||||
}
|
||||
|
||||
st1663i_touch_down(buf, touchid, x, y, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Up
|
||||
st1663i_touch_up(buf, touchid);
|
||||
}
|
||||
|
||||
} // for (i = 0; i < sStRegMap.u8TDStatus; i++)
|
||||
|
||||
pre_touch = sStRegMap.u8Fingers;
|
||||
|
||||
return read_num;
|
||||
|
||||
exit_read_point:
|
||||
|
||||
pre_touch = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t st1663i_control(struct rt_touch_device *touch, int cmd, void *arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_TOUCH_CTRL_GET_INFO:
|
||||
{
|
||||
struct rt_touch_info *info = (struct rt_touch_info *)arg;
|
||||
RT_ASSERT(arg);
|
||||
|
||||
rt_memcpy(info, &touch->info, sizeof(struct rt_touch_info));
|
||||
break;
|
||||
}
|
||||
case RT_TOUCH_CTRL_GET_ID:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_X_RANGE:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_Y_RANGE:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_X_TO_Y:
|
||||
break;
|
||||
case RT_TOUCH_CTRL_SET_MODE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct rt_touch_ops st1663i_touch_ops =
|
||||
{
|
||||
.touch_readpoint = st1663i_read_point,
|
||||
.touch_control = st1663i_control,
|
||||
};
|
||||
|
||||
static void st1663i_init(struct rt_i2c_client *dev)
|
||||
{
|
||||
st1663i_write_reg(dev, 0x0, 0);
|
||||
}
|
||||
|
||||
int rt_hw_st1663i_init(const char *name, struct rt_touch_config *cfg)
|
||||
{
|
||||
struct rt_touch_device *touch_device = RT_NULL;
|
||||
rt_uint32_t bus_speed = 400000;
|
||||
|
||||
touch_device = (struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));
|
||||
if (touch_device == RT_NULL)
|
||||
{
|
||||
LOG_E("touch device malloc fail");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));
|
||||
|
||||
/* hw init*/
|
||||
rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
|
||||
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);
|
||||
rt_thread_delay(5);
|
||||
rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);
|
||||
rt_thread_delay(200);
|
||||
|
||||
rt_pin_mode(cfg->irq_pin.pin, cfg->irq_pin.mode);
|
||||
|
||||
st1663i_client.bus = (struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);
|
||||
|
||||
if (st1663i_client.bus == RT_NULL)
|
||||
{
|
||||
LOG_E("Can't find %s device", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_device_open((rt_device_t)st1663i_client.bus, RT_DEVICE_FLAG_RDWR) != RT_EOK)
|
||||
{
|
||||
LOG_E("open %s device failed", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (rt_device_control((rt_device_t)st1663i_client.bus, RT_I2C_DEV_CTRL_CLK, &bus_speed) != RT_EOK)
|
||||
{
|
||||
LOG_E("control %s device failed", cfg->dev_name);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
st1663i_client.client_addr = ST1663I_ADDRESS;
|
||||
|
||||
st1663i_init(&st1663i_client);
|
||||
|
||||
rt_memset(&pre_x[0], 0xff, ST_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_y[0], 0xff, ST_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_w[0], 0xff, ST_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&s_tp_dowm[0], 0, ST_MAX_TOUCH * sizeof(int16_t));
|
||||
rt_memset(&pre_id[0], 0xff, ST_MAX_TOUCH * sizeof(int8_t));
|
||||
|
||||
/* register touch device */
|
||||
touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
|
||||
touch_device->info.vendor = RT_TOUCH_VENDOR_UNKNOWN;
|
||||
touch_device->info.range_x = BSP_LCD_WIDTH;
|
||||
touch_device->info.range_y = BSP_LCD_HEIGHT;
|
||||
touch_device->info.point_num = ST_MAX_TOUCH;
|
||||
|
||||
rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
|
||||
touch_device->ops = &st1663i_touch_ops;
|
||||
|
||||
rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL);
|
||||
|
||||
LOG_I("touch device st1663i init success");
|
||||
|
||||
return RT_EOK;
|
||||
}
|
73
bsp/nuvoton/libraries/nu_packages/TPC/st1663i.h
Normal file
73
bsp/nuvoton/libraries/nu_packages/TPC/st1663i.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-04-11 Wayne the first version
|
||||
*/
|
||||
|
||||
#ifndef __ST1663I_H__
|
||||
#define __ST1663I_H__
|
||||
|
||||
#include "touch.h"
|
||||
|
||||
#define ST_REGITER_LEN 1
|
||||
#define ST_MAX_TOUCH 5
|
||||
#define ST1663I_ADDRESS 0x55
|
||||
|
||||
#pragma anon_unions
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//012H*n+0 (n=0, 1, ...,4)
|
||||
union
|
||||
{
|
||||
uint8_t m_u8XY0_H;
|
||||
struct
|
||||
{
|
||||
uint8_t u8Y0_H: 3;
|
||||
uint8_t : 1;
|
||||
uint8_t u8X0_H: 3;
|
||||
uint8_t u8Valid: 1;
|
||||
};
|
||||
};
|
||||
|
||||
//012H*n+1 (n=0, 1, ...,4)
|
||||
uint8_t m_u8X0_L;
|
||||
|
||||
//012H*n+2 (n=0, 1, ...,4)
|
||||
uint8_t m_u8Y0_L;
|
||||
|
||||
//012H*n+3 (n=0, 1, ...,4)
|
||||
uint8_t m_u8Z;
|
||||
|
||||
} S_ST_TP;
|
||||
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(4)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8_t m_u8TouchInfo;
|
||||
struct
|
||||
{
|
||||
uint8_t u8Fingers: 4;
|
||||
uint8_t : 4;
|
||||
};
|
||||
};
|
||||
|
||||
uint8_t m_u8Keys;
|
||||
|
||||
S_ST_TP m_sTP[ST_MAX_TOUCH];
|
||||
|
||||
} S_ST_REGMAP;
|
||||
#pragma pack(pop)
|
||||
|
||||
int rt_hw_st1663i_init(const char *name, struct rt_touch_config *cfg);
|
||||
|
||||
#endif /* __ST1663I_H__ */
|
195
bsp/nuvoton/nk-n9h30/applications/lvgl/lv_gpu_n9h30_ge2d.c
Normal file
195
bsp/nuvoton/nk-n9h30/applications/lvgl/lv_gpu_n9h30_ge2d.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-12-17 Wayne The first version
|
||||
*/
|
||||
/**
|
||||
* @file lv_gpu_n9h30_ge2d.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <lvgl.h>
|
||||
|
||||
#if LV_USE_GPU_N9H30_GE2D && LV_VERSION_CHECK(8, 2, 0)
|
||||
|
||||
#include "lv_gpu_n9h30_ge2d.h"
|
||||
#include "nu_2d.h"
|
||||
#include "mmu.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_COLOR_16_SWAP
|
||||
#error "Can't use GE2D with LV_COLOR_16_SWAP 1"
|
||||
#endif
|
||||
|
||||
#if !((LV_COLOR_DEPTH == 16) || (LV_COLOR_DEPTH == 32))
|
||||
/*Can't use GPU with other formats*/
|
||||
#error "Can't use GPU with other formats"
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void lv_draw_n9h30_ge2d_blend_fill(lv_color_t *dest_buf, lv_coord_t dest_stride, const lv_area_t *fill_area,
|
||||
lv_color_t color);
|
||||
|
||||
|
||||
static void lv_draw_n9h30_ge2d_blend_map(lv_color_t *dest_buf, const lv_area_t *dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t *src_buf, lv_coord_t src_stride, lv_opa_t opa);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Turn on the peripheral and set output color mode, this only needs to be done once
|
||||
*/
|
||||
void lv_draw_n9h30_ge2d_ctx_init(lv_disp_drv_t *drv, lv_draw_ctx_t *draw_ctx)
|
||||
{
|
||||
lv_draw_sw_init_ctx(drv, draw_ctx);
|
||||
|
||||
lv_draw_n9h30_ge2d_ctx_t *ge2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
|
||||
|
||||
ge2d_draw_ctx->blend = lv_draw_n9h30_ge2d_blend;
|
||||
ge2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_n9h30_ge2d_wait_cb;
|
||||
}
|
||||
|
||||
void lv_draw_n9h30_ge2d_ctx_deinit(lv_disp_drv_t *drv, lv_draw_ctx_t *draw_ctx)
|
||||
{
|
||||
LV_UNUSED(drv);
|
||||
LV_UNUSED(draw_ctx);
|
||||
}
|
||||
|
||||
void lv_draw_n9h30_ge2d_blend(lv_draw_ctx_t *draw_ctx, const lv_draw_sw_blend_dsc_t *dsc)
|
||||
{
|
||||
lv_area_t blend_area;
|
||||
int32_t blend_area_w;
|
||||
bool done = false;
|
||||
|
||||
if (!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
|
||||
|
||||
blend_area_w = lv_area_get_width(&blend_area);
|
||||
|
||||
if ((lv_area_get_size(&blend_area) > 7200) &&
|
||||
(((blend_area_w * (LV_COLOR_DEPTH / 2)) & 0x3) == 0) &&
|
||||
(dsc->mask_buf == NULL) && (dsc->blend_mode == LV_BLEND_MODE_NORMAL))
|
||||
{
|
||||
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
||||
|
||||
lv_color_t *dest_buf = draw_ctx->buf;
|
||||
dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
|
||||
|
||||
const lv_color_t *src_buf = dsc->src_buf;
|
||||
if (src_buf)
|
||||
{
|
||||
lv_coord_t src_stride;
|
||||
src_stride = lv_area_get_width(dsc->blend_area);
|
||||
src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1);
|
||||
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
|
||||
lv_draw_n9h30_ge2d_blend_map(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa);
|
||||
done = true;
|
||||
}
|
||||
else if (dsc->opa >= LV_OPA_MAX)
|
||||
{
|
||||
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
|
||||
lv_draw_n9h30_ge2d_blend_fill(dest_buf, dest_stride, &blend_area, dsc->color);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) lv_draw_sw_blend_basic(draw_ctx, dsc);
|
||||
}
|
||||
|
||||
static void lv_draw_n9h30_ge2d_blend_fill(lv_color_t *dest_buf, lv_coord_t dest_stride, const lv_area_t *fill_area,
|
||||
lv_color_t color)
|
||||
{
|
||||
int32_t fill_area_w = lv_area_get_width(fill_area);
|
||||
int32_t fill_area_h = lv_area_get_height(fill_area);
|
||||
|
||||
lv_color_t *start_buf = dest_buf - (fill_area->y1 * dest_stride) - fill_area->x1;
|
||||
|
||||
//rt_kprintf("[blend_fill %d %08x] %dx%d %d %d\n", lv_area_get_size(fill_area), dest_buf, fill_area_w, fill_area_h, fill_area->x1, fill_area->y1 );
|
||||
|
||||
if (IS_CACHEABLE_VRAM(dest_buf))
|
||||
mmu_clean_invalidated_dcache((uint32_t)dest_buf, sizeof(lv_color_t) * (dest_stride * fill_area_h + fill_area_w));
|
||||
|
||||
/*Hardware filling*/
|
||||
// Enter GE2D ->
|
||||
ge2dInit(sizeof(lv_color_t) * 8, dest_stride, fill_area->y2, (void *)start_buf);
|
||||
|
||||
ge2dClip_SetClip(fill_area->x1, fill_area->y1, fill_area->x2, fill_area->y2);
|
||||
|
||||
if (sizeof(lv_color_t) == 4)
|
||||
ge2dFill_Solid(fill_area->x1, fill_area->y1, fill_area_w, fill_area_h, color.full);
|
||||
else if (sizeof(lv_color_t) == 2)
|
||||
ge2dFill_Solid_RGB565(fill_area->x1, fill_area->y1, fill_area_w, fill_area_h, color.full);
|
||||
|
||||
ge2dClip_SetClip(-1, 0, 0, 0);
|
||||
// -> Leave GE2D
|
||||
}
|
||||
|
||||
static void lv_draw_n9h30_ge2d_blend_map(lv_color_t *dest_buf, const lv_area_t *dest_area, lv_coord_t dest_stride,
|
||||
const lv_color_t *src_buf, lv_coord_t src_stride, lv_opa_t opa)
|
||||
{
|
||||
/*Simple copy*/
|
||||
int32_t dest_x = dest_area->x1;
|
||||
int32_t dest_y = dest_area->y1;
|
||||
int32_t dest_w = lv_area_get_width(dest_area);
|
||||
int32_t dest_h = lv_area_get_height(dest_area);
|
||||
|
||||
const lv_color_t *dest_start_buf = dest_buf - (dest_area->y1 * dest_stride) - dest_area->x1;
|
||||
|
||||
//rt_kprintf("[blend_map %d %08x -> %08x] (x:%d y:%d, %dx%d) <stride src:%d dst:%d>\n", lv_area_get_size(dest_area), src_buf, dest_buf, dest_x, dest_y, dest_w, dest_h, src_stride, dest_stride);
|
||||
|
||||
// Enter GE2D ->
|
||||
ge2dInit(sizeof(lv_color_t) * 8, dest_stride, dest_area->y2, (void *)dest_start_buf);
|
||||
|
||||
if (opa >= LV_OPA_MAX)
|
||||
{
|
||||
ge2dBitblt_SetAlphaMode(0, 0, 0);
|
||||
ge2dBitblt_SetDrawMode(0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ge2dBitblt_SetAlphaMode(1, opa, opa);
|
||||
}
|
||||
|
||||
// flush
|
||||
mmu_clean_dcache((uint32_t)src_buf, sizeof(lv_color_t) * (src_stride * dest_h + dest_w));
|
||||
|
||||
ge2dSpriteBlt_Screen(dest_x, dest_y, dest_w, dest_h, (void *)src_buf);
|
||||
// -> Leave GE2D
|
||||
}
|
||||
|
||||
void lv_gpu_n9h30_ge2d_wait_cb(lv_draw_ctx_t *draw_ctx)
|
||||
{
|
||||
lv_draw_sw_wait_for_finish(draw_ctx);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif // #if (LV_USE_GPU_N9H30_GE2D && LV_VERSION_CHECK(8, 2, 0))
|
64
bsp/nuvoton/nk-n9h30/applications/lvgl/lv_gpu_n9h30_ge2d.h
Normal file
64
bsp/nuvoton/nk-n9h30/applications/lvgl/lv_gpu_n9h30_ge2d.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-29 Wayne The first version
|
||||
*/
|
||||
#ifndef LV_GPU_N9H_GE2D_H
|
||||
#define LV_GPU_N9H_GE2D_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../misc/lv_color.h"
|
||||
#include "../../hal/lv_hal_disp.h"
|
||||
#include "../sw/lv_draw_sw.h"
|
||||
|
||||
#if LV_USE_GPU_N9H30_GE2D && LV_VERSION_CHECK(8, 2, 0)
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
struct _lv_disp_drv_t;
|
||||
typedef lv_draw_sw_ctx_t lv_draw_n9h30_ge2d_ctx_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Turn on the peripheral and set output color mode, this only needs to be done once
|
||||
*/
|
||||
void lv_draw_n9h30_ge2d_init(void);
|
||||
|
||||
void lv_draw_n9h30_ge2d_ctx_init(struct _lv_disp_drv_t *drv, lv_draw_ctx_t *draw_ctx);
|
||||
|
||||
void lv_draw_n9h30_ge2d_ctx_deinit(struct _lv_disp_drv_t *drv, lv_draw_ctx_t *draw_ctx);
|
||||
|
||||
void lv_draw_n9h30_ge2d_blend(lv_draw_ctx_t *draw_ctx, const lv_draw_sw_blend_dsc_t *dsc);
|
||||
|
||||
void lv_gpu_n9h30_ge2d_wait_cb(lv_draw_ctx_t *draw_ctx);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*#if LV_USE_GPU_N9H30_GE2D && LV_VERSION_CHECK(8, 2, 0)*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_N9H_GE2D_H*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user