LPCXpresso54608 Eval Board External SDRAM Problem

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

LPCXpresso54608 Eval Board External SDRAM Problem

2,183 Views
fatihozen
Contributor IV

Hello I am very new at NXP community. I bought LPCXpresso54608 demoboard. I am trying to use BOARD_SDRAM via SDK but could not be successful or I am missing sth .

pastedImage_1.png

I do not know how to use external sdram with via example code. I dont know what I have to add. Is there anybody to help me about it ?

I used "SDK_2.2_LPCXpresso54608_OOBE\boards\lpcxpresso54608\driver_examples\emc\sdram" example downloaded from SDK for LPCXpresso54608 v2.2 .

Labels (1)
Tags (2)
0 Kudos
10 Replies

1,404 Views
fatihozen
Contributor IV

Hi Brendon,

I looked at your examples and I could not see any usage of external Ram in both 2 bpp and 16 bpp projects. My project is emwin_touch_and_draw from SDK_2_3_0_LpcXpresso_54608. I modified it a bit as you see below. I used timer etc. and I modified the pin_mux.c file to use sdram and emwin library at the same time.

as you see I add there a header file " #include "cr_section_macros.h" " to use  this macro :                         __attribute__(( section(".noinit.$RAM4"), aligned(8) ))

my sdram is fourth one. when I make a new buffer and use it in 'int main()' I can see that I use an external sdram. That is okay. But I could not find framebuffer for emwin library. If I find it I can move lots of my datas to external ram.

I have tried one more thing. I made my external ram's priority first from Project>Properties>C/C++ Build/MCU Settings.

pastedImage_2.png

I changed its location with SRAM_0_1_2_3's location. I added its driver. when I compiled it there was no error and all datas was looked in BOARD_SDRAM.
pastedImage_4.png
But when I debug it, It gave an error as expected. Error picture is here. I don't know what to do on this step.
pastedImage_3.png

/* Standard C Included Files */
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "fsl_debug_console.h"
#include "emwin_support.h"
#include "fsl_ctimer.h"
#include "GUI.h"
#include "GUIDRV_Lin.h"
#include "BUTTON.h"
#include "pin_mux.h"
#include "fsl_sctimer.h"
#include "fsl_emc.h"
#include "fsl_lcdc.h"
#include "fsl_i2c.h"
#include "fsl_ft5406.h"
#include "cr_section_macros.h"

/*******************************************************************************
* Definitions
******************************************************************************/
#define EXAMPLE_I2C_MASTER_BASE (I2C2_BASE)
#define I2C_MASTER_CLOCK_FREQUENCY (12000000)

#define SDRAM_BASE_ADDR 0xa0000000
#define SDRAM_SIZE_BYTES 8 * 1024 * 1024

#define APP_LCD LCD
#define APP_LCD_IRQHandler LCD_IRQHandler
#define APP_LCD_IRQn LCD_IRQn

#define LCD_PANEL_CLK 9000000
#define LCD_PPL 480
#define LCD_HSW 2
#define LCD_HFP 8
#define LCD_HBP 43
#define LCD_LPP 272
#define LCD_VSW 10
#define LCD_VFP 4
#define LCD_VBP 12
#define LCD_POL_FLAGS kLCDC_InvertVsyncPolarity | kLCDC_InvertHsyncPolarity
#define LCD_INPUT_CLK_FREQ CLOCK_GetFreq(kCLOCK_LCD)
#define LCD_WIDTH 480
#define LCD_HEIGHT 272
#define LCD_BITS_PER_PIXEL 16

/* Work memory for emWin */
#define GUI_NUMBYTES 0x20000
#define GUI_MEMORY_ADDR (SDRAM_BASE_ADDR)

/* Display framebuffer */
#define GUI_BUFFERS 2
#define VRAM_ADDR (GUI_MEMORY_ADDR + GUI_NUMBYTES)
#define VRAM_SIZE (LCD_HEIGHT * LCD_WIDTH * LCD_BITS_PER_PIXEL / 8)

