Summary of SPI

Serial Peripheral Interface Universal Serial Peripheral interface

Motorola first defined it on its MC68HCXX family of processors. The SPI interface is mainly used between EEPROM, FLASH, real-time clock, AD converter, and digital signal processor and digital signal decoder.

SPI is a high-speed, full-duplex, synchronous communication bus that takes up only four wires on the pin of the chip, saving the pin of the chip and space on the PCB layout.

Characteristics of SPI

The Master-Slave control mode is adopted

SPI specifies that communication between two SPI devices must be controlled by the Master device (Slave device). A Master device can control multiple Slave devices by providing clocks and performing Slave Select. SPI protocol also stipulates that the Clock of the Slave device is provided by the Master device to the Slave device through SCK pins. The Slave device cannot generate or control Clock itself. Without Clock, the Slave device cannot work normally.

The clock and phase in SPI here refer to the characteristics of SCLk clock, that is, to ensure that the clock characteristics of master and slave devices are consistent, so as to ensure that SPI communication between them can be realized normally.

Data is transmitted in Synchronous mode

The Master device generates a corresponding Clock Pulse based on the data to be exchanged, which is the Clock Signal. The clock signal uses CPOL and CPHA to control when data is exchanged between the two SPI devices and when the received data is sampled to ensure synchronous data transmission between the two devices.

Working mechanism

An overview of the

First, take a look at the DIAGRAM of SPI Data Transfer module.

The figure above is just a simple description of the communication between SPI devices. The following modules are explained in detail:

SSPBUF

Synchronous Serial Port Buffer, the internal Buffer in an SPI unit that physically stores temporary data during transmission, usually in the form of a FIFO.

We know that the data exchanged between the Master and Slave during each clock cycle is actually copied from the SSPBUF by the SPI internal shift registers. We can indirectly control the SSPBUF inside the SPI device by reading and writing Data into the corresponding REGISTER (TX-data/RX-data register).

For example, before sending Data, we should write the Data to the Master tX-data register. The Data will be automatically moved by the master-sSPSR shift register according to the bus-width to Master-SSPBUF. Master-sspsr will then remove the data from master-SSPBUf according to channel-width and pass it to slave-SDI via master-SDO pins. Slave-sspsr moves the data received from slave-SDI to slave-SSPBUF. At the same time, the data in slave-SSPBUF is sent to master-SDI through slave-SDO according to the channel-width of each received data. Master-sspsr then moves the data received from master-SDI to master-SSPBUF. After a single Data transfer, the user program can read the Master Data exchange Data from the Master device’s RX-DATA register.

SSPSR

Synchronous Serial Port Register, commonly referred to the Shift Regitser in the SPI device, which moves data in and out of the SSPBUF according to the set bit width;

SSPSR is the internal Shift Register of an SPI device. It is used to move data in and out of the SSPBUF according to the SPI clock signal status. The size of each move is determined by bus-width and channel-width. Bus-width specifies the unit of data transfer between the address Bus and the Master device. For example, we want to write 16 bytes of data to the Master SSPBUF: first, set bus-width to Byte in the Master configuration register; Then write Data to the Master tX-data shift register in the address bus entry, write 1 Byte of Data each time (using the writeb function); After writing 1 Byte of Data, the TX-Data shift register in the Master device automatically moves 1 Byte of Data from the address bus to the SSPBUF. Repeat the preceding steps 16 times.

Channel-width specifies the unit of data transmission between the Master and Slave devices. Similar to bus-width, the Master shift register automatically transfers data from master-sSPbuf to slave-sDI pins in Slave according to channel-width. Slave-sspsr then moves the received data to slave-SSPBUF. Bus-width is always greater than or equal to channel-width. This ensures that the data exchanged between Master and Slave is faster than the data exchanged between Master and Slave. The data stored in the SSPBUF is invalid

Controller

Control registers in an SPI device that can be configured to set the transmission mode of the SPI bus. Typically, we only need to program the four pins (PINS) described above to control data communication between the entire SPI devices.

The Controller on the Master device controls the Slave device through Clock Signal and Slave Select Signal. The Slave device waits until it receives the chip selection signal from the Master device and then works according to the clock signal.

The chip selection operation of the Master device must be implemented by the program. For example, the clock signal of SS/CS pin is pulled low by the program to complete the preliminary work of SPI device data communication; When the program wants the SPI device to terminate data communication, the clock signal on the SS/CS pin is pulled to a high level.

SCK

The Serial Clock is used to transmit Clock signals from the Master device to the Slave device to control the timing and rate of data exchange.

SS/CS

Slave Select/Chip Select is used to Select the Slave device from the Master device so that the selected Slave device can be accessed by the Master device.

SDO/MOSI

Serial Data Output/Master Out Slave In, also called tX-channel on the Master, serves as the Data egress for the SPI device to send Data.

SDI/MISO

Serial Data Input/Master In Slave Out, also known as RX-channel on Master, serves as the Data entry point for SPI devices to receive Data.

In the process of SPI device’s communication, a Data Loop will be generated between Master device and Slave device. As shown in the figure above, SSPSR controls Data moving in and out of SSPBUF through SDO and SDI pins. The Controller determines the communication mode of the SPI bus and the SCK transmits the clock signal.

Polarity and phase

