向韦东山学:spi协议+oled裸板程序

go spi 系列— spi协议+oled裸板程序

作者:titer1 
联系:1307316一九六八(仅接受短信) 
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。

本文所有代码版权归原作者所有 
目录 
Alt text

图说 spi 简要原理

Alt text

  • 基础 数据传输原理 dataoutput + clock + selections

图说 arm2240 + spi

2440系统如何使用spi的 
Alt text

tips:同步后 ,ctrl+ alt +enter 预览

图说 结合di引脚说明不同spi传输场景

当arm读取spi设备时,

这是 spi transfer format细节, 
送完一个字节,下一个时钟周期没有到来之前,di内容存在差异 
详细如图: 
Alt text

韦大大说,时钟周末没来之前的事情 不用在乎,在乎时钟边缘

还有时钟的极性差别,如下图橙色标示: 
Alt text
上图我看来,就是时钟开始时电平的高/低

至于如何选定正确的极性作为开始,要看外接芯片的约定

图说 芯片 clock极性

结合 SPEC UG-2864TMBEG01 手册,可以看到图中时钟起始选择可高可低,不用担心 
Alt text

韦大大说,arm spi format a/b 
不过外接的spi芯片 DO数据是在上升沿由外接芯片锁存住。

那么 ,最终arm 2440可选的format格式剩下为; 
Alt text

Alt text

以上场景区分是 arm的 cpol /cpha的值

下面开始代码了 
当前是 spi第一课第一节,修改代码在 spi_i2c_adc里面

代码实战

内容框架

Alt text

一个文件负责 显示, 
一个文件负责传输 
目标实现函数有:

SPIInit();
OLEDInit();
OLEDPrint();

主要分析内容来源是:源码source\裸板\01th_spi_i2c_adc_jz2440_oled

oled.c

简单来说就是OLED开头的函数实现,在这里。

从芯片SPEC UG-2864TMBEG01 手册看来,vcc产生是 内部dc上拉结果? 
改装芯片手册内部的初始化设置

oledinit 向oled发送命令

详细的cpu和芯片的连线图如下,这次跟之前给出的连线图差别在,给出data/控制信号切换的方法

Alt text


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); /*  */
}

//入口函数
void OLEDInit(void)
{
    /* 向OLED发命令以初始化 */
    OLEDWriteCmd(0xAE); /*display off*/ 
...
    OLEDWriteCmd(0x14); 
...    
}

继续看 oled控制器 (?)的手册 SSD1306-Revision 1.1 (Charge Pump)

细节:实现 dc +cs 片选信号

这里 dc对应gpg4 ,cs对应gpf1

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

###实现 Oledprint 
关键在 oled 地址设定+ 数据设定 
这里采用的取地址方式是:页寻址 
显存这里大小为:128*64 
一行64字节,分为8页,每页8行

手册解释 详细看 
10 COMMAND DESCRIPTIONS 
10.1 Fundamental Command 
10.1.1 Set Lower Column Start Address for Page Addressing Mode (00h~0Fh) 
10.1.2 Set Higher Column Start Address for Page Addressing Mode (10h~1Fh) 
10.1.3 Set Memory Addressing Mode (20h) 
There are 3 different memory addressing mode in SSD1306: page addressing mode, 
horizontal addressing mode and vertical addressing mode. 

情景如图: 
Alt text

中文总结如下:

  • 先发送 列地址 高位
  • 再发送 列地址 低位
  • 配置寻址模式
再说如何放到Led显示屏幕上去的

看手册 
Alt text
看最终屏幕上的布局,这里就可以理解为什么要两行了,下面说明相关代码

//每一个字节的字模数据都分解为高4位+低4位传输
//之所以相加:因为是bit 0:1 ,后面处理了高位和低位
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 */
}

Alt text 
下面的函数OLEDPutChar形象的说明了绘制字模的过程。



//涵盖字符转换为字模
/* 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++;
    }
}
其他oled函数

oled设置page模式 
oled清屏函数

此处暂时忽略。

!总结

至此:字符–》字模点阵–》spi 数据传输的过程就通过以上看到

OLEDPrint -->OLEDPutChar -->( OLEDWriteDat-->OLEDWriteCmd)
!细节 实现spisendbyte 重要的

cloc对应gpg7 do对应gpd6,非常有趣重要的是上升沿的do实现

 SPI_Set_CLK(0);
 SPI_Set_DO(val & 0x80);//典型取高位
 SPI_Set_CLK(1);

完整的SPISendByte逻辑在下面

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

}

gpio_spi.c 联通arm和spi芯片

首先看spi芯片的电路图 
Alt text
然后使用gpio模拟spi,尤其注意里面的注释,这里比较细节就是gpio方向

/* 用GPIO模拟SPI */
//called by SPIInit
static void SPI_GPIO_Init(void)
{
    /* GPF1 OLED_CSn output */
    GPFCON &= ~(3<<(1*2)); 
    GPFCON |= (1<<(1*2));
    GPFDAT |= (1<<1); //设置为高电平,保证片选引脚pin1(GPF1 OLED_CSn)和其他相关引脚不同时为0,

    /* 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);//设置为高电平,保证片选引脚pin2(GPG2 FLASH_CSn) 和其他相关引脚不同时为0,
}

当前进度是在 1-1 30分钟位置

其他

作者所使用的代码在 spi_i2c_adc相关文件夹中

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值