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.
Previous article:Introducing the interrupt masking method of the ARM7 core
Next article:Introduction to ARM technology to modify the simulation parameters of D1N4002
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- 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!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Urgently looking for chip model
- ESP32-S3 KORVO-2 2.4'' ARDUINO TFT Unboxing Report
- A troubleshooting example of connecting XDS100V3 debugging target board with CCS
- 【Android Development Learning Road】Part 2-- HelloEEWorld
- 51 MCU library serial port sends a segment of characters and the digital tube receives and displays them (use the serial port debugging assistant to modify the data)
- pic18F27Q10 eeprom erase problem
- 【BearPi-HM Micro】Part 4: Familiar with the Openharmomy compilation framework and serial port interactive output
- 50 ways to use TI CC6678 digital signal processor (DSP)
- Definition of Direct Current and Alternating Current
- [Reference Book] PCB Design Tips (ADI Think Tank)