如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78979855

一、SPI简介

参看:SPI详解

SPI(serial peripheral interface,串行外围设备接口)总线技术是 Motorola 公司推出的一种同步串行接口。它用于CPU与各种外围器件进行全双工、同步串行通讯。它只需四条线就可以完成 MCU 与各种外围器件的通讯,这四条线是:串行时钟线(CSK)、主机输入->从机输出数据线(MISO)、主机输出<-从机输入数据线(MOSI)、低电平有效从机选择线CS。当SPI工作时,在移位寄存器中的数据逐位从输出引脚(MOSI)输出(高位在前),同时从输入引脚(MISO)接收的数据逐位移到移位寄存器(高位在前)。发送一个字节后,从另一个外围器件接收的字节数据进入移位寄存器中。即完成一个字节数据传输的实质是两个器件寄存器内容的交换。主SPI的时钟信号(SCK)使传输同步。

二、SPI 主、从硬件连接图

参看:SPI -- 维基百科

SPI是用来跟各种外设,如:
传感器:温度,压力,ADC,触摸屏,视频游戏控制器
控制设备:音频编解码器,数字电位器,DAC
相机镜头:佳能EF镜头卡口
通讯:以太网,USB,USART,CAN,IEEE 802.15.4,IEEE 802.11,手持视频游戏
内存:闪存和EEPROM
实时时钟
LCD,有时甚至用于管理的图像数据
任何MMC或SD卡(包括SDIO变体[6] )
对于高性能系统中,FPGA中有时使用SPI接口作为从一台主机,作为主传感器,或用于用于引导如果它们是基于SRAM的闪存。

查看芯片手册和原理图 DM368 有 5 组 SPI 总线,每组 3 个片选;Hi3516A 有 2 组 SPI 总线,每组 3 个片选。

SPI总线一个主机接多个从机连接方法:

典型的SPI总线:主站和三个独立的从站

在独立从配置,存在用于每个从一个独立的片选线。电源和芯片选择线之间的上拉电阻强烈建议为每个独立的装置,以减少设备之间的串扰。[3]这是通常使用SPI的方式。因为从站的MISO引脚连接在一起时,它们需要是三态销(高,低或高阻抗)。

菊花链式SPI总线:主站和协同从站

实现SPI一些产品可在被连接的菊花链配置中,第一从输出被连接到第二从输入等每个从属的SPI端口被设计第二组时钟的过程中发出脉冲的精确副本数据它的第一组时钟脉冲的期间接收到的。整个链充当通信移位寄存器 ; 菊花链通常与移位寄存器完成通过SPI提供的输入或输出的银行。这种特征仅需要从主,而不是为每个从一个单独的SS线的单个SS线。可以与SPI需要菊花链配置潜在互操作的其它应用包括SGPIO,JTAG,[5]和双线接口。

三、SPI 四种工作模式

(1)工作模式

SPI 有四种工作模式,各个工作模式的不同在于 SCLK 不同, 具体工作由 CPOL,CPHA 决定。

CPOL: (Clock Polarity),时钟极性:
当CPOL为0时,时钟空闲时电平为低;

当CPOL为1时,时钟空闲时电平为高;
CPHA:(Clock Phase),时钟相位:
当CPHA为0时,时钟周期的上升沿采集数据,时钟周期的下降沿输出数据;
当CPHA为1时,时钟周期的下降沿采集数据,时钟周期的上升沿输出数据;

CPOL和CPHA,分别都可以是0或时1,对应了四种组合。

四种工作方式时序分别为:

(2)辨识技巧

上面讲到了有四种工作模式,该如何确认自己的设备使用的是哪种工作模式呢?

以GV7601SDI 解码芯片为例:

参看:GV7601 SDI解码芯片DATASHEET

参看:Hi3516A开发--GV7601 硬件设计

1、先确认从机需求的 SCLK 极性,不工作时是在低电位还是高电位,由此确认 CPOL 为 0 或 1

时钟空闲时电平为低,得出:CPOL 为 0

2、再由slave芯片 datasheet 中的时序图确认 slave 芯片是在 SCLK 的下降沿采集数据,还是在SCLK的上升沿

翻译一下:

在读取序列(命令字R / W位设置为高电平)期间,将传输串行数据或先接收MSB,与串行时钟SCLK的上升沿同步。芯片选择(CS)信号必须在第一个之前设置为低至少1.5ns(图4-62中的t0)时钟边缘以确保正确的操作。串行输出(SDOUT)的第一位(MSB)在读命令的最后一个下降SCLK沿之后是可用的(图4-63中的t5)字,剩余的位在SCLK的负边沿输出。
注意:当多个设备连接到GSPI链时,只能有一个CS在读取序列期间被断言。
在写序列(命令字R / W位设置为低电平)期间,等待状态为37.1ns(t4 in命令字和以下数据字之间需要图4-62)。这个在连续的命令字/数据字之间也必须保持等待状态写序列。当选择自动增量模式(AutoInc = 1)时,等待状态必须在初始命令之后的连续数据字之间保持字/数据字序列。在写序列期间,所有命令和随后的数据字输入到SDIN引脚输出在SDOUT引脚不变。当几个设备连接到GSPI链,数据可以同时写入所有CS设备低。

得出:CPHA为 0

四、优缺点

优点[ 编辑]

  • 在这个协议的默认版本全双工通信。
  • 推挽式驱动器(而不是开漏)提供良好的信号完整性和高速
  • 更高的吞吐量比I²C或SMBus的。不限于任何最大时钟速度,从而使潜在的高速
  • 完整的协议的灵活性传输的比特
    • 不限于8位字
    • 邮件大小,内容和目的任意选择
  • 极其简单的硬件接口
    • 通常较低的功率要求I²C或SMBus由于较少的电路(包括上拉电阻)
    • 没有仲裁或相关的故障模式
    • 从器件使用主时钟,不需要精密振荡器
    • 奴隶并不需要一个唯一的地址 -不像I²C或GPIB或SCSI
    • 不需要收发器
  • 仅使用4上的IC封装引脚,和电线中的电路板布局或连接器,比并行接口少得多的
  • 在每个装置最多一个唯一的总线信号(芯片选择); 所有其他人共享
  • 信号单向允许简单的电隔离
  • 简单的软件实现

