MIMXRT1064 - NXP emWin not working in HyperRAM

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MIMXRT1064 - NXP emWin not working in HyperRAM

491 Views
m_mollo
Contributor I

We are developing a custom board based on the MIMXRT1064 and the application will implement an UI based on NXP SEGGER emWin with a 800x480 LCD touchscreen.
Our board should mount an HyperRAM instead of the classic parallel SDRAM to save many pins. We adapted the MIMXRT1064-EVK to replace the HyperFlash with an HyperRAM as indicated in the “AN12239 - How to Enable HyperRAM with i.MX RT”. The device used is the ISSI IS66WVH32M8DALL.
We started the SW development with the MCUXpresso IDE v11.5.0 and the SDK v2.11.1 MIMXRT1064.

We adapted the code package hyper_ram.zip for our needs to test the HyperRAM functionality with the MIMXRT1064-EVK and all seems to work correctly.

Here the steps we followed:

We modified the function BOARD_ConfigMPU() and the memory mappings inside the project to manage the proper regions. The 32MB of the HyperRAM is divided in two zones: the first 16MB (cacheable - write-back) for the HYPERRAM region and the second 16MB (non cacheable) to hold the NCACHE_REGION region.

/* MPU configuration. */
void BOARD_ConfigMPU(void)
{
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$RW_m_ncache$$Base[];
/* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
extern uint32_t Image$$RW_m_ncache_unused$$Base[];
extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
uint32_t nonCacheStart = (uint32_t)Image$$RW_m_ncache$$Base;
uint32_t size = ((uint32_t)Image$$RW_m_ncache_unused$$Base == nonCacheStart) ?
0 :
((uint32_t)Image$$RW_m_ncache_unused$$ZI$$Limit - nonCacheStart);
#elif defined(__MCUXPRESSO)
extern uint32_t __base_NCACHE_REGION;
extern uint32_t __top_NCACHE_REGION;
uint32_t nonCacheStart = (uint32_t)(&__base_NCACHE_REGION);
uint32_t size = (uint32_t)(&__top_NCACHE_REGION) - nonCacheStart;
#elif defined(__ICCARM__) || defined(__GNUC__)
extern uint32_t __NCACHE_REGION_START[];
extern uint32_t __NCACHE_REGION_SIZE[];
uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START;
uint32_t size = (uint32_t)__NCACHE_REGION_SIZE;
#endif
volatile uint32_t i = 0;
....

/* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */
MPU->RBAR = ARM_MPU_RBAR(9, 0x60000000U);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_16MB);

while ((size >> i) > 0x1U)
{
i++;
}

if (i != 0)
{
/* The MPU region size should be 2^N, 5<=N<=32, region base should be multiples of size. */
assert(!(nonCacheStart % size));
assert(size == (uint32_t)(1 << i));
assert(i >= 5);

/* Region 10 setting: Memory with Normal type, not shareable, non-cacheable */
MPU->RBAR = ARM_MPU_RBAR(10, nonCacheStart);
MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, i - 1);
}

Image3.png

int main(void)
{
BOARD_ConfigMPU();
BOARD_InitBootPins();
BOARD_InitBootClocks();

BOARD_InitHyperRamPins();
BOARD_InitHyperRam();

BOARD_InitLcdifPixelClock();
BOARD_InitDebugConsole();
BOARD_InitLcd();
BOARD_InitGPT();

...

We also implemented the functions BOARD_InitHyperRamPins() and BOARD_InitHyperRam() for the low level inizialization.
#define FLASH_SIZE 0x8000 /* 32MB */

#define HYPERRAM_CMD_LUT_SEQ_IDX_READDATA 0
#define HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA 1
#define HYPERRAM_CMD_LUT_SEQ_IDX_READREG 2
#define HYPERRAM_CMD_LUT_SEQ_IDX_WRITEREG 3

status_t flexspi_hyper_ram_get_id(FLEXSPI_Type *base, uint32_t *vendorId)
{
flexspi_transfer_t flashXfer;
status_t status;
uint32_t id;

/* Write data */
flashXfer.deviceAddress = 0x0U;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = HYPERRAM_CMD_LUT_SEQ_IDX_READREG;
flashXfer.data = &id;
flashXfer.dataSize = 4;

status = FLEXSPI_TransferBlocking(base, &flashXfer);

*vendorId = id & 0xffffU;

return status;
}

static int BOARD_InitHyperRam(void)
{
flexspi_config_t config;
uint32_t vendorID = 0;
status_t status;

const uint32_t customLUT[20] =
{
/* Read Data */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x06),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READDATA + 2] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),

