1. Register Operations
In embedded development, it is often necessary to manipulate registers, performing operations such as writing and reading. Each register has its inherent address, making it particularly important to access these addresses using C language.
#define GSTATUS1 (*(volatile unsigned int *)0x560000B0)
Here, we provide an example. This is a macro definition for a status register. Firstly, through unsigned int, we can see that this register is 32 bits. To avoid reading data directly from the cache during program execution, we use volatile as a modifier. This means we need to read the value at that address again each time. Firstly, (volatile unsigned int *) is a pointer, let’s assume it is p.
The address it stores is the following 0x560000B0, and then we retrieve the value at this address, which is *p. Therefore, the source code becomes (* (volatile unsigned int *)0x560000B0), and we can directly assign values to GSTATUS1 to change the value stored at address 0x560000B0.
/* 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;
static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;
Sometimes, you will see a case like this for assignment. Actually, it is quite similar to what we just discussed. Here, we define a pointer while assigning it a value. First, we define the structure S3C2410_NAND, which contains all 32-bit variables. We also define a pointer of this structure type, pointing to the address 0x4e000000, meaning that s3c2410nand now points to an actual physical address.
The s3c2410nand pointer accesses the NFSTAT variable, but we want its address, not the value at that address. Therefore, we use & to get the address of NFSTAT, and then force it to be converted to an unsigned char pointer, assigning it to p. Now we can directly assign values to NFSTAT through p.
Recommended Article:
Long Article | Compiled Some C Language Knowledge in STM32 Over Two Days, A Benefit for Beginners! A Review for Experienced Developers
2. Function Pointer Operations
Pointers can not only point to variables, strings, and arrays, but they can also point to functions. In C language, it is allowed to assign the entry address of a function to a pointer. This way, functions can be accessed through pointers. Function pointers can also be passed as parameters. They simplify code and reduce the workload when modifying code. You will appreciate this point through the following explanations.
#include <iostream>
using namespace std;
/* Comparison function declaration */
int max(int,int);
int (*test)(int,int);
int main(int argc,char* argv[])
{
int largernumber;
/* Assign the entry address of the max function to the function pointer test */
test=max;
/* Call the max function through pointer test to compare sizes */
largernumber=(*test)(1,2);
cout<<largernumber<<endl;
return 0;
}
int max(int a,int b)
{
return (a>b?a:b);
}
Through the comments, it should be easy for everyone to understand that function pointers are quite similar to variable pointers and string pointers. If you understand this small program, it will be much easier to understand the source code related to NAND flash that follows.
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 t_nand_chip nand_chip;
/* NAND Flash operation entry, they will call the corresponding functions of S3C2410 or 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);
/* S3C2410 NAND Flash processing functions */
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();
/* S3C2440 NAND Flash processing functions */
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);
/* Initialize NAND Flash */
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
/* Determine if it is S3C2410 or S3C2440 */
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;
/* Enable NAND Flash controller, initialize ECC, disable chip select, set timing */
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;
#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();
}
This code is used for operating NAND Flash. First, we see the definition of a structure, which contains function pointers. They are waiting to be assigned. Then, a variable of this structure type nand_chip is defined. Following that are the function declarations for the operations.
These functions will be called by functions from other files. Because these functions generally contain only one statement, which is to call the function pointer from the structure.
Next, we see the function declarations for two architectures. Then, in the nand_init function, nand_chip is assigned values, which is what we just discussed: assigning the entry address of functions to pointers. Now that nand_chip has been assigned, if we want to perform read and write operations on NAND, we just need to call nand_chip.read_data() or nand_chip.write_cmd() and so on.
This is quite convenient, and another point is that this code has strong portability. If we use another chip, we do not need to change the entire code; we only need to add a judgment for the new chip in the nand_init function and then assign values to nand_chip. Therefore, I say function pointers make the code portable and easy to modify.
Recommended Article:
C Language, Embedded Key Knowledge: Callback Functions
3. Bit Operations on Registers
#define GPFCON (*(volatile unsigned long *)0x56000050)
GPFCON &=~ (0x1<<3);
GPFCON |= (0x1<<3);
Combining what we just discussed, we first macro-define the register, allowing us to assign values directly. In bit operations, we need to learn from the second line of the program, which clears the target bit to 0; here it clears bit 3. The third line sets bit 3 to 1.
Recommended Article:
C Language, Embedded Bit Operation Essentials Compilation
Copyright Statement:This article is sourced from the internet, freely disseminating knowledge, and the copyright belongs to the original author. If there are copyright issues, please contact me for deletion.
Related Articles:
Embedded Miscellaneous Weekly | Issue 8 AMetal
Embedded Miscellaneous Weekly | Issue 7 zlog
Embedded Miscellaneous Weekly | Issue 6 FlexibleButton
Embedded Miscellaneous Weekly | Issue 5 smartlink
Embedded Miscellaneous Weekly | Issue 4 cola_os
Embedded Miscellaneous Weekly | Issue 3 sys/queue.h
Embedded Miscellaneous Weekly | Issue 2 llgui
Embedded Miscellaneous Weekly | Issue 1 gear-lib
Sharing a Compact and Useful Code Comparison Tool
Sharing Several Useful Shell Scripts in Embedded Systems!
Sharing an Embedded Software Tools List!
Reply with1024 in the WeChat public account chat interface to obtain embedded resources; reply with m to view the article summary.
Click Read the Original for more sharing.