Design of SPI driver based on ARM embedded system

Publisher:MagicGardenLatest update time:2021-02-02 Source: eefocusKeywords:ARM Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Embedded systems have been widely used in defense electronics, digital home, industrial automation, automotive electronics and other fields. In the process of embedded development, many systems usually use serial port drivers to meet communication requirements, but in actual applications, using SPI communication will be more efficient and faster. The SPI interface is a high-speed and efficient serial interface technology, so SPI devices are very convenient in data communication applications. This paper designs an SPI driver based on the S3C2440 of the ARM9 chip and the Linux operating system. The driver is reliable, flexible, easy to port, and can be applied to a variety of embedded platforms to achieve communication between arm and devices.


1 Hardware Description

1.1 S3C2440 Development Platform

The SoC chip S3C2440[4] from Samsung is used as the core processor with a main frequency of 400 MHz, and together with 64 MB SDRAM and 64 MB NAND Flash, it forms the core part. In addition, the platform also provides users with a large number of communication, display, debugging and I/O interfaces. To meet the design requirements, the Linux 2.6.21 kernel is ported to the platform.


1.2 SPI Hardware Module

S3C2440 has two SPIs, each with two 8-bit shift registers for independent data transmission and reception. It is compatible with SPI ver.2.11 protocol and supports 8-bit logic pre-scaling. The system can use polling, interrupt, and DMA to determine the SPI transmission and reception status. This SPI module contains the following signal lines [5]:

(1) SCK: Data synchronization clock signal, driven by the master device and output to the slave device, so that the slave device receives or sends data in the pace of the synchronization clock.

(2) nCS (GPIO specified by the user): The slave select signal line (SS) is sent by the master device to select and activate a slave device. The low level is valid.

(3) MISO (SPIMISO0): Master-in, slave-out signal line, indicating that the signal is used as input in the master device and as output in the slave device.

(4)MOSI (SPIMOSI0): Master-out slave-in signal line, indicating that the signal is output in the master device and input in the slave device.

(5)/SS(nSS): Multi-master error detection.


2 SPI device driver design under Linux

Linux device drivers play an important role in the Linux kernel. They enable certain specific hardware to respond to a well-defined internal programming interface that completely hides the details of the device's operation. User operations can be performed through a set of standardized calls that are completely independent of specific drivers in form. Mapping these calls to the specific operations of the actual hardware device is the driver's task [6]. The SPI driver designed in this paper mainly defines three operations: initialization, read, and write. The initialization operation is used to initialize some kernel mechanisms and memories when the driver is first loaded into the kernel. The write operation is responsible for copying user data to the kernel buffer and controlling the local master SPI to send data to the slave SPI register. The read operation will continuously read the data received in the local master SPI according to the number of bytes required by the user, and copy it to the user space. The driver will use interrupts to notify the system whether the SPI data has been sent. That is, when the SPI hardware module sends each data, it will initiate an interrupt to the system through the interrupt line. After the system responds to the interrupt, the driver will call the interrupt handling routine.


2.1 SPI Initialization

(1) Apply for interrupt. This driver design uses interrupts to determine whether the data has been sent, so it is necessary to apply for SPI0-related interrupts and register the corresponding interrupt processing function. The interrupt processing function of this driver is declared as follows:

static irqreturn_t s3c2440_isr_spi(int irq,void*dev_id,struct pt_regs*reg)

Use request_irq to apply for an interrupt number from the kernel and register an interrupt handling function:

request_irq(IRQ_SPI0,s3c2440_isr_spi,SA_INTERRUPT,DEVICE_NAME,s3c2440_isr_spi);


(2) Virtual address mapping. The driver can directly access the register corresponding to the device physical address by accessing the virtual address in the kernel and operate it. The address mapping process of the SPI device is as follows:

request_mem_region(S3C2440_PA_SPI,0x30,"s3c2440-spi");

base_addr = ioremap(S3C2440_PA_SPI,0x30);


Among them, S3C2440_PA_SPI is the physical address of SPI (defined in /asm-arch/arch-s3c2440/map.h), and a memory area of ​​0x30 size is allocated starting from S3C2440_PA_SPI, and then it is moved to kernel space.


(3) Setting of related registers. Set the SPI working mode by configuring the SPI function register. Use the virtual address returned by ioremap as the base address and access the corresponding register by adding different offsets. This design sets the local SPI as the master device, turns on the SCK signal enable, sets CPOL and CPHA to 0, and the SPI works in normal mode. Set the division ratio in the baud rate pre-division register (SPPRE) to 8. The specific design is as follows:

__raw_writel((S3C2440_SPCON_SMOD_INT|S3C2440_SPCON_ENSCK|S3C2440_SPCON_MSTR), s3c2440_SPCON);

DPRINTK(DEVICE_NAME"SPCON initializen");

__raw_writel((S3C2440_SPPIN_ENMUL | S3C2440_SPPIN_KEEP),s3c2440_SPPIN);

DPRINTK(DEVICE_NAME"SPPIN initializen");

__raw_writel(0x07,s3c2440_SPPRE);

DPRINTK(DEVICE_NAME"SPPRE initializen");


(4) Initialize the send and receive data buffers. The data buffer uses a ring buffer structure and realizes dynamic management of the buffer by circular movement of the head and tail pointers. Its definition is as follows:

typedef struct

{

spi_buf buf[MAX_SPI_BUF];

unsigned int head, tail;

wait_queue_head_t wq;

} SPI_BUF; static SPI_BUF spi_Tx_buf;static SPI_BUF spi_Rec_buf;

Where spi_buf represents char type, MAX_SPI_BUF is the buffer size, set to 1 024 B. head and tail represent the head and tail array subscripts respectively, and wq is the waiting queue head. This structure is managed by the following macros:

#define SPI_Tx_BUF_HEAD(spi_Tx_buf.buf[spi_Tx_buf.head])

#define SPI_Tx_BUF_TAIL(spi_Tx_buf.buf[spi_Tx_buf.tail])

#define INCBUF(x,mod)((++(x))&((mod)-1))


The first two macros are used to reference elements in the buffer, and the last macro is used to move the head and tail subscripts forward and ensure that the head and tail subscript values ​​can change cyclically without overflow.


During initialization, the head and tail pointers of the receive and send buffers are cleared, as follows:

spi_Tx_buf.head=spi_Tx_buf.tail=0;spi_Rec_buf.head=spi_Rec_buf.tail = 0;


(5) Initialization of data structures related to the kernel mechanism. The kernel mechanism used in this design includes the operation of the upper and lower interrupt halves and the sleep waiting mechanism. Therefore, it is necessary to initialize the send and receive waiting queues and the tasklet structure, and register the tasklet processing function. The initialization process is as follows:

init_waitqueue_head(&(spi_Tx_buf.wq));

init_waitqueue_head(&(spi_Rec_buf.wq));


tasklet_init(&spi_tasklet, spi_tasklet_handler, data); (6) Initialize the corresponding port. According to the S3C2440 external pin configuration, set the GPIO multiplexed with the SPI function pin to the corresponding SPI function. The specific operations are as follows:

s3c2440_gpio_cfgpin

(S3C2440_GPE11,S3C2440_GPE11_SPIMISO0);

s3c2440_gpio_cfgpin

(S3C2440_GPE12,S3C2440_GPE12_SPIMOSI0);

s3c2440_gpio_cfgpin

(S3C2440_GPE13,S3C2440_GPE13_SPICLK0);

s3c2440_gpio_cfgpin

(S3C2440_GPG2, S3C2440_GPG2_INP); //Set nSS

s3c2440_gpio_cfgpin(S3C2440_GPB10,

S3C2440_GPB10_OUTP); //Set chip select signal

s3c2440_gpio_setpin(S3C2440_GPB10,1);


2.2 SPI Write Operation

The write operation mainly copies the data in the user space of the upper application to the ring buffer in the kernel space, and then sends the data in the buffer to the SPI transmit register. After the SPI sends a data, the system generates an interrupt, and the lower half of the interrupt routine will call the tasklet to determine the buffer status. If there is corresponding space in the buffer, the next data can be filled into the SPI transmit register until all the buffer data is sent.


The write operation of this design realizes the dynamic management of the ring buffer, that is, when the buffer deletes data and the tail pointer moves forward, it is allowed to add data to the buffer and move the head pointer forward. This design allows the user space task and the kernel space data to be sent simultaneously, which improves the execution efficiency of the user space task, and when the copy_from_user function is used to copy data from the user space to the kernel space, the data transmission is still in progress, that is, the data copy process from the user space to the kernel space is concurrent with the data transmission process, which improves the efficiency of the driver.


In order to realize dynamic management of the ring buffer, the two functions copy_to_Tx_buf_init and copy_to_Tx_buf are defined to complete the operation of copying data to the buffer.


(1) copy_to_Tx_buf_init function. This function is mainly used in two situations:

① If the buffer is empty, when a set of data arrives and the size of this data is smaller than the space size of the buffer, the data is directly placed in the buffer.


②If the size of the data to be sent is larger than the remaining buffer space, only the data of the buffer size will be copied to the buffer.


When the buffer is full, the process goes to sleep until all the data in the buffer is sent. When the buffer is empty again, the current process is awakened, copies the unsent part of this group of user data to the buffer, and continues to send it.


(2) copy_to_Tx_buf function. This function is mainly used to copy a new set of user data to the buffer when the buffer is being sent but has not been sent completely. First, calculate the remaining space in the buffer. If the remaining space is larger than the size of the current set of user data, all the user data is directly copied to the buffer; if the remaining space is smaller than the size of the current set of data, copy the user data of the same size as the remaining space to the buffer.

[1] [2]
Keywords:ARM Reference address:Design of SPI driver based on ARM embedded system

Previous article:Introducing the interrupt masking method of the ARM7 core
Next article:Introduction to ARM technology to modify the simulation parameters of D1N4002

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
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号