/* Write Data */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x06),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA + 2] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),

/* Read Register */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xE0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READREG + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x06),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_READREG + 2] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),

/* Write Register */
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEREG] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEREG + 1] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x06),
[4 * HYPERRAM_CMD_LUT_SEQ_IDX_WRITEREG + 2] = FLEXSPI_LUT_SEQ(
kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
};

/* Set flexspi root clock to 320MHZ. */
const clock_usb_pll_config_t g_ccmConfigUsbPll =
{
.loopDivider = 0, /* PLL loop divider, Fout = Fin * 20 */
.src=0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */
};

CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);

CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, 27); /* Set PLL2 PFD2 clock 320MHZ. */
CLOCK_SetMux(kCLOCK_FlexspiMux, 0x2); /* Choose PLL2 PFD2 clock as flexspi source clock. */
CLOCK_SetDiv(kCLOCK_FlexspiDiv, kCLOCK_Flexio1DivBy1); /* Divide the clock by 1 to get flexspi root clock 320MHZ */

/* Get FLEXSPI default settings and configure the flexspi. */
FLEXSPI_GetDefaultConfig(&config);

/* Init FLEXSPI. */
config.rxSampleClock = kFLEXSPI_ReadSampleClkExternalInputFromDqsPad;
config.enableSckBDiffOpt = true;
config.enableCombination = true;
config.ahbConfig.enableAHBPrefetch = true;
config.ahbConfig.enableAHBBufferable = true;
config.ahbConfig.enableAHBCachable = true;

FLEXSPI_Init(FLEXSPI, &config);

flexspi_device_config_t deviceconfig =
{
/* Get FlexSPI clock frequency. The frequency output on SCLK A/B will be half of this as we run DDR */
.flexspiRootClk = CLOCK_GetFreq(kCLOCK_Usb1PllPfd2Clk),
.isSck2Enabled = false,
.flashSize = FLASH_SIZE,
.CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
.CSInterval = 2,
.CSHoldTime = 0,
.CSSetupTime = 4,
.dataValidTime = 1,
.columnspace = 3,
.enableWordAddress = true,
.AWRSeqIndex = HYPERRAM_CMD_LUT_SEQ_IDX_WRITEDATA,
.AWRSeqNumber = 1,
.ARDSeqIndex = HYPERRAM_CMD_LUT_SEQ_IDX_READDATA,
.ARDSeqNumber = 1,
.AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
.AHBWriteWaitInterval = 0,
.enableWriteMask = true,
};

/* Configure RAM settings according to serial RAM feature. */
FLEXSPI_SetFlashConfig(FLEXSPI, &deviceconfig, kFLEXSPI_PortA1);

/* Update LUT table. */
FLEXSPI_UpdateLUT(FLEXSPI, 0, customLUT, ARRAY_SIZE(customLUT));

/* Do software reset. */
FLEXSPI_SoftwareReset(FLEXSPI);

/* Get vendor ID. */
status = flexspi_hyper_ram_get_id(FLEXSPI, &vendorID);
if (status != kStatus_Success)
{
return -1;
}
if (vendorID != 0x830E)
{
return -1;
}

