在ARM Linux下使用GPIO模拟SPI时序详解

Author:杨正  Data2016.1.1  Mailyz2012ww@gmail.com

一、       概述

SPI是英文SerialPeripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI是一种高速、全双工、同步通信总线,标准的SPI有4个引脚,常用于单片机和EEPROM、FLASH、实时时钟、数字信号处理等器件的通信。SPI通信原理要比I2C简单,它主要是主从方式通信,这种通信方式通常只有一个主机和一个或多个从机,标准的SPI是4根线,分别是SSEL(片选)、SCLK(时钟,也写作SCK)、MOSI(主机输入,从机输出)和MISO(主机输入,从机输出)。

SSEL:从设备片选使能信号。譬如从设备是低电平使能的话,当拉低这个引脚,从设备就会被选中,主机和这个被选中的从设备通信。

SCLK:时钟信号,即主机产生。

MOSI:主机给从机发送指令或者数据的通道。

MISO:主机读取从机的状态或者数据的通道。

 

在某些情况下,也可以用3根或者2根线的SPI进行通信。譬如,主机只给从机发送指令,从机不需要回复数据的时候,MISO就可以不要;而主机只读从机的数据,不需要给从机发送数据的时候,MOSI就可以不要;当一个主机与一个从机通信时,从机的片选有时可以固定为有效电平而一直处于使能状态,那么SSEL可以不要,此时如果主机只给从机发数据,那么SSEL和MISO都可以不要;如果主机只读取从机发送来的数据,那么SSEL和MOSI都可以不要。当然一般情况下说的SPI都指的是标准的SPI,有4根线进行通信。

 

 

二、  时序分析

众所周知,SPI时序有4种模式,在讲解4种模式之前先学习两个单词,即PolarityPhase,这两个单词分别是SPI的时钟极性(Polarity)和相位(Phase),最常见的写法CPOLCPHA,也有其它的一些写法,如:

(1) CKPOL (Clock Polarity) = CPOL = POL = Polarity =(时钟)极性
(2) CKPHA (Clock Phase)   = CPHA = PHA = Phase =
(时钟)相位

 

那么时钟极性是什么概念呢?SPI通信过程分为空闲状态和通信状态,空闲状态是指SCLK在数据发送之前和发送完之后的状态,通信状态当然就是指发送数据的状态。CPOL=1,那么空闲状态SCLK为高电平,反之,CPOL=0,则空闲状态SCLK为低电平。

 

SPI是一个环形的总线结构,主要是在SCLK的控制下,两个双向移位寄存器进行数据交换。那么主机和从机在进行交换数据的时候就设计到一个问题,即主机在什么时刻输出到MOSI上而从机在什么时刻采样这个数据,或者从机什么时刻输出到MISO上而主机什么时刻采样这个数据。同步通信的一个特点就是所有数据的变化和采样都是伴随着时钟沿进行的,也就是说数据总是在时钟的边沿附近变化或被采样,而一个完整的时钟周期必定包含了一个上升沿和一个下降沿,这是周期的定义所决定的,只是这两个沿的先后并无规定。又因为数据从产生到它稳定是需要一定的时间,那么如果主机在上升沿输出数据到MOSI,从机就只能在下降沿去采样这个数据了。反之,如果一方在下降沿输出数据,那么另一方就必须在上升沿采样这个数据。那么由谁来决定上升沿采样还是下降沿采样,上升沿输出还是下降沿输出呢?

 

CPHA=1时,表示数据的输出在一个时钟周期的第一个沿上,至于这个沿是上升沿还是下降沿,就得由CPOL来决定。CPOL=1那就是下降沿,反之就是上升沿。那么数据采样自然就是第二个沿上了。

CPHA=0时,表示数据采样在一个时钟周期的第一个沿上,至于这个沿是上升沿还是下降沿,就得由CPOL来决定。CPOL=1那就是下降沿,反之就是上升沿。那么数据输出自然就是第二个沿上了。

 

通过以上的学习,SPI的4中模式其实已经浮现出来了,下面对此做一总结:

Mode0

CPOL=0CPHA=0

Mode1

CPOL=0CPHA=1

Mode2

CPOL=1CPHA=0

Mode3

CPOL=1CPHA=1

 

