Problems encountered when debugging nandflash bare metal program on s3c2440

Publisher:科技创新实践者Latest update time:2024-08-01 Source: cnblogsKeywords:s3c2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

According to the previous sdram code, the startup code turns off the watchdog, initializes the storage controller (mainly Norflash of BANK0 and SDRAM of BANK6), sets the stack to the highest address of SDRAM, and takes the data of the text segment directly from Norflash.



The code is as follows:

head.S


@*************************************************************************

@ File:head.S

@ Function: Set up SDRAM, set the stack to SDRAM, and then continue execution

@*************************************************************************

.equMEM_CTL_BASE,   0x48000000

.equSDRAM_BASE, 0x30000000

.text

.global _start

_start:

b reset

reset:

bl disable_watch_dog @ Disable WATCHDOG, otherwise the CPU will restart continuously

bl memsetup@ Set up the memory controller

ldr sp, =0x34000000 @ Set up the stack

bl  main

halt_loop:

b    halt_loop

disable_watch_dog:

@ Write 0 to the WATCHDOG register

move r1, #0x53000000

mov r2, #0x0

str r2, [r1]

mov pc, lr @ return

memsetup:

@ Set up the memory controller to use peripherals such as SDRAM

mov r1, #MEM_CTL_BASE @ The starting address of the 13 registers of the storage controller

adrlr2, mem_cfg_val @ The starting storage address of these 13 values

add r3, r1, #52 @ 13*4 = 54

@ Write the memory control unit's SDRAM initialization parameters to the registers in sequence

str_loop:

ldr r4, [r2], #4@ Read the setting value and add 4 to r2

str r4, [r1], #4@ Write this value to the register and add 4 to r1

cmp r1, r3 @ Determine whether all 13 registers have been set

bne str_loop@ If not written, continue

mov pc, lr @ return

.align 4

mem_cfg_val:

@ Storage controller 13 register settings

.long   0x22011110  @ BWSCON

.long 0x00000700 @ BANKCON0

.long 0x00000700 @ BANKCON1

.long 0x00000700 @ BANKCON2

.long 0x00000700 @ BANKCON3

.long   0x00000700  @ BANKCON4

.long 0x00000700 @ BANKCON5

.long   0x00018005  @ BANKCON6

.long   0x00018005  @ BANKCON7

.long   0x008C07A3  @ REFRESH

.long 0x000000B1 @ BANKSIZE

.long   0x00000030  @ MRSRB6

.long   0x00000030  @ MRSRB7

nand.c


#define LARGER_NAND_PAGE

#define GSTATUS1        (*(volatile unsigned int *)0x560000B0)

#define BUSY            1

#define NAND_SECTOR_SIZE    512

#define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)

#define NAND_SECTOR_SIZE_LP    2048

#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

typedef unsigned int S3C24X0_REG32;

/* NAND FLASH (see S3C2410 manual chapter 6) */

typedef struct {

S3C24X0_REG32   NFCONF;

S3C24X0_REG32   NFCMD;

S3C24X0_REG32   NFADDR;

S3C24X0_REG32   NFDATA;

S3C24X0_REG32   NFSTAT;

S3C24X0_REG32   NFECC;

} S3C2410_NAND;

/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */

typedef struct {

S3C24X0_REG32   NFCONF;

S3C24X0_REG32   NFCONT;

S3C24X0_REG32   NFCMD;

S3C24X0_REG32   NFADDR;

S3C24X0_REG32   NFDATA;

S3C24X0_REG32   NFMECCD0;

S3C24X0_REG32   NFMECCD1;

S3C24X0_REG32   NFSECCD;

S3C24X0_REG32   NFSTAT;

S3C24X0_REG32   NFESTAT0;

S3C24X0_REG32   NFESTAT1;

S3C24X0_REG32   NFMECC0;

S3C24X0_REG32   NFMECC1;

S3C24X0_REG32   NFSECC;

S3C24X0_REG32   NFSBLK;

S3C24X0_REG32   NFEBLK;

} S3C2440_NAND;

typedef struct {

void (*nand_reset)(void);

void (*wait_idle)(void);

void (*nand_select_chip)(void);

void (*nand_deselect_chip)(void);

void (*write_cmd)(int cmd);

void (*write_addr)(unsigned int addr);

unsigned char (*read_data)(void);

}t_nand_chip;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

static t_nand_chip nand_chip;

/* Function for external calls*/

void nand_init(void);

void nand_read(unsigned char *buf, unsigned long start_addr, int size);