return 0;
}
void BOARD_InitHyperRamPins(void)
{
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_00_FLEXSPIB_DATA03, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_FLEXSPIB_DATA02, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_FLEXSPIB_DATA01, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_FLEXSPIB_DATA00, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_04_FLEXSPIB_SCLK, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_00_FLEXSPIB_DATA03, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_FLEXSPIB_DATA02, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_FLEXSPIB_DATA01, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_FLEXSPIB_DATA00, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_04_FLEXSPIB_SCLK, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, 0x0130F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, 0x10F1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, 0x10F1U);
}

After we got the HyperRAM tested and working, we proceeded with the adaptation of an emwin example for our 800x480 LCD. We took the only example available in the SDK 2.11.1 EVK-MIMXRT1064, that is “emwin_gui_example”.
emwin_support.h
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_BITS_PER_PIXEL 32
#define LCD_BYTES_PER_PIXEL (LCD_BITS_PER_PIXEL /

/* Color depth dependent definitions */
#define DISPLAY_DRIVER GUIDRV_LIN_32
#define COLOR_CONVERSION GUICC_M8888I
#define ELCDIF_PIXEL_FORMAT kELCDIF_PixelFormatXRGB8888
#define APP_LCDIF_DATA_BUS kELCDIF_DataBus16Bit

#define GUI_BUFFERS 2
#define GUI_NUMBYTES (0xC0000) /*! Amount of memory assigned to the emWin library */

#define FRAME_BUFFER_ALIGN 64

#define VRAM_SIZE (LCD_HEIGHT * LCD_WIDTH * LCD_BYTES_PER_PIXEL)
#define EXAMPLE_GPT GPT2
#define EXAMPLE_GPT_TICK_TO_MS 25

emwin_support.c
__NOINIT(NCACHE_REGION) uint8_t s_vram_buffer[VRAM_SIZE * GUI_BUFFERS]
__attribute__((aligned(FRAME_BUFFER_ALIGN)));
__NOINIT(BOARD_SDRAM) uint32_t s_gui_memory[GUI_NUMBYTES];

/* Memory address definitions */
#define GUI_MEMORY_ADDR ((uint32_t)s_gui_memory)
#define VRAM_ADDR ((uint32_t)s_vram_buffer)
We first verified that the example worked correctly in SDRAM (SDRAM gets still initialized by means of the DCD). First we restored the regions BOARD_SDRAM and NCACHE_REGION to map the SDRAM addresses. The GUI application worked as expected.

Image5.png

NOTE: emWin needs its video framebuffer to be placed in a non cacheable region.
Then we moved the buffers s_vram_buffer[] and s_gui_memory[] into the HyperRAM’s regions.

Image6.png

__NOINIT(NCACHE_REGION) uint8_t s_vram_buffer[VRAM_SIZE * GUI_BUFFERS]
__attribute__((aligned(FRAME_BUFFER_ALIGN)));
__NOINIT(HYPERRAM) uint32_t s_gui_memory[GUI_NUMBYTES];

With emWin working in HyperRAM we noted a strange behavior. When tapping on the touchscreen to interact with the controls, a strange flickering is observed (during the framebuffer swapping?) and then the image is randomly shifted horizontally.

Image4.png

Can the emWin be used with an HyperRAM?
Is there anything wrong during the initialization of the FlexSPI or the HyperRAM?
Is this bahavior caused by the HyperRAM performance compared with a standard SDRAM?
I controlled many times all the initialization and configuration steps and they seem correct to me.

Any suggestions will be appreciated.

Labels (1)
0 Kudos
1 Reply

474 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
1) Can the emWin be used with an HyperRAM?
-- Yes, I think so.
2) I'd like to suggest you test the other two simple demos prior to working with the emWin, firstly, like as the semc_sdram.c shows, test the write and read operation of the FlexRAM, next is evkmimxrt1064_elcdif_rgb demo that from the SDK library.
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos