Hi,
i've modified i.MX28 On-Board Diagnostics Suite (OBDS) 1.0 to run on a custom hardware (still i.MX28 + USB but without SD card slot).
After that i generated the mx28-obds.sb file with tools/linux/build_mx28.sh and modified the XML of the Mfgtool:
<UCL>
<CFG>
<STATE name="Recovery" dev="IMX28"/>
<STATE name="Updater" dev="Updater" />
<DEV name="IMX28" vid="15A2" pid="004F"/>
<DEV name="Updater" vid="066F" pid="37FF" />
</CFG>
<LIST name="Custom img" desc="Start OBDS">
<CMD type="boot" body="Recovery" file="mx28-obds.sb" >Start OBDS</CMD>
</LIST>
</UCL>
If i run the MfgTool, the custom hardware only prints
HTLLCL
But if i try the original updater_ivt.sb with MfgTool, everything is fine. So i think the mx28-obds.sb has the wrong format.
Here is the content of the bd file:
options {
driveTag = 0x00;
flags = 0x01;
}
constants {
IVT_ADDR = 0x70;
LOAD_ADDR = 0x100;
ENTRY_ADDR = 0x40800000;
}
sources {
ipl = "../../output/mx28/bin/ipl";
obds = "../../output/mx28/bin/diag-obds-mx28evk.bin";
}
section (0) {
load ipl > LOAD_ADDR;
load ivt (entry=LOAD_ADDR) > IVT_ADDR;
hab call IVT_ADDR;
load obds > ENTRY_ADDR;
load ivt (entry=ENTRY_ADDR) > IVT_ADDR;
hab jump IVT_ADDR;
}
How can i generate a sb file which works like a bare metal application in internal i.MX28 RAM?
Do i need to change the bd file?
Stefan,
since you want to make a memory test, take a look on the mem_test that Yuri posted on my thread i.MX28 DDR stress test.
The .sb file on the mem_test loaded on my board, but the processor freezes after power initialization.
I changed the power initialization code to (kind of) match the power_prep bootlet with NO_DCDC_BATT_SOURCE defined (my board is running from an external power supply with no battery). Now the code runs on my board and catches some errors if I increase the EMI frequency.
You can apply the patch attached to the mem_test code that Yuri posted and try it if you want.
You will need windows with the arm-none-eabi-gcc from CodeSourcery (Mentor) and make to compile the code. I use Windows XP 32 bits on VirtualBox to do it.
It should be as simple as that:
>make
>usb_load.bat
You may change the DDR2 memory parameters on the main file to match the PN you're using.
Hello Fernando,
thank you very much. I'll try it, if i've got more time.
BR Stefan
Hi Stefan,
Both the link file mx28.ld and bd file show the diag-obds-mx28evk.bin is loaded to address 0x40800000 which is SDRAM.
If you want to load to IRAM, you need modify mx28.ld and bd.
Grace
Hi Grace,
you are right. I thought the obds runs completly in OCRAM, but that's impossible because the binary is too big.
First i reduced the size of the binary to 67 kb by removing all unnecessary drivers. After that i tried many settings ( ENTRY_ADDR = 0, 0x200, 0x4000 or 0x8000) but the results are worse. I got the message "Pref" or "Undefined Ins" without any errorcode.
Hi Yuri,
I tried your standalone LED program to test the board is working or not using internal SRAM. When using the sb_loader to send the test.sb file to board there is error during download but in board, i can see the blinking of LED and print message in Hyperterminal. The log information for your reference.
D:\sharelinux\LED>sb_loader.exe -f test.sb
Downloading test.sb to device.
.. CStHidDevice::Download() Error(258) during read.
Quitting.
Error(258) during download.
Quitting.
Can you give me an idea to test the SDRAM. I modified your code and cross compiled to test the SDRAM but it ends with error as follows
pause
DDR2 Test Starting
Writing
Bank Selection done
Writing 0
0x8020a014
Test program to test DDR
!
#include "stdio.h"
#include "hardware.h" /* note, this is where the SoC specific header file is included */
#define TXFE 0x0080
#define R32 volatile unsigned long *
#define R16 volatile unsigned short *
#define R8 volatile unsigned char *
#define PARAM_DDR_TEST_DENSITY (128 * 1024 * 1024)
#define PARAM_DDR_TEST_CS_NR 1
#define HW_UARTDBG_FR (*(R32)(0x80074018)) // UART Flag Register
#define HW_UARTDBG_DR (*(R32)(0x80074000)) // UART Data Register
#define HW_PWM_CTRL (*(R32)(0x80064000))
#define HW_PWM_ACTIVE0 (*(R32)(HW_PWM_CTRL + 0x10))
#define HW_PWM_PERIOD0 (*(R32)(HW_PWM_CTRL + 0x20))
#define HW_PWM_ACTIVE1 (*(R32)(HW_PWM_CTRL + 0x30))
#define HW_PWM_PERIOD1 (*(R32)(HW_PWM_CTRL + 0x40))
#define PINCTRL_MUXSEL6 (*(R32)(0x80018160))
#define PINCTRL_MUXSEL7 (*(R32)(0x80018170))
#define PINCTRL_MUXSEL7_SET (*(R32)(0x80018174))
#define PINCTRL_DOE3 (*(R32)(0x80018B30))
#define PINCTRL_DOUT3 (*(R32)(0x80018730))
void pwm1_init(U32 bright)
{
HW_PWM_CTRL = 0 ; //disable pwm 1
HW_PWM_ACTIVE1 = (bright<<16) & 0x01FF0000 ; // set pwm 1 0<bright<0x200
HW_PWM_PERIOD1 = 0x5B0200; // set pwm 1
HW_PWM_CTRL = 0x2 ; //enable pwm 1
}
void pause(int time)
{
volatile int i ;
while (time--) i = time ;
}
void outbyte(int c)
{
while( !(HW_UARTDBG_FR & TXFE) );
HW_UARTDBG_DR = c ;
}
int ddr_test(u32 density, u32 number_of_cs)
{
unsigned int failCount = 0;
unsigned int i;
unsigned int mem_src;
unsigned int *ps;
int bank_size = density / 8;
/* Data bus, walking ones test */
/* Looking for shorts on the board, so no need to test both chip selects */
printf("\n\rWriting \n\r");
/* First, write walking ones to DDR memory */
ps = (unsigned int *)(CSD0_BASE_ADDR + bank_size * 4);
printf("\n\r Bank Selection done \n\r");
for (i = 0; i <= 31; i++) {
printf("\n\r Writing %d \n\r",i);
*ps = 0x1 << i;
ps++;
}
printf("\n\r Reading \n\r");
/* Now, read-verify the memory */
ps = (unsigned int *)(CSD0_BASE_ADDR + bank_size * 4);
for (i = 0; i <= 31; i++) {
if (*ps != (0x1 << i)) {
failCount++;
}
ps++;
}
/* BANK ADDRESS test */
/* CS0 bank address test - note since code is stored in first part of DDR in CSD0
do not write data to the first bank to avoid overwriting code.
Hence variable "i" starts at 1 not 0 */
/* First, write data to each bank */
for (i = 1; i <= 7; i++) {
ps = (unsigned int *)(CSD0_BASE_ADDR + bank_size * i);
*ps = 0x11111111 * i;
}
/* Second, read back data from each bank to verify */
for (i = 1; i <= 7; i++) {
ps = (unsigned int *)(CSD0_BASE_ADDR + bank_size * i);
if (*ps != 0x11111111 * i) {
failCount++;
}
}
if (number_of_cs == 2) {
/* CS1 bank address test */
/* First, write data to each bank */
for (i = 0; i <= 7; i++) {
ps = (unsigned int *)(CSD1_BASE_ADDR + bank_size * i);
*ps = 0x88888888 + 0x11111111 * i;
}
/* Second, read back data from each bank to verify */
for (i = 0; i <= 7; i++) {
ps = (unsigned int *)(CSD1_BASE_ADDR + bank_size * i);
if (*ps != (0x88888888 + 0x11111111 * i)) {
failCount++;
}
}
}
/* DDR ADDRESS test, test the last two banks for each chip select */
/* CS0 */
/* First, write data to each row */
mem_src = CSD0_BASE_ADDR + bank_size * 6;
for (i = 0; i < bank_size * 2; i = i + 512) {
ps = (unsigned int *)(mem_src + i);
*ps = 0x12345678 + 0x11111111 * i;
}
/* Second, read back data from each row to verify */
mem_src = CSD0_BASE_ADDR + bank_size * 6;
for (i = 0; i < bank_size * 2; i = i + 512) {
ps = (unsigned int *)(mem_src + i);
if (*ps != (0x12345678 + 0x11111111 * i)) {
failCount++;
}
}
if (number_of_cs == 2) {
/* CS1 */
/* First, write data to each row */
mem_src = CSD1_BASE_ADDR + bank_size * 6;
for (i = 0; i < bank_size * 2; i = i + 512) {
ps = (unsigned int *)(mem_src + i);
*ps = 0x87654321 + 0x11111111 * i;
}
/* Second, read back data from each row to verify */
mem_src = CSD1_BASE_ADDR + bank_size * 6;
for (i = 0; i < bank_size * 2; i = i + 512) {
ps = (unsigned int *)(mem_src + i);
if (*ps != (0x87654321 + 0x11111111 * i)) {
failCount++;
}
}
}
if (failCount == 0) {
printf(" DDR test passed \n");
return 1;
} else {
printf(" DDR test failed \n");
return 0;
}
}
int main ()
{
printf("pause \n\r");
pause (100);
printf("DDR2 Test Starting\n\r");
pause (100);
ddr_test(PARAM_DDR_TEST_DENSITY, PARAM_DDR_TEST_CS_NR);
printf("DDR Test Finished\n\r");
PINCTRL_DOE3 = 0x30 ;
while (1)
{
pause(2000000);
PINCTRL_DOUT3 = 0x10 ;
printf("RAM 1\n\r");
pause(2000000);
PINCTRL_DOUT3 = 0 ;
printf("test 0\n\r");
PINCTRL_DOUT3 = 0x20 ;
printf("test 1\n\r");
pause(2000000);
PINCTRL_DOUT3 = 0 ;
printf("test 0\n\r");
}
}
!
Thanks,
RAM
Hi Ram,
i see you need the same program :smileygrin:
Do you also copied the startup code (Assembler in plat_startup.h) from obds into your project? Without the SDRAM isn't initialized and accessable.
Which toolchain and version do you use?
Hi Stefan,
I haven't included the SDRAM init code from plat_startup.h. Basically what am doing is just modifying the OBDS project to test only DDR. My main aim is to test the DDR using standalone program using internal RAM.
Steps followed :
1) untar "imx_28_obds_release_v1_0.tar.gz"
2) cd \imx_28_obds_release_v1_0\201040_mx28_evk_release\src\mx28
3) vi mx28.ld
4) changed this line
-->
RAM (rwx) : ORIGIN = 0x0, LENGTH = 120K
-->
.vectors :
{
__vectors_start = .;
*o(.vectors)
__vectors_end = .;
}>RAM
5) save and exit
6) vi mx28evk_mmcsd.bd
7) changed this line
IVT_ADDR = 0x8000;
LOAD_ADDR = 0x100;
ENTRY_ADDR = 0x0;
8) save and exit
9) cd \imx_28_obds_release_v1_0\201040_mx28_evk_release\src\drivers
10) vi makefile
11) To decrease the size of SB file, modify this line "SUB_DIRS := ddr timer uart dma"
12) Delete the sub folder except ddr, timer, uart, dma
13) cd \imx_28_obds_release_v1_0\201040_mx28_evk_release
14) ./tools/linux/build_mx28.sh
15) flash the \imx_28_obds_release_v1_0\201040_mx28_evk_release\output\mx28\bin\mx28-obds.sb file using sb_loader through USB.
16) But flashing it showing an error of
LCLLJ
LLCLLJ
UndefiîHTLLCLLJ
Undefin HTLLCLLJ
Undefin HTLLCLLJ
UndefineHTLLCLLJ
HTLLCLLJ
HTLLCLLJ
I don't know the what am missing here, please suggest me to fix this issue or give some other idea to test DDR.
Thanks,
RAM
Hi Ram,
okay if you modify obds and not led example you don't need plat_startup.h.
My changes on obds are very close to yours, except:
- i removed the C file for the application uart
- i removed the static structures for test cases
- i placed the call for run_ddr_test() direct into platform_init()
But finally i get the same results as you (see reply to GraceSi). So i decided to implement the DDR test in the led example. But than comes the problem with the collision.
Here are my assumptions why it won't work with obds:
- the binary of obds is still too big and there are not enough memory for variables and stack
- the settings in mx28.ld are wrong (try to reduce LENGTH to a smaller value than 120k)
- the settings in mx28evk_mmcsd.bd are wrong (may be the ipl image overlaps obds)
Best regards
Stefan
Hi Yuri,
thanks for the application. If i compile the example with my toolchain (gcc version 4.8.3 20131129, newlib), i get some strange messages, but it seems to work:
Heap and stack collision
Heap and stack collision
pause
start
What toolchain should i use for the example?
Hi Yuri,
i changed many settings in the crt.s and MX28_ocram.ld, but i always get "Heap and stack collision" also with original LED example. Because i didn't get this message with the precompiled binary test.sb from the ZIP file, i thought the problem has something to do with my toolchain.
Do you know for which toolchain the LED example was designed for?
Hi Stefan,
I got the same error as you when I compile the LED example in my linux toolchain (https://launchpad.net/gcc-arm-embedded/+download).
If I compile with the windows version of the arm-none-eabi-gcc from CodeSourcery (Mentor) I don't get this error using these flags:
CXXFLAGS = | -Os -Wall -mcpu=arm926ej-s -march=armv5te -mfloat-abi=soft |
The -s flag don't let the code run on my board and I only get an error code on the UART: 0x8050100f.