/* The total entry for NAND Flash operations, which will call the corresponding functions of S3C2440*/

static void nand_reset(void);

static void wait_idle(void);

static void nand_select_chip(void);

static void nand_deselect_chip(void);

static void write_cmd(int cmd);

static void write_addr(unsigned int addr);

static unsigned char read_data(void);

/* S3C2440 NAND Flash processing function*/

static void s3c2440_nand_reset(void);

static void s3c2440_wait_idle(void);

static void s3c2440_nand_select_chip(void);

static void s3c2440_nand_deselect_chip(void);

static void s3c2440_write_cmd(int cmd);

static void s3c2440_write_addr(unsigned int addr);

static unsigned char s3c2440_read_data(void);

/* S3C2440 NAND Flash operation function*/

/* Reset */

static void s3c2440_nand_reset(void)

{

s3c2440_nand_select_chip();

s3c2440_write_cmd(0xff); // reset command

s3c2440_wait_idle();

s3c2440_nand_deselect_chip();

}

/* Wait for NAND Flash to be ready */

static void s3c2440_wait_idle(void)

{

int i;

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

while(!(*p & BUSY))

for(i=0; i<10; i++);

}

/* Send chip select signal */

static void s3c2440_nand_select_chip(void)

{

int i;

s3c2440nand->NFCONT &= ~(1<<1);

for(i=0; i<10; i++);

}

/* Cancel chip select signal*/

static void s3c2440_nand_deselect_chip(void)

{

s3c2440nand->NFCONT |= (1<<1);

}

/* Issue a command */

static void s3c2440_write_cmd(int cmd)

{

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;

*p = cmd;

}

/* Sending address */

static void s3c2440_write_addr(unsigned int addr)

{

int i;

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

*p = addr & 0xff;

for(i=0; i<10; i++);

*p = (addr >> 9) & 0xff;

for(i=0; i<10; i++);

*p = (addr >> 17) & 0xff;

for(i=0; i<10; i++);

*p = (addr >> 25) & 0xff;

for(i=0; i<10; i++);

}

static void s3c2440_write_addr_lp(unsigned int addr)

{

int i;

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

int col, page;

col = addr & NAND_BLOCK_MASK_LP;

page = addr / NAND_SECTOR_SIZE_LP;

*p = col & 0xff; /* Column Address A0~A7 */

for(i=0; i<10; i++);

*p = (col >> 8) & 0x0f; /* Column Address A8~A11 */

for(i=0; i<10; i++);

*p = page & 0xff; /* Row Address A12~A19 */

for(i=0; i<10; i++);

*p = (page >> 8) & 0xff; /* Row Address A20~A27 */

for(i=0; i<10; i++);

*p = (page >> 16) & 0x03; /* Row Address A28~A29 */

for(i=0; i<10; i++);

}

/* Read data */

static unsigned char s3c2440_read_data(void)

{

volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;

return *p;

}

/* Reset NAND Flash before using it for the first time */

static void nand_reset(void)

{

nand_chip.nand_reset();

}

static void wait_idle(void)

{

nand_chip.wait_idle();

}

static void nand_select_chip(void)

{

int i;

nand_chip.nand_select_chip();

for(i=0; i<10; i++);

}

static void nand_deselect_chip(void)

{

nand_chip.nand_deselect_chip();

}

static void write_cmd(int cmd)

{

nand_chip.write_cmd(cmd);

}

static void write_addr(unsigned int addr)

{

nand_chip.write_addr(addr);

}

static unsigned char read_data(void)

{

return nand_chip.read_data();

}

/* Initialize NAND Flash */

void nand_init(void)

{

#define TACLS   0

#define TWRPH0  3

#define TWRPH1  0

nand_chip.nand_reset         = s3c2440_nand_reset;

nand_chip.wait_idle          = s3c2440_wait_idle;

nand_chip.nand_select_chip   = s3c2440_nand_select_chip;

nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;

nand_chip.write_cmd          = s3c2440_write_cmd;

#ifdef LARGER_NAND_PAGE

nand_chip.write_addr         = s3c2440_write_addr_lp;

#else

nand_chip.write_addr = s3c2440_write_addr;

#endif

nand_chip.read_data          = s3c2440_read_data;

/* Set timing */

s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

/* Enable NAND Flash controller, initialize ECC, disable chip select*/

s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

/* Reset NAND Flash */

nand_reset();

}

/* Read function */

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

