Disclaimer: This article is an original work and copyright belongs to the author of this blog.All. If you need to repost, please indicate the sourceHttp://www.cnblogs.com/kingst/
Introduction
In this section, let's talk about the usage of the SPI bus in the nioshi II. First of all, let's briefly introduce the SPI bus. SPI is short for serial peripheral interface. It means serial peripheral device interface in Chinese and is a synchronous serial communication method launched by Motorola, it is a four-line synchronous bus, because of its strong hardware functions, SPI-related software is quite simple, so that the CPU has more time to process other transactions.
The communication principle of SPI is very simple. It works in the master-slave mode. In this mode, there is usually a master device and one or more slave devices, and at least four lines are required, in fact, three can also be used (for unidirectional transmission, that is, half duplex mode ). It is also common to all SPI-based devices, including miso, Mosi, sck, and CS ).
(1) miso-master device data output, from device data input
(2) Mosi-master device data input, output from device data
(3) sck-clock signal generated by the master device
(4) CS-enable signals from the master device
Among them, CS is to control whether the chip is selected, that is, only when the chip selection signal is a pre-defined enable signal (high potential or low potential), this chip operation is effective. This allows connecting multiple SPI devices on the same bus.
I have introduced so much about the SPI bus theory. I 'd like to take a look at the specific points and go to Baidu on the Internet. Now let's start the SPI bus development journey.
Hardware development
In our development board, the network port is implemented using the SPI bus, and the network chip is the enc28j60 of the microchip company. Let's take a look at this part of the circuit, as shown in, which is related to the SPI bus, lan_miso, lan_mosi, and lan_sck are all implemented through the PIO module. In addition, some cables are unavailable, such as lan_nwol.
This section mainly teaches you how to implement the SPI bus function. The principle of enc28j60 is relatively complicated. I will not explain it in detail here. If you are interested, you can study it yourself.
Next, we will build the SPI module. after entering the system System of the system, as shown in, click the Red Circle (SPI)
After clicking, as shown in, there are five points to note,
In the red circle, the master-slave mode is selected, and the master mode is selected );
The number of devices in the red circle 2 is counted. We select 1;
The SPI clock rate at the Red Circle 3 is selected as 10 M. Note that, the frequency we set is sometimes different from the actual frequency (the actual frequency is shown below). For example, if we input 50 MHz, the actual frequency is only 25 MHz.
The four digits in the red circle are the data digits. We choose 8;
The red circle 5 is the shift direction, that is, when the serial data comes over, it is the highest bit first or the lowest bit first. Let's choose MSB first.
After completing the preceding steps, click Finish to complete the building.
Next, we need to build two Pio modules, one for CS signal control and the other for interrupt signal. The reason why CS does not use SPI bus itself is thatProgramProcessing depends on itself. For the PIO module of the interrupt signal, you must pay attention to the content during the construction process. First, as the interrupt signal, it is the input signal. Therefore, during the selection process, as shown in, set the value of 1 in the red circle, select "input ports only" at "red circle 2" and use it as the input port only. Click "Next" to proceed to the next step.
Click Next to go to the next step, as shown in. The level of the external interrupt is required to be triggered, so select the mode in the red circle.
Then, click Finish to complete the build.
After the above content is complete, we need to rename the module, as shown in,
Everything is ready. Don't forget automatic Address Allocation and interrupt allocation. Oh, let's start compiling. Wait ......
After compilation, we return to the Quartus interface and allocate pins Based on the Tcl script file, as shown in
Next we will run the script file, compile it, and wait a long time ......
After the compilation is successful, we start to develop the software.
Software Development
Open the nio ii 9.0 IDE and compile it. Press Ctrl + B. After the compilation is successful, let's take a look at what is more in system. H, as shown in the following table,
/** LAN configuration **/# define lan_name "/dev/LAN" # define lan_type "altera_avalon_spi" # define lan_base 0x00201020 ...... /** Lan_cs configuration **/# define lan_cs_name "/dev/lan_cs" # define lan_cs_type "altera_avalon_pio" # define lan_cs_base 0x00201060 ...... /** Lan_nint configuration **/# define lan_nint_name "/dev/lan_nint" # define lan_nint_type "altera_avalon_pio" # define lan_nint_base 0x00201070 ......
We need the following content:
# Define lan_base 0x00201020 # define lan_cs_base 0x00201060 # define lan_nint_base 0x00201070
Next, we need to modify the System File System (. h) and add the followingCode
Typedef struct {volatile unsigned long int rxdata; volatile unsigned long int txdata; Union {struct {volatile unsigned long int NC: 3; volatile unsigned long int ROE: 1; volatile unsigned long int toe: 1; volatile unsigned long int TMT: 1; volatile unsigned long int trdy: 1; volatile unsigned long int rrdy: 1; volatile unsigned long int e: 1; volatile unsigned long int NC1: 23;} bits; volatile unsigned long int word;} status; Union {struct {volatile unsigned long int NC: 3; volatile unsigned long int Iroe: 1; volatile unsigned long int itoe: 1; volatile unsigned long int NC1: 1; volatile unsigned long int itrdy: 1; volatile unsigned long int irrdy: 1; volatile unsigned long int ie: 1; volatile unsigned long int NC2: 1; volatile unsigned long int SSO: 21;} bits; volatile unsigned long int control;} control; unsigned long int reserved0; unsigned long int slave_select ;} spi_str;
This part of the code is based on "n2cpu_embedded peripherals.pdf" Page 7-10, as shown in the following table, the structure sequence is designed according to the order of the following table, and the principle of the structure in the serial port is the same.
In addition to the above struct, we also need to add the following code to the system. h:
# Ifdef _ LAN # define LAN (spi_str *) lan_base) # define lan_cs (pio_str *) lan_cs_base) # endif/* _ LAN */
Modify the system disk. h later, we need to create an enc28j60 In the INC folder. h, add the following content to it (this is only enc28j60. A part of the H file, and a large part of the macro definition is not written)
/* Initialize * data struct * initialize */typedef const struct {unsigned char (* read_control_register) (unsigned char address); void (* initialize) (void); void (* packet_send) (unsigned short Len, unsigned char * packet); unsigned int (* packet_receive) (unsigned short maxlen, unsigned char * packet);} enc28j60; /* optional * external variable * ---------------------------------------------------------- */extern enc28j60 enc28j60;
As you can see, in our program, such struct can be seen everywhere. We are using the previous serial program or the SPI program. Its advantage is that it can integrate scattered functions and variables and process them in the form of struct, greatly improving the readability of the program and enhancing the maintainability and portability of the program.
After processing the above content, we began to write the enc28j60 driver, which contains a lot of content. We cut some of the content about SPI for explanation.
/** =================================================== ========================================= * Filename: enc28j60. C * Description: enc28j60 device driver * version: 1.0.0 * created: 13:05:54 * revision: none * Compiler: NiO II ide * Author: AVIC * company: golden Beach Studio ======================= * // * ----------------------------------------------------------- * include *---------- ----------------------------------------------------- */# Include ".. /INC/enc28j60. H "# include ".. /INC/systems. H "# include <stdio. h>/* role * function prototype * parameters */static unsigned char enc28j60_read_control_register (unsigned char address); static void enc28j60_initialize (void); static void Enc28j60_packet_send (unsigned short Len, unsigned char * packet); static unsigned int enc28j60_packet_receive (unsigned short maxlen, unsigned char * packet ); /* optional * variable * ---------------------------------------------------------- * // initialize the struct. Note the initialization method: enc28j60 enc28j60 = {. read_control_register = enc28j60_read_control_register ,. initialize = E Nc28j60_initialize ,. packet_send = enc28j60_packet_send ,. packet_receive = enc28j60_packet_receive}; static unsigned char enc28j60_bank = 1; static unsigned short next_packet_pointer; /** = function ================================================== ========================== * Name: set_cs * description: * ===================================================== =================================== */static void set_cs (unsigned char level) {If (level) lan_cs-> DATA = 1; else lan_cs-> DATA = 0 ;} /** = function ================================================== ================ * Name: enc28j60_write_operation * description: enc28j60 write operation * ============================================ =======================*/static void enc28j60_write_operation (unsigned char op, unsigned char address, unsigned char data) {// set CS to low first, and set CS to valid set_cs (0) When Cs is low; // write the command first, the TMT bit of the Wait Status Register. When this bit is 0 indicates that the data is being sent. When this bit // is 1, it indicates that the data is sent. At this time, the register is empty Lan-> txdata = (OP | (address & 0x1f )); while (! (Lan-> status. bits. TMT); // write data. The TMT bit of the Wait Status Register. When the bit is 0, it indicates that the data is being sent. When the bit // is 1, indicates that the message has been sent. At this time, the register is empty Lan-> txdata = data; while (! (Lan-> status. bits. TMT); // after sending, set CS to high set_cs (1 );} /** = function ================================================== ================== * Name: enc28j60_read_operation * description: enc28j60 read Operations * ==================================== =========================*/static unsigned char enc28j60_read_operation (unsigned char op, unsigned char address) {unsigned char data; // first, set CS to low and CS to valid set_cs (0); // First, write the command and wait for the TMT bit of the Status Register. When the bit is 0, it indicates that the data is being sent. When the bit // is 1, it indicates that the sending is complete, at this time, the register is empty Lan-> txdata = op | (address & 0x1f); While (! (Lan-> status. bits. TMT); // write data, send 0x00, 0x00 is a random number, in order to enable the clock, the sent data is related to the hardware Lan-> txdata = 0x00; // 0x00 is random number, to enable clock while (! (Lan-> status. bits. TMT); // The first byte read by the Mac and MII registers is invalid, so they need to write the IF (address & 0x80) twice) {Lan-> txdata = 0x00; while (! (Lan-> status. bits. TMT);} // start to read data Data = Lan-> rxdata; // after reading, set CS to high set_cs (1); return data ;}
For the network port, this part of the program requires the combination of TCP/IP protocol for communication, so this part of the main function will not be written for the moment, when talking about the TCP/IP protocol that part, let's explain it again.
This section describes how to use the SPI bus and how to send and receive data. I hope you can fully understand the programming method. For the complete driver of enc28j60, I will provide it to you in the form of an attachment. This section is over now. If you have any questions about this part, you can join our Nias technical group, or contact me via email. Thank you.