Summary of this chapter
The current code is after 4096, and we need to control NAND Flash to read and execute them.
firtst 0x00000000 : { head.o init.o nand.o}
second 0x30000000 : AT(4096) { main.o }
firtst 0x00000000 : { head.o init.o nand.o}
second 0x30000000 : AT(4096) { main.o }
@Functions disable_watch_dog, memsetup, init_nand, nand_read_ll are defined in init.c
ldr sp, =4096 @Set up the stack
bl disable_watch_dog @offWATCH DOG
bl memsetup @ Initialize SDRAM
bl nand_init @Initialize NAND Flash
@Copy the 1024-byte code starting at address 4096 in NAND Flash (compiled from main.c) to SDRAM
The @nand_read_ll function requires 3 parameters:
ldr r0, =0x30000000 @1. Target address = 0x30000000, which is the starting address of SDRAM
mov r1, #4096 @2. Source address = 4096. When linking, the code in main.c is stored at the beginning of NAND Flash address 4096.
mov r2, #2048 @3. Copy length = 2048 (bytes), which is enough for main.c of this experiment
bl nand_read @Call C function nand_read
ldr sp, =0x34000000 @Set up the stack
ldr lr, =halt_loop @Set the return address
ldr pc, =main @b instruction and bl instruction can only jump forward and backward within the range of 32M, so here we use the method of assigning value to pc to jump
b halt_loop
ldr r0, =0x30000000 @1. Target address = 0x30000000, which is the starting address of SDRAM
mov r1, #4096 @2. Source address = 4096. When linking, the code in main.c is stored at the beginning of NAND Flash address 4096.
mov r2, #2048 @3. Copy length = 2048 (bytes), which is enough for main.c of this experiment
bl nand_read @Call C function nand_read
int i, j;
if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
return ;
}
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ;
}
nand_select_chip();
for(i=start_addr; i < (start_addr + size);) {
write_cmd(0);
write_addr(i);
write_cmd(0x30);
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = read_data();
buf++;
}
}
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFECC;
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;
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);
s3c2410_nand_select_chip();
s3c2410_write_cmd(0xff); // reset command
s3c2410_wait_idle();
s3c2410_nand_deselect_chip();
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
int i;
s3c2410nand->NFCONF &= ~(1<<11);
for(i=0; i<10; i++);
s3c2410nand->NFCONF |= (1<<11);
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD;
*p = cmd;
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->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++);
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA;
return *p;
s3c2440_nand_select_chip();
s3c2440_write_cmd(0xff); // reset command
s3c2440_wait_idle();
s3c2440_nand_deselect_chip();
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
int i;
s3c2440nand->NFCONT &= ~(1<<1);
for(i=0; i<10; i++);
s3c2440nand->NFCONT |= (1<<1);
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
*p = cmd;
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++);
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
return *p;
nand_chip.nand_reset();
nand_chip.wait_idle();
int i;
nand_chip.nand_select_chip();
for(i=0; i<10; i++);
nand_chip.nand_deselect_chip();
nand_chip.write_cmd(cmd);
nand_chip.write_addr(addr);
return nand_chip.read_data();
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
nand_chip.nand_reset = s3c2410_nand_reset;
nand_chip.wait_idle = s3c2410_wait_idle;
nand_chip.nand_select_chip = s3c2410_nand_select_chip;
nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;
nand_chip.write_cmd = s3c2410_write_cmd;
nand_chip.write_addr = s3c2410_write_addr;
nand_chip.read_data = s3c2410_read_data;
s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else
{
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;
nand_chip.write_addr = s3c2440_write_addr_lp;
nand_chip.read_data = s3c2440_read_data;
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
}
nand_reset();
int i, j;
if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
return ;
}
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ;
}
nand_select_chip();
for(i=start_addr; i < (start_addr + size);) {
write_cmd(0);
write_addr(i);
write_cmd(0x30);
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = read_data();
buf++;
}
}
nand_deselect_chip();
return ;
{
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;
nand_chip.write_addr = s3c2440_write_addr_lp;
nand_chip.read_data = s3c2440_read_data;
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
}
Keywords:ARM Nand Flash
Reference address:ARM Nand Flash Control
I personally think that the content of this chapter is too complicated. You only need to remember that if the 4096 program in nand wants to be copied and executed, just write this code in. The red part is the real code, which can be copied and used directly. I don’t need to understand the rest. After listening for an hour, the teacher’s lecture is quite confusing. No one can remember so many things. . .
【head.S init.c main.c nand.c Makefile】
Detailed explanation of the code: Here, a part of the code is stored after NAND Flash address 4096. When the program is started, it is read out and executed through the NAND Flash controller.
Note: All previous codes are less than 4096, and they are automatically copied into "Steppingstone" after the development board is started;
【nand.lds】
SECTIONS {
}
Here is how I understand it. head.o init.o nand.o are all placed at the address of Nand flash 0, 0x0000 0000 is its link address, that is, it is placed at 0x0000 0000 to run; main.o is stored at the address of Nand flash 4096, 0x3000 0000 is its link address, that is, it is placed at 0x3000 0000 to run
(This may be the difference between the link address and the load address I saw a while ago)
When the development board starts, the first 4k of code is loaded into SRAM, so we need to complete the initialization and jump in SRAM
【head.s】
SECTIONS {
} @************************************************ ****************************
@File:head.s
@ Function: Set up SDRAM, copy the program to SDRAM, and then jump to SDRAM to continue execution
@****************************************************** *****************************
.text
.global _start
_start:
halt_loop:
*For this string of codes, many of them are knowledge learned before. Here we only focus on the red code for configuring Nand.
bl nand_init
*Destination address, source address, destination length
Here we can jump to nand_read and take a look
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
#ifdef LARGER_NAND_PAGE
#else
#endif
#ifdef LARGER_NAND_PAGE
#endif
#ifdef LARGER_NAND_PAGE
#else
#endif
【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;
typedef struct {
} S3C2410_NAND;
typedef struct {
} S3C2440_NAND;
typedef struct {
}t_nand_chip;
static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
static t_nand_chip nand_chip;
void nand_init(void);
void nand_read(unsigned char *buf, unsigned long start_addr, int size);
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);
static void s3c2410_nand_reset(void);
static void s3c2410_wait_idle(void);
static void s3c2410_nand_select_chip(void);
static void s3c2410_nand_deselect_chip(void);
static void s3c2410_write_cmd(int cmd);
static void s3c2410_write_addr(unsigned int addr);
static unsigned char s3c2410_read_data();
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);
static void s3c2410_nand_reset(void)
{
}
static void s3c2410_wait_idle(void)
{
}
static void s3c2410_nand_select_chip(void)
{
}
static void s3c2410_nand_deselect_chip(void)
{
}
static void s3c2410_write_cmd(int cmd)
{
}
static void s3c2410_write_addr(unsigned int addr)
{
}
static unsigned char s3c2410_read_data(void)
{
}
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)
{
}
[page]
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;
for(i=0; i<10; i++);
*p = (col >> 8) & 0x0f;
for(i=0; i<10; i++);
*p = page & 0xff;
for(i=0; i<10; i++);
*p = (page >> 8) & 0xff;
for(i=0; i<10; i++);
*p = (page >> 16) & 0x03;
for(i=0; i<10; i++);
}
static unsigned char s3c2440_read_data(void)
{
}
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)
{
}
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#ifdef LARGER_NAND_PAGE
#else
nand_chip.write_addr = s3c2440_write_addr;
#endif
}
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
#ifdef LARGER_NAND_PAGE
#else
#endif
#ifdef LARGER_NAND_PAGE
#endif
#ifdef LARGER_NAND_PAGE
#else
#endif
}
This long string of red code is the initialization of Nand Flash. We can carefully analyze the control register of Nand.
Looking at the code again, we can jump from head.s to the gray part in nand.c;
1) A judgment between S3C2410 and S3C2440
2) Define a structure
#ifdef LARGER_NAND_PAGE
#else
nand_chip.write_addr = s3c2440_write_addr;
#endif
*The structure is defined above, and the right column contains the functions that can be called in s3c2440;
*In the setup sequence: [NFCONF] register
Enable NAND Flash controller, initialize ECC, and disable chip select: [NFCONT] register
(I think it's good to understand it. I actually went to look at the timing. The teacher didn't explain it clearly. I guess it's the default value.)
【NFCONF】
【NFCONT】
Previous article:ARM·MMU
Next article:ARM·System clock (MPLL, UPLL)
Recommended ReadingLatest update time:2024-11-17 08:50
Pi Zi Heng Embedded: ARM Cortex-M Files (2) - Link File (.icf)
In the previous lesson Source Files (.c/.h/.s), Pi Ziheng systematically introduced source files to everyone. Source files are typical input files in embedded projects. So are there other types of input files? Since Pi Ziheng asked this question, the answer must be yes. The linker file that Pi Ziheng is going to tal
[Microcontroller]
Design of ARM and Bluetooth wireless signal acquisition system
1 Introduction Wireless testing technology has a wide range of application prospects in the industrial field. In situations where the connection is complex and the connection between the device under test and the test equipment needs to be repeatedly disassembled and assembled, the use of wireless can reduce the com
[Microcontroller]
Let the ARM Cortex-M7 think for a while
With the development of the Internet of Things, the embedded processing field increasingly requires powerful mathematical computing capabilities. ARM has developed the ARM Cortex-M7 based on the original Cortex-M, which is currently the highest performance microcontroller product.
Figure 1 Cortx-M7 block diagram
[Microcontroller]
ARM study notes three (arm instruction set)
arm instruction set
Jump instruction to implement process jump
Special jump instruction
b Jump instruction
Format:
B{condition} target address
The sample code is as follows: When the z condition code in the cpsr register is set, the program jumps to the label label to execute
CMP R1,#0
[Microcontroller]
ARM40-A5 application - adaptation of fbset and LCD screen parameters
To use a certain type of LCD on an ARM board, you often have to modify the LCD driver or device tree, which is very inconvenient.
In ARM40-A5, we store the configuration instructions of commonly used LCD models in the /etc/init.d/S01user1lcd file. By modifying this file, we can easily adapt to different LCDs.
[Microcontroller]
Software Implementation Method of Digital Filter Based on ARM Platform
As the most basic processing component in applications such as speech and image processing, pattern recognition, radar signal processing, and spectrum analysis, digital filters have become one of the most commonly used tools. They can not only meet the strict requirements of filters on amplitude and phase characterist
[Microcontroller]
Communication interface design of DSP ARM dual-core system
Communication Interface Design of DSP/ARM Dual-core System
The core of embedded systems is embedded microprocessors and embedded operating systems. The hardware core of early embedded systems was various types of 8-bit and 16-bit single-chip microcomputers; in recent years, 32-bit processors have been widel
[Embedded]
ARM Standard Library
1 Introduction to ARM Standard Library
ADS provides ANSI C and C++ standard libraries. This article only discusses the ANSI C library, which includes the following parts:
◇ Functions defined by the IS0 C library standard;
◇ Functions used to implement C library functions and target-related functions in a semihosted
[Microcontroller]
Recommended Content
Latest Microcontroller Articles
He Limin Column
Microcontroller and Embedded Systems Bible
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
MoreSelected Circuit Diagrams
MorePopular Articles
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
MoreDaily News
- New breakthrough! Ultra-fast memory accelerates Intel Xeon 6-core processors
- New breakthrough! Ultra-fast memory accelerates Intel Xeon 6-core processors
- Consolidating vRAN sites onto a single server helps operators reduce total cost of ownership
- Consolidating vRAN sites onto a single server helps operators reduce total cost of ownership
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
Guess you like
- Design of multi-machine communication dispatching and commanding system based on I2C bus
- [Xianji HPM6750 Review 4] SPI peripheral verification of two screen refresh performances
- Qorvo Solution Interoperates with Apple* U1 Chip, Enabling New Ultra-Wideband Experiences
- Design of Adaptive PID Controller Based on FPGA
- Make a beautiful snowflake crystal ball
- 2-megapixel camera module with MIPI CSI-2 video interface, FPD-Link III and POC technology
- Ambilight-FPGA-HDMI Video Atmosphere Light Controller DIY
- How to reduce the brightness of the digital tube
- Summary of the points to note when using CCS8.0 to program MSP430G2553
- [TI Course] Can gesture recognition only be done with awr1642?