{

int i, j;

#ifdef LARGER_NAND_PAGE

if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {

return ; /* Address or length is not aligned */

}

#else

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

return ; /* Address or length is not aligned */

}

#endif

/* Select chip */

nand_select_chip();

for(i=start_addr; i < (start_addr + size);) {

/* Issue READ0 command */

write_cmd(0);

/* Write Address */

write_addr(i);

#ifdef LARGER_NAND_PAGE

write_cmd(0x30);

#endif

wait_idle();

#ifdef LARGER_NAND_PAGE

for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {

#else

for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

#endif

*buf = read_data();

buf++;

}

}

/* Cancel chip select signal*/

nand_deselect_chip();

return ;

}

int main(void)

{

unsigned int buffer;

unsigned long nandPtr = 0x00000000;

nand_init();

while(1)

{

nand_read((unsigned char *)&buffer, nandPtr, 4);

nandPtr = nandPtr + 4;

}

return 0;

}

Makefile


CROSS_TOOLCHAIN := arm-linux

nand.bin : head.S  nand.c

$(CROSS_TOOLCHAIN)-gcc -g -nostdlib -c -o head.o head.S

$(CROSS_TOOLCHAIN)-gcc -g -nostdlib -c -o nand.o nand.c

$(CROSS_TOOLCHAIN)-ld -Ttext 0x00000000 head.o nand.o -o nand_elf

$(CROSS_TOOLCHAIN)-objcopy -O binary -S nand_elf nand.bin

[1] [2]
Keywords:s3c2440 Reference address:Problems encountered when debugging nandflash bare metal program on s3c2440

Previous article:About the use of 128M memory in ARM9 S3C2440 wince6.0
Next article:Embedded bare-metal development using the GNU toolchain

Recommended ReadingLatest update time:2024-11-15 07:32

s3c2440 Learning Road-011 Code Relocation
1 Basic principles Following the last blog s3c2440 learning path-010 sdram, sdram has been initialized, and now the value of SDRAM can be officially brought into play. (SDRAM can be read and written at will, and the subsequent codes will be placed on it to run) 1.1 Division of program segments After a program is com
[Microcontroller]
s3c2440 Learning Road-011 Code Relocation
S3C2440 bare metal -------I2C_S3C2440 I2C controller control timing
1. Register The I2C of S3C2440 is mainly controlled by the following four registers.  2. Data transmission process  
[Microcontroller]
S3C2440 bare metal -------I2C_S3C2440 I2C controller control timing
Understanding of S3C2440 clock settings
Understanding of S3C2440 clock settings 1) Relationship between FLCK, HCLK and PCLK S3C2440 has three clocks: FLCK, HCLK and PCLK The manual says P7-8: FCLK is used by ARM920T, core clock, main frequency. HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, the interrupt controller, t
[Microcontroller]
Understanding of S3C2440 clock settings
S3c2440 bus frequency and clock settings in LINUX
The normal operation of many hardware requires the support of bus clock, such as LCD, I2C and other devices. This article analyzes the bus clock of s3c2440 and the related operations of s3c2440 bus clock frequency in Linux. First, analyze the bus clock of hardware s3c2440. 1. FCLK HCLK PCLK of s3c2440: The clock s
[Microcontroller]
Samsung S3C2440 GPIO output driver LED
From today on, stm32 has come to an end, and I have started to learn Samsung's S3C2440 with ARM920T architecture. Today is the first day of learning, and I feel that it is much more difficult than STM32, mainly because it gives me a headache when it comes to the operating system. It's the same as the steps when learni
[Microcontroller]
S3C2440 Driver - Linux Platform Device Driver
In device drivers, you often see fields related to platform, which are distributed in many corners of the driver. This is also a relatively important mechanism in the 2.6 kernel. Understanding its principle is very helpful for analyzing drivers in the future: In the Linux 2.6 device model, the three entities of bus,
[Microcontroller]
S3c2440 I2C driver and test program trace cross analysis
VMware virtual machine + Fedora10, hardware platform TQ2440, kernel 2.6.30.4 Recently I learned about the linux I2C driver and used teacher Liu Hongtao's test program to test the kernel's built-in driver. After turning on the debugging statement dev_dbg (refer to my other blog for details), I found that the driver cor
[Microcontroller]
Application of s3c2440 watchdog timer
The main function of the watchdog timer is to reset the system after the program runs away due to interference, so as not to make the system die forever.   Its principle is not much different from that of a general timer, that is, you need to set a period of time first, and when this period of time is exceeded, it wi
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号