缺点[ 编辑]

  • 需要在IC封装大于销I²C,即使是在三线变种
  • 没有带寻址; 外的带芯片选择信号需要在共享总线
  • 没有硬件流量控制由从属(但主机可以延迟下一个时钟边沿以减慢传输速率)
  • 没有硬件从确认(主可以传输到任何地方和不知道它)
  • 通常只支持一个主设备(取决于设备的硬件实现)
  • 没有错误检查协议被定义
  • 如果没有一个正式的标准,验证一致性是不可能的
  • 相比仅处理短距离RS-232,RS-485,或CAN总线。(其距离可以使用收发器等来扩展RS-422)
  • 许多现有的变化,因此很难找到发展的工具,如支持这些变化的主机适配器
  • SPI不支持热插拔(动态添加节点)。
  • 中断必须要么与出的带外信号来实现,或通过使用定期轮询类似于USB 1.1和2.0可以伪造
  • 像一些变体多I / O SPI和三线串行总线定义见下文是半双工。

五、单片机上 SPI 通信

参看:单片机软件模拟SPI接口—加深理解SPI总线协议

参看:Coding SPI software

参看:SOFTWARE SPI EXAMPLES FOR THE C8051F30X FAMILY

//-----------------------------------------------------------------------------
// SPI_defs.h
//-----------------------------------------------------------------------------
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 7 DEC 01
//
// This file defines the pins used for the SPI device.
// The SPI device is mapped to pins P0.0 - P0.3, but can be modified to map to
// any of the available GPIO pins on the device.
//
#ifndef SPI_DEFS
#define SPI_DEFS
sbit MOSI = P0^0; // Master Out / Slave In (output)
sbit MISO = P0^1; // Master In / Slave Out (input)
sbit SCK = P0^2; // Serial Clock (output)
sbit NSS = P0^3; // Slave Select (output to chip select)
#endif

工作模式为:(0,0)

//-----------------------------------------------------------------------------
// SPI_MODE0.c
//-----------------------------------------------------------------------------
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This file contains a ‘C’ Implementation of a Mode 0 Master SPI device.
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//
#include <c8051f300.h> // SFR declarations
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// SPI_Transfer
//-----------------------------------------------------------------------------
//
// Simultaneously transmits and receives one byte <SPI_byte> using
// the SPI protocol. SCK is idle-low, and bits are latched on SCK rising.
//
// Timing for this routine is as follows:
//
// Parameter Clock Cycles
// MOSI valid to SCK rising edge 6
// SCK rising to MISO latched 2
// SCK falling to MOSI valid 7
// SCK high time 8
// SCK low time 13
char SPI_Transfer (char SPI_byte)
{unsigned char SPI_count; // counter for SPI transactionfor (SPI_count = 8; SPI_count > 0; SPI_count--) // single byte SPI loop{MOSI = SPI_byte & 0x80; // put current outgoing bit on MOSISPI_byte = SPI_byte << 1; // shift next bit into MSBSCK = 0x01; // set SCK highSPI_byte |= MISO; // capture current bit on MISOSCK = 0x00; // set SCK low}return (SPI_byte);
} // END SPI_Transfer

工作模式为(0,1)

// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This file contains a ‘C’ Implementation of a Mode 1 Master SPI device.
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//
#include <c8051f300.h> // SFR declarations
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// SPI_Transfer
//-----------------------------------------------------------------------------
//
// Simultaneously transmits and receives one byte <SPI_byte> using
// the SPI protocol. SCK is idle-low, and bits are latched on SCK falling.
//
// Timing for this routine is as follows:
//
// Parameter Clock Cycles
// SCK rising edge to MOSI valid 4
// MOSI valid to SCK falling edge 6
// SCK falling to MISO latch 2
// SCK high time 10
// SCK low time 11
char SPI_Transfer (char SPI_byte)
{unsigned char SPI_count; // counter for SPI transactionfor (SPI_count = 8; SPI_count > 0; SPI_count--) // single byte SPI loop{SCK = 0x01; // set SCK highMOSI = SPI_byte & 0x80; // put current outgoing bit on MOSISPI_byte = SPI_byte << 1; // shift next bit into MSBSCK = 0x00; // set SCK lowSPI_byte |= MISO; // capture current bit on MISO}return (SPI_byte);
} // END SPI_Transfer

工作模式为(1,0)

// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This file contains a ‘C’ Implementation of a Mode 2 Master SPI device.
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//
#include <c8051f300.h> // SFR declarations
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// SPI_Transfer
//-----------------------------------------------------------------------------
//
// Simultaneously transmits and receives one byte <SPI_byte> using
// the SPI protocol. SCK is idle-high, and bits are latched on SCK falling.
//
// Timing for this routine is as follows:
//
// Parameter Clock Cycles
// MOSI valid to SCK falling edge 6
// SCK falling to MISO latched 2
// SCK rising to MOSI valid 7
// SCK low time 8
// SCK high time 13
char SPI_Transfer (char SPI_byte)
{unsigned char SPI_count; // counter for SPI transactionfor (SPI_count = 8; SPI_count > 0; SPI_count--) // single byte SPI loop{MOSI = SPI_byte & 0x80; // put current outgoing bit on MOSISPI_byte = SPI_byte << 1; // shift next bit into MSBSCK = 0x00; // set SCK lowSPI_byte |= MISO; // capture current bit on MISOSCK = 0x01; // set SCK high}return (SPI_byte);
} // END SPI_Transfer

工作模式为(1,1)

// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This file contains a ‘C’ Implementation of a Mode 3 Master SPI device.
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//
#include <c8051f300.h> // SFR declarations
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// SPI_Transfer
//-----------------------------------------------------------------------------
//
// Simultaneously transmits and receives one byte <SPI_byte> using
// the SPI protocol. SCK is idle-high, and bits are latched on SCK rising.
//
// Timing for this routine is as follows:
//
// Parameter Clock Cycles
// SCK falling edge to MOSI valid 4
// MOSI valid to SCK rising edge 6
// SCK rising to MISO latch 2
// SCK low time 10
// SCK high time 11
char SPI_Transfer (char SPI_byte)
{unsigned char SPI_count; // counter for SPI transactionfor (SPI_count = 8; SPI_count > 0; SPI_count--) // single byte SPI loop{SCK = 0x00; // set SCK lowMOSI = SPI_byte & 0x80; // put current outgoing bit on MOSISPI_byte = SPI_byte << 1; // shift next bit into MSBSCK = 0x01; // set SCK highSPI_byte |= MISO; // capture current bit on MISO}return (SPI_byte);
} // END SPI_Transfer

测试程序:

//-----------------------------------------------------------------------------
// SPI_F300_Test.c
//-----------------------------------------------------------------------------
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This program demonstrates how a collection of SPI master
// routines for the 8051F30x processors can be used in a C program.
//
// This program sets up the GPIO pins on the C8051F30x device for the correct
// functionality, then uses the SPI_Transfer function to send and receive
// information through the SPI pins. As information is sent, the progress of
// the program is sent out through the UART to be monitored on a connected
// terminal program.
//
// For this code to be functional, *one* of the following files should also be
// compiled or assembled, and the resulting object file must be linked to the
// object file produced from this file:
//
// SPI_MODE0.c Mode 0 SPI Master Implementation in C
// SPI_MODE0.asm Mode 0 SPI Master Implementation in Assembly
// SPI_MODE1.c Mode 1 SPI Master Implementation in C
// SPI_MODE1.asm Mode 1 SPI Master Implementation in Assembly
// SPI_MODE2.c Mode 2 SPI Master Implementation in C
// SPI_MODE2.asm Mode 2 SPI Master Implementation in Assembly
// SPI_MODE3.c Mode 3 SPI Master Implementation in C
// SPI_MODE3.asm Mode 3 SPI Master Implementation in Assembly
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f300.h> // SFR declarations
#include <stdio.h> // Standard I/O
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for ‘F30x
//-----------------------------------------------------------------------------
sfr16 DP = 0x82; // data pointer
sfr16 TMR2RL = 0xca; // Timer2 reload value
sfr16 TMR2 = 0xcc; // Timer2 counter
sfr16 PCA0CP1 = 0xe9; // PCA0 Module 1 Capture/Compare
sfr16 PCA0CP2 = 0xeb; // PCA0 Module 2 Capture/Compare
sfr16 PCA0 = 0xf9; // PCA0 counter
sfr16 PCA0CP0 = 0xfb; // PCA0 Module 0 Capture/Compare
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 24500000 // SYSCLK frequency in Hz
#define BAUDRATE 115200 // Baud rate of UART in bps
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void PORT_Init (void); // Port I/O configuration
void SYSCLK_Init (void); // SYSCLK Initialization
void UART0_Init (void); // UART0 Initialization
extern char SPI_Transfer (char); // SPI Transfer routine//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void) {unsigned char test_counter, SPI_return; // used to test SPI routine// Disable Watchdog timerPCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer// enable)SYSCLK_Init (); // initialize oscillatorPORT_Init (); // initialize ports and GPIOUART0_Init (); // initialize UART0EA = 1; // enable global interruptswhile (1){for (test_counter = 0; test_counter <= 0xFF; test_counter++){NSS = 0x00; // select SPI Slave deviceSPI_return = SPI_Transfer(test_counter); // send/receive SPI byteNSS = 0x01; // de-select SPI Slave deviceprintf(“\nSPI Out = 0x%02X, SPI In = 0x%02X”, (unsigned)test_counter,(unsigned)SPI_return);// send SPI data out to UART// for verification purposes}}
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports.
// P0.0 - MOSI (push-pull)
// P0.1 - MISO
// P0.2 - SCK (push-pull)
// P0.3 - NSS (push-pull)
// P0.4 - UART TX (push-pull)
// P0.5 - UART RX
// P0.6 -
// P0.7 -
//
void PORT_Init (void)
{XBR0 = 0x0F; // skip SPI pins in XBARXBR1 = 0x03; // UART0 TX and RX pins enabledXBR2 = 0x40; // Enable crossbar and weak pull-upsP0MDOUT |= 0x1D; // enable TX0, MOSI, SCK, and NSS as// push-pull outputs
}
//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clock to use the internal 24.5 MHz clock
// as its clock source.
//
void SYSCLK_Init (void)
{OSCICN = 0x07; // select internal oscillator as SYSCLK// source
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//
void UART0_Init (void)
{SCON0 = 0x10; // SCON0: 8-bit variable bit rate// level of STOP bit is ignored// RX enabled// ninth bits are zeros// clear RI0 and TI0 bitsif (SYSCLK/BAUDRATE/2/256 < 1){TH1 = -(SYSCLK/BAUDRATE/2);CKCON &= ~0x13;CKCON |= 0x10; // T1M = 1; SCA1:0 = xx}else if (SYSCLK/BAUDRATE/2/256 < 4){TH1 = -(SYSCLK/BAUDRATE/2/4);CKCON &= ~0x13;CKCON |= 0x01; // T1M = 0; SCA1:0 = 01}else if (SYSCLK/BAUDRATE/2/256 < 12){TH1 = -(SYSCLK/BAUDRATE/2/12);CKCON &= ~0x13; // T1M = 0; SCA1:0 = 00}else{TH1 = -(SYSCLK/BAUDRATE/2/48);CKCON &= ~0x13;CKCON |= 0x02; // T1M = 0; SCA1:0 = 10}TL1 = 0xff; // set Timer1 to overflow immediatelyTMOD |= 0x20; // TMOD: timer 1 in 8-bit autoreloadTMOD &= ~0xD0; // modeTR1 = 1; // START Timer1TI0 = 1; // Indicate TX0 ready
}

SPI程序:

//-----------------------------------------------------------------------------
// SPI_EE_F30x.c
//-----------------------------------------------------------------------------
// Copyright 2001 Cygnal Integrated Products, Inc.
//
// AUTH: BD
// DATE: 14 DEC 01
//
// This program demonstrates how a collection of SPI master routines for the
// 8051F30x devices can be used in a C program.
//
// In this example, a Microchip 25LC320 4k X 8 Serial EEPROM is interfaced to a
// SPI master device implemented in the C8051F30x. The EEPROM is written with
// two test patterns: 1) all locations are 0xFF and 2) each location is written
// with the LSB of the corresponding address.
// The EEPROM contents are then verified with the test patterns. If the test
// patterns are verified with no errors, the LED blinks on operation completion.
// Otherwise, the LED stays off. Progress can also be monitored by a terminal
// connected to UART0 operating at 115.2kbps.
//
// For this code to be functional, *one* of the following files should also be
// compiled or assembled, and the resulting object file must be linked to the
// object file produced from this code:
//
// SPI_MODE0.c Mode 0 SPI Master Implementation in C
// SPI_MODE0.asm Mode 0 SPI Master Implementation in Assembly
// SPI_MODE3.c Mode 3 SPI Master Implementation in C
// SPI_MODE3.asm Mode 3 SPI Master Implementation in Assembly
//
// This EEPROM’s serial port will only operate with a Mode 0 or Mode 3
// SPI configuration.
//
// Target: C8051F30x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f300.h> // SFR declarations
#include <stdio.h> // Standard I/O
#include “SPI_defs.h” // SPI port definitions
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for ‘F30x
//-----------------------------------------------------------------------------
sfr16 DP = 0x82; // data pointer
sfr16 TMR2RL = 0xca; // Timer2 reload value
sfr16 TMR2 = 0xcc; // Timer2 counter
sfr16 PCA0CP1 = 0xe9; // PCA0 Module 1 Capture/Compare
sfr16 PCA0CP2 = 0xeb; // PCA0 Module 2 Capture/Compare
sfr16 PCA0 = 0xf9; // PCA0 counter
sfr16 PCA0CP0 = 0xfb; // PCA0 Module 0 Capture/Compare
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define SYSCLK 24500000 // SYSCLK frequency in Hz
#define BAUDRATE 115200 // Baud rate of UART in bps
#define EE_SIZE 4096 // EEPROM size in bytes
#define EE_READ 0x03 // EEPROM Read command
#define EE_WRITE 0x02 // EEPROM Write command
#define EE_WRDI 0x04 // EEPROM Write disable command
#define EE_WREN 0x06 // EEPROM Write enable command
#define EE_RDSR 0x05 // EEPROM Read status register
#define EE_WRSR 0x01 // EEPROM Write status register
sbit LED = P0^6; // LED Indicator
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void PORT_Init (void); // Port I/O configuration
void SYSCLK_Init (void); // SYSCLK Initialization
void UART0_Init (void); // UART0 Initialization
extern char SPI_Transfer (char); // SPI Transfer routine
void Timer0_ms (unsigned ms);
void Timer0_us (unsigned us);
unsigned char EE_Read (unsigned Addr);
void EE_Write (unsigned Addr, unsigned char value);//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void) {unsigned EE_Addr; // address of EEPROM byteunsigned char test_byte;// Disable Watchdog timerPCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer// enable)SYSCLK_Init (); // initialize oscillatorPORT_Init (); // initialize ports and GPIOUART0_Init (); // initialize UART0EA = 1; // enable global interruptsSCK = 0;// fill EEPROM with 0xFF’sLED = 1;for (EE_Addr = 0; EE_Addr < EE_SIZE; EE_Addr++){test_byte = 0xff;EE_Write (EE_Addr, test_byte);// print status to UART0if ((EE_Addr % 16) == 0){printf (“\nwriting 0x%04x: %02x “, EE_Addr, (unsigned) test_byte);}else{printf (“%02x “, (unsigned) test_byte);}}// verify EEPROM with 0xFF’sLED = 0;for (EE_Addr = 0; EE_Addr < EE_SIZE; EE_Addr++){test_byte = EE_Read (EE_Addr);// print status to UART0if ((EE_Addr % 16) == 0){printf (“\nverifying 0x%04x: %02x “, EE_Addr, (unsigned) test_byte);}else{printf (“%02x “, (unsigned) test_byte);}if (test_byte != 0xFF){printf (“Error at %u\n”, EE_Addr);while (1); // stop here on error}}// fill EEPROM memory with LSB of EEPROM address.LED = 1;for (EE_Addr = 0; EE_Addr < EE_SIZE; EE_Addr++) {test_byte = EE_Addr & 0xff;EE_Write (EE_Addr, test_byte);// print status to UART0if ((EE_Addr % 16) == 0){printf (“\nwriting 0x%04x: %02x “, EE_Addr, (unsigned) test_byte);}else{printf (“%02x “, (unsigned) test_byte);}}// verify EEPROM memory with LSB of EEPROM addressLED = 0;for (EE_Addr = 0; EE_Addr < EE_SIZE; EE_Addr++){test_byte = EE_Read (EE_Addr);// print status to UART0if ((EE_Addr % 16) == 0){printf (“\nverifying 0x%04x: %02x “, EE_Addr, (unsigned) test_byte);}else{printf (“%02x “, (unsigned) test_byte);}if (test_byte != (EE_Addr & 0xFF)){printf (“Error at %u\n”, EE_Addr);while (1); // stop here on error}}while (1){ // Flash LED when doneTimer0_ms (100);LED = ~LED;}
}
//-----------------------------------------------------------------------------
// Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports.
// P0.0 - MOSI (push-pull)
// P0.1 - MISO
// P0.2 - SCK (push-pull)
// P0.3 - NSS (push-pull)
// P0.4 - UART TX (push-pull)
// P0.5 - UART RX
// P0.6 - LED
// P0.7 -
//
void PORT_Init (void)
{XBR0 = 0x0F; // skip SPI pins in XBARXBR1 = 0x03; // UART0 TX and RX pins enabledXBR2 = 0x40; // Enable crossbar and weak pull-upsP0MDOUT |= 0x5D; // enable TX0, MOSI, SCK, LED and NSS as// push-pull outputs
}
//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clock to use the internal 24.5 MHz clock
// as its clock source.
//
void SYSCLK_Init (void)
{OSCICN = 0x07; // select internal oscillator as SYSCLK// source
}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//
void UART0_Init (void)
{SCON0 = 0x10; // SCON0: 8-bit variable bit rate// level of STOP bit is ignored// RX enabled// ninth bits are zeros// clear RI0 and TI0 bitsif (SYSCLK/BAUDRATE/2/256 < 1){TH1 = -(SYSCLK/BAUDRATE/2);CKCON &= ~0x13;CKCON |= 0x10; // T1M = 1; SCA1:0 = xx}else if (SYSCLK/BAUDRATE/2/256 < 4){TH1 = -(SYSCLK/BAUDRATE/2/4);CKCON &= ~0x13;CKCON |= 0x01; // T1M = 0; SCA1:0 = 01}else if (SYSCLK/BAUDRATE/2/256 < 12){TH1 = -(SYSCLK/BAUDRATE/2/12);CKCON &= ~0x13; // T1M = 0; SCA1:0 = 00}else{TH1 = -(SYSCLK/BAUDRATE/2/48);CKCON &= ~0x13;CKCON |= 0x02; // T1M = 0; SCA1:0 = 10}TL1 = 0xff; // set Timer1 to overflow immediatelyTMOD |= 0x20; // TMOD: timer 1 in 8-bit autoreloadTMOD &= ~0xD0; // modeTR1 = 1; // START Timer1TI0 = 1; // Indicate TX0 ready
}
//-----------------------------------------------------------------------------
// Timer0_ms
//-----------------------------------------------------------------------------
//
// Configure Timer0 to delay <ms> milliseconds before returning.
//
void Timer0_ms (unsigned ms)
{unsigned i; // millisecond counterTCON &= ~0x30; // STOP Timer0 and clear overflow flagTMOD &= ~0x0f; // configure Timer0 to 16-bit modeTMOD |= 0x01;CKCON |= 0x08; // Timer0 counts SYSCLKsfor (i = 0; i < ms; i++) // count milliseconds{TR0 = 0; // STOP Timer0TH0 = (-SYSCLK/1000) >> 8; // set Timer0 to overflow in 1msTL0 = -SYSCLK/1000;TR0 = 1; // START Timer0while (TF0 == 0); // wait for overflowTF0 = 0; // clear overflow indicator}
}
//-----------------------------------------------------------------------------
// Timer0_us
//-----------------------------------------------------------------------------
//
// Configure Timer0 to delay <us> microseconds before returning.
//
void Timer0_us (unsigned us)
{unsigned i; // millisecond counterTCON &= ~0x30; // STOP Timer0 and clear overflow flagTMOD &= ~0x0f; // configure Timer0 to 16-bit modeTMOD |= 0x01;CKCON |= 0x08; // Timer0 counts SYSCLKsfor (i = 0; i < us; i++) { // count microsecondsTR0 = 0; // STOP Timer0TH0 = (-SYSCLK/1000000) >> 8; // set Timer0 to overflow in 1usTL0 = -SYSCLK/1000000;TR0 = 1; // START Timer0while (TF0 == 0); // wait for overflowTF0 = 0; // clear overflow indicator}
}
//-----------------------------------------------------------------------------
// EE_Read
//-----------------------------------------------------------------------------
//
// This routine reads and returns a single EEPROM byte whose address is
// given in <Addr>.
//
unsigned char EE_Read (unsigned Addr)
{unsigned char retval; // value to returnNSS = 0; // select EEPROMTimer0_us (1); // wait at least 250ns (CS setup time)// transmit READ opcoderetval = SPI_Transfer(EE_READ);// transmit Address MSB-firstretval = SPI_Transfer((Addr & 0xFF00) >> 8); // transmit MSB of addressretval = SPI_Transfer((Addr & 0x00FF)); // transmit LSB of address// initiate dummy transmit to read dataretval = SPI_Transfer(0x00);Timer0_us (1); // wait at least 250ns (CS hold time)NSS = 1; // de-select EEPROMTimer0_us (1); // wait at least 500ns (CS disable time)return retval;
}
//-----------------------------------------------------------------------------
// EE_Write
//-----------------------------------------------------------------------------
//
// This routine writes a single EEPROM byte <value> to address <Addr>.
//
void EE_Write (unsigned Addr, unsigned char value)
{unsigned char retval; // return value from SPINSS = 0; // select EEPROMTimer0_us (1); // wait at least 250ns (CS setup time)// transmit WREN (Write Enable) opcoderetval = SPI_Transfer(EE_WREN);Timer0_us (1); // wait at least 250ns (CS hold time)NSS = 1; // de-select EEPROM to set WREN latchTimer0_us (1); // wait at least 500ns (CS disable// time)NSS = 0; // select EEPROMTimer0_us (1); // wait at least 250ns (CS setup time)// transmit WRITE opcoderetval = SPI_Transfer(EE_WRITE);// transmit Address MSB-firstretval = SPI_Transfer((Addr & 0xFF00) >> 8); // transmit MSB of addressretval = SPI_Transfer((Addr & 0x00FF)); // transmit LSB of address// transmit dataretval = SPI_Transfer(value);Timer0_us (1); // wait at least 250ns (CS hold time)NSS = 1; // deselect EEPROM (initiate EEPROM// write cycle)// now poll Read Status Register (RDSR) for Write operation completedo {Timer0_us (1); // wait at least 500ns (CS disable// time)NSS = 0; // select EEPROM to begin pollingTimer0_us (1); // wait at least 250ns (CS setup time)retval = SPI_Transfer(EE_RDSR);retval = SPI_Transfer(0x00);Timer0_us (1); // wait at least 250ns (CS hold// time)NSS = 1; // de-select EEPROM} while (retval & 0x01); // poll until WIP (Write In// Progress) bit goes to ‘0’Timer0_us (1); // wait at least 500ns (CS disable// time)
}