图形比文字更容易看懂,所以SPI4种模式的时序图如下:


再进一步说明模式1SPI处于使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低,表示开始传输数据。来自Slave的数据立刻发送到Master的接收数据线MISO。半个SCLK时钟周期之后,有效的Master数据传输到MOSI。此时MasterSlave数据都已经有效,SCLK管脚在接下来的半个SCLK时钟周期之后变为高电平。数据在SCLK时钟的上升沿被捕获(采样),在时钟的下降沿被传送(输出),传输完成后SSEL恢复为高电平。

 

再进一步说明模式2。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。半个SCLK时钟周期之后,MasterSlave的有效数据分别在各自的传输线上有效。同时,SCLK从第一个上升沿开始有效。数据在SCLK时钟的下降沿被捕获,在时钟的上升沿被传送,传输完成后SSEL恢复为高电平。

 

再进一步的说明模式3。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。此时Slave的数据立刻发送到Master的接收数据线MISO。半个SCLK周期之后,Master的有效数据传送到MOSI。再过半个SCLK时钟周期之后,SCLK管脚设置为低。这表示数据在SCLK时钟的下降沿被捕获,在SCLK时钟的上升沿被传送,传输完成后SSEL恢复为高电平。

 

再进一步的说明模式4。当SPI为使能状态,而且发送FIFO内有有效数据时,设置SSEL信号为低表示开始传输数据。半个SCLK时钟周期后,MasterSlave数据在各自的传输线上有效。同时,时钟SCLK1个下降沿开始有效。数据在SCLK时钟的上升沿被捕获,在时钟的下降沿被传送,传输完成后SSEL恢复为高电平。

 

 

 

三、  SPI访问寄存器模式

 

常见的SPI访问寄存器模式有3种,分别是SingleAccess(单次访问)、Burst Access(突发访问)、FIFO Access(FIFO访问)。

 

SingleAccess:通过写访问发送一个地址字节后跟一个数据字节,或者发送一个地址字节,再通过读访问接收一个数据字节。发送帧时SSEL为低,发送完最后一个字节后SSEL变为高。如下图,将0x0A写到寄存器0x02上,再从该寄存器上读其值。


W + addr. 0x02 Data: 0x0A                      R + addr. 0x02 Data:

注意:SSEL第一次为低电平使能时,MISO变为高电平,然后立即变为低电平,这表示从设备芯片已经装备好(Thefirst time CSn goes low, MISO goes high and then low again immediately,indicating that the chip is ready.)。


Single Byte Access (Write and Read)

 

 

BurstAccess:一个地址字节后跟多个数据字节。在每个数据字节之间地址字节会在内部自动增加,并且片选信号SSEL在发送帧时为低电平,在每个数据字节之间也保持低电平,当发送完最后一个字节后变为高电平。如:

BYTE xdata regValues[] = {1,2,3};

halSpiWriteBurstReg(0x00, regValues,sizeof(regValues));

halSpiReadReg(0x00);

halSpiReadReg(0x01);

halSpiReadReg(0x02);


BurstWrite Followed by Single Read

 

 

FIFO Access:如果地址字节对应的是FIFO地址,那么随后的数据字节将针对FIFO。该地址字节没有自动递增而被存储,并且不需要在每个数据字节之间发送该地址。片选信号SSEL在发送帧时为低电平,在每个数据字节之间也保持低电平,当发送完最后一个字节后变为高电平。

 

特别说明不同的SPI从设备地址字节的内容不一定相同,需要查看相关手册,才能知道地址字节的构成是什么样的。例如:RFM69H这个模块SPI的地址字节的组成如下:

The first byteis the address byte. It is made of:

wnr bit, whichis 1 for write access and 0 for read access

7 bits of address, MSB first

 

又如CCXX00的地址字节组成如下:

The R/W bit in the address header controlsif the register should be written or read, and the burst bit controls if it

is a single access or a burst access.

R/W

Burst

A5

A4

A3

A2

A1

A0

:其实地址位只有5位,最高位为读写位,1为读,0为写;后面一位是burstAccess的使能位,当为1时使能。

 

 

四、  例程解析

