S3c2440裸机-spi编程-3.gpio模拟spi驱动OLED

发布时间:2023-07-21  

操作OLED,通过三条线(SCK、DO、CS)与OLED相连,这里没有DI是因为2440只会向OLED传数据而不用接收数据。

gpio_spi.c来实现gpio模拟spi,负责spi通讯。对于OLED,有专门的指令和数据格式,要传输的数据内容,在oled.c这一层来实现,负责组织数据。

因此,我们需要实现以上两个文件。

 

1.SPI初始化

新建一个gpio_spi.c文件,实现SPI初始化SPIInt()

 

1.1 GPIO init(pinmux管脚等配置)

上图J3为板子pin2pin到OLED的底座。

GPF1作为OLED片选引脚,设置为输出;
GPG4作为OLED的数据(Data)/命令(Command)选择引脚,设置为输出;
GPG5作为SPI的MISO,设置为输入(实际用不到);
GPG6作为SPI的MOSI,设置为输出;
GPG7作为SPI的时钟CLK,设置为输出;

 

 

 根据gpio相关寄存器进行配置如下:用gpio配置成spi使用的各个引脚。

void SPIInit(void){

    /* 初始化引脚 */

    SPI_GPIO_Init();

}

static void SPI_GPIO_Init(void){

    /* GPF1 as OLED_CSn output */

    GPFCON &= ~(3<    GPFCON |= (1<    GPFDAT |= (1<<1);//取消OLED_CSn片选,pull up

   /* GPG2 FLASH_CSn output

    * GPG4 OLED_DC   output

    * GPG5 SPIMISO   input

    * GPG6 SPIMOSI   output

    * GPG7 SPICLK    output

    */

    GPGCON &= ~((3<    GPGCON |= ((1<    GPGDAT |= (1<<2);//取消FLASH_CSn 片选,pull up

}


2.OLED初始化 

再新建一个oled.c文件,以实现初始化OLEDInit(),这里就对应power up sequence。


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);

}


D/C即数据(Data)/命令(Command)选择引脚,它为高电平时,OLED即认为收到的是数据;它为低电平时,OLED即认为收到的是命令。先设置为命令模式,再片选OLED,再传输命令,再恢复成原来的模式和取消片选。

2.1 实现OLED写功能

写命令和写数据:

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); /*  gpio output default is pull up*/

}

static void OLEDWriteDat(unsigned char data){

    OLED_Set_DC(1); /* data*/

    OLED_Set_CS(0); /* select OLED */

SPISendByte(data);

OLED_Set_CS(1); /* de-select OLED */

}

命令模式和片选就是单纯的gpio操作,非常简单如下:


static void OLED_Set_DC(char val){

    if (val)

        GPGDAT |= (1<<4);

    else

        GPGDAT &= ~(1<<4);

}

static void OLED_Set_CS(char val){

    if (val)

        GPFDAT |= (1<<1);

    else

        GPFDAT &= ~(1<<1);

}


2.2 SPISendByte()

还剩下SPISendByte()函数,它属于SPI协议,放在gpio_spi.c里面:


void SPISendByte(unsigned char val){

    int i;

    for (i = 0; i < 8; i++){

        SPI_Set_CLK(0);

        SPI_Set_DO(val & 0x80);//MSB

        SPI_Set_CLK(1);

        val <<= 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);

}


发送数据要满足SPI的时序要求,参考前面的介绍:

 

SPISendByte是把一个byte数据从高位往低位依次发送到DO。spi配置模式0, 主控先设置CLK为低,由于是MSB, 先传送高位,然后CLK为高,在CLK这个上升沿,DO的数据被锁存,OLED就读取了一位数据。接着左移一位,传输下一位。通过SPI_Set_CLK()和SPI_Set_DO()配置SCK和DO的时序,用gpio模拟出了spi。至此,SPI初始化和OLED初始化就基本完成了,接下来就是OLED显示部分。

这里gpio模拟spi传送时主控没有加延时控制SCK的频率,那是由于jz2440本身cpu运行就很慢,这里不延时也是能满足该款外设的spi传输时序,如果cpu很快,那么需要控制spi时序。

3.驱动显示OLED

如何在OLED上显示一个字符?根据前面一节OLED面板的显示原理。代码实现如下:


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 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 */

}

static void OLEDClear(void){

    int page, i;

    for (page = 0; page < 8; page ++){

        OLEDSetPos(page, 0);

        for (i = 0; i < 128; i++)

            OLEDWriteDat(0);

    }

}

完整代码如下:


/************************** gpio_spi.c ****************/

#include "s3c24xx.h"

/* 用GPIO模拟SPI */

static void SPI_GPIO_Init(void)

{

    /* GPF1 OLED_CSn output */

    GPFCON &= ~(3<    GPFCON |= (1<    GPFDAT |= (1<<1);

 

    /* GPG2 FLASH_CSn output

    * GPG4 OLED_DC   output

    * GPG5 SPIMISO   input

    * GPG6 SPIMOSI   output

    * GPG7 SPICLK    output

    */

    GPGCON &= ~((3<    GPGCON |= ((1<    GPGDAT |= (1<<2);

}

 

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;

    }

     

}

 

void SPIInit(void)

{

    /* 初始化引脚 */

    SPI_GPIO_Init();

}

 

/******************* oled.c****************/

#include "oledfont.h"

#include "gpio_spi.h"

#include "s3c24xx.h"

static void OLED_Set_DC(char val)

{

    if (val)

        GPGDAT |= (1<<4);

    else

        GPGDAT &= ~(1<<4);

}

static void OLED_Set_CS(char val)

{

    if (val)

        GPFDAT |= (1<<1);

    else

        GPFDAT &= ~(1<<1);

}

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 OLEDSetPageAddrMode(void)

{

    OLEDWriteCmd(0x20);

    OLEDWriteCmd(0x02);

}

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 */

}

static void OLEDClear(void)

{

    int page, i;

    for (page = 0; page < 8; page ++)

    {

        OLEDSetPos(page, 0);

        for (i = 0; i < 128; i++)

            OLEDWriteDat(0);

    }

}

void OLEDInit(void)

{

    /* 向OLED发命令以初始化 */

    OLEDWriteCmd(0xAE); /*display off*/

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>