再有参看:

参看: 基于51单片机的SPI总线

参看:利用51单片机实现SPI总线通信

//实例:基于DS1302的日历时钟
#include<reg51.h>     //包含单片机寄存器的头文件
#include<intrins.h>   //包含_nop_()函数定义的头文件
/*********************************
以下是DS1302芯片的操作程序
**********************************/
unsigned char code digit[10]={"0123456789"};
//定义字符数组显示数字
sbit DATA="P1"^1;   //位定义1302的数据输出端定义在P1.1引脚
sbit RST="P1"^2;    //位定义1302的复位端口定义在P1.2引脚
sbit SCLK="P1"^0;   //位定义1302的时钟输出端口定义在P1.0引脚
/*****************************
函数功能:延时若干微秒
入口参数:n
******************************/
void delaynus(unsigned char n)
{unsigned char i;for(i=0;i<n;i++);}
/**********************************
函数功能:向1302写一个字节数据
入口参数:dat
***********************************/
void Write1302(unsigned char dat)
{unsigned char i;SCLK=0;            //拉低SCLK,为脉冲上升沿写入数据做好准备delaynus(2);       //稍微等待,使硬件做好准备for(i=0;i<8;i++)      //连续写8个二进制位数据{DATA=dat&0x01;    //取出dat的第0位数据写入1302delaynus(2);       //稍微等待,使硬件做好准备SCLK=1;           //上升沿写入数据delaynus(2);      //稍微等待,使硬件做好准备SCLK=0;           //重新拉低SCLK,形成脉冲dat>>=1;   //将dat的各数据位右移1位,准备写入下一个数据位}
}
/***********************************************
函数功能:根据命令字,向1302写一个字节数据
入口参数:Cmd,储存命令字;dat,储存待写的数据
************************************************/
void WriteSet1302(unsigned char Cmd,unsigned char dat)
{RST=0;           //禁止数据传递SCLK=0;          //确保写数居前SCLK被拉低RST=1;           //启动数据传输delaynus(2);     //稍微等待,使硬件做好准备Write1302(Cmd);  //写入命令字Write1302(dat);  //写数据SCLK=1;          //将时钟电平置于已知状态RST=0;           //禁止数据传递
}
/********************************
函数功能:从1302读一个字节数据
出口参数:dat
*********************************/unsigned char Read1302(void)
{unsigned char i,dat;delaynus(2);       //稍微等待,使硬件做好准备for(i=0;i<8;i++)   //连续读8个二进制位数据{dat>>=1;       //将dat的各数据位右移1位if(DATA==1)    //如果读出的数据是1dat|=0x80;    //将1取出,写在dat的最高位SCLK=1;       //将SCLK置于高电平,为下降沿读出delaynus(2);  //稍微等待SCLK=0;       //拉低SCLK,形成脉冲下降沿delaynus(2);  //稍微等待}   return dat;        //将读出的数据返回
}
/**********************************************
函数功能:根据命令字,从1302读取一个字节数据
入口参数:Cmd   出口参数:dat
**********************************************/
unsigned char  ReadSet1302(unsigned char Cmd)
{unsigned char dat;RST=0;                 //拉低RSTSCLK=0;                //确保写数居前SCLK被拉低RST=1;                 //启动数据传输Write1302(Cmd);       //写入命令字dat=Read1302();       //读出数据SCLK=1;              //将时钟电平置于已知状态RST=0;               //禁止数据传递return dat;          //将读出的数据返回
}
/********************************
函数功能: 1302进行初始化设置
*********************************/
void Init_DS1302(void)
{ WriteSet1302(0x8E,0x00);  //写入不保护指令WriteSet1302(0x80,((0/10)<<4|(0%10)));   //写入秒的初始值WriteSet1302(0x82,((0/10)<<4|(0%10)));   //写入分的初始值WriteSet1302(0x84,((12/10)<<4|(12%10))); //写入小时的初始值WriteSet1302(0x86,((24/10)<<4|(24%10))); //写入日的初始值WriteSet1302(0x88,((4/10)<<4|(4%10))); //写入月的初始值WriteSet1302(0x8c,((10/10)<<4|(10%10)));   //写入年的初始值
}
/*******************************
以下是对液晶模块的操作程序
********************************/
sbit RS="P2"^0;           //寄存器选择位,将RS位定义为P2.0引脚
sbit RW="P2"^1;           //读写选择位,将RW位定义为P2.1引脚
sbit E="P2"^2;            //使能信号位,将E位定义为P2.2引脚
sbit BF="P0"^7;           //忙碌标志位,,将BF位定义为P0.7引脚
/*******************************************************************
函数功能:延时1ms
(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
********************************************************************/
void delay1ms()
{unsigned char i,j;  for(i=0;i<10;i++)for(j=0;j<33;j++);
}
/*****************************
函数功能:延时若干毫秒
入口参数:n
*******************************/
void delaynms(unsigned char n)
{unsigned char i;for(i=0;i<n;i++)delay1ms();
}
/***********************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***********************************************************/
bit BusyTest(void)
{bit result;RS=0;      //根据规定,RS为低电平,RW为高电平时,可以读状态RW=1;E=1;        //E=1,才允许读写_nop_();   //空操作_nop_();_nop_();_nop_();   //空操作四个机器周期,给硬件反应时间result=BF;  //将忙碌标志电平赋给resultE=0;         //将E恢复低电平_nop_();_nop_();_nop_();_nop_();return result;
}
/**************************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:dictate
***************************************************************/
void WriteInstruction (unsigned char dictate)
{  while(BusyTest()==1);   //如果忙就等待RS=0;        //根据规定,RS和R/W同时为低电平时,可以写入指令RW=0;  E=0;     //E置低电平,为了让E从0到1发生正跳变,所以应先置"0"_nop_();_nop_();               //空操作两个机器周期,给硬件反应时间P0=dictate;            //将数据送入P0口,即写入指令或地址_nop_();_nop_();_nop_();_nop_();               //空操作四个机器周期,给硬件反应时间E=1;                   //E置高电平_nop_();_nop_();_nop_();_nop_();               //空操作四个机器周期,给硬件反应时间E=0;         //当E由高电平跳变成低电平时,液晶模块开始执行命令_nop_();_nop_();_nop_();_nop_();
}
/*********************************************
函数功能:指定字符显示的实际地址
入口参数:x
************************************************/
void WriteAddress(unsigned char x)
{WriteInstruction(x|0x80); //显示位置的确定方法为"80H+地址码x"
}
/***************************************************************
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
******************************************************************/
void WriteData(unsigned char y)
{while(BusyTest()==1); RS=1;           //RS为高电平,RW为低电平时,可以写入数据RW=0;E=0;     //E置低电平,为了让E从0到1发生正跳变,所以应先置"0"P0=y;           //将数据送入P0口,即将数据写入液晶模块_nop_();_nop_();_nop_();_nop_();       //空操作四个机器周期,给硬件反应时间E=1;           //E置高电平_nop_();_nop_();_nop_();_nop_();        //空操作四个机器周期,给硬件反应时间E=0;         //当E由高电平跳变成低电平时,液晶模块开始执行命令_nop_();_nop_();_nop_();_nop_();
}
/*******************************************************
函数功能:对LCD的显示模式进行初始化设置
*************************************************************/
void LcdInitiate(void)
{delaynms(15);       //首次写指令时应给LCD一段较长的反应时间WriteInstruction(0x38);
//显示模式设置:16×2显示,5×7点阵,8位数据delaynms(5);                //给硬件一点反应时间WriteInstruction(0x38);delaynms(5);               //给硬件一点反应时间WriteInstruction(0x38);     //连续三次,确保初始化成功delaynms(5);               //给硬件一点反应时间WriteInstruction(0x0c);
//显示模式设置:显示开,无光标,光标不闪烁delaynms(5);               //给硬件一点反应时间WriteInstruction(0x06);     //显示模式设置:光标右移,字符不移delaynms(5);                //给硬件一点反应时间WriteInstruction(0x01);     //清屏幕指令,将以前的显示内容清除delaynms(5);             //给硬件一点反应时间
}
/**********************************
以下是1302数据的显示程序
***********************************/
/************************
函数功能:显示秒
入口参数:x
*************************/
void DisplaySecond(unsigned char x)
{unsigned char i,j;     //i,j分别储存秒的十位和个位i=x/10;                  //取十位j=x%10;                 //取个位    WriteAddress(0x49);    //写显示地址,将在第2行第7列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //延时1ms给硬件一点反应时间
}
/************************
函数功能:显示分钟
入口参数:x
**************************/
void DisplayMinute(unsigned char x)
{unsigned char i,j;     //i,j分别储存分钟的十位和个位i=x/10;                  //取十位j=x%10;                 //取个位    WriteAddress(0x46);    //写显示地址,将在第2行第7列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //延时1ms给硬件一点反应时间
}
/*************************
函数功能:显示小时
入口参数:x
***************************/
void DisplayHour(unsigned char x)
{unsigned char i,j;     //i,j分别储存小时的十位和个位i=x/10;                       //取十位j=x%10;                       //取个位    WriteAddress(0x43);    //写显示地址,将在第2行第7列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //延时1ms给硬件一点反应时间
}
/*********************
函数功能:显示日
入口参数:x
**********************/
void DisplayDay(unsigned char x)
{unsigned char i,j;     //i,j分别储存日的十位和个位i=x/10;                  //取十位j=x%10;                 //取个位    WriteAddress(0x0d);    //写显示地址,将在第1行第14列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //给硬件一点反应时间
}
/*********************
函数功能:显示月
入口参数:x
************************/
void DisplayMonth(unsigned char x)
{unsigned char i,j;     //i,j分别储存月的十位和个位i=x/10;                       //取十位j=x%10;                       //取个位    WriteAddress(0x0a);    //写显示地址,将在第1行第11列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //给硬件一点反应时间
}
/**********************
函数功能:显示年
入口参数:x
***********************/
void DisplayYear(unsigned char x)
{unsigned char i,j;     //i,j分别储存年的十位和个位i=x/10;                       //取十位j=x%10;                       //取个位    WriteAddress(0x07);    //写显示地址,将在第1行第8列开始显示WriteData(digit[i]);    //将十位数字的字符常量写入LCDWriteData(digit[j]);    //将个位数字的字符常量写入LCDdelaynms(50);         //给硬件一点反应时间
}
/***********************
函数功能:主函数
************************/
void main(void)
{unsigned char second,minute,hour,day,month,year;    //分别储存秒、分、小时,日,月,年unsigned char ReadValue;   //储存从1302读取的数据LcdInitiate();             //将液晶初始化WriteAddress(0);  //写Date的显示地址,将在第1行第1列开始显示WriteData('D');      //将字符常量写入LCDWriteData('a');      //将字符常量写入LCDWriteData('t');      //将字符常量写入LCDWriteData('e');      //将字符常量写入LCDWriteData(':');      //将字符常量写入LCDWriteData('2');      //将字符常量写入LCDWriteData('0');      //将字符常量写入LCDWriteAddress(0x09);  //写年月分隔符的显示地址WriteData('-');      //将字符常量写入LCDWriteAddress(0x0c);  //写月日分隔符的显示地址WriteData('-');      //将字符常量写入LCDWriteAddress(0x45);  //写小时与分钟分隔符的显示地址WriteData(':');      //将字符常量写入LCDWriteAddress(0x48);  //写分钟与秒分隔符的显示地址WriteData(':');      //将字符常量写入LCDInit_DS1302();       //将1302初始化while(1){ReadValue = ReadSet1302(0x81);   //从秒寄存器读数据second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
//将读出数据转化DisplaySecond(second);          //显示秒ReadValue = ReadSet1302(0x83);  //从分寄存器读数据minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
//将读出数据转化DisplayMinute(minute);        //显示分ReadValue = ReadSet1302(0x85);  //从时寄存器读数据hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
//将读出数据转化DisplayHour(hour);              //显示小时ReadValue = ReadSet1302(0x87);  //从日寄存器读数据day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
//将读出数据转化DisplayDay(day);                //显示日ReadValue = ReadSet1302(0x89);  //从月寄存器读数据month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//将读出数据转化DisplayMonth(month);            //显示月ReadValue = ReadSet1302(0x8d);  //从年寄存器读数据year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
//将读出数据转化DisplayYear(year);              //显示年}
}

