向韦东山学:spi协议+oled裸板程序
2015-12-19 17:43
274 查看
go spi 系列— spi协议+oled裸板程序
作者:titer1 联系:1307316一九六八(仅接受短信)
声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处。
本文所有代码版权归原作者所有
目录
图说 spi 简要原理
基础 数据传输原理 dataoutput + clock + selections
图说 arm2240 + spi
2440系统如何使用spi的 tips:同步后 ,ctrl+ alt +enter 预览
图说 结合di引脚说明不同spi传输场景
当arm读取spi设备时,这是 spi transfer format细节,
送完一个字节,下一个时钟周期没有到来之前,di内容存在差异
详细如图:
韦大大说,时钟周末没来之前的事情 不用在乎,在乎时钟边缘
还有时钟的极性差别,如下图橙色标示:
上图我看来,就是时钟开始时电平的高/低
至于如何选定正确的极性作为开始,要看外接芯片的约定
图说 芯片 clock极性
结合 SPEC UG-2864TMBEG01 手册,可以看到图中时钟起始选择可高可低,不用担心 韦大大说,arm spi format a/b
不过外接的spi芯片 DO数据是在上升沿由外接芯片锁存住。
那么 ,最终arm 2440可选的format格式剩下为;
以上场景区分是 arm的 cpol /cpha的值
下面开始代码了
当前是 spi第一课第一节,修改代码在 spi_i2c_adc里面
代码实战
内容框架
一个文件负责 显示,
一个文件负责传输
目标实现函数有:
SPIInit(); OLEDInit(); OLEDPrint();
主要分析内容来源是:源码source\裸板\01th_spi_i2c_adc_jz2440_oled
oled.c
简单来说就是OLED开头的函数实现,在这里。从芯片SPEC UG-2864TMBEG01 手册看来,vcc产生是 内部dc上拉结果?
改装芯片手册内部的初始化设置
oledinit 向oled发送命令
详细的cpu和芯片的连线图如下,这次跟之前给出的连线图差别在,给出data/控制信号切换的方法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对应gpf1static 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.
情景如图:
中文总结如下:
先发送 列地址 高位
再发送 列地址 低位
配置寻址模式
再说如何放到Led显示屏幕上去的
看手册 看最终屏幕上的布局,这里就可以理解为什么要两行了,下面说明相关代码
//每一个字节的字模数据都分解为高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 */ }
下面的函数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芯片的电路图 然后使用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相关文件夹中
相关文章推荐
- Python连接Mysql
- Git常用命令
- 【杭电】[2006]求奇数的乘积
- 分享个人maven本地库
- 一位Erlang程序员的自白
- Java中Properties文件值的获取
- 树莓派玩耍笔记4 -- 树莓派ssh党必备的配置
- C/C++ 常量指针,指针常量
- WordPress中给文章添加自定义字段及后台编辑功能区域
- ios客户端学习-日历控件
- Leetcode: Longest Increasing Subsequence
- 集合总结
- C/C++ 内存传递 指针
- Android 当Volley遇到Https
- 运算符的优先级
- Gradle Buildscript
- Codevs_P3372 选学霸(并查集+DP+背包)
- VBA实现数组Array与集合Collection互换
- ffmpeg avfilter小结
- 【杭电】[1001]Sum Problem