#define CTIMER CTIMER3 /* Timer 3 */
#define CTIMER_MAT0_OUT kCTIMER_Match_0 /* Match output 0 */
#define CTIMER_MAT1_OUT kCTIMER_Match_1 /* Match output 1 */
#define BUS_CLK_FREQ CLOCK_GetFreq(kCLOCK_BusClk)

#define APP_BOARD_TEST_GPIO_PORT1 BOARD_LED3_GPIO_PORT
#define APP_BOARD_TEST_GPIO_PORT2 BOARD_LED1_GPIO_PORT
#define APP_BOARD_TEST_GPIO_PORT3 BOARD_LED2_GPIO_PORT
#define APP_BOARD_TEST_LED1_PIN BOARD_LED3_GPIO_PIN
#define APP_BOARD_TEST_LED2_PIN BOARD_LED1_GPIO_PIN
#define APP_BOARD_TEST_LED3_PIN BOARD_LED2_GPIO_PIN
#define APP_SW1_PORT BOARD_SW4_GPIO_PORT
#define APP_SW2_PORT BOARD_SW2_GPIO_PORT
#define APP_SW1_PIN BOARD_SW4_GPIO_PIN
#define APP_SW2_PIN BOARD_SW2_GPIO_PIN

/*******************************************************************************
* Prototypes
******************************************************************************/

/*******************************************************************************
* Variables
******************************************************************************/
/* Match Configuration for Channel 0 */
static ctimer_match_config_t matchConfig0;
/* Match Configuration for Channel 1 */
static ctimer_match_config_t matchConfig1;

#define CLEAR_BUTTON_ID (GUI_ID_BUTTON0)

#define COLOR_BUTTONS 8
#define COLOR_BUTTON_FIRST_ID (GUI_ID_USER)
#define COLOR_BUTTON_LAST_ID (COLOR_BUTTON_FIRST_ID + COLOR_BUTTONS - 1)

static GUI_COLOR button_color[COLOR_BUTTONS] = {GUI_WHITE, GUI_YELLOW, GUI_ORANGE, GUI_BLACK,
GUI_MAGENTA, GUI_BLUE, GUI_GREEN, GUI_RED};

void ctimer_match1_callback(uint32_t flags);
void ctimer_match0_callback(uint32_t flags);
/* Array of function pointers for callback for each channel */
ctimer_callback_t ctimer_callback_table[] = {
ctimer_match0_callback, ctimer_match1_callback, NULL, NULL, NULL, NULL, NULL, NULL};
/*******************************************************************************
* Code
******************************************************************************/
status_t SDRAM_DataBusCheck(volatile uint32_t *address)
{
uint32_t data = 0;

/* Write the walking 1's data test. */
for (data = 1; data != 0; data <<= 1)
{
*address = data;

/* Read the data out of the address and check. */
if (*address != data)
{
return kStatus_Fail;
}
}
return kStatus_Success;
}

status_t SDRAM_AddressBusCheck(volatile uint32_t *address, uint32_t bytes)
{
uint32_t pattern = 0x55555555;
uint32_t size = bytes / 4;
uint32_t offset;
uint32_t checkOffset;

/* write the pattern to the power-of-two address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = pattern;
}
address[0] = ~pattern;

/* Read and check. */
for (offset = 1; offset < size; offset <<= 1)
{
if (address[offset] != pattern)
{
return kStatus_Fail;
}
}

if (address[0] != ~pattern)
{
return kStatus_Fail;
}

/* Change the data to the revert one address each time
* and check there is no effect to other address. */
for (offset = 1; offset < size; offset <<= 1)
{
address[offset] = ~pattern;
for (checkOffset = 1; checkOffset < size; checkOffset <<= 1)
{
if ((checkOffset != offset) && (address[checkOffset] != pattern))
{
return kStatus_Fail;
}
}
address[offset] = pattern;
}
return kStatus_Success;
}