六、SPI 设备驱动

参看:linux spi 设备驱动简析 一(基于s5pv210)
参看:linux spi 设备驱动简析 二(基于s5pv210)
参看:Linux SPI总线设备驱动模型详解
参看:A10+Linux+SPI设备驱动开发-2012.1.31

参看:spi驱动框架全面分析,从master驱动到设备驱动

驱动程序可以参看Linux下 drivers/spi 目录下的程序:

以GV7601为例:

参看:Hi3516A开发--GV7601 硬件设计

参看:DM8168平台中完成gv7601的spi总线驱动笔记

下载:GV7601 资料下载

如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78979855

S5PV210开发 -- SPI 你知道多少?相关推荐

  1. S5PV210开发 -- I2C 你知道多少?(二)

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78782558 上一篇主要是介绍了下芯片手册 I2C 部分,都应该看些什么,以 ...

  2. S5PV210开发 -- 前言

    这段时间终于把图像和流媒体部分的内容如 FFmpeg.MP4V2.LIVE555.RTSP.H.264 等过了一遍,然后做了一个PM2.5采集项目,学习了MQTT. 接下来我们会以基于 210v3开发 ...

  3. S5PV210开发系列五_sd卡驱动实现

    S5PV210开发系列五 sd卡驱动实现 象棋小子    1048272975 SD卡(Secure Digital Memory Card)具有体积小.容量大.数据传输快.可插拔.安全性好等优点,被 ...

  4. S5PV210开发 -- I2C 你知道多少?(三)

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78835639 I2C部分已经接近尾声了,接下来我们回过头来看一下剩下的一些小 ...

  5. S5PV210开发 -- 串口驱动开发

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78579074 上篇文章讲的 UART,更多的是硬件相关的知识.接下来进入正题 ...

  6. S5PV210开发 -- QT4.8 移植

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78498784 今天应网友要求给他,生成一下nand平台的根文件系统.由此简单 ...

  7. S5PV210开发 -- 启动流程

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78433564 讲完启动模式.烧写更新,接下来我们看一下启动流程. 参看:S5 ...

  8. S5PV210开发 -- 通过 DNW、fastboot 烧写

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78364548 这个烧写过程真是一波三折啊,足足搞了两天才实现  通过 DNW ...

  9. 三星官方smdkv210 uboot移植到我的s5pv210开发板

    北京 2020-7-26 19:44 周日 昨天外面闷热 今日凉快.空调一开啥事没有!O(∩_∩)O 用了差不多两个周末蹲家里移植的.进度比较慢,算是把uboot相关的一些东西基本了解了. uboot ...