特别注意:在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。但要注意的是,由于主设备的SDO连接从设备的SDI,从设备的SDO连接主设备的SDI,从设备SDI接收的数据是主设备的SDO发送过来的,主设备SDI接收的数据是从设备SDO发送过来的,所以主设备这边SPI时钟极性的配置(即SDO的配置)跟从设备的SDI接收数据的极性是相反的,跟从设备SDO发送数据的极性是相同的。

 

通过手册得知(MOSI is generated by the master on the falling edge ofSCK and is sampled by the slave (i.e. this SPI interface) on the rising edge ofSCK. MISO is generated by the slave on the falling edge of SCK.A transferalways starts by the NSS pin going low. MISO is high impedance when NSS ishigh.),本例程使用的从设备的SPI工作在Mode1,即CPOL= 0 and CPHA = 0,且SSEL低电平使能,当SSEL为高电平时,MISO为高。故主机的MOSI在空闲状态时为高。

/*********************************************************************************
*     Copyright:  (C) 2015 YangZheng<yz2012ww@gmail.com> 
*                  All rights reserved.
*
*      Filename:  dev_rfm69h.c
*   Description:  This file
*                
*       Version:  1.0.0(12/28/2015~)
*        Author:  Yang Zheng<yz2012ww@gmail.com>
*     ChangeLog:  1, Release initialversion on "12/28/2015 07:46:07 PM"
*                
********************************************************************************/
#include<linux/kernel.h>
#include<linux/version.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/errno.h>
#include<linux/fcntl.h>
#include<linux/mm.h>
#include<linux/proc_fs.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<linux/init.h>
#include<asm/uaccess.h>
#include<asm/io.h>
#include <asm/system.h>
#include<linux/miscdevice.h>
#include<linux/delay.h>
#include<linux/sched.h>
#include<linux/proc_fs.h>
#include<linux/poll.h>
#include<asm/bitops.h>
#include<asm/uaccess.h>
#include<asm/irq.h>
#include<linux/moduleparam.h>
#include <linux/ioport.h>
#include<linux/interrupt.h>
#include<linux/cdev.h>
#include<linux/semaphore.h>
#include<linux/wait.h>
#define IOCONFIG4_4                                 IO_ADDRESS(0x200f0000+ 0x054)          //复用管脚gpio4_4
#define IOCONFIG4_5                                 IO_ADDRESS(0x200f0000+ 0x050)          //复用管脚gpio4_5
#define IOCONFIG4_6                                 IO_ADDRESS(0x200f0000+ 0x04c)          //复用管脚gpio4_6
#define IOCONFIG4_7                                 IO_ADDRESS(0x200f0000+ 0x048)          //复用管脚gpio4_7
#define GPIO4_BASE                                    0x20180000                        //gpio基地址
#define GPIO4_SIZE                                     0x10000             // 64KB
#define GPIO4_DIR                                      IO_ADDRESS(GPIO4_BASE + 0x400)     //gpio4方向寄存器
#defineGPIO_SPI_CS_REG                         IO_ADDRESS(GPIO4_BASE+ 0x40)          //gpio4_4数据寄存器
#defineGPIO4_SPI_SCK_REG                    IO_ADDRESS(GPIO4_BASE + 0x80)          //gpio4_5数据寄存器
#defineGPIO4_SPI_MOSI_REG                 IO_ADDRESS(GPIO4_BASE+ 0x100)     //gpio4_6数据寄存器
#defineGPIO4_SPI_MISO_REG                 IO_ADDRESS(GPIO4_BASE+ 0x200)     //gpio4_7数据寄存器
#define GPIO4_4                                           (1<< 4)   //gpio4_4
#define GPIO4_5                                           (1<< 5)   //gpio4_5
#define GPIO4_6                                           (1<< 6)   //gpio4_6
#define GPIO4_7                                           (1<< 7)   //gpio4_7
#define DATA_LENGTH                                21
#define DRV_AUTHOR                                "Yang Zheng<yz2012ww@gmail.com>"
#define DRV_DESC                                       "spi driver"                                                                                
#define DRV_VERSION                                "v0.0.1"
#if 0
#defineDBG(x...)   printk(x)
#define DBG_PRINT
#else
#defineDBG(x...)   do {} while (0)
#endif
staticDECLARE_WAIT_QUEUE_HEAD(spi_waitq);
unsigned char                                       read_tmp_data[DATA_LENGTH] = {0};
void __iomem                                       *reg_ssp_base_va;
typedef unsignedchar                       byte;
typedef unsignedshort                      word;
static int                                                read_flag = 0;
/******************************************************************************
**函数名称:Set_nCS
**函数功能:禁用片选
**输入参数:无
**输出参数:无
**注意:   高电平为禁用片选,低电平为使能片选
******************************************************************************/
void Set_nCS(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_4);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_4;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO_SPI_CS_REG); 
regvalue |= GPIO4_4;
writel(regvalue, GPIO_SPI_CS_REG);  //禁用片选
}
/******************************************************************************
**函数名称:Clr_nCS
**函数功能:使能片选
**输入参数:无
**输出参数:无
**注意:   高电平为禁用片选,低电平为使能片选
******************************************************************************/
void Clr_nCS(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_4);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_4;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO_SPI_CS_REG); 
regvalue &= ~GPIO4_4;
writel(0, GPIO_SPI_CS_REG);  //使能片选
}
/******************************************************************************
**函数名称:Set_SCK
**函数功能:SCK为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Set_SCK(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_5);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_SCK_REG);  //设置gpio输出高电平
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_SPI_SCK_REG);
}
/******************************************************************************
**函数名称:Set_SCK
**函数功能:SCK为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Clr_SCK(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_5);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_5;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_SCK_REG);  //设置gpio输出低电平
regvalue &= ~GPIO4_5;
writel(regvalue,GPIO4_SPI_SCK_REG); 
}
/******************************************************************************
**函数名称:Set_MOSI
**函数功能:MOSI为高电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Set_MOSI(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_6);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO4_DIR);  //设置gpio输出高电平
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_SPI_MOSI_REG);
}
/******************************************************************************
**函数名称:Set_MOSI
**函数功能:MOSI为低电平
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
void Clr_MOSI(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_6);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输出
regvalue |= GPIO4_6;
writel(regvalue, GPIO4_DIR);
regvalue = readl(GPIO4_DIR);  //设置gpio输出低电平
regvalue &= ~GPIO4_6;
writel(regvalue, GPIO4_SPI_MOSI_REG);
}
/******************************************************************************
**函数名称:MISO_H
**函数功能:读取MISO_H的值
**输入参数:无
**输出参数:无
**注意:    
******************************************************************************/
unsigned charMISO_H(void)
{
unsigned char regvalue;
writel(0, IOCONFIG4_7);   //gpio模式
regvalue = readl(GPIO4_DIR);  //设置gpio输入
regvalue &= ~GPIO4_7;
writel(regvalue, GPIO4_DIR);
regvalue =readl(GPIO4_SPI_MISO_REG);  //读取输入值
//DBG("regvalue = %x\n",regvalue);
return regvalue;
}
/******************************************************************************
**函数名称:SPICmd8bit
**函数功能:SPI写入参数8bit
**输入参数:WrPara
**输出参数:无
**注意:   保留nCS输出Low
******************************************************************************/
voidSPICmd8bit(byte WrPara)
{
byte bitcnt;     
Clr_nCS();
Clr_SCK();
for(bitcnt = 8; bitcnt != 0; bitcnt--)
{
Clr_SCK();
if(WrPara&0x80)
{
Set_MOSI();
}
else
{
Clr_MOSI();
}
Set_SCK();
WrPara <<= 1;
}
Clr_SCK();
Set_MOSI();
//Set_nCS();            //*此处不关闭nCS,使用连续模式*
}
/******************************************************************************
**函数名称:SPIRead8bitt
**函数功能:SPI读取参数8bit
**输入参数:读取8bit数据——RdPara
**输出参数:无
**注意:   保留nCS输出Low
******************************************************************************/
byte SPIRead8bit(void)
{
byte RdPara = 0;
byte bitcnt;
Clr_nCS();
Set_MOSI();               //读FIFO,维持SDI为H 
for(bitcnt=8; bitcnt!=0; bitcnt--)
{
Clr_SCK();
RdPara <<= 1;
Set_SCK();
if(MISO_H())
{
RdPara |= 0x01;
}
else
{
;
}
}
Clr_SCK();
//Set_nCS();               //*此处不关闭nCS,使用连续模式*
//DBG("RdPara = %x\n",RdPara);
return(RdPara);
}
/******************************************************************************
**函数名称:SPIRead
**函数功能:SPI读取一个地址数据
**输入参数:adr
**输出参数:无
******************************************************************************/
byte SPIRead(byteadr)
{
byte tmp;         
SPICmd8bit(adr);               //发送要读取的地址
tmp = SPIRead8bit();    //读取数据    
Set_nCS();
return(tmp);
}
/******************************************************************************
**函数名称:SPIWrite
**函数功能:SPI写入一个16数据(高8位地址,低8位数据)
**输入参数:WrPara
**输出参数:无
******************************************************************************/
void SPIWrite(wordWrPara)                                                                    
{                                                      
byte bitcnt;   
Clr_SCK();                           //注意SCK先清0,保持低
Clr_nCS();
WrPara |= 0x8000;           //写数据高位置1
for(bitcnt=16; bitcnt!=0; bitcnt--)
{
Clr_SCK();
if(WrPara&0x8000)
{
Set_MOSI();
}
else
{
Clr_MOSI();
}
Set_SCK();
WrPara <<= 1;
}
Clr_SCK();
Set_MOSI();
Set_nCS();
}         
/******************************************************************************
**函数名称:SPIBurstRead
**函数功能:SPI连续读取模式
**输入参数:adr——读取地址
**          ptr——存储数据指针
**          length 读取长度
**输出参数:无,数据存在ptr中
******************************************************************************/
voidSPIBurstRead(byte adr, byte *ptr, byte length)
{
byte i;
if(length<=1)                       //读取长度必须大于1
{
return;
}
else
{
Clr_SCK();                          //注意SCK先清0,保持低
Clr_nCS();
SPICmd8bit(adr);               //读取地址
for(i=0;i<length;i++)
{
ptr[i]= SPIRead8bit();
}
Set_nCS();        
}
}
/******************************************************************************
**函数名称:SPIBurstWrite
**函数功能:SPI连续写入模式
**输入参数:adr——写入地址
**          ptr——存储数据指针
**          length 写入长度
**输出参数:无
******************************************************************************/
voidBurstWrite(byte adr, byte *ptr, byte length)
{
byte i;
if(length<=1)                       //读取长度不为0或1
{
return;
}
else 
{      
Clr_SCK();                           //注意SCK先清0,保持低
Clr_nCS();                                             
SPICmd8bit(adr|0x80);    //连续写
for(i=0;i<length;i++)
{
SPICmd8bit(ptr[i]);
}
Set_nCS();        
}
}
longspi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
……
switch(cmd)
{
case SSP_READ_ALT:
…...
val = *(unsigned int*)arg;
addr = (unsignedchar)(val&0xff);
data =SPIRead(addr);
……
*(unsigned int *)arg= (unsigned int)(data&0x0000ff);
break;
case SSP_READ_BURST:
{
unsignedchar          addr = 0x00;
……
/*读取数据 */
SPIBurstRead(addr,read_tmp_data, DATA_LENGTH);
…...
break;
}
case SSP_WRITE_ALT:
data = 0;
val  = *(unsigned int *)arg;
tmp = (unsignedshort)((val&0xff0000)>>8);      
tmp |= (unsignedshort)((val&0x0000ff)>>0);
……
SPIWrite(tmp);
break; 
case SSP_WRITE_BURST:
res =copy_from_user(tmp_str, (unsigned char *)arg, sizeof(tmp_str));
if (res != 0)
{
printk("copydata from the user space error\n");
}
……
BurstWrite(addr,data, DATA_LENGTH);
break;
default:
{
printk("Nosuch spi command %#x!\n", cmd);
return -1;
}
}
return 0;
}
int spi_open(structinode * inode, struct file * file)
{
……
return 0;
}
intspi_close(struct inode * inode, struct file * file)
{
return 0;
}
static structfile_operations spi_fops = {
.owner          =THIS_MODULE,
.unlocked_ioctl        = spi_ioctl,
.open           =spi_open,
.release           =spi_close
};
static structmiscdevice spi_dev = {
.minor                =MISC_DYNAMIC_MINOR,                                                                                      
.name               =DEV_NAME,
.fops                           =&spi_fops,
};
static int __initspi_gpio_init(void)
{
int ret;
ret = misc_register(&spi_dev);
if (ret < 0)
{
printk("registerspi_gpio device failed!\n");
return -1;
}
printk("SPI driver initializesuccessful! .\n");
return 0;
}
static void __exitspi_gpio_exit(void)
{
misc_deregister(&spi_dev);
printk("SPI driver exit!\n");
}
module_init(spi_gpio_init);
module_exit(spi_gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_DESCRIPTION(DRV_DESC);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git clone时出现 error:inflate:data stream error(incorrect data check)

git clone时出现 error:inflate:data stream error(incorrect data check) fatal:serrious inflate inconsistency fatal:index-pack failed 经了解&#xff0c;此问题是遗留问题&#xff0c;之前是因为公司对gitlab服务器进行数据迁移而引起这种git clone失败的原因&#xff0…

CentOS 7.5 使用 yum 安装 Kubernetes 集群(二)

一、安装方式介绍 1、yum 安装 目前CentOS官方已经把Kubernetes源放入到自己的默认 extras 仓库里面&#xff0c;使用 yum 安装&#xff0c;好处是简单&#xff0c;坏处也很明显&#xff0c;需要官方更新 yum 源才能获得最新版本的软件&#xff0c;而所有软件的依赖又不能自己指…

zbb20171108 tomcat 性能优化

原文地址http://www.cnblogs.com/NiceTime/p/6665416.html 1)内存优化(调整配置堆的大小&#xff0c;修改文件&#xff1a;catalina.sh) JAVA_OPTS"-Djava.awt.headlesstrue -Dfile.encodingUTF-8 -server -XX:MinHeapFreeRatio80 -XX:MaxHeapFreeRatio80 -XX:ThreadStack…

Python Socket通信黏包问题分析及解决方法

参考&#xff1a;http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 1.黏包的表现(以客户端远程操作服务端命令为例) 注&#xff1a;只有在TCP协议通信的情况下&#xff0c;才会产生黏包问题 基于TCP协议实现的黏包 #!/usr/bin/env python # -*- coding: utf-8 -*- …

2440内存管理

title: 2440内存管理 tags: ARM date: 2018-10-17 19:08:49 --- 2440内存管理 特性 大/小端&#xff08;通过软件选择&#xff09;地址空间&#xff1a;每个 Bank 有 128M 字节(总共 1G/8 个 Bank)除了 BANK0&#xff08;16/32 位&#xff09;之外【引导ROM&#xff0c;其总线宽…

C#设计模式之十二代理模式(Proxy Pattern)【结构型】

一、引言 今天我们要讲【结构型】设计模式的第七个模式&#xff0c;也是“结构型”设计模式中的最后一个模式&#xff0c;该模式是【代理模式】&#xff0c;英文名称是&#xff1a;Proxy Pattern。还是老套路&#xff0c;先从名字上来看看。“代理”可以理解为“代替”&#…

CentOS7.5 使用二进制程序部署Kubernetes1.12.2(三)

一、安装方式介绍 1、yum 安装 目前CentOS官方已经把Kubernetes源放入到自己的默认 extras 仓库里面&#xff0c;使用 yum 安装&#xff0c;好处是简单&#xff0c;坏处也很明显&#xff0c;需要官方更新 yum 源才能获得最新版本的软件&#xff0c;而所有软件的依赖又不能自己指…

马来西亚热情拥抱阿里巴巴 马云倡议的eWTP首次落地海外

摘要&#xff1a;3月22日&#xff0c;马来西亚总理纳吉布与阿里巴巴集团董事局主席马云一同出现在吉隆坡一场盛大启动仪式上&#xff0c;他们将共同见证马云的eWTP理念落地马来西亚。 3月22日&#xff0c;在邀请阿里巴巴集团董事局主席马云、阿里巴巴集团CEO张勇、蚂蚁金服集团…

随便玩玩之PostgreSQL(第一章)PostgreSQL简介

随便玩玩之PostgreSQL 未经授权不得转载 第1章PostgreSQL简介 1.1什么是PostgreSQLPostgresql是数据库&#xff08;软件&#xff09;。The worlds most advanced open source database.世界上最先进的开源数据库。 1.2PostgreSQL的优势随便用、不要钱 比MySQL好&#xff0c;媲美…

生产环境中Oracle常用函数总结

1>to_char,将日期转换为字符&#xff1b;add_months,在第一个参数的日期上加或者减第二个参数的值&#xff1b;select dkzh,jkhtbh,yhkrq,dkffrq,shqs,dqyqcs,to_char(add_months(dkffrq,shqsdqyqcs1),yyyymm) from grdk_dk_zz a where a.dkzt in(02,03) and jgbm like 01||…

Dockerfile构建容器镜像 - 运维笔记

在Docker的运用中&#xff0c;从下载镜像&#xff0c;启动容器&#xff0c;在容器中输入命令来运行程序&#xff0c;这些命令都是手工一条条往里输入的&#xff0c;无法重复利用&#xff0c;而且效率很低。所以就需要一 种文件或脚本&#xff0c;我们把想执行的操作以命令的方式…

201421123042 《Java程序设计》第8周学习总结

1. 本周学习总结 以你喜欢的方式&#xff08;思维导图或其他&#xff09;归纳总结集合相关内容。 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contains源代码 源代码&#xff1a; 答&#xff1a;查找对象是否再数组中&#xff0c;并且返回在数组中的下标。如果不在数…

Linux学习-11月12日(Apache安装)

2019独角兽企业重金招聘Python工程师标准>>> 11.6 MariaDB安装 11.7/11.8/11.9 Apache安装 扩展 apache dso https://yq.aliyun.com/articles/6298 apache apxs https://wizardforcel.gitbooks.io/apache-doc/content/51.html apache工作模式 https://blog.csdn.…

Linux C 读取文件夹下所有文件(包括子文件夹)的文件名

本文&#xff1a;http://www.cnblogs.com/xudong-bupt/p/3504442.html Linux C 下面读取文件夹要用到结构体struct dirent&#xff0c;在头#include <dirent.h>中&#xff0c;如下&#xff1a; #include <dirent.h> struct dirent {long d_ino; /* inode number 索…

报表工具实现单据套打

【摘要】 单据套打再也不用手动测量&#xff0c;反复调试了&#xff0c;报表工具实现单据套打&#xff0c;去乾学院看个究竟&#xff1a;报表工具实现单据套打!实际项目开发中&#xff0c;很多情况会涉及到单据的打印。即在一张印刷好的空白单据上&#xff0c;准确无误地打印上…

session机制详解以及session的相关应用

session是web开发里一个重要的概念&#xff0c;在大多数web应用里session都是被当做现成的东西&#xff0c;拿来就直接用&#xff0c;但是一些复杂的web应用里能拿来用的session已经满足不了实际的需求&#xff0c;当碰到这样的情况时候我们需要更加深入的理解session的机制&am…

(转)Shell中获取字符串长度的七种方法

Shell中获取字符串长度的七种方法 原文&#xff1a;http://blog.csdn.net/jerry_1126/article/details/51835119 求字符串操作在shell脚本中很常用&#xff0c;下面归纳、汇总了求字符串的几种可能方法: 【方法一】:利用${#str}来获取字符串的长度 【方法二】:利用awk的length方…

linux下用core和gdb查询出现段错误的地方

有些时候我们在一段C代码的时候&#xff0c;由于对一个非法内存进行了操作&#xff0c;在程序运行的过程中&#xff0c;出现了"段错误"。呵呵&#xff0c;这种问题我想很多人会经常遇到。遇到这种问题是非常无语的&#xff0c;只是提示了"段错误"&#xff…

什么是js的严格模式

设立严格模式的原因&#xff1a; - 消除Javascript语法的一些不合理、不严谨之处&#xff0c;减少一些怪异行为; - 消除代码运行的一些不安全之处&#xff0c;保证代码运行的安全&#xff1b; - 提高编译器效率&#xff0c;增加运行速度&#xff1b; - 为未来新版本的Javascrip…

代码解说Android Scroller、VelocityTracker

在编写自己定义滑动控件时经常会用到Android触摸机制和Scroller及VelocityTracker。Android Touch系统简单介绍&#xff08;二&#xff09;:实例具体解释onInterceptTouchEvent与onTouchEvent的调用过程对Android触摸机制须要用到的函数进行了具体的解释。本文主要介绍两个重要…