void ctimer_match1_callback(uint32_t flags)
{
GPIO_TogglePinsOutput(GPIO, APP_BOARD_TEST_GPIO_PORT1, 1u << APP_BOARD_TEST_LED1_PIN);
Scheduled_Tasks();

}

void ctimer_match0_callback(uint32_t flags)
{


}


void BOARD_InitPWM(void)
{
sctimer_config_t config;
sctimer_pwm_signal_param_t pwmParam;
uint32_t event;

CLOCK_AttachClk(kMCLK_to_SCT_CLK);

CLOCK_SetClkDiv(kCLOCK_DivSctClk, 2, true);

SCTIMER_GetDefaultConfig(&config);

SCTIMER_Init(SCT0, &config);

pwmParam.output = kSCTIMER_Out_5;
pwmParam.level = kSCTIMER_HighTrue;
pwmParam.dutyCyclePercent = 5;

SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 1000U, CLOCK_GetFreq(kCLOCK_Sct), &event);
}


static void cbBackgroundWin(WM_MESSAGE *pMsg)
{
int widget_id;

switch (pMsg->MsgId)
{
case WM_NOTIFY_PARENT:
widget_id = WM_GetId(pMsg->hWinSrc);
if (widget_id >= COLOR_BUTTON_FIRST_ID && widget_id <= COLOR_BUTTON_LAST_ID)
{
GUI_SetColor(button_color[widget_id - COLOR_BUTTON_FIRST_ID]);
}
else if (widget_id == CLEAR_BUTTON_ID && pMsg->Data.v == WM_NOTIFICATION_CLICKED)
{
GUI_Clear();
}
break;
default:
WM_DefaultProc(pMsg);
}
}

void drawpixel (int x,int y,int color){
// GUI_SetColor (color);
// LCD_HL_DrawPixel(x, y);

char* adres;
int temp_color = 0;
temp_color = ((color & 0xf800) >> 11) | ((color & 0x001f) << 11) | ((color & 0x07e0)) ;
adres=VRAM_ADDR;
adres[(x + y*480)*2]=temp_color&0x000000ff;
adres[(x + y*480)*2+1]=(temp_color&0x0000ff00)>>8;
}

int main(void)
{

gpio_pin_config_t led_config = {
kGPIO_DigitalOutput, 0,
};


ctimer_config_t config;
/* Board pin, clock, debug console init */
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

/* Route Main clock to LCD. */
CLOCK_AttachClk(kMCLK_to_LCD_CLK);

/* attach 12 MHz clock to FLEXCOMM2 (I2C master for touch controller) */
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2);

CLOCK_EnableClock(kCLOCK_Gpio2);

CLOCK_SetClkDiv(kCLOCK_DivLcdClk, 1, true);

BOARD_InitPins();
BOARD_BootClockFROHF96M();//BOARD_BootClockPLL220M();
BOARD_InitDebugConsole();
BOARD_InitSDRAM();

/* Set the back light PWM. */
BOARD_InitPWM();


CTIMER_GetDefaultConfig(&config);

CTIMER_Init(CTIMER, &config);

/* Configuration 0 */
matchConfig0.enableCounterReset = true;
matchConfig0.enableCounterStop = false;
matchConfig0.matchValue = BUS_CLK_FREQ / 10;
matchConfig0.outControl = kCTIMER_Output_Toggle;
matchConfig0.outPinInitState = false;
matchConfig0.enableInterrupt = true;

/* Configuration 1 */
matchConfig1.enableCounterReset = true;
matchConfig1.enableCounterStop = false;
matchConfig1.matchValue = BUS_CLK_FREQ / 1000;
matchConfig1.outControl = kCTIMER_Output_Toggle;
matchConfig1.outPinInitState = true;
matchConfig1.enableInterrupt = true;

CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
CTIMER_SetupMatch(CTIMER, CTIMER_MAT0_OUT, &matchConfig0);
CTIMER_SetupMatch(CTIMER, CTIMER_MAT1_OUT, &matchConfig1);
CTIMER_StartTimer(CTIMER);


GPIO_PinInit(GPIO, APP_BOARD_TEST_GPIO_PORT1, APP_BOARD_TEST_LED1_PIN, &led_config);
GPIO_WritePinOutput(GPIO, APP_BOARD_TEST_GPIO_PORT1, APP_BOARD_TEST_LED1_PIN, 1);

/* emWin start */
GUI_Init();

/* Set size and default color for the background window */
WM_SetSize(WM_HBKWIN, LCD_WIDTH, LCD_HEIGHT);
WM_SetDesktopColor(GUI_BLUE);

/* Set callback for the backgroung window */
WM_SetCallback(WM_HBKWIN, cbBackgroundWin);


GUI_Clear();


Tasks();

}

0 Kudos

1,404 Views
bernhardfink
NXP Employee
NXP Employee

You don't specify the emWin frame buffer base address somewhere in the MCUXpresso environment, it's done somewhere in the source code.

I'm not fully up-to-date with emWin, but in the past for LPC4300 you had it like this:

In LCDConf.c:

There is this define

#define VRAM_ADDR  0x28000000

Later on the pointer to this base address is set with this function call

LCD_SetVRAMAddrEx(0, (void *)VRAM_ADDR);

In your example I see this:

#define SDRAM_BASE_ADDR 0xa0000000

:

/* Work memory for emWin */
#define GUI_NUMBYTES 0x20000
#define GUI_MEMORY_ADDR (SDRAM_BASE_ADDR)

 

/* Display framebuffer */
#define GUI_BUFFERS 2
#define VRAM_ADDR (GUI_MEMORY_ADDR + GUI_NUMBYTES)

And or sure there is somewhere a pointer definition like above (something with (void *) ) which defines the pointer to the frame buffer base address in SDRAM.

Next thing: your debug problem. In a first step it's not a debug problem, it's a setup problem.

Think about if the SDRAM is already up and running (= initialized) when the system tries to use it. With your linker map you instructed the linker to put all variables into the external SDRAM. This means that all variables right from the beginning of C code are located in external SDRAM. Again, are you sure that at this point in time the SDRAM is already initialized??

Regards,

Bernhard.

0 Kudos

1,404 Views
fatihozen
Contributor IV

Hi Bernhard,

Yes there is a buffer and it is the same as yours. it is in board>emwin_support.c.
There is a function void LCD_X_Config(void). and this pointer is called in this function. and It gives an error when I write attribute macro.

void LCD_X_Config(void)
{
status_t status;

GUI_MULTIBUF_Config(GUI_BUFFERS);
GUI_DEVICE_CreateAndLink(GUIDRV_LIN_16, GUICC_565, 0, 0);

LCD_SetSizeEx(0, LCD_WIDTH, LCD_HEIGHT);
LCD_SetVSizeEx(0, LCD_WIDTH, LCD_HEIGHT);

LCD_SetVRAMAddrEx(0, (void *)VRAM_ADDR);
/* Initialize touch panel controller */
status = APP_Touch_Init();
assert(status == kStatus_Success);

/* Initialize LCD controller */
status = APP_LCDC_Init();
assert(status == kStatus_Success);
}


I don't know how to initialize SDRAM before all these points.

0 Kudos

1,404 Views
bernhardfink
NXP Employee
NXP Employee

After this function

BOARD_InitSDRAM();

the SDRAM should be accessible. So if you set a breakpoint somewhere after this function, then you should be able to look into memory addresses located in the SDRAM.

The emWin setup takes place after this SDRAM initialization, so it should work.

Regards,

Bernhard.

0 Kudos