最新文章

  1. ImageLazyLoad-图片随着滚动而进行加载
  2. NVIDIA GPU持久模式是什么?(驱动程序持久性 Driver Persistence Daemon 守护程序)
  3. 给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?
  4. 初探数位DP-hdu2089
  5. Java2精要_java知识精要(一)
  6. java中的基本数据类型的取值范围分别是多少?
  7. LVS+Keepalived实现高可用负载均衡
  8. IBATIS的优缺点
  9. Scala下载安装和环境变量配置
  10. 南航计算机英语面试经验,南航面试英文自我介绍
  11. php 滑块 爬虫_php中强大爬虫工具querylist
  12. Mysql系统参数查询和设置
  13. FOI2019算法冬令营D1
  14. tp6 使用 redis
  15. 《幸福来敲门》观后感
  16. Git Pull Failed:You have not concluded your merge.Exiting because of unfinished merge
  17. 安智市场发展史:刷机产业链的”中间商”
  18. hash算法和常见的hash函数
  19. CDA携手云网德国公司共同打造数据精英的国际化舞台
  20. 系统构架设计应考虑的因素

热门文章

  1. CC2530基础实验:(9)AD采集cc2530温度串口显示
  2. 基于ssm微信小程序的英语学习激励系统
  3. 封印之门 转换为图 最短路floyd
  4. Violence detection-Hockey Fight-CNN+LSTM暴力检测CNN+LSTM实例
  5. 监控案例实战 -- Zabbix 监控 企业级路由器
  6. Android 界面设计练习——电视直播软件界面
  7. 如何成为一名oracle DBA
  8. mysql 8介绍,MySQL 8.0 简介
  9. 任务调度系统--重跑和断点续跑
  10. 车牌号图像的垂直投影