Study Notes --- S3C2440 DMA Operation Principle

Publisher:创新驿站Latest update time:2022-04-02 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

DMA (Direct Memory Access) is a data exchange mode that directly accesses data from memory without going through the CPU. In situations where a large amount of data needs to be exchanged, using DMA well can greatly improve system performance because DMA operations hardly occupy CPU resources. S3C2440 provides 4 channels of DMA


Each DMA channel can handle data transfer in the following four situations:

(1) Both the source device and the destination device are on the system bus APB

(2) The source device is on the system bus and the destination device is on the peripheral bus

(3) The source device is on the peripheral bus and the destination device is on the system bus

(4) Both the source device and the destination device are on the peripheral bus AHB

The following DMA driver uses the fourth type. The memory belongs to the AHB bus. We plan to open two continuous spaces in the memory as the source and the destination. We use two methods to write the data in the source to the destination. One method is to let the CPU do it, and the other method is to let DMA do it:


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#define MEM_CPY_NO_DMA 0

#define MEM_CPY_DMA 1

 

#define BUF_SIZE (512*1024)

 

#define DMA0_BASE_ADDR 0x4B000000

#define DMA1_BASE_ADDR 0x4B000040

#define DMA2_BASE_ADDR 0x4B000080

#define DMA3_BASE_ADDR 0x4B0000C0

 

struct s3c_dma_regs {

 unsigned long disrc;

 unsigned long disrcc;

 unsigned long didst;

 unsigned long didstc;

 unsigned long dcon;

 unsigned long dstat;

 unsigned long dcsrc;

 unsigned long dcdst;

 unsigned long dmasktrig;

};

 

 

static int major = 0;

 

static char *src;

static u32 src_phys;

 

static char *dst;

static u32 dst_phys;

 

static struct class *cls;

 

static volatile struct s3c_dma_regs *dma_regs;

 

static DECLARE_WAIT_QUEUE_HEAD(dma_waitq);

/* Interrupt event flag, the interrupt service routine sets it to 1, and ioctl clears it to 0 */

static volatile int ev_dma = 0;

 

static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

 int i;

 

 memset(src, 0xAA, BUF_SIZE);

 memset(dst, 0x55, BUF_SIZE);

 

 switch (cmd)

 {

                //This is non-DMA mode

  case MEM_CPY_NO_DMA :

  {

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

    dst[i] = src[i]; //CPU directly copies the source to the destination

   if (memcmp(src, dst, BUF_SIZE) == 0)

   {

    printk("MEM_CPY_NO_DMA OKn");

   }

   else

   {

    printk("MEM_CPY_DMA ERRORn");

   }

   break;

  }

 

                //This is DMA mode

  case MEM_CPY_DMA :

  {

   ev_dma = 0;

   

   /* Tell DMA the source, destination, and length */

                        /* Regarding the specific situation of the following registers, we will explain it in detail in Note 3*/

   dma_regs->disrc = src_phys; /* physical address of source*/

   dma_regs->disrcc = (0<<1) | (0<<0); /* Source is on AHB bus, source address increments*/

   dma_regs->didst = dst_phys; /* Physical address of destination*/

   dma_regs->didstc = (0<<2) | (0<<1) | (0<<0); /* Destination is on AHB bus, destination address increments*/

   dma_regs->dcon = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(BUF_SIZE<<0); /* AHP bus synchronization, enable interrupt, full speed transmission (BIT27), software trigger (BIT23), */

 

   /* Start DMA */

   dma_regs->dmasktrig = (1<<1) | (1<<0); //Open the channel and start the software

 

   /* How do I know when DMA is complete? */

   /* Sleep */

   wait_event_interruptible(dma_waitq, ev_dma);

 

   if (memcmp(src, dst, BUF_SIZE) == 0)

   {

    printk("MEM_CPY_DMA OKn");

   }

   else

   {

    printk("MEM_CPY_DMA ERRORn");

   }

   

   break;

  }

 }

 

 return 0;

}

 

static struct file_operations dma_fops = {

 .owner = THIS_MODULE,

 .ioctl = s3c_dma_ioctl,

};

 

static irqreturn_t s3c_dma_irq(int irq, void *devid)

{

 /* wake up */

 ev_dma = 1;

    wake_up_interruptible(&dma_waitq); /* wake up the sleeping process*/

 return IRQ_HANDLED;

}

 

static int s3c_dma_init(void)