1,404 Views
fatihozen
Contributor IV

I think there is a problem on SDRAM initializing. I got en error when I want to debug the project : 
"Debug port inaccessable after access at location 0xA0000000

Beside all I want to move all data to external sdram. I don't want any data in Flash and internal Sram.

pastedImage_1.png

I moved datas from flash to internal ram by activating Link application to RAM box. Project>Properties>C/C++ Build>Settings>Tool Settings>MCU Linker>Managed Linker Script.

0 Kudos

1,404 Views
bernhardfink
NXP Employee
NXP Employee

To be honest with you, I think you're missing quite some fundamentals when it comes to microcontroller software design. Take a sheet of paper, sit down and try to reproduce what the ARM Cortex-M4 is doing when it catches the very first instruction from the reset handler, located in the Flash boot memory.

Try to find out what happens when, especially the relocation of code. For example if you want your object main.o, which is the compiled version of main.c, to be in SDRAM, try to see when this copy from flash to SDRAM is done and if at this point in time the SDRAM has alread been initialized.

Same story for the debugger: if you instruct the debugger to do something with the SDRAM, make sure that the SDRAM has already been initialized.

The following links contain some information about this:

Placing specific functions into RAM blocks 

Relocating code from FLASH to RAM 

Using your own linker scripts 

There are many more papers when you search for keywords like "placing functions in RAM" or "relocate code into SDRAM"

0 Kudos

1,404 Views
brendonslade
NXP TechSupport
NXP TechSupport

Hi Fatih,

looks like your issue is actually one of knowing how to set up the linker to specify SDRAM. The SDK includes an example for use of the SDRAM, so I suggest you take a look at that... you can find it here: <INSTALL DIRECTORY>\boards\lpcxpresso54628\driver_examples\emc or just add the emc\sdram example using "Add example from SDK" in the Quickstart panel if using MCUXpresso IDE.

regards,

Brendon

0 Kudos

1,404 Views
fatihozen
Contributor IV

Hi Brendon,

Thank you so much for reply to this basic question rapidly but I also did what you said. As you see in picture I shared on first post, I have imported SDK example and built it. I am talking about step after all these. I thougt I see some used size in BOARD_SDRAM but I didn't. My problem is not how sdk examples work on MCUXpresso IDE. I want to use external SDram and want to see it when I build the emc/sdram example. Any other suggestion ?

Best regards,
Fatih

0 Kudos

1,404 Views
brendonslade
NXP TechSupport
NXP TechSupport

Hi Fatih,

This app note / example shows how a frame buffer in SDRAM is used. Its built on SDK drivers ... maybe this can give you a few pointers to get started.

https://www.nxp.com/docs/en/application-note/TN00015.zip 

As Bernhard states, my comments were a little misleading and his description is more accurate. The SDRAM example in the SDK is more about showing how to use the sdram/emc driver. The example in this app note is more about real usage of a buffer in that location. However, it is possible to use the SDRAM without it appearing in the output of your build; if you arent defining variables or executable code to be resident there.

regards

Brendon

0 Kudos

1,404 Views
bernhardfink
NXP Employee
NXP Employee

I didn't look into the example, but as it is an example for SDRAM, I assume it is used somehow. So my best guess is:

If you write program code, you can declare variables, arrays etc and let the linker allocate memory for it. In this example it seems that the first memory for the linker is the internal SRAM. In case the external SDRAM is available for the linker as allocatable memory, it would use it when it's running out of internal SRAM or if a structure is too big to fit into the (remaining) internal SRAM.

Most likley in this example a buffer structure (for example a display frame buffer) is hardcoded to be in external SDRAM, so it's not up to the linker to decide where to place the buffer, it has been decided by the programmer. In this case it does not appear in this linker memory map, simply because it has not been allocated by the linker.

But it will for sure appear in the overall map file as memory area in the external SDRAM

Regards,

Bernhard.