To understand SPI’s data transmission, you first need to understand the concept of Phase and Polarity, namely Polarity Polarity and Phase Phase of SPI.

The most common are CPOL and CPHA, but there are a few others, which can be summarized as follows:

  • (1) CKPOL = CPOL = POL = Polarity
  • CKPHA (Clock Phase) = CPHA = PHA = Phase = (Clock Phase
  • (3) SCK=SCLK=SPI clock
  • (4) Edge= Edge, which is the moment when the clock level changes, namely rising Edge or falling Edge.

For a clock cycle, there are two edges, called:

  • (1)Leading edge= previous edge= first edge, for the starting voltage is 1,

So that’s when 1 goes to 0, for voltage 0 at the beginning, that’s when 0 goes to 1;

  • (2)Trailing edge= Trailing edge= second edge, for the starting voltage is 1,

So that’s when 0 becomes 1, and for voltage 0 at the beginning, that’s when 1 becomes 0;

This post uses the following usages:

  1. Polarity = CPOL
  2. Phase = CPHA
  3. SCLK = clock
  4. The first edge and the second edge

CPOL and CPHA can both be 0 or time 1 respectively. The corresponding four combinations are:

model Polar phase
Mode 1 CPOL=0,CPHA=0
Mode 2 CPOL=0,CPHA=1
Mode 3 CPOL=1,CPHA=0
Mode 4 CPOL=1,CPHA=1

CPOL=0,CPHA=0

The pulse is kept low before and after transmission, so CPOL=0, i.e. low is the level when idle. Sampling data on the first edge (rising edge), output data on the second edge (falling edge), corresponding to CPHA=0.

CPOL=0,CPHA=1

The pulse is kept low before and after transmission, so CPOL=0, i.e. low is the level when idle. Sampling data on the second edge (falling edge), output data on the first edge (rising edge), corresponding to CPHA=1.

CPOL=1,CPHA=0

The pulse is kept at high level before and after transmission, so CPOL=1, i.e. high level is the level when idle. Sampling data on the first edge (falling edge), output data on the second edge (rising edge), corresponding to CPHA=0.

CPOL=1,CPHA=1

The pulse is kept at high level before and after transmission, so CPOL=1, i.e. high level is the level when idle. Sampling data on the second edge (rising edge), output data on the first edge (falling edge), corresponding to CPHA=1.

How to set the polarity and phase of SPI in the software

SPI consists of master and slave devices, which communicate through the SPI protocol. The mode to set the SPI, the mode of the slave device, determines the mode of the master device. Therefore, it is necessary to first understand the mode of SPI of the slave device, and then set the mode of SPI of the master device to be the same as that of the slave device, and then normal communication can be achieved.

There are two modes of SPI for slave devices:

  • (1) Fixed, SPI is determined by the device hardware

SPI from the device, the specific mode, will be described in the relevant description, you need to find the relevant description, namely: SPI from the device, at idle, is high level or low level, that is, determines the CPOL is 0 or 1; Then find out whether the device is on the rising edge or the falling edge to sample data. In this way, on the premise of determining the value of CPOL, the corresponding CPHA can be calculated as 0 or 1.

  • (2) Configurable, set by the software

The slave device is also an SPI controller and supports all four modes, as long as you set it to a certain mode. After knowing the mode of the slave device, set the mode of the SPI master device to be the same as that of the slave device. How to configure THE CPOL and CPHA of SPI is not detailed. Most of them are written directly to the CPOL and CPHA in the corresponding register of SPI controller. Write 0 or 1.

Data Exchanges

SPI has only master and slave modes. There are no read and write modes, because SPI is essentially a master/slave device exchanging data each time. In other words, if you send a piece of data, you will receive a piece of data; If you want to receive a number you have to send a number first.

Data transmission between SPI devices is also called data exchange because the SPI protocol stipulates that an SPI device cannot be merely a “Transmitter” or “Receiver” in the process of data communication. During each Clock cycle, the SPI device sends and receives one bit of data, which is equivalent to one bit of data exchanged on the device.

To receive control signals from the Master, a Slave device must be accessed by the Master device. Therefore, the Master device must first slice through the SS/CS PIN to select the Slave device that it wants to access. During data transfer, each received data must be sampled before the next data transfer. If previously received data is not read, the received data may be discarded, resulting in the eventual failure of the SPI physical module.

Therefore, it is common for programs to read Data from the SPI device after SPI transmission, even though the Dummy Data is useless in our program.

SPI, for example,

Let me give you an example to help you understand.

SPI is a ring bus structure, composed of SS (CS), SCK, SDI, SDO, its timing is actually very simple, mainly under the control of SCK, two two-way shift registers for data exchange.

Suppose the following 8-bit register holds the data 10101010 to be sent. The rising edge sends, the falling edge receives, and the high edge sends first. So the first rising edge is going to be sdo=1; Register = 0101010X. When the falling edge arrives, the level on the SDI will be stored in the register, then register = 0101010SDI, so that after 8 clock pulses, the contents of the two registers will be exchanged once. This completes an SPI sequence.

For example:Assuming that the master and slave are ready for initialization: and that the master’s sbuff= 0xAA and the slave’s sbuff=0x55, the following is a step-by-step demonstration of the data situation for the 8 clock cycles of spi: Assume that the rising edge sends data

This completes the 8-bit swap of the two registers, with the top representing the rising edge and the bottom representing the falling edge, sDI and SDO relative to the host.

The next step is to animate the above process

Compare the bit order after the swap.

After understanding the SPI protocol specification, let’s use the SPI controller based on exynos-4412 of the Cortex-A9 architecture.

Cortex-a9 SPI controller

The hardware design

This example is based on FS4412 development board. The SPI controller is externally connected to MCP2515. The hardware connection between MCP2515 and Exynos-4412 is shown in the figure below.

Pin connection description

The connection relation between SPI pins and SOC PIN can be seen from the figure above:

  • CS <———> BUF_BK_LED <———> GPC1_2

  • SO <———> BUF_I2C_SDA6 <———> GPC1_3

  • SI <———> BUF_I2C_SCL6 <———> GPC1_4

  • SCK <———> BUF_GPC1_1 <———> GPC1_1

  • INT <——————————————-> BUF_GPX0_0

  • MCP2515 chip is connected to SPI2 of 4412 chip.

  • The broken connection is on GPX0_0;

CS, SO, SI, SCK reuse GPIO pin GPC1 pin.

The OUTPUT of the MCP2515 connects to the SN65HVD230 CAN bus transceiver, a 3.3V CAN transceiver produced by Texas Instruments. In order to save power consumption and reduce circuit size, LVTTL is used in logic level of MCP2515 CAN bus controller, SN65HVD230 is its matching transceiver.

Cortex-a9 SPI controller

The serial peripheral interface (SPI) in the exynos4412 SCP transmits serial data through various peripherals. SPI includes two 8, 16, and 32 bit shift registers for transmitting and receiving data. In SPI transmission, it transmits (serial shift out) and receives (serial shift) data at the same time.

features

  • Full duplex
  • 8/16/32 bit shift register for Tx/Rx
  • Support 8 bit /16 bit /32 bit bus interface
  • Support MOTOROLA SPI protocol and National Semiconductor Microwire
  • Two separate 32-bit wide send and receive FIFOS: port 0 has a depth of 64, and ports 1 and 2 have a depth of 16
  • Master mode and slave mode
  • The operation of receiving without sending
  • The maximum transmit/receive frequency is 50 MHz

The operation of the SPI

SPI transfers 1-bit serial data between the Exynos 4412 SCP and external devices. SPI in the Exynos 4412 SCP supports both CPU or DMA sending or receiving FIFO and bi-directional transmission data, respectively. SPI has two channels, the Tx channel and the Rx channel. The Tx channel has a path from Tx

FIFO to external devices. The Rx channel has a path from the external device to the Rx FIFO.

The CPU (or DMA) must write data to the SPI_TX_DATA register in order to write data to the FIFO. The data on the register is automatically moved to the Tx FIFO. To read data from the Rx FIFO, the CPU (or DMA) must access the SPI_RX_DATA register, and the data is automatically sent to the SPI_RX_DATA register.

The CMU register controls the operating frequency of the SPI.

Operating mode

SPI has two modes, master mode and slave mode. In the main mode, SPICLK is generated and transmitted to external devices. XspiCS# is the slave selection signal indicating low data availability when XspiCS is set up. XspiCS must be set to low before packets can be sent or received.

FIFO access

SPI supports CPU access and DMA access to fifO. The data size for CPU access and DMA access to the FIFO is selected from 8-bit, 16-bit, or 32-bit data. When it selects an 8-bit data size, the significant bits are 0 to 7 bits. You can define triggering thresholds to trigger CPU interrupts. The trigger level of each FIFO in port 0 steps from 0 to 252 bytes to 4 bytes, and the trigger level of each FIFO in port 1 steps from 0 to 63 bytes to 1 byte. The TxDMAOn or RxDMAOn bits of the SPI_MODE_CFG register must be set to use DMA access. DMA access supports only single transfer and 4 burst transfers. In the Tx FIFO, the DMA request signal is high until the Tx FIFO is full. In Rx FIFO, if the FIFO is not empty, the DMA request signal is high.

Piece of selected control

Chip selection XspiCS is activated by low signal. In other words, when the XspiCS input is 0, the chip is selected. You can control XspiCS automatically or manually. No need to change. Manual mode When you use manual control mode, you should clear AUTO_N_MANUAL (default is 0). The NSSOUT bit controls the XspiCS level. Automatic mode If the automatic control mode is used, AUTO_N_MANUAL must be set to 1. XspiCS in packets and automatic packaging. NCS_TIME_COUNT controls the deactivation period of XspiCS. NSSOUT is not available at this time.

SPI register Description

Configure register CH_CFGn

[bit:5] This bit must be set to 1 before software reset, and then set to 0 after a delay. [bit:4] Set SPI port to master or slave. 0: master, 1: slave. [Bit :2-3] Set phase and polarity; [bit:1] Enable bit of the channel to receive data; [bit:0] Enable bit of the channel for sending data.

Data width register MODE_CFGn

Set the bus data width, usually 1 byte.

Chip selection register CS_REGn

Data will be transferred only when NSSOUT is pulled down

Shift register Status register SPI_STATUSn

The send operation starts. If the shift register is empty, this value is set to 1 to determine whether the data is sent or not.

Send buffer register SPI_TX_DATA

Receive buffer register SPI_RX_DATA

SPI initialization process

  1. Set GPIO pin to SPI mode;
  2. Set the clock;
  3. Software reset;
  4. Set the CPOL CPHA mode to 00 and the host mode.
  5. Set data bits;
  6. Optional.

1. Set the GPIO pin to SPI mode

Because CS, SO, SI, SCK reuse GPIO pin GPC1 pin. First you need to set the GPIO pin to SPI mode.

As shown above, the register is set as follows:

GPC1.CON = (GPC1.CON & ~0xffff0) | 0x55550;// Set the IO pin to SPI mode
Copy the code

Step 1 Set CPOL and CPHA to 00

SPI2.CH_CFG&=~((0x1<< 4)|(0x1<<3)|(0x1<< 2)|0x3);

//master mode, CPOL = 0, CPHA = 0 (Format A)

2 set the clock

The clock setting depends on the PLL clock generator.Section 30.2.1 shows that you need to refer to the CMU for clock configuration. According to the figure above, the CLOCK source of SPI is SCLK_SPI.

Search SCLK_SPI

Search all SPIs from Chapter 7Continue to searchSPI0~2 is controlled by CLKMPLL_USER_T. This clock is located in the bit[27:24] of register CLK_SRC_PERIL1.Continue searching SPI2.Search for CLK_SRC_MASK_PERIL1 and CLK_DIV_PERIL2. The register CLK_SRC_MASK_PERIL1 is open by default, so do not set it. CLK_DIV_PERIL2 is used to set THE SPI2 divider, so the register is set as follows:

CLK_SRC_PERIL1 = (CLK_SRC_PERIL1 & ~(0xF<<24)) | 6<<24;
// 0x6: 0110 = SCLKMPLL_USER_T 800Mhz
CLK_DIV_PERIL2 = 19 <<8 | 3;//SPI_CLK = 800/(19+1)/(3+1)
Copy the code

3. The software resets

void soft_reset(void)
{	SPI2.CH_CFG |= 0x1 << 5;
	delay(1);                     / / delay
	SPI2.CH_CFG &= ~(0x1 << 5);
}
Copy the code

4. Set the CPOL CPHA mode to 00 and the host mode

SPI2.CH_CFG &= ~( (0x1 << 4) | (0x1 << 3) | (0x1 << 2) | 0x3);
Copy the code

5. Set the data bit MODE_CFG

SPI2.MODE_CFG &= ~((0x3 << 17) | (0x3 << 29));
   //BUS_WIDTH=8bit,CH_WIDTH=8bit 
Copy the code

6. Optional

SPI2.CS_REG &= ~(0x1 << 1);        // Select manually select chip
Copy the code

With the initialization done, let’s look at how SPI sends and receives data.

Data sending and receiving Process

The data sending and receiving process is as follows:

  1. Spi reset
  2. Choose from the machine
  3. Sending and receiving data
  4. Cancel the piece to choose

[Note] The following code sets the value of reading and writing 1 byte data at a time. Perform the preceding steps for each read and write 1 byte data.

1 spi reset

void soft_reset(void)
{	SPI2.CH_CFG |= 0x1 << 5;
	 delay(1);                     / / delay
	 SPI2.CH_CFG &= ~(0x1 << 5);
}
Copy the code

2 pieces selection machine

void slave_enable(void)
{
	SPI2.CS_REG &= ~0x1; //enable salve
	delay(3);
}
Copy the code

3.1 Sending Data

void send_byte(unsigned char data)
{
	SPI2.CH_CFG |= 0x1; // enable Tx Channel
	delay(1);
	SPI2.SPI_TX_DATA = data;
	while( !(SPI2.SPI_STATUS & (0x1 << 25))); SPI2.CH_CFG &= ~0x1; // disable Tx Channel
}
Copy the code

3.2 Receiving Data

unsigned char recv_byte(a)
{
	unsigned char data;
	SPI2.CH_CFG |= 0x1 << 1; // enable Rx Channel
	delay(1);
	data = SPI2.SPI_RX_DATA;
	delay(1);
	SPI2.CH_CFG &= ~(0x1 << 1); //disable Rx Channel
	return  data;
}
Copy the code

Cancel the piece to choose

void slave_disable(void)
{

	SPI2.CS_REG |= 0x1; //disable salve
	delay(1);
}
Copy the code

OK, so far, we can already implement how to send and receive data through SPI, but SPI tends to call back various slave devices externally. Let’s look at how SPI operates on the slave device.

We said above, FS4412 development board SPI2 peripheral connected to MCP2515, now we come to analyze MCP2515.

MCP2515

MCP2515 Datasheet “Independent CAN controller with SPI interface”

Introduction to the

MCP2515 is an independent CAN bus communication controller, which is the upgrade component of the first independent CAN solution of Microchip. Its transmission capacity is twice as high as Microchip’s original CAN controller (MCP2510), and the high communication rate CAN reach 1Mbps. The MCP2515 can receive and send standard and extended data frames as well as remote frames, reducing the CPU burden by filtering out irrelevant messages through two receive masking registers and six receive filtering registers.

features

The main functional parameters and electrical characteristics of MCP2515 are as follows:

  • (1) Support CAN technical specification 2.0A/B, high transmission rate up to 1Mbps;
  • (2) Support standard data frame, extended data frame and remote frame, the length of each frame data field can be 0~8 bytes;
  • (3) including two receiving buffers and three sending buffers, and programmable setting priority;
  • (4) contains six 29-bit receive filter registers and two 29-bit receive mask registers;
  • (5) high-speed SPI interface, supporting SPI 0,0 and 1,1 mode;
  • (6) One-time mode can ensure that the message is transmitted at one time;
  • (7) With programmable clock pulse output pin, can be used as other chip clock signal source;
  • (8) Frame initiation (SOF) signal output function CAN be used to perform time slot function in certain systems (such as time-triggered CAN-TTCAN), or to determine early bus exit stage in CAN bus diagnosis;
  • (9) Low power CMOS technology, working voltage: 2.7V~5.5V, working current: 5mA (standby state: 1μA);
  • (10) operating temperature range :(I) -40℃ to +85℃, (E) -40℃ to +125℃.

Structure diagram

The CAN module

The MCP2515 is a standalone CAN controller that simplifies applications that need to connect to the CAN bus. The diagram above briefly shows the structure diagram of MCP2515. The device is mainly composed of three parts:

  1. CAN module, including CAN protocol engine, acceptance filter storage

Receiver, acceptance mask register, send and receive buffer. 2. Control logic and registers used to configure the device and its operation. 3. SPI protocol module.

The function of THE CAN module is to process the receiving and sending of all messages on the CAN bus. When a message is sent, it is first loaded into the correct message buffer and control register. The send operation can be initiated by setting the corresponding bit in the control register through the SPI interface or by using the send enable pin. The communication status and errors can be checked by reading the corresponding register. Any message detected on the CAN bus is checked for errors and then matched with a user-defined filter to determine whether the message is moved to one of the two receive buffers.

SPI protocol module

MCU is connected to the device through an SPI interface. Use standard SPI read/write instructions and special SPI commands to read/write all registers. The MCP2515 is designed to be directly connected to serial peripheral interfaces (SPI) of many single chip computers, supporting 0,0 and 1,1 operating modes. External data and commands are transmitted to the device via SI pins, and data is transmitted on the rising edge of the SCK clock signal. The MCP2515 is transmitted through the SO pin at the descending edge of the SCK. The CS pin must be kept low during any operation.

Communicate with MCP2515

SPI instruction set

If we want to operate MCP2515, we can only use SPI bus to send some data to MCP2515. According to the regulation, sending different data represents different operations, so the corresponding instruction set is formed.As shown in the figure above, for example, if we want to perform a reset operation, ALL I need to do is write 11000000, or 0xC0, through the SPI bus.

The following is a detailed analysis of how to send the reset command to MCP2515 and how to read and write data.

reset

Because reset only needs to send 0XC0 and no additional operations are required, we only need to operate the SPI data flow interface as described in the previous section.

void reset_2515(a)
{
	soft_reset();      // Resets the SPI controller
    slave_enable() ;   // Select a slave
	send_byte(0xc0);   // Send the reset command
	slave_disable() ;  // Cancel the selection

}
Copy the code

Read the data

According to the figure above, the data reading process is as follows:

  1. Choose from the machine
  2. Send instruction 0x03 via SPI
  3. Send the address
  4. Read the data
  5. Cancel the piece to choose
unsigned char read_byte_2515(unsigned char Addr)
{
	unsigned char ret;
    slave_enable();
    send_byte(0x03);
    send_byte(Addr);
    ret = recv_byte();
    slave_disable();
    return(ret);
}
Copy the code

To send data

According to the figure above, the data sending process is as follows:

  1. Choose from the machine
  2. Send instruction 0x02 via SPI
  3. Send the address
  4. To send data
  5. Cancel the piece to choose
void write_byte_2515(unsigned char addr,unsigned char data)
{
    slave_enable();
    send_byte(0x02);
    send_byte(addr);
    send_byte(data);
    slave_disable();
}
Copy the code

Read RX buffer

Load TX buffer

Request send (RTS) instruction

Bit modification instruction

In order to modify the corresponding bit of some registers, this instruction must be sent first to send the masked byte, and then the value of the corresponding bit 1 in the masked byte can be modified. Examples will be given later.

CAN

Knowing how to communicate with CAN, let’s see how to initialize CAN.

CAN initialize

CAN initialization steps are as follows:

  1. MCP2515 reset
  2. Example Set MCP2515 to configuration mode
  3. Bit timing configuration, with configuration registers CNF1, CNF2,CNF3 control
  4. The interrupt enable
  5. Receive buffer configuration
  6. Pin control register and status register

In addition, for the convenience of testing, we add another step: 7. Loopback mode for testing

1. The MCP2515 reset

That was implemented in the previous section.

void reset_2515(a)
Copy the code

2. Set MCP2515 to configuration mode

As shown in the figure above, just write data 0x80 to address 0X0F.

 write_byte_2515(0x0f.0x80);    CANCTRL register -- Enter configuration mode, Chinese Page 58
Copy the code

3. Bit timing configuration, with configuration registers CNF1, CNF2,CNF3 control

All nodes on the CAN bus must have the same nominal bit rate. CAN protocol adopts non-return to Zero (NRZ) encoding mode, which does not encode clock signal in data stream. Therefore, the receiving clock signal must be recovered by the receiving node and synchronized with the clock of the transmitter.

Because the oscillator frequency and transmission time of different nodes are different, the receiver should have some kind of Phase Lock Loop (PLL) that can synchronize with the data transmission edge to synchronize the clock and maintain this synchronization.

Given that the data is NRZ encoded, bit padding is necessary to ensure that edges occur at least every 6 bits of time to synchronize Digital Phase LockLoop (DPLL). MCP2515 uses DPLL to implement bit timing. DPLL is configured to synchronize input data and provide nominal timing for sending data. DPLL divides each bit of Time into multiple Time periods consisting of the smallest unit of Time Quanta (TQ).

Bus timing functions performed in in-place time frames, such as synchronization with the local oscillator, network transmission delay compensation, and sampling point location, are specified by DPLL’s programmable bit-timing logic.

CNF1 BRP<5:0> Controls the setting of baud rate predivision ratio. These bits set the length of the TQ based on the OSC1 input frequency. When BRP<5:0> = ‘b000000’, the minimum TQ value is 2 TOSC. SJW<1:0> is used to select the synchronization jump width measured in TQ.

PRSEG<2:0> bit of CNF2 sets the propagation time in terms of TQ. PHSEG1<2:0> bit sets the length of phase buffer PS1 in terms of TQ.

CNF3 If the CNF2.bTLMode bit is 1, the phase buffer PS2 time length will be set by PHSEG2<2:0> bit, in TQ. If the BTLMODE bit is 0, the PHSEG2<2:0> bit has no effect.

MCP2515 Baud rate configuration Take 16M crystal oscillator as an example, number of SJW segments (1+PRSEG+PRSEG1+PRSEG2)

#define CNF1_20K     0xd3        / / 4 20 (1 + 4 + 8 + 7)
#define CNF2_20K     0xfb          
#define CNF3_20K     0x46           

// Configurable baud rate 5K 10K 15K 20K 25K 40K 50K 80K 100K 125K 200K 400K 500K 667K 800K 1M
write_byte_2515(0x2A, CNF1_20K); //CNF1 bit timing configuration transmitter
write_byte_2515(0x29, CNF2_20K); //CNF2 bit timing configuration transmitter
write_byte_2515(0x28, CNF3_20K); //CNF3 bit timing configuration transmitter
Copy the code

4. Enable the interrupt function

MCP2515 has eight interrupt sources. The CANINTE register contains the interrupt enable bits that enable each interrupt source. The CANINTF register contains the interrupt flag bits of each interrupt source. When an interrupt occurs, the INT pin will be pulled low by MCP2515 and remain low until the MCU clears the interrupt. Interrupts are cleared only after the condition that caused the interrupt has disappeared. It is recommended to reset the flag bit in the CANINTF register using bit-modification commands rather than general write operations. This is to avoid accidentally modifying the flag bit during write command execution, resulting in interrupt loss. It should be noted that the interrupt flag bit in CANINTF is a read-write bit, so under the premise of the relevant CANINTE interrupt enable position 1, MCU can generate interrupt request for any of the above position 1.

write_byte_2515(0x2B.0x1f);     //CANINTE interrupt enable register
Copy the code

5. Configure the receive buffer

The MCP2515 has two full receive buffers. Each receiving buffer is equipped with multiple filter detectors. In addition to the above dedicated receiver Buffer, the MCP2515 also has a separate Message Assembly Buffer (MAB) that can be used as a third receiver Buffer.Bit5:6 is set to 1 and the remaining bits are set to 0.

 write_byte_2515(0x60.0x60);   //RXB0CTRL receives buffer 0 control register
Copy the code

6. Pin control register and status register

When the pin is configured as a digital output pin, the BFPCtrl.bxBFM bit in the corresponding receive buffer should be cleared and the BFPCtrl.bnbfe bit should be set to 1. In this operating mode, the state of the pin is controlled by the BFPCtrL.bnbfs bit. Writing the BnBFS bit 1 causes the corresponding buffer full interrupt pin to output high, and writing the BnBFS bit 0 causes the pin to output low. When a pin is in this mode, the state of the pin should only be modified by the bit modification SPI command to avoid interference with any buffer full interrupt pins.

void bit_modify_2515(unsigned char addr, unsigned char mask, unsigned char data)
{
// CS_SPI = 0 ;
    slave_enable() ;
    send_byte(0x05); send_byte(addr) ; send_byte(mask) ; send_byte(data) ; slave_disable() ;// CS_SPI = 1 ;
}
bit_modify_2515(0x0C.0x0f.0x0f); //BFPCTRL_RXnBF Pin control register and Status Register In Chinese Page 29
Copy the code

7. Loopback mode for testing

write_byte_2515(0x0f.0x40);   //CAN control register -- loop mode, used for testing
Copy the code

Can buffer data sending and receiving

The MCP2515 uses three send buffers. Each send buffer occupies 14 bytes of SRAM and is mapped to device memory. The first byte TXBnCTRL is the control register associated with the message buffer. The information in this register determines the conditions under which a message is sent and indicates its status when it is sent.

Five bytes are used to load standard and extended identifiers and other message mediation information (see registers 3-3 through registers 3-7). The last eight bytes are used to load the eight possible bytes of data waiting for the message to be sent.

At a minimum, the TXBnSIDH, TXBnSIDL and TXBnDLC registers must be loaded with data. If the message contains data bytes, the TXBnDm register also needs to be loaded. If the message uses an extended identifier, the TXBnEIDm register should be loaded and the tXBNsidl.exide position 1.

Let’s look at how to send and receive data to buffer 0 of CAN.

Data sent

Can buffer 0 data sending process is as follows:

  1. Set this parameter to the highest priority
  2. Set the high level of the standard identifier of send buffer 0
  3. Sets the standard identifier low of send buffer 0
  4. Set send buffer 0 data length code to 8 bytes
  5. Writes data to the buffer, starting at 0x36
  6. Send request command 0x81 to send data

1. Set this parameter to the highest priority

write_byte_2515(0x30.0x03); // Set it to the highest priority
Copy the code

2. Set the high level of the standard identifier of send buffer 0

write_byte_2515(0x31.0xff); // Send buffer 0 standard identifier high
Copy the code

3. Set the standard identifier of send buffer 0

write_byte_2515(0x32.0x00); // Send buffer 0 standard identifier low
Copy the code

4. Set the data length code of send buffer 0 to 8 bytes

write_byte_2515(0x35.0x08);  // Send buffer 0 data length code 8 bytes
Copy the code

5. Write data to the buffer starting from 0x36

write_byte_2515(0x36+i ,tx_buff[i]); // Write 8 bytes to TXB buffer
Copy the code

6. Send the request command 0x81 to send data

void send_req_2515(a)
{
 // CS_SPI = 0; / / reset
	soft_reset();      // Resets the SPI controller
    slave_enable() ;   // Select a slave
	send_byte(0x81);   // Send the request command
	slave_disable() ;  // Cancel the selection
//	CS_SPI=1;
}
Copy the code

Can data reception

The process of reading data from the CAN buffer is as follows:

  1. Read the value of interrupt flag register 0x2c to determine whether bit0 is 1
  2. Read data from the receive buffer, starting at address 0X66
  3. Soft reset
  4. Writes a bitmask to interrupt flag register 0x2c
  5. Write data 0 to interrupt flag register 0x2C and clear terminal

1. Read the value of the interrupt flag register 0x2c and check whether bit0 is 1

When a message is sent to a receive buffer, the canintf. RXnIF bit corresponding to the receive buffer is set to 1. Once the message in the buffer is processed, the MCU must clear the bit to zero to receive the next message. The locking function provided by this control bit ensures that the MCP2515 does not load a new message into the receive buffer until the MCU has processed the previous message.

If the CANINTE.RXnIE bit is set to 1, the device generates an interrupt at the INT pin indicating that the received message is valid. In addition, if configured as a receive buffer full interrupt pin, the corresponding RXnBF pin will be pulled down.

MCP2515 has eight interrupt sources. The CANINTE register contains the interrupt enable bits that enable each interrupt source. The CANINTF register contains the interrupt flag bits of each interrupt source. When an interrupt occurs, the INT pin will be pulled low by MCP2515 and remain low until the MCU clears the interrupt. Interrupts are cleared only after the condition that caused the interrupt has disappeared.

It is recommended to reset the flag bit in the CANINTF register using bit-modification commands rather than general write operations. This is to avoid accidentally modifying the flag bit during write command execution, resulting in interrupt loss.

It should be noted that the interrupt flag bit in CANINTF is a read-write bit, so under the premise of the relevant CANINTE interrupt enable position 1, MCU can generate interrupt request for any of the above position 1.

2. Read data from the receive buffer

rx_buff[i]= read_byte_2515(0x66+i);
Copy the code

3. The soft reset

soft_reset();
Copy the code

4. Write the bitmask to the interrupt flag register 0x2c

bit_modify_2515(0x2c.0x01.0x00);// Change bit 0
Copy the code

5. Clear the interrupt

write_byte_2515(0x2c.0x00);
Copy the code

The final operation code is as follows

Save space, repeat the function is not posted.

#define CNF1_20K     0xd3        / / 4 20 (1 + 4 + 8 + 7)
#define CNF2_20K     0xfb          
#define CNF3_20K     0x46  
         
void  Init_can(void)
{
    reset_2515(); / / reset
    write_byte_2515(0x0f.0x80); CANCTRL register -- Enter configuration mode, Chinese Page 58
	// Configurable baud rate 5K 10K 15K 20K 25K 40K 50K 80K 100K 125K 200K 400K 500K 667K 800K 1M
    write_byte_2515(0x2A, CNF1_20K); //CNF1 bit Timing Configuration transmitter Chinese DATASHEET page 41-42
    write_byte_2515(0x29, CNF2_20K); //CNF2 bit Timing Configuration transmitter Chinese DATASHEET page 41-42
    write_byte_2515(0x28, CNF3_20K); //CNF3 timing Configuration transmitter Chinese DATASHEET pages 41-43
    write_byte_2515(0x2B.0x1f);     //CANINTE Interrupt Enable Register Chinese DATASHEET 50 pages
    write_byte_2515(0x60.0x60);     //RXB0CTRL Receiver buffer 0 control register Chinese DATASHEET 27 pages
    //write_byte_2515(0x70, 0x20); // Receive buffer 1 control register
    bit_modify_2515(0x0C.0x0f.0x0f); //BFPCTRL_RXnBF Pin control register and Status Register In Chinese Page 29
    write_byte_2515(0x0f.0x40);   //CAN control register -- loop mode, used for testing
}
void send_byte(unsigned char data)
{
	SPI2.CH_CFG |= 0x1; // enable Tx Channel
	delay(1);
	SPI2.SPI_TX_DATA = data;
	while( !(SPI2.SPI_STATUS & (0x1 << 25))); SPI2.CH_CFG &= ~0x1; // disable Tx Channel
}
unsigned char recv_byte(a)
{
	unsigned char data;
	SPI2.CH_CFG |= 0x1 << 1; // enable Rx Channel
	delay(1);
	data = SPI2.SPI_RX_DATA;
	delay(1);
	SPI2.CH_CFG &= ~(0x1 << 1); //disable Rx Channel
	return  data;
}
void bit_modify_2515(unsigned char addr, unsigned char mask, unsigned char data)
{
// CS_SPI = 0 ;
    slave_enable() ;
    send_byte(0x05); send_byte(addr) ; send_byte(mask) ; send_byte(data) ; slave_disable() ;// CS_SPI = 1 ;
}
void Can_send(unsigned char *tx_buff)
{
	unsigned char i;
	write_byte_2515(0x30.0x03); // Set it to the highest priority
	write_byte_2515(0x31.0xff); // Send buffer 0 standard identifier high
	write_byte_2515(0x32.0x00); // Send buffer 0 standard identifier low
	write_byte_2515(0x35.0x08);  // Send buffer 0 data length code 8 bytes
	for(i = 0; i < 8; i++)
	{
		write_byte_2515(0x36+i ,tx_buff[i]); // Write 8 bytes to TXB buffer
// printf("%x ",tx_buff[i]);
	}
	send_req_2515();

}

unsigned char Can_receive(unsigned char *rx_buff)
{
	unsigned char i,flag;
    flag = read_byte_2515(0x2c); //CANINTF -- Interrupt flag register
    printf("flag=%x\n",flag);
  // printf(" SPI2.SPI_STATUS =%x\n", SPI2.SPI_STATUS );
 // soft_reset();
    if (flag&0x1)                Receive buffer 0 full interrupt flag bit
    {
    	for(i = 0; i < 16; i++)
		{
    		rx_buff[i]= read_byte_2515(0x66+i);
    // printf("%x ",rx_buff[i]);
    // printf(" SPI2.SPI_STATUS =%x\n", SPI2.SPI_STATUS );
    		soft_reset();
		}
    	bit_modify_2515(0x2c.0x01.0x00);
    	write_byte_2515(0x2c.0x00);
		if(! (rx_buff[1] &0x08)) return(1);	  // Receive standard data frames
    }
    return(0);
}
int main(void)
{
	GPX2.CON = 0x1 << 28;
	uart_init();

	unsigned char ID[4],buff[8];            					/ / state
	unsigned char key;
	unsigned char ret;//,j,k,ret0,ret1,ret2,ret3,ret4,ret5,ret6,ret7,ret8,ret9;
	unsigned int rx_counter;
	volatile int i=0;

	GPC1.CON = (GPC1.CON & ~0xffff0) | 0x55550;// Set the IO pin to SPI mode

/*spi clock config*/
	CLK_SRC_PERIL1 = (CLK_SRC_PERIL1 & ~(0xF<<24)) | 6<<24;// 0x6: 0110 = SCLKMPLL_USER_T 800Mhz
	CLK_DIV_PERIL2 = 19 <<8 | 3;//SPI_CLK = 800/(19+1)/(3+1)

	soft_reset();	                   // Soft reset SPI controller
	SPI2.CH_CFG &= ~( (0x1 << 4) | (0x1 << 3) | (0x1 << 2) | 0x3);//master mode, CPOL = 0, CPHA = 0 (Format A)
	SPI2.MODE_CFG &= ~((0x3 << 17) | (0x3 << 29));   //BUS_WIDTH=8bit,CH_WIDTH=8bit
	SPI2.CS_REG &= ~(0x1 << 1);        // Select manually select chip
	mydelay_ms(10);    / / delay
    Init_can();   // Initialize MCP2515

    printf("\n************ SPI CAN test!! ************\n");

    while(1)
    {
		//Turn on led
		GPX2.DAT = GPX2.DAT | 0x1 << 7;
		mydelay_ms(50);

    	printf("\nplease input 8 bytes\n");

    	for(i=0; i<8; i++) { src[i] = getchar(); putc(src[i]); }printf("\n");

    	Can_send(src); // Send a standard frame
        mydelay_ms(100);
        ret = Can_receive(dst); // Receive CAN bus data
        printf("ret=%x\n",ret);
        printf("src=");
        for(i=0; i<8; i++)printf(" %x", src[i]);// Send the data received on the CAN bus to the serial port

        printf("\n");

        printf("dst=");
        for(i=0; i<8; i++)printf(" %x",dst[6+i]); // Send the data received on the CAN bus to the serial port
		printf("\n");

		//Turn off
		GPX2.DAT = GPX2.DAT & ~(0x1 << 7);
		mydelay_ms(100);
    } //while(1)

	return 0;
} //main

Copy the code

Question 1. What is the Feddback clock? 2 buffer register group principle of Can