{

         /* Register an interrupt here, this interrupt will occur when DMA data transfer is completed*/

 if (request_irq(IRQ_DMA3, s3c_dma_irq, 0, "s3c_dma", 1))

 {

  printk("can't request_irq for DMAn");

  return -EBUSY;

 }

 

 /* Allocate the buffers corresponding to SRC and DST: We know that kmalloc function can be used to open up space in the kernel, but dma_alloc_writecombine is used here. Why? This is because the logical address of the space opened by kmalloc is continuous, but its actual physical address may not be continuous. When DMA transfers data, the physical address is required to be continuous, and dma_alloc_writecombine meets this requirement. The prototype of this function is: dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) where size represents the size of the opened space, handle represents the physical address of the opened space, and the return value is the logical address of the opened space*/

 src = dma_alloc_writecombine(NULL, BUF_SIZE, &src_phys, GFP_KERNEL); // source

 if (NULL == src)

 {

  printk("can't alloc buffer for srcn");

  free_irq(IRQ_DMA3, 1);

  return -ENOMEM;

 }

 

 dst = dma_alloc_writecombine(NULL, BUF_SIZE, &dst_phys, GFP_KERNEL); //Purpose

 if (NULL == dst)

 {

  free_irq(IRQ_DMA3, 1);

  dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);

  printk("can't alloc buffer for dstn");

  return -ENOMEM;

 }

 

 major = register_chrdev(0, "s3c_dma", &dma_fops); //Register character device

 

 /* To automatically create device nodes */

 cls = class_create(THIS_MODULE, "s3c_dma");

 class_device_create(cls, NULL, MKDEV(major, 0), NULL, "dma"); /* /dev/dma */

 

 dma_regs = ioremap(DMA3_BASE_ADDR, sizeof(struct s3c_dma_regs)); //This is to map the DMA control register to kernel space

  

 return 0;

}

 

static void s3c_dma_exit(void)

{

 iounmap(dma_regs);

 class_device_destroy(cls, MKDEV(major, 0));

 class_destroy(cls);

 unregister_chrdev(major, "s3c_dma");

 dma_free_writecombine(NULL, BUF_SIZE, src, src_phys);

 dma_free_writecombine(NULL, BUF_SIZE, dst, dst_phys); 

 free_irq(IRQ_DMA3, 1);

}

 

module_init(s3c_dma_init);

module_exit(s3c_dma_exit);

 

MODULE_LICENSE("GPL");

test program:


#include

#include

#include

#include

#include

#include

 

/* ./dma_test nodma

 * ./dma_test dma

 */

#define MEM_CPY_NO_DMA 0

#define MEM_CPY_DMA 1

 

void print_usage(char *name)

{

 printf("Usage:n");

 printf("%s n", name);

}

 

 

int main(int argc, char **argv)

{

 int fd;

 

  if (argc != 2)

 {

  print_usage(argv[0]);

  return -1;

 }

 

 fd = open("/dev/dma", O_RDWR);

 if (fd < 0)

 {

  printf("can't open /dev/dman");

  return -1;

 }

 

 if (strcmp(argv[1], "nodma") == 0)

 {

  while (1)

  {

   ioctl(fd,MEM_CPY_NO_DMA);

  }

 }

 else if (strcmp(argv[1], "dma") == 0)

 {

  while (1)

  {

   ioctl(fd,MEM_CPY_DMA);

  }

 }

 else

 {

  print_usage(argv[0]);

  return -1;

 }

 return 0;  

}

Test Methods:

# insmod dma.ko //Load driver

# cat /proc/interrupts //View interrupts

           CPU0

 30: 52318 s3c S3C2410 Timer Tick

 33: 0 s3c s3c-mci

 34: 0 s3c I2SSDI

 35: 0 s3c I2SSDO

 36: 0 s3c s3c_dma

 37: 12 s3c s3c-mci

 42: 0 s3c ohci_hcd:usb1

 43: 0 s3c s3c2440-i2c

 51: 2725 s3c-ext eth0

 60: 0 s3c-ext s3c-mci

 70: 97 s3c-uart0 s3c2440-uart

 71: 100 s3c-uart0 s3c2440-uart

 83: 0 - s3c2410-wdt

Err: 0


# ls /dev/dma //View device

/dev/dma


# ./dmatest //This will print the usage

Usage:

./dmatest


# ./dmatest dma //Copy via DMA, CPU can do other things

MEM_CPY_DMA OK

MEM_CPY_DMA OK

MEM_CPY_DMA OK

MEM_CPY_DMA OK

MEM_CPY_DMA OK

MEM_CPY_DMA OK

MEM_CPY_DMA OK


# ./dmatest nodma //CPU copy, various competing CPUs

MEM_CPY_NO_DMA


MEM_CPY_NO_DMA

MEM_CPY_NO_DMA


————————————————————————————————————————————————————————————————————————————


After getting familiar with DMA and register configuration, let's see how to use DMA to play audio when running S3C2440:


Reprinted from: http://blog.csdn.net/zhaocj/article/details/5583935


