目录
SPI简介
数据传输配图
SPI模式
举例OLED
软件SPI
硬件SPI
SPI协议是一种同步串行接口技术(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,SPI是一主多从的,SPI通信都是由主机发起的,SPI只需要4根线
例如我们发出0x56的数据即0b0101 0110,首先我们需要选中引脚CS,然后数据从最高位0开始传输让DO引脚变为0,假设SCK是在上升沿的时候数据发送出去,执行8次,最后再取消片选引脚
SPI有四种工作模式,CPOL表示SPICLK初始状态是高电平还是低电平,CPHA表示在第几个时钟沿采样数据,具体选择哪种模式主要取决于外接的SPI设备
CPOL | CPHA | |
模式0 | 0 | 0 |
模式1 | 0 | 1 |
模式2 | 1 | 0 |
模式3 | 1 | 11 |
CPOL为高电平一般SCK初始状态为高电平,CPHA为高电平一般在第二个上升沿采样数据,经常使用模式0和模式3,因为模式0和模式3都是在上升沿采样数据,不需要我们在乎SPICLK的初始状态是什么,只要在上升沿采样数据就行了
对于OLED来说只需要单向传输,因此只需要CS、SCK和DO三条线,并不需要读取OLED的,这里通过软件来模拟SPI和硬件SPI两种方式来实现,首先需要实现SPI的写操作例如gpio_spi.c,然后写出oled的控制oled.c
static void SPI_GPIO_Init(void)
{
/* GPF1 OLED_CSn output */
GPFCON &= ~(3<<(1*2));
GPFCON |= (1<<(1*2));
GPFDAT |= (1<<1);
/* GPG2 FLASH_CSn output
* GPG4 OLED_DC output
* GPG5 SPIMISO input
* GPG6 SPIMOSI output
* GPG7 SPICLK output
*/
GPGCON &= ~((3<<(2*2)) | (3<<(4*2)) | (3<<(5*2)) | (3<<(6*2)) | (3<<(7*2)));
GPGCON |= ((1<<(2*2)) | (1<<(4*2)) | (1<<(6*2)) | (1<<(7*2)));
GPGDAT |= (1<<2);
}
void OLEDInit(void)
{
/* 向OLED发命令以初始化 */
OLEDWriteCmd(0xAE); /*display off*/
OLEDWriteCmd(0x00); /*set lower column address*/
OLEDWriteCmd(0x10); /*set higher column address*/
OLEDWriteCmd(0x40); /*set display start line*/
OLEDWriteCmd(0xB0); /*set page address*/
OLEDWriteCmd(0x81); /*contract control*/
OLEDWriteCmd(0x66); /*128*/
OLEDWriteCmd(0xA1); /*set segment remap*/
OLEDWriteCmd(0xA6); /*normal / reverse*/
OLEDWriteCmd(0xA8); /*multiplex ratio*/
OLEDWriteCmd(0x3F); /*duty = 1/64*/
OLEDWriteCmd(0xC8); /*Com scan direction*/
OLEDWriteCmd(0xD3); /*set display offset*/
OLEDWriteCmd(0x00);
OLEDWriteCmd(0xD5); /*set osc division*/
OLEDWriteCmd(0x80);
OLEDWriteCmd(0xD9); /*set pre-charge period*/
OLEDWriteCmd(0x1f);
OLEDWriteCmd(0xDA); /*set COM pins*/
OLEDWriteCmd(0x12);
OLEDWriteCmd(0xdb); /*set vcomh*/
OLEDWriteCmd(0x30);
OLEDWriteCmd(0x8d); /*set charge pump enable*/
OLEDWriteCmd(0x14);
OLEDSetPageAddrMode();
OLEDClear();
OLEDWriteCmd(0xAF); /*display ON*/
}
static void OLEDWriteCmd(unsigned char cmd)
{
OLED_Set_DC(0); /* command */
OLED_Set_CS(0); /* select OLED */
SPISendByte(cmd);
OLED_Set_CS(1); /* de-select OLED */
OLED_Set_DC(1); /* */
}
static void OLEDWriteDat(unsigned char dat)
{
OLED_Set_DC(1); /* data */
OLED_Set_CS(0); /* select OLED */
SPISendByte(dat);
OLED_Set_CS(1); /* de-select OLED */
OLED_Set_DC(1); /* */
}
static void SPI_Set_CLK(char val)
{
if (val)
GPGDAT |= (1<<7);
else
GPGDAT &= ~(1<<7);
}
static void SPI_Set_DO(char val)
{
if (val)
GPGDAT |= (1<<6);
else
GPGDAT &= ~(1<<6);
}
void SPISendByte(unsigned char val)
{
int i;
for (i = 0; i < 8; i++)
{
SPI_Set_CLK(0);
SPI_Set_DO(val & 0x80);
SPI_Set_CLK(1);
val <<= 1;
}
}
static char SPI_Get_DI(void)
{
if (GPGDAT & (1<<5))
return 1;
else
return 0;
}
unsigned char SPIRecvByte(void)
{
int i;
unsigned char val = 0;
for (i = 0; i < 8; i++)
{
val <<= 1;
SPI_Set_CLK(0);
if (SPI_Get_DI())
val |= 1;
SPI_Set_CLK(1);
}
return val;
}
static void OLEDSetPos(int page, int col)
{
OLEDWriteCmd(0xB0 + page); /* page address */
OLEDWriteCmd(col & 0xf); /* Lower Column Start Address */
OLEDWriteCmd(0x10 + (col >> 4)); /* Lower Higher Start Address */
}
/* page: 0-7
* col : 0-127
* 字符: 8x16象素
*/
void OLEDPutChar(int page, int col, char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLEDSetPos(page, col);
/* 发出8字节数据 */
for (i = 0; i < 8; i++)
OLEDWriteDat(dots[i]);
OLEDSetPos(page+1, col);
/* 发出8字节数据 */
for (i = 0; i < 8; i++)
OLEDWriteDat(dots[i+8]);
}
/* page: 0-7
* col : 0-127
* 字符: 8x16象素
*/
void OLEDPrint(int page, int col, char *str)
{
int i = 0;
while (str[i])
{
OLEDPutChar(page, col, str[i]);
col += 8;
if (col > 127)
{
col = 0;
page += 2;
}
i++;
}
}
static void OLEDClear(void)
{
int page, i;
for (page = 0; page < 8; page ++)
{
OLEDSetPos(page, 0);
for (i = 0; i < 128; i++)
OLEDWriteDat(0);
}
}
static void OLEDSetPageAddrMode(void)
{
OLEDWriteCmd(0x20);
OLEDWriteCmd(0x02);
}
硬件SPI没什么好说的直接怼寄存器
#include "s3c24xx.h"
/* SPI controller */
static void SPI_GPIO_Init(void)
{
/* GPF1 OLED_CSn output */
GPFCON &= ~(3<<(1*2));
GPFCON |= (1<<(1*2));
GPFDAT |= (1<<1);
/* GPG2 FLASH_CSn output
* GPG4 OLED_DC output
* GPG5 SPIMISO
* GPG6 SPIMOSI
* GPG7 SPICLK
*/
GPGCON &= ~((3<<(2*2)) | (3<<(4*2)) | (3<<(5*2)) | (3<<(6*2)) | (3<<(7*2)));
GPGCON |= ((1<<(2*2)) | (1<<(4*2)) | (3<<(5*2)) | (3<<(6*2)) | (3<<(7*2)));
GPGDAT |= (1<<2);
}
void SPISendByte(unsigned char val)
{
while (!(SPSTA1 & 1));
SPTDAT1 = val;
}
unsigned char SPIRecvByte(void)
{
SPTDAT1 = 0xff;
while (!(SPSTA1 & 1));
return SPRDAT1;
}
static void SPIControllerInit(void)
{
/* OLED : 100ns, 10MHz
* FLASH : 104MHz
* 取10MHz
* 10 = 50 / 2 / (Prescaler value + 1)
* Prescaler value = 1.5 = 2
* Baud rate = 50/2/3=8.3MHz
*/
SPPRE0 = 2;
SPPRE1 = 2;
/* [6:5] : 00, polling mode
* [4] : 1 = enable
* [3] : 1 = master
* [2] : 0
* [1] : 0 = format A
* [0] : 0 = normal mode
*/
SPCON0 = (1<<4) | (1<<3);
SPCON1 = (1<<4) | (1<<3);
}
void SPIInit(void)
{
/* 初始化引脚 */
SPI_GPIO_Init();
SPIControllerInit();
}