Next, we will use DMA to play audio. Since DMA is used, system resources are not occupied during playback. We can easily implement various sound operations without affecting the playback effect, such as volume increase and decrease, mute, pause, etc. Here, it is also necessary to emphasize that when using DMA to transfer data, the maximum byte size that can be transferred at one time is: DSZ×TSZ×TC, DSZ represents the data size (byte, half word or word, that is, 1, 2 or 4), TSZ represents the transfer size (unit transfer or burst transfer, that is, 1 or 4), and TC represents the transfer count value (that is, the data stored in the lower 20 bits of register DCONn). Therefore, if the byte size to be transferred exceeds the size of the product of these three parameters, further processing is required. In the program we give, we have considered this aspect. The following is a specific program, in which we use UART to play, stop, pause, mute, increase and decrease the volume of audio signals.


…… ……

//A pure audio data array

unsigned char music[] = {

0xF9, 0xFF, 0xF5, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0xFF, 0xF9, 0xFF,

0xF6, 0xFF, 0xF6, 0xFF, 0xFA, 0xFF, 0xFD, 0xFF, 0xFA, 0xFF, 0xFA, 0xFF, 0xFF, 0xF7, 0xFF, 0xF6, 0xFF,

…… ……

};

 

int result;

int remainder;

char flag;

char cmd;

char play_state;

 

void __irq uartISR(void)

{

       char ch;

       rSUBSRCPND |= 0x1;

       rSRCPND |= 0x1<<28;

       rINTPND |= 0x1<<28;

       ch=rURXH0;

      

       switch(ch)

       {

              case 0x55: //play

                     cmd = 1;

                     break;

              case 0x1: //Mute

                     cmd = 0x11;

                     break;

              case 0x2: //volume up

                     cmd = 0x12;

                     break;

              case 0x3: //Volume down

                     cmd = 0x13;

[1] [2]
Reference address:Study Notes --- S3C2440 DMA Operation Principle

Previous article:Study Notes --- S3C2440 NANDFLASH operation principle and test code analysis
Next article:S3C2440's RAM and boot process!

Recommended ReadingLatest update time:2024-11-23 15:23

S3C2440 external interrupt response register setting method
If the following settings are not followed, the interrupt will not be executed or the next interrupt will not be entered. /*Interrupt suspension setting, this process is added to the main function and loaded at startup*/ void Eint_wait() {    rSRCPND=rSRCPND; //Interrupt pending register clear    rINTPND=rINTPND; //In
[Microcontroller]
S3C2440 bare metal learning [2] - LCD driver principle and code analysis [I]
1. Hardware requirements for LCD operation: To make an LCD display text or image normally, it needs not only LCD driver but also corresponding LCD controller. Usually, the manufacturer will make LCD driver together with LCD glass substrate in the form of COF/COG, while LCD controller is realized by external circuit. N
[Microcontroller]
RTEMS porting on S3C2440 - (4)
    With the preparation of the previous article, the transplantation work is basically half successful. The next step is to modify the BSP of 2410 according to the differences between 2410 and 2440 and the differences between different development board modules and interfaces. Since the registers of 2410 are basicall
[Microcontroller]
Design of digital voltage-stabilized power supply for test system based on S3C2440
  0 Preface   DC regulated power supply is a relatively common electronic device, which has been widely used in many fields such as electronic circuits, experimental teaching, scientific research, etc. In recent years, embedded technology has developed extremely rapidly, and highly integrated processors with single-ch
[Microcontroller]
Design of digital voltage-stabilized power supply for test system based on S3C2440
s3c2440 bare metal - resistive touch screen - 4-isr design _ get touch screen coordinates
1. Enter automatic measurement mode The previous section introduced the initialization of TSC and the interrupt service routine framework , which can perform basic press and release detection on the touch screen. Then set bit =1, bit =00 to enter auto measurement. If bit =0, you n
[Microcontroller]
S3C2440 uses C language to light up LED
1. From assembly to C function 1. Set up the stack Why do we need to set up a stack when calling a C function from an assembly? 1. Because the parameters of the arm assembly call to a C function must follow the APCS rule. That is, if the number of parameters is less than or equal to 4, R0-R3 can be u
[Microcontroller]
S3C2440 uses C language to light up LED
S3C2440—9. Copy the program to SDRAM for execution
1. How to start S3C2440 The S3C2440 MMU has a "steppingstone" technology, which is a method to assist the MCU to execute the boot program from the NAND FLASH that cannot execute the program. The boot steps are as follows: 1. After the system is powered on, it will first automatically determine whether it is in autob
[Microcontroller]
Design of digital voltage-stabilized power supply for test system based on S3C2440
0 Introduction DC regulated power supply is a common electronic device, which has been widely used in many fields such as electronic circuits, experimental teaching, scientific research, etc. In recent years, embedded technology has developed rapidly, and high-integration processors with single-chip microcomputers an
[Microcontroller]
Design of digital voltage-stabilized power supply for test system based on S3C2440
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号