发布: 14_编写SPI_OLED模块驱动程序,15_编写OLED驱动_上机实验_IMX6ULL,15_编写OLED驱动_上机实验_STM32MP157

This commit is contained in:
weidongshan
2022-04-29 12:15:43 +08:00
parent 0f865b253c
commit 4389f43102
28 changed files with 3292 additions and 4 deletions

View File

@@ -0,0 +1,270 @@
# 编写SPI_OLED模块驱动程序 #
* 源码:
![image-20220427090822149](pic/74_src_oled_drv.png)
## 1. 硬件
### 1.1 原理图
IMX6ULL:
![image-20220316120535482](pic/47_imx6ull_oled_sch.png)
STM32MP157:
![image-20220316120427564](pic/48_stm32mp157_oled_sch.png)
原理图:
![image-20220314114847437](pic/49_oled_sch.png)
### 1.2 连接
无论是使用IMX6ULL开发板还是STM32MP157开发板都有类似的扩展板。把OLED模块接到扩展板的SPI_A插座上如下
![image-20220314115446373](pic/50_oled_on_extend_brd.png)
## 2. 编写设备树
### 2.1.1 IMX6ULL
![](pic/44_imx6ull_pro_extend_spi_a.png)
DC引脚使用GPIO4_20也需在设备树里指定。
设备树如下:
```shell
&ecspi1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi1>;
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
status = "okay";
oled: oled {
compatible = "100ask,oled";
reg = <0>;
spi-max-frequency = <10000000>;
dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;
};
};
```
### 2.1.2 STM32MP157
![](pic/45_stm32mp157_pro_extend_spi_a.png)
DC引脚使用GPIOA_13也需要在设备树里指定。
设备树如下:
```shell
&spi5 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi5_pins_a>;
pinctrl-1 = <&spi5_sleep_pins_a>;
status = "okay";
cs-gpios = <&gpioh 5 GPIO_ACTIVE_LOW>, <&gpioz 4 GPIO_ACTIVE_LOW>;
spidev: icm20608@0{
compatible = "invensense,icm20608";
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpioz>;
spi-max-frequency = <8000000>;
reg = <0>;
};
oled: oled@1{
compatible = "100ask,oled";
spi-max-frequency = <10000000>;
reg = <1>;
dc-gpios = <&gpioa 13 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&oled_pins>;
};
};
```
arch/arm/boot/dts/stm32mp157-100ask-pinctrl.dtsi:
```shell
oled_pins: oled_pins {
pins {
pinmux = <STM32_PINMUX('A', 13, GPIO)>;
bias-disable;
drive-push-pull;
slew-rate = <1>;
};
};
```
## 3. 编译替换设备树
### 3.1 IMX6ULL
#### 3.1.1 设置工具链
```shell
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
```
#### 3.1.2 编译、替换设备树
* 编译设备树:
在Ubuntu的IMX6ULL内核目录下执行如下命令,
得到设备树文件:`arch/arm/boot/dts/100ask_imx6ull-14x14.dtb`
```shell
make dtbs
```
* 复制到NFS目录
```shell
$ cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
```
* 开发板上挂载NFS文件系统
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 更新设备树
```shell
[root@100ask:~]# cp /mnt/100ask_imx6ull-14x14.dtb /boot
[root@100ask:~]# sync
```
* 重启开发板
### 3.2 STM32MP157
#### 3.2.1 设置工具链
```shell
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
```
#### 3.2.2 编译、替换设备树
* 编译设备树:
在Ubuntu的STM32MP157内核目录下执行如下命令,
得到设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb`
```shell
make dtbs
```
* 复制到NFS目录
```shell
$ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/
```
* 开发板上挂载NFS文件系统
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 确定设备树分区挂载在哪里
由于版本变化STM32MP157单板上烧录的系统可能有细微差别。
在开发板上执行`cat /proc/mounts`后,可以得到两种结果(见下图)
* mmcblk2p2分区挂载在/boot目录下(下图左边):无需特殊操作,下面把文件复制到/boot目录即可
* mmcblk2p2挂载在/mnt目录下(下图右边)
* 在视频里、后面文档里,都是更新/boot目录下的文件所以要先执行以下命令重新挂载
* `mount /dev/mmcblk2p2 /boot`
![](pic/46_boot_mount.png)
* 更新设备树
```shell
[root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot/
[root@100ask:~]# sync
```
* 重启开发板
## 4. 编译OLED驱动
## 5. 编译APP
```shell
arm-buildroot-linux-gnueabihf-gcc -o spi_oled spi_oled.c
```
## 6. 上机实验
如果spidev没有被编译进内核那么先执行
```shell
insmod oled_drv.ko
```
确定设备节点:
```shell
ls /dev/100ask_oled
```
假设设备节点为`/dev/100ask_oled`,执行测试程序:
```shell
./spi_oled /dev/100ask_oled
```

View File

@@ -0,0 +1,270 @@
# 编写OLED驱动_上机实验 #
* 源码:
![image-20220427142603006](pic/75_src_oled_drv_ok.png)
## 1. 硬件
### 1.1 原理图
IMX6ULL:
![image-20220316120535482](pic/47_imx6ull_oled_sch.png)
STM32MP157:
![image-20220316120427564](pic/48_stm32mp157_oled_sch.png)
原理图:
![image-20220314114847437](pic/49_oled_sch.png)
### 1.2 连接
无论是使用IMX6ULL开发板还是STM32MP157开发板都有类似的扩展板。把OLED模块接到扩展板的SPI_A插座上如下
![image-20220314115446373](pic/50_oled_on_extend_brd.png)
## 2. 编写设备树
### 2.1.1 IMX6ULL
![](pic/44_imx6ull_pro_extend_spi_a.png)
DC引脚使用GPIO4_20也需在设备树里指定。
设备树如下arch/arm/boot/dts/100ask_imx6ull-14x14.dts
```shell
&ecspi1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi1>;
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio4 26 GPIO_ACTIVE_LOW>, <&gpio4 24 GPIO_ACTIVE_LOW>;
status = "okay";
oled: oled {
compatible = "100ask,oled";
reg = <0>;
spi-max-frequency = <10000000>;
dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;
};
};
```
### 2.1.2 STM32MP157
![](pic/45_stm32mp157_pro_extend_spi_a.png)
DC引脚使用GPIOA_13也需要在设备树里指定。
设备树如下:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts`
```shell
&spi5 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi5_pins_a>;
pinctrl-1 = <&spi5_sleep_pins_a>;
status = "okay";
cs-gpios = <&gpioh 5 GPIO_ACTIVE_LOW>, <&gpioz 4 GPIO_ACTIVE_LOW>;
spidev: icm20608@0{
compatible = "invensense,icm20608";
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpioz>;
spi-max-frequency = <8000000>;
reg = <0>;
};
oled: oled@1{
compatible = "100ask,oled";
spi-max-frequency = <10000000>;
reg = <1>;
dc-gpios = <&gpioa 13 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&oled_pins>;
};
};
```
arch/arm/boot/dts/stm32mp157-100ask-pinctrl.dtsi:
```shell
oled_pins: oled_pins {
pins {
pinmux = <STM32_PINMUX('A', 13, GPIO)>;
bias-disable;
drive-push-pull;
slew-rate = <1>;
};
};
```
## 3. 编译替换设备树
### 3.1 IMX6ULL
#### 3.1.1 设置工具链
```shell
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
```
#### 3.1.2 编译、替换设备树
* 编译设备树:
在Ubuntu的IMX6ULL内核目录下执行如下命令,
得到设备树文件:`arch/arm/boot/dts/100ask_imx6ull-14x14.dtb`
```shell
make dtbs
```
* 复制到NFS目录
```shell
$ cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
```
* 开发板上挂载NFS文件系统
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 更新设备树
```shell
[root@100ask:~]# cp /mnt/100ask_imx6ull-14x14.dtb /boot
[root@100ask:~]# sync
```
* 重启开发板
### 3.2 STM32MP157
#### 3.2.1 设置工具链
```shell
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
```
#### 3.2.2 编译、替换设备树
* 编译设备树:
在Ubuntu的STM32MP157内核目录下执行如下命令,
得到设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb`
```shell
make dtbs
```
* 复制到NFS目录
```shell
$ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/
```
* 开发板上挂载NFS文件系统
```shell
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
```
* 确定设备树分区挂载在哪里
由于版本变化STM32MP157单板上烧录的系统可能有细微差别。
在开发板上执行`cat /proc/mounts`后,可以得到两种结果(见下图)
* mmcblk2p2分区挂载在/boot目录下(下图左边):无需特殊操作,下面把文件复制到/boot目录即可
* mmcblk2p2挂载在/mnt目录下(下图右边)
* 在视频里、后面文档里,都是更新/boot目录下的文件所以要先执行以下命令重新挂载
* `mount /dev/mmcblk2p2 /boot`
![](pic/46_boot_mount.png)
* 更新设备树
```shell
[root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot/
[root@100ask:~]# sync
```
* 重启开发板
## 4. 编译OLED驱动
## 5. 编译APP
```shell
arm-buildroot-linux-gnueabihf-gcc -o spi_oled spi_oled.c
```
## 6. 上机实验
如果spidev没有被编译进内核那么先执行
```shell
insmod oled_drv.ko
```
确定设备节点:
```shell
ls /dev/100ask_oled
```
假设设备节点为`/dev/100ask_oled`,执行测试程序:
```shell
./spi_oled /dev/100ask_oled
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -13,10 +13,6 @@
#include "font.h"
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;

View File

@@ -0,0 +1,22 @@
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o spi_oled spi_oled.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order spi_oled
obj-m += oled_drv.o

View File

@@ -0,0 +1,106 @@
#ifndef _FONT_H_
#define _FONT_H_
const unsigned char oled_asc2_8x16[95][16]=
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// 0
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00},//!1
{0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//"2
{0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00},//#3
{0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00},//$4
{0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00},//%5
{0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10},//&6
{0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//'7
{0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00},//(8
{0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00},//)9
{0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00},//*10
{0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00},//+11
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00},//,12
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01},//-13
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00},//.14
{0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00},///15
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},//016
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//117
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},//218
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},//319
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},//420
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},//521
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},//622
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},//723
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},//824
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00},//925
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},//:26
{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00},//;27
{0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00},//<28
{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00},//=29
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00},//>30
{0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00},//?31
{0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00},//@32
{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20},//A33
{0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00},//B34
{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},//C35
{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},//D36
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00},//E37
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00},//F38
{0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00},//G39
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},//H40
{0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//I41
{0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00},//J42
{0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00},//K43
{0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00},//L44
{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00},//M45
{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},//N46
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00},//O47
{0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00},//P48
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00},//Q49
{0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20},//R50
{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},//S51
{0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//T52
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//U53
{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},//V54
{0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00},//W55
{0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20},//X56
{0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//Y57
{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},//Z58
{0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00},//[59
{0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00},//\60
{0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00},//]61
{0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//^62
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},//_63
{0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//`64
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20},//a65
{0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00},//b66
{0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00},//c67
{0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20},//d68
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00},//e69
{0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//f70
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00},//g71
{0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//h72
{0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//i73
{0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00},//j74
{0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00},//k75
{0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//l76
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},//m77
{0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//n78
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//o79
{0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00},//p80
{0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80},//q81
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00},//r82
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00},//s83
{0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00},//t84
{0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},//u85
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00},//v86
{0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00},//w87
{0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00},//x88
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00},//y89
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00},//z90
{0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40},//{91
{0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},//|92
{0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00},//}93
{0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//~94
};
const unsigned char hz_1616[][32]={
{0x02,0x00,0x02,0x00,0xE2,0xFF,0x22,0x42,0x22,0x42,0x32,0x42,0x2A,0x42,0x26,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0xE2,0xFF,0x02,0x00,0x02,0x00,0x00,0x00},/*"百",0*/
{0x00,0x00,0xF8,0xFF,0x01,0x00,0x02,0x00,0x00,0x00,0xE2,0x1F,0x22,0x08,0x22,0x08,0x22,0x08,0xE2,0x1F,0x02,0x00,0x02,0x40,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"问",1*/
{0x00,0x00,0xFE,0xFF,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x0E,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x4E,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"网",2*/
};
#endif

View File

@@ -0,0 +1,300 @@
/*
* Simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>
* Copyright (C) 2007 David Brownell (simplification, cleanup)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
/*-------------------------------------------------------------------------*/
static struct spi_device *oled;
static int major;
static gpio_desc *dc_gpio;
static void dc_pin_init(void)
{
gpiod_direction_output(dc_gpio, 1);
}
static void oled_set_dc_pin(int val)
{
gpiod_set_value(dc_gpio, val);
}
static void spi_write_datas(const unsigned char *buf, int len)
{
spi_write(oled, buf, len);
}
/**********************************************************************
* 函数名称: oled_write_cmd
* 功能描述: oled向特定地址写入数据或者命令
* 输入参数:@uc_data :要写入的数据
@uc_cmd:为1则表示写入数据为0表示写入命令
* 输出参数:无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/04 V1.0 芯晓 创建
***********************************************************************/
static void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)
{
unsigned char uc_read=0;
if(uc_cmd==0)
{
oled_set_dc_pin(0);
}
else
{
oled_set_dc_pin(1);//拉高,表示写入数据
}
spi_write_datas(&uc_data, 1);//写入
}
/**********************************************************************
* 函数名称: oled_init
* 功能描述: oled_init的初始化包括SPI控制器得初始化
* 输入参数:无
* 输出参数: 初始化的结果
* 返 回 值: 成功则返回0否则返回-1
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static int oled_init(void)
{
unsigned char uc_dev_id = 0;
oled_write_cmd_data(0xae,OLED_CMD);//关闭显示
oled_write_cmd_data(0x00,OLED_CMD);//设置 lower column address
oled_write_cmd_data(0x10,OLED_CMD);//设置 higher column address
oled_write_cmd_data(0x40,OLED_CMD);//设置 display start line
oled_write_cmd_data(0xB0,OLED_CMD);//设置page address
oled_write_cmd_data(0x81,OLED_CMD);// contract control
oled_write_cmd_data(0x66,OLED_CMD);//128
oled_write_cmd_data(0xa1,OLED_CMD);//设置 segment remap
oled_write_cmd_data(0xa6,OLED_CMD);//normal /reverse
oled_write_cmd_data(0xa8,OLED_CMD);//multiple ratio
oled_write_cmd_data(0x3f,OLED_CMD);//duty = 1/64
oled_write_cmd_data(0xc8,OLED_CMD);//com scan direction
oled_write_cmd_data(0xd3,OLED_CMD);//set displat offset
oled_write_cmd_data(0x00,OLED_CMD);//
oled_write_cmd_data(0xd5,OLED_CMD);//set osc division
oled_write_cmd_data(0x80,OLED_CMD);//
oled_write_cmd_data(0xd9,OLED_CMD);//ser pre-charge period
oled_write_cmd_data(0x1f,OLED_CMD);//
oled_write_cmd_data(0xda,OLED_CMD);//set com pins
oled_write_cmd_data(0x12,OLED_CMD);//
oled_write_cmd_data(0xdb,OLED_CMD);//set vcomh
oled_write_cmd_data(0x30,OLED_CMD);//
oled_write_cmd_data(0x8d,OLED_CMD);//set charge pump disable
oled_write_cmd_data(0x14,OLED_CMD);//
oled_write_cmd_data(0xaf,OLED_CMD);//set dispkay on
return 0;
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static void OLED_DIsp_Set_Pos(int x, int y)
{ oled_write_cmd_data(0xb0+y,OLED_CMD);
oled_write_cmd_data((x&0x0f),OLED_CMD);
oled_write_cmd_data(((x&0xf0)>>4)|0x10,OLED_CMD);
}
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int x, y;
/* 根据cmd操作硬件 */
switch (cmd)
{
case OLED_IOC_INIT: /* init */
{
dc_pin_init();
oled_init();
break;
}
case OLED_IOC_SET_POS: /* set pos */
{
x = arg & 0xff;
y = (arg >> 8) & 0xff;
OLED_DIsp_Set_Pos(x, y);
break;
}
}
return 0;
}
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
char *ker_buf;
int err;
ker_buf = kmalloc(count, GFP_KERNEL);
err = copy_from_user(ker_buf, buf, count);
oled_set_dc_pin(1);//拉高,表示写入数据
spi_write_datas(ker_buf, count);
return count;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage. It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.unlocked_ioctl = spidev_ioctl,
};
/*-------------------------------------------------------------------------*/
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "100ask,oled" },
{},
};
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
/* 1. 记录spi_device */
oled = spi;
/* 2. 注册字符设备 */
major = register_chrdev(0, "100ask_oled", &spidev_fops);
spidev_class = class_create(THIS_MODULE, "100ask_oled");
device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_oled");
/* 3. 获得GPIO引脚 */
dc_gpio = gpiod_get(&spi->dev, "dc", 0);
return 0;
}
static int spidev_remove(struct spi_device *spi)
{
gpiod_put(dc_gpio);
/* 反注册字符设备 */
device_destroy(spidev_class, MKDEV(major, 0));
class_destroy(spidev_class);
unregister_chrdev(major, "100ask_oled");
return 0;
}
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "100ask_spi_oled_drv",
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller. The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
int status;
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,239 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "font.h"
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;
void oled_write_datas(const unsigned char *buf, int len)
{
write(fd_spidev, buf, len);
}
/**********************************************************************
* 函数名称: OLED_DIsp_Clear
* 功能描述: 整个屏幕显示数据清0
* 输入参数:无
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Clear(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_All
* 功能描述: 整个屏幕显示全部点亮,可以用于检查坏点
* 输入参数:无
* 输出参数:无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_All(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0xff, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Set_Pos(int x, int y)
{
ioctl(fd_spidev, OLED_IOC_SET_POS, x | (y << 8));
}
/**********************************************************************
* 函数名称: OLED_DIsp_Char
* 功能描述:在某个位置显示字符 1-9
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@c 要显示的字符的ascii码
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Char(int x, int y, unsigned char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLED_DIsp_Set_Pos(x, y);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
// oled_write_cmd_data(dots[i], OLED_DATA);
oled_write_datas(&dots[0], 8);
OLED_DIsp_Set_Pos(x, y+1);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
//oled_write_cmd_data(dots[i+8], OLED_DATA);
oled_write_datas(&dots[8], 8);
}
/**********************************************************************
* 函数名称: OLED_DIsp_String
* 功能描述: 在指定位置显示字符串
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@str :要显示的字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_String(int x, int y, char *str)
{
unsigned char j=0;
while (str[j])
{
OLED_DIsp_Char(x, y, str[j]);//显示单个字符
x += 8;
if(x > 127)
{
x = 0;
y += 2;
}//移动显示位置
j++;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_CHinese
* 功能描述:在指定位置显示汉字
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@chr :要显示的汉字,三个汉字“百问网”中选择一个
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no)
{
unsigned char t,adder=0;
OLED_DIsp_Set_Pos(x,y);
for(t=0;t<16;t++)
{//显示上半截字符
oled_write_datas(&hz_1616[no][t*2], 1);
adder+=1;
}
OLED_DIsp_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{//显示下半截字符
oled_write_datas(&hz_1616[no][t*2+1], 1);
adder+=1;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_Test
* 功能描述: 整个屏幕显示测试
* 输入参数:无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Test(void)
{
int i;
OLED_DIsp_String(0, 0, "wiki.100ask.net");
OLED_DIsp_String(0, 2, "book.100ask.net");
OLED_DIsp_String(0, 4, "bbs.100ask.net");
for(i = 0; i < 3; i++)
{ //显示汉字 百问网
OLED_DIsp_CHinese(32+i*16, 6, i);
}
}
/* spi_oled /dev/100ask_oled */
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s /dev/100ask_oled\n", argv[0]);
return -1;
}
fd_spidev = open(argv[1], O_RDWR);
if (fd_spidev < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
ioctl(fd_spidev, OLED_IOC_INIT);
OLED_DIsp_Clear();
OLED_DIsp_Test();
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifndef _OLED_H_
#define _OLED_H_
void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd);
int oled_init(void);
int oled_fill_data(unsigned char fill_Data);
void OLED_DIsp_Clear(void);
void OLED_DIsp_All(void);
void OLED_DIsp_Set_Pos(int x, int y);
void OLED_DIsp_Char(int x, int y, unsigned char c);
void OLED_DIsp_String(int x, int y, char *str);
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no);
void OLED_DIsp_Test();
#endif

View File

@@ -0,0 +1,22 @@
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o spi_oled spi_oled.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order spi_oled
obj-m += oled_drv.o

View File

@@ -0,0 +1,106 @@
#ifndef _FONT_H_
#define _FONT_H_
const unsigned char oled_asc2_8x16[95][16]=
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// 0
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00},//!1
{0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//"2
{0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00},//#3
{0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00},//$4
{0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00},//%5
{0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10},//&6
{0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//'7
{0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00},//(8
{0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00},//)9
{0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00},//*10
{0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00},//+11
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00},//,12
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01},//-13
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00},//.14
{0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00},///15
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},//016
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//117
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},//218
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},//319
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},//420
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},//521
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},//622
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},//723
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},//824
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00},//925
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},//:26
{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00},//;27
{0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00},//<28
{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00},//=29
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00},//>30
{0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00},//?31
{0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00},//@32
{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20},//A33
{0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00},//B34
{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},//C35
{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},//D36
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00},//E37
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00},//F38
{0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00},//G39
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},//H40
{0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//I41
{0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00},//J42
{0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00},//K43
{0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00},//L44
{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00},//M45
{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},//N46
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00},//O47
{0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00},//P48
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00},//Q49
{0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20},//R50
{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},//S51
{0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//T52
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//U53
{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},//V54
{0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00},//W55
{0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20},//X56
{0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//Y57
{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},//Z58
{0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00},//[59
{0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00},//\60
{0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00},//]61
{0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//^62
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},//_63
{0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//`64
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20},//a65
{0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00},//b66
{0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00},//c67
{0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20},//d68
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00},//e69
{0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//f70
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00},//g71
{0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//h72
{0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//i73
{0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00},//j74
{0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00},//k75
{0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//l76
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},//m77
{0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//n78
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//o79
{0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00},//p80
{0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80},//q81
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00},//r82
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00},//s83
{0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00},//t84
{0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},//u85
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00},//v86
{0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00},//w87
{0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00},//x88
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00},//y89
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00},//z90
{0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40},//{91
{0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},//|92
{0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00},//}93
{0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//~94
};
const unsigned char hz_1616[][32]={
{0x02,0x00,0x02,0x00,0xE2,0xFF,0x22,0x42,0x22,0x42,0x32,0x42,0x2A,0x42,0x26,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0xE2,0xFF,0x02,0x00,0x02,0x00,0x00,0x00},/*"百",0*/
{0x00,0x00,0xF8,0xFF,0x01,0x00,0x02,0x00,0x00,0x00,0xE2,0x1F,0x22,0x08,0x22,0x08,0x22,0x08,0xE2,0x1F,0x02,0x00,0x02,0x40,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"问",1*/
{0x00,0x00,0xFE,0xFF,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x0E,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x4E,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"网",2*/
};
#endif

View File

@@ -0,0 +1,299 @@
/*
* Simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>
* Copyright (C) 2007 David Brownell (simplification, cleanup)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>
#include <linux/gpio/consumer.h>
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//<2F><>? 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
/*-------------------------------------------------------------------------*/
static struct spi_device *oled;
static int major;
static struct gpio_desc *dc_gpio;
static void dc_pin_init(void)
{
gpiod_direction_output(dc_gpio, 1);
}
static void oled_set_dc_pin(int val)
{
gpiod_set_value(dc_gpio, val);
}
static void spi_write_datas(const unsigned char *buf, int len)
{
spi_write(oled, buf, len);
}
/**********************************************************************
* 函数名称<E5908D><E7A7B0>?oled_write_cmd
* 功能描述<E68F8F><E8BFB0>?oled向特定地址写入数据或者命<E88085><E591BD>? * 输入参数:@uc_data :要写入的数据
@uc_cmd:<3A><>?则表示写入数据<E68DAE><EFBC8C>?表示写入命令
* 输出参数:无
* <20><>?<3F><>?值: <20><>? * 修改日期 版本<E78988><E69CAC>? 修改<E4BFAE><E694B9>? 修改内容
* -----------------------------------------------
* 2020/03/04 V1.0 芯晓 创建
***********************************************************************/
static void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)
{
if(uc_cmd==0)
{
oled_set_dc_pin(0);
}
else
{
oled_set_dc_pin(1);//拉高表示写入数<E585A5><E695B0>? }
spi_write_datas(&uc_data, 1);//写入
}
/**********************************************************************
* 函数名称<E5908D><E7A7B0>?oled_init
* 功能描述<E68F8F><E8BFB0>?oled_init的初始化包括SPI控制器得初始<E5889D><E5A78B>? * 输入参数:无
* 输出参数<E58F82><E695B0>?初始化的结果
* <20><>?<3F><>?值: 成功则返<E58899><E8BF94>?否则返<E58899><E8BF94>?1
* 修改日期 版本<E78988><E69CAC>? 修改<E4BFAE><E694B9>? 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static int oled_init(void)
{
oled_write_cmd_data(0xae,OLED_CMD);//关闭显示
oled_write_cmd_data(0x00,OLED_CMD);//设置 lower column address
oled_write_cmd_data(0x10,OLED_CMD);//设置 higher column address
oled_write_cmd_data(0x40,OLED_CMD);//设置 display start line
oled_write_cmd_data(0xB0,OLED_CMD);//设置page address
oled_write_cmd_data(0x81,OLED_CMD);// contract control
oled_write_cmd_data(0x66,OLED_CMD);//128
oled_write_cmd_data(0xa1,OLED_CMD);//设置 segment remap
oled_write_cmd_data(0xa6,OLED_CMD);//normal /reverse
oled_write_cmd_data(0xa8,OLED_CMD);//multiple ratio
oled_write_cmd_data(0x3f,OLED_CMD);//duty = 1/64
oled_write_cmd_data(0xc8,OLED_CMD);//com scan direction
oled_write_cmd_data(0xd3,OLED_CMD);//set displat offset
oled_write_cmd_data(0x00,OLED_CMD);//
oled_write_cmd_data(0xd5,OLED_CMD);//set osc division
oled_write_cmd_data(0x80,OLED_CMD);//
oled_write_cmd_data(0xd9,OLED_CMD);//ser pre-charge period
oled_write_cmd_data(0x1f,OLED_CMD);//
oled_write_cmd_data(0xda,OLED_CMD);//set com pins
oled_write_cmd_data(0x12,OLED_CMD);//
oled_write_cmd_data(0xdb,OLED_CMD);//set vcomh
oled_write_cmd_data(0x30,OLED_CMD);//
oled_write_cmd_data(0x8d,OLED_CMD);//set charge pump disable
oled_write_cmd_data(0x14,OLED_CMD);//
oled_write_cmd_data(0xaf,OLED_CMD);//set dispkay on
return 0;
}
//坐标设置
/**********************************************************************
* 函数名称<E5908D><E7A7B0>?OLED_DIsp_Set_Pos
* 功能描述设置要显示的位<E79A84><E4BD8D>? * 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数<E58F82><E695B0>?<3F><>? * <20><>?<3F><>?值:
* 修改日期 版本<E78988><E69CAC>? 修改<E4BFAE><E694B9>? 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static void OLED_DIsp_Set_Pos(int x, int y)
{ oled_write_cmd_data(0xb0+y,OLED_CMD);
oled_write_cmd_data((x&0x0f),OLED_CMD);
oled_write_cmd_data(((x&0xf0)>>4)|0x10,OLED_CMD);
}
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int x, y;
/* 根据cmd操作硬件 */
switch (cmd)
{
case OLED_IOC_INIT: /* init */
{
dc_pin_init();
oled_init();
break;
}
case OLED_IOC_SET_POS: /* set pos */
{
x = arg & 0xff;
y = (arg >> 8) & 0xff;
OLED_DIsp_Set_Pos(x, y);
break;
}
}
return 0;
}
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
char *ker_buf;
int err;
ker_buf = kmalloc(count, GFP_KERNEL);
err = copy_from_user(ker_buf, buf, count);
oled_set_dc_pin(1);//拉高表示写入数<E585A5><E695B0>? spi_write_datas(ker_buf, count);
kfree(ker_buf);
return count;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage. It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.unlocked_ioctl = spidev_ioctl,
};
/*-------------------------------------------------------------------------*/
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "100ask,oled" },
{},
};
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
/* 1. 记录spi_device */
oled = spi;
/* 2. 注册字符设备 */
major = register_chrdev(0, "100ask_oled", &spidev_fops);
spidev_class = class_create(THIS_MODULE, "100ask_oled");
device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_oled");
/* 3. 获得GPIO引脚 */
dc_gpio = gpiod_get(&spi->dev, "dc", 0);
return 0;
}
static int spidev_remove(struct spi_device *spi)
{
gpiod_put(dc_gpio);
/* 反注册字符设<E7ACA6><E8AEBE>?*/
device_destroy(spidev_class, MKDEV(major, 0));
class_destroy(spidev_class);
unregister_chrdev(major, "100ask_oled");
return 0;
}
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "100ask_spi_oled_drv",
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller. The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
int status;
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,241 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "font.h"
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;
void OLED_DIsp_Set_Pos(int x, int y);
void oled_write_datas(const unsigned char *buf, int len)
{
write(fd_spidev, buf, len);
}
/**********************************************************************
* 函数名称: OLED_DIsp_Clear
* 功能描述: 整个屏幕显示数据清0
* 输入参数:无
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Clear(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_All
* 功能描述: 整个屏幕显示全部点亮,可以用于检查坏点
* 输入参数:无
* 输出参数:无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_All(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0xff, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Set_Pos(int x, int y)
{
ioctl(fd_spidev, OLED_IOC_SET_POS, x | (y << 8));
}
/**********************************************************************
* 函数名称: OLED_DIsp_Char
* 功能描述:在某个位置显示字符 1-9
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@c 要显示的字符的ascii码
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Char(int x, int y, unsigned char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLED_DIsp_Set_Pos(x, y);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
// oled_write_cmd_data(dots[i], OLED_DATA);
oled_write_datas(&dots[0], 8);
OLED_DIsp_Set_Pos(x, y+1);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
//oled_write_cmd_data(dots[i+8], OLED_DATA);
oled_write_datas(&dots[8], 8);
}
/**********************************************************************
* 函数名称: OLED_DIsp_String
* 功能描述: 在指定位置显示字符串
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@str :要显示的字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_String(int x, int y, char *str)
{
unsigned char j=0;
while (str[j])
{
OLED_DIsp_Char(x, y, str[j]);//显示单个字符
x += 8;
if(x > 127)
{
x = 0;
y += 2;
}//移动显示位置
j++;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_CHinese
* 功能描述:在指定位置显示汉字
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@chr :要显示的汉字,三个汉字“百问网”中选择一个
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no)
{
unsigned char t,adder=0;
OLED_DIsp_Set_Pos(x,y);
for(t=0;t<16;t++)
{//显示上半截字符
oled_write_datas(&hz_1616[no][t*2], 1);
adder+=1;
}
OLED_DIsp_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{//显示下半截字符
oled_write_datas(&hz_1616[no][t*2+1], 1);
adder+=1;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_Test
* 功能描述: 整个屏幕显示测试
* 输入参数:无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Test(void)
{
int i;
OLED_DIsp_String(0, 0, "wiki.100ask.net");
OLED_DIsp_String(0, 2, "book.100ask.net");
OLED_DIsp_String(0, 4, "bbs.100ask.net");
for(i = 0; i < 3; i++)
{ //显示汉字 百问网
OLED_DIsp_CHinese(32+i*16, 6, i);
}
}
/* spi_oled /dev/100ask_oled */
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s /dev/100ask_oled\n", argv[0]);
return -1;
}
fd_spidev = open(argv[1], O_RDWR);
if (fd_spidev < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
ioctl(fd_spidev, OLED_IOC_INIT);
OLED_DIsp_Clear();
OLED_DIsp_Test();
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifndef _OLED_H_
#define _OLED_H_
void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd);
int oled_init(void);
int oled_fill_data(unsigned char fill_Data);
void OLED_DIsp_Clear(void);
void OLED_DIsp_All(void);
void OLED_DIsp_Set_Pos(int x, int y);
void OLED_DIsp_Char(int x, int y, unsigned char c);
void OLED_DIsp_String(int x, int y, char *str);
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no);
void OLED_DIsp_Test();
#endif

View File

@@ -558,6 +558,14 @@ git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
13_编写DAC驱动_上机实验_STM32MP157
```
* 2021.04.29 发布"SPI子系统"
```shell
14_编写SPI_OLED模块驱动程序
15_编写OLED驱动_上机实验_IMX6ULL
15_编写OLED驱动_上机实验_STM32MP157
```

View File

@@ -0,0 +1,21 @@
# 1. 使用不同的开发板内核<E58685><E6A0B8>? 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编<E38081><E7BC96>? 为了能编译内<E8AF91><E58685>? 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相<E5AE9A><E79BB8>?
# 请参考各开发板的高级用户使用手<E794A8><E6898B>?
KERN_DIR = /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o spi_oled spi_oled.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order spi_oled
obj-m += oled_drv.o

View File

@@ -0,0 +1,106 @@
#ifndef _FONT_H_
#define _FONT_H_
const unsigned char oled_asc2_8x16[95][16]=
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// 0
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00},//!1
{0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//"2
{0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00},//#3
{0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00},//$4
{0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00},//%5
{0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10},//&6
{0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//'7
{0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00},//(8
{0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00},//)9
{0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00},//*10
{0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00},//+11
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00},//,12
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01},//-13
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00},//.14
{0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00},///15
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},//016
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//117
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},//218
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},//319
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},//420
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},//521
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},//622
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},//723
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},//824
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00},//925
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},//:26
{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00},//;27
{0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00},//<28
{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00},//=29
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00},//>30
{0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00},//?31
{0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00},//@32
{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20},//A33
{0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00},//B34
{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},//C35
{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},//D36
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00},//E37
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00},//F38
{0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00},//G39
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},//H40
{0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//I41
{0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00},//J42
{0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00},//K43
{0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00},//L44
{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00},//M45
{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},//N46
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00},//O47
{0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00},//P48
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00},//Q49
{0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20},//R50
{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},//S51
{0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//T52
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//U53
{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},//V54
{0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00},//W55
{0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20},//X56
{0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//Y57
{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},//Z58
{0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00},//[59
{0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00},//\60
{0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00},//]61
{0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//^62
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},//_63
{0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//`64
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20},//a65
{0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00},//b66
{0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00},//c67
{0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20},//d68
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00},//e69
{0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//f70
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00},//g71
{0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//h72
{0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//i73
{0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00},//j74
{0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00},//k75
{0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//l76
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},//m77
{0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//n78
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//o79
{0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00},//p80
{0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80},//q81
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00},//r82
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00},//s83
{0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00},//t84
{0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},//u85
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00},//v86
{0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00},//w87
{0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00},//x88
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00},//y89
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00},//z90
{0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40},//{91
{0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},//|92
{0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00},//}93
{0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//~94
};
const unsigned char hz_1616[][32]={
{0x02,0x00,0x02,0x00,0xE2,0xFF,0x22,0x42,0x22,0x42,0x32,0x42,0x2A,0x42,0x26,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0xE2,0xFF,0x02,0x00,0x02,0x00,0x00,0x00},/*"百",0*/
{0x00,0x00,0xF8,0xFF,0x01,0x00,0x02,0x00,0x00,0x00,0xE2,0x1F,0x22,0x08,0x22,0x08,0x22,0x08,0xE2,0x1F,0x02,0x00,0x02,0x40,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"问",1*/
{0x00,0x00,0xFE,0xFF,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x0E,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x4E,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"网",2*/
};
#endif

View File

@@ -0,0 +1,300 @@
/*
* Simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>
* Copyright (C) 2007 David Brownell (simplification, cleanup)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
/*-------------------------------------------------------------------------*/
static struct spi_device *oled;
static int major;
static gpio_desc *dc_gpio;
static void dc_pin_init(void)
{
gpiod_direction_output(dc_gpio, 1);
}
static void oled_set_dc_pin(int val)
{
gpiod_set_value(dc_gpio, val);
}
static void spi_write_datas(const unsigned char *buf, int len)
{
spi_write(oled, buf, len);
}
/**********************************************************************
* 函数名称: oled_write_cmd
* 功能描述: oled向特定地址写入数据或者命令
* 输入参数:@uc_data :要写入的数据
@uc_cmd:为1则表示写入数据为0表示写入命令
* 输出参数:无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/04 V1.0 芯晓 创建
***********************************************************************/
static void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)
{
unsigned char uc_read=0;
if(uc_cmd==0)
{
oled_set_dc_pin(0);
}
else
{
oled_set_dc_pin(1);//拉高,表示写入数据
}
spi_write_datas(&uc_data, 1);//写入
}
/**********************************************************************
* 函数名称: oled_init
* 功能描述: oled_init的初始化包括SPI控制器得初始化
* 输入参数:无
* 输出参数: 初始化的结果
* 返 回 值: 成功则返回0否则返回-1
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static int oled_init(void)
{
unsigned char uc_dev_id = 0;
oled_write_cmd_data(0xae,OLED_CMD);//关闭显示
oled_write_cmd_data(0x00,OLED_CMD);//设置 lower column address
oled_write_cmd_data(0x10,OLED_CMD);//设置 higher column address
oled_write_cmd_data(0x40,OLED_CMD);//设置 display start line
oled_write_cmd_data(0xB0,OLED_CMD);//设置page address
oled_write_cmd_data(0x81,OLED_CMD);// contract control
oled_write_cmd_data(0x66,OLED_CMD);//128
oled_write_cmd_data(0xa1,OLED_CMD);//设置 segment remap
oled_write_cmd_data(0xa6,OLED_CMD);//normal /reverse
oled_write_cmd_data(0xa8,OLED_CMD);//multiple ratio
oled_write_cmd_data(0x3f,OLED_CMD);//duty = 1/64
oled_write_cmd_data(0xc8,OLED_CMD);//com scan direction
oled_write_cmd_data(0xd3,OLED_CMD);//set displat offset
oled_write_cmd_data(0x00,OLED_CMD);//
oled_write_cmd_data(0xd5,OLED_CMD);//set osc division
oled_write_cmd_data(0x80,OLED_CMD);//
oled_write_cmd_data(0xd9,OLED_CMD);//ser pre-charge period
oled_write_cmd_data(0x1f,OLED_CMD);//
oled_write_cmd_data(0xda,OLED_CMD);//set com pins
oled_write_cmd_data(0x12,OLED_CMD);//
oled_write_cmd_data(0xdb,OLED_CMD);//set vcomh
oled_write_cmd_data(0x30,OLED_CMD);//
oled_write_cmd_data(0x8d,OLED_CMD);//set charge pump disable
oled_write_cmd_data(0x14,OLED_CMD);//
oled_write_cmd_data(0xaf,OLED_CMD);//set dispkay on
return 0;
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static void OLED_DIsp_Set_Pos(int x, int y)
{ oled_write_cmd_data(0xb0+y,OLED_CMD);
oled_write_cmd_data((x&0x0f),OLED_CMD);
oled_write_cmd_data(((x&0xf0)>>4)|0x10,OLED_CMD);
}
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int x, y;
/* 根据cmd操作硬件 */
switch (cmd)
{
case OLED_IOC_INIT: /* init */
{
dc_pin_init();
oled_init();
break;
}
case OLED_IOC_SET_POS: /* set pos */
{
x = arg & 0xff;
y = (arg >> 8) & 0xff;
OLED_DIsp_Set_Pos(x, y);
break;
}
}
return 0;
}
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
char *ker_buf;
int err;
ker_buf = kmalloc(count, GFP_KERNEL);
err = copy_from_user(ker_buf, buf, count);
oled_set_dc_pin(1);//拉高,表示写入数据
spi_write_datas(ker_buf, count);
return count;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage. It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.unlocked_ioctl = spidev_ioctl,
};
/*-------------------------------------------------------------------------*/
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "100ask,oled" },
{},
};
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
/* 1. 记录spi_device */
oled = spi;
/* 2. 注册字符设备 */
major = register_chrdev(0, "100ask_oled", &spidev_fops);
spidev_class = class_create(THIS_MODULE, "100ask_oled");
device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_oled");
/* 3. 获得GPIO引脚 */
dc_gpio = gpiod_get(&spi->dev, "dc", 0);
return 0;
}
static int spidev_remove(struct spi_device *spi)
{
gpiod_put(dc_gpio);
/* 反注册字符设备 */
device_destroy(spidev_class, MKDEV(major, 0));
class_destroy(spidev_class);
unregister_chrdev(major, "100ask_oled");
return 0;
}
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "100ask_spi_oled_drv",
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller. The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
int status;
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,239 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "font.h"
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;
void oled_write_datas(const unsigned char *buf, int len)
{
write(fd_spidev, buf, len);
}
/**********************************************************************
* 函数名称: OLED_DIsp_Clear
* 功能描述: 整个屏幕显示数据清0
* 输入参数:无
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Clear(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_All
* 功能描述: 整个屏幕显示全部点亮,可以用于检查坏点
* 输入参数:无
* 输出参数:无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_All(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0xff, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Set_Pos(int x, int y)
{
ioctl(fd_spidev, OLED_IOC_SET_POS, x | (y << 8));
}
/**********************************************************************
* 函数名称: OLED_DIsp_Char
* 功能描述:在某个位置显示字符 1-9
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@c 要显示的字符的ascii码
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Char(int x, int y, unsigned char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLED_DIsp_Set_Pos(x, y);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
// oled_write_cmd_data(dots[i], OLED_DATA);
oled_write_datas(&dots[0], 8);
OLED_DIsp_Set_Pos(x, y+1);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
//oled_write_cmd_data(dots[i+8], OLED_DATA);
oled_write_datas(&dots[8], 8);
}
/**********************************************************************
* 函数名称: OLED_DIsp_String
* 功能描述: 在指定位置显示字符串
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@str :要显示的字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_String(int x, int y, char *str)
{
unsigned char j=0;
while (str[j])
{
OLED_DIsp_Char(x, y, str[j]);//显示单个字符
x += 8;
if(x > 127)
{
x = 0;
y += 2;
}//移动显示位置
j++;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_CHinese
* 功能描述:在指定位置显示汉字
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@chr :要显示的汉字,三个汉字“百问网”中选择一个
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no)
{
unsigned char t,adder=0;
OLED_DIsp_Set_Pos(x,y);
for(t=0;t<16;t++)
{//显示上半截字符
oled_write_datas(&hz_1616[no][t*2], 1);
adder+=1;
}
OLED_DIsp_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{//显示下半截字符
oled_write_datas(&hz_1616[no][t*2+1], 1);
adder+=1;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_Test
* 功能描述: 整个屏幕显示测试
* 输入参数:无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Test(void)
{
int i;
OLED_DIsp_String(0, 0, "wiki.100ask.net");
OLED_DIsp_String(0, 2, "book.100ask.net");
OLED_DIsp_String(0, 4, "bbs.100ask.net");
for(i = 0; i < 3; i++)
{ //显示汉字 百问网
OLED_DIsp_CHinese(32+i*16, 6, i);
}
}
/* spi_oled /dev/100ask_oled */
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s /dev/100ask_oled\n", argv[0]);
return -1;
}
fd_spidev = open(argv[1], O_RDWR);
if (fd_spidev < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
ioctl(fd_spidev, OLED_IOC_INIT);
OLED_DIsp_Clear();
OLED_DIsp_Test();
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifndef _OLED_H_
#define _OLED_H_
void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd);
int oled_init(void);
int oled_fill_data(unsigned char fill_Data);
void OLED_DIsp_Clear(void);
void OLED_DIsp_All(void);
void OLED_DIsp_Set_Pos(int x, int y);
void OLED_DIsp_Char(int x, int y, unsigned char c);
void OLED_DIsp_String(int x, int y, char *str);
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no);
void OLED_DIsp_Test();
#endif

View File

@@ -0,0 +1,22 @@
# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH, 比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
# 请参考各开发板的高级用户使用手册
KERN_DIR = /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o spi_oled spi_oled.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order spi_oled
obj-m += oled_drv.o

View File

@@ -0,0 +1,106 @@
#ifndef _FONT_H_
#define _FONT_H_
const unsigned char oled_asc2_8x16[95][16]=
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// 0
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00},//!1
{0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//"2
{0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00},//#3
{0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00},//$4
{0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00},//%5
{0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10},//&6
{0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//'7
{0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00},//(8
{0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00},//)9
{0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00},//*10
{0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00},//+11
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00},//,12
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01},//-13
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00},//.14
{0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00},///15
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},//016
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//117
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},//218
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},//319
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},//420
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},//521
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},//622
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},//723
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},//824
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00},//925
{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00},//:26
{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00},//;27
{0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00},//<28
{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00},//=29
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00},//>30
{0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00},//?31
{0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00},//@32
{0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20},//A33
{0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00},//B34
{0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00},//C35
{0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00},//D36
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00},//E37
{0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00},//F38
{0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00},//G39
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20},//H40
{0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//I41
{0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00},//J42
{0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00},//K43
{0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00},//L44
{0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00},//M45
{0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00},//N46
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00},//O47
{0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00},//P48
{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00},//Q49
{0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20},//R50
{0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00},//S51
{0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//T52
{0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//U53
{0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00},//V54
{0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00},//W55
{0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20},//X56
{0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00},//Y57
{0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00},//Z58
{0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00},//[59
{0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00},//\60
{0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00},//]61
{0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//^62
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},//_63
{0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//`64
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20},//a65
{0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00},//b66
{0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00},//c67
{0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20},//d68
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00},//e69
{0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//f70
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00},//g71
{0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//h72
{0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//i73
{0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00},//j74
{0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00},//k75
{0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},//l76
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F},//m77
{0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20},//n78
{0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00},//o79
{0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00},//p80
{0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80},//q81
{0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00},//r82
{0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00},//s83
{0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00},//t84
{0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20},//u85
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00},//v86
{0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00},//w87
{0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00},//x88
{0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00},//y89
{0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00},//z90
{0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40},//{91
{0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00},//|92
{0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00},//}93
{0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},//~94
};
const unsigned char hz_1616[][32]={
{0x02,0x00,0x02,0x00,0xE2,0xFF,0x22,0x42,0x22,0x42,0x32,0x42,0x2A,0x42,0x26,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0x22,0x42,0xE2,0xFF,0x02,0x00,0x02,0x00,0x00,0x00},/*"百",0*/
{0x00,0x00,0xF8,0xFF,0x01,0x00,0x02,0x00,0x00,0x00,0xE2,0x1F,0x22,0x08,0x22,0x08,0x22,0x08,0xE2,0x1F,0x02,0x00,0x02,0x40,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"问",1*/
{0x00,0x00,0xFE,0xFF,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x0E,0x02,0x10,0x22,0x08,0x42,0x06,0x82,0x01,0x72,0x4E,0x02,0x80,0xFE,0x7F,0x00,0x00,0x00,0x00},/*"网",2*/
};
#endif

View File

@@ -0,0 +1,306 @@
/*
* Simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>
* Copyright (C) 2007 David Brownell (simplification, cleanup)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>
#include <linux/gpio/consumer.h>
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
/*-------------------------------------------------------------------------*/
static struct spi_device *oled;
static int major;
static struct gpio_desc *dc_gpio;
static void dc_pin_init(void)
{
gpiod_direction_output(dc_gpio, 1);
}
static void oled_set_dc_pin(int val)
{
gpiod_set_value(dc_gpio, val);
}
static void spi_write_datas(const unsigned char *buf, int len)
{
spi_write(oled, buf, len);
}
/**********************************************************************
* 函数名称: oled_write_cmd
* 功能描述: oled向特定地址写入数据或者命令
* 输入参数:@uc_data :要写入的数据
@uc_cmd:为1则表示写入数据为0表示写入命令
* 输出参数:无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/04 V1.0 芯晓 创建
***********************************************************************/
static void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)
{
if(uc_cmd==0)
{
oled_set_dc_pin(0);
}
else
{
oled_set_dc_pin(1);//拉高,表示写入数据
}
spi_write_datas(&uc_data, 1);//写入
}
/**********************************************************************
* 函数名称: oled_init
* 功能描述: oled_init的初始化包括SPI控制器得初始化
* 输入参数:无
* 输出参数: 初始化的结果
* 返 回 值: 成功则返回0否则返回-1
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static int oled_init(void)
{
oled_write_cmd_data(0xae,OLED_CMD);//关闭显示
oled_write_cmd_data(0x00,OLED_CMD);//设置 lower column address
oled_write_cmd_data(0x10,OLED_CMD);//设置 higher column address
oled_write_cmd_data(0x40,OLED_CMD);//设置 display start line
oled_write_cmd_data(0xB0,OLED_CMD);//设置page address
oled_write_cmd_data(0x81,OLED_CMD);// contract control
oled_write_cmd_data(0x66,OLED_CMD);//128
oled_write_cmd_data(0xa1,OLED_CMD);//设置 segment remap
oled_write_cmd_data(0xa6,OLED_CMD);//normal /reverse
oled_write_cmd_data(0xa8,OLED_CMD);//multiple ratio
oled_write_cmd_data(0x3f,OLED_CMD);//duty = 1/64
oled_write_cmd_data(0xc8,OLED_CMD);//com scan direction
oled_write_cmd_data(0xd3,OLED_CMD);//set displat offset
oled_write_cmd_data(0x00,OLED_CMD);//
oled_write_cmd_data(0xd5,OLED_CMD);//set osc division
oled_write_cmd_data(0x80,OLED_CMD);//
oled_write_cmd_data(0xd9,OLED_CMD);//ser pre-charge period
oled_write_cmd_data(0x1f,OLED_CMD);//
oled_write_cmd_data(0xda,OLED_CMD);//set com pins
oled_write_cmd_data(0x12,OLED_CMD);//
oled_write_cmd_data(0xdb,OLED_CMD);//set vcomh
oled_write_cmd_data(0x30,OLED_CMD);//
oled_write_cmd_data(0x8d,OLED_CMD);//set charge pump disable
oled_write_cmd_data(0x14,OLED_CMD);//
oled_write_cmd_data(0xaf,OLED_CMD);//set dispkay on
return 0;
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static void OLED_DIsp_Set_Pos(int x, int y)
{ oled_write_cmd_data(0xb0+y,OLED_CMD);
oled_write_cmd_data((x&0x0f),OLED_CMD);
oled_write_cmd_data(((x&0xf0)>>4)|0x10,OLED_CMD);
}
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int x, y;
/* 根据cmd操作硬件 */
switch (cmd)
{
case OLED_IOC_INIT: /* init */
{
dc_pin_init();
oled_init();
break;
}
case OLED_IOC_SET_POS: /* set pos */
{
x = arg & 0xff;
y = (arg >> 8) & 0xff;
OLED_DIsp_Set_Pos(x, y);
break;
}
}
return 0;
}
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
char *ker_buf;
int err;
ker_buf = kmalloc(count, GFP_KERNEL);
err = copy_from_user(ker_buf, buf, count);
oled_set_dc_pin(1);//拉高,表示写入数据
spi_write_datas(ker_buf, count);
kfree(ker_buf);
return count;
}
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, so that userspace
* gets more complete API coverage. It'll simplify things
* too, except for the locking.
*/
.write = spidev_write,
.unlocked_ioctl = spidev_ioctl,
};
/*-------------------------------------------------------------------------*/
/* The main reason to have this class is to make mdev/udev create the
* /dev/spidevB.C character device nodes exposing our userspace API.
* It also simplifies memory management.
*/
static struct class *spidev_class;
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "100ask,oled" },
{},
};
/*-------------------------------------------------------------------------*/
static int spidev_probe(struct spi_device *spi)
{
/* 1. 记录spi_device */
oled = spi;
/* 2. 注册字符设备 */
major = register_chrdev(0, "100ask_oled", &spidev_fops);
spidev_class = class_create(THIS_MODULE, "100ask_oled");
device_create(spidev_class, NULL, MKDEV(major, 0), NULL, "100ask_oled");
/* 3. 获得GPIO引脚 */
dc_gpio = gpiod_get(&spi->dev, "dc", 0);
return 0;
}
static int spidev_remove(struct spi_device *spi)
{
gpiod_put(dc_gpio);
/* 反注册字符设备 */
device_destroy(spidev_class, MKDEV(major, 0));
class_destroy(spidev_class);
unregister_chrdev(major, "100ask_oled");
return 0;
}
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "100ask_spi_oled_drv",
.of_match_table = of_match_ptr(spidev_dt_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
/* NOTE: suspend/resume methods are not necessary here.
* We don't do anything except pass the requests to/from
* the underlying controller. The refrigerator handles
* most issues; the controller driver handles the rest.
*/
};
/*-------------------------------------------------------------------------*/
static int __init spidev_init(void)
{
int status;
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
}
return status;
}
module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
}
module_exit(spidev_exit);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,241 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "font.h"
#define OLED_IOC_INIT 123
#define OLED_IOC_SET_POS 124
//为0 表示命令为1表示数据
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;
void OLED_DIsp_Set_Pos(int x, int y);
void oled_write_datas(const unsigned char *buf, int len)
{
write(fd_spidev, buf, len);
}
/**********************************************************************
* 函数名称: OLED_DIsp_Clear
* 功能描述: 整个屏幕显示数据清0
* 输入参数:无
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Clear(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_All
* 功能描述: 整个屏幕显示全部点亮,可以用于检查坏点
* 输入参数:无
* 输出参数:无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_All(void)
{
unsigned char x, y;
char buf[128];
memset(buf, 0xff, 128);
for (y = 0; y < 8; y++)
{
OLED_DIsp_Set_Pos(0, y);
oled_write_datas(buf, 128);
}
}
//坐标设置
/**********************************************************************
* 函数名称: OLED_DIsp_Set_Pos
* 功能描述:设置要显示的位置
* 输入参数:@ x 要显示的column address
@y :要显示的page address
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Set_Pos(int x, int y)
{
ioctl(fd_spidev, OLED_IOC_SET_POS, x | (y << 8));
}
/**********************************************************************
* 函数名称: OLED_DIsp_Char
* 功能描述:在某个位置显示字符 1-9
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@c 要显示的字符的ascii码
* 输出参数: 无
* 返 回 值:
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Char(int x, int y, unsigned char c)
{
int i = 0;
/* 得到字模 */
const unsigned char *dots = oled_asc2_8x16[c - ' '];
/* 发给OLED */
OLED_DIsp_Set_Pos(x, y);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
// oled_write_cmd_data(dots[i], OLED_DATA);
oled_write_datas(&dots[0], 8);
OLED_DIsp_Set_Pos(x, y+1);
/* 发出8字节数据 */
//for (i = 0; i < 8; i++)
//oled_write_cmd_data(dots[i+8], OLED_DATA);
oled_write_datas(&dots[8], 8);
}
/**********************************************************************
* 函数名称: OLED_DIsp_String
* 功能描述: 在指定位置显示字符串
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@str :要显示的字符串
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_String(int x, int y, char *str)
{
unsigned char j=0;
while (str[j])
{
OLED_DIsp_Char(x, y, str[j]);//显示单个字符
x += 8;
if(x > 127)
{
x = 0;
y += 2;
}//移动显示位置
j++;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_CHinese
* 功能描述:在指定位置显示汉字
* 输入参数:@ x 要显示的column address
@y :要显示的page address
@chr :要显示的汉字,三个汉字“百问网”中选择一个
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no)
{
unsigned char t,adder=0;
OLED_DIsp_Set_Pos(x,y);
for(t=0;t<16;t++)
{//显示上半截字符
oled_write_datas(&hz_1616[no][t*2], 1);
adder+=1;
}
OLED_DIsp_Set_Pos(x,y+1);
for(t=0;t<16;t++)
{//显示下半截字符
oled_write_datas(&hz_1616[no][t*2+1], 1);
adder+=1;
}
}
/**********************************************************************
* 函数名称: OLED_DIsp_Test
* 功能描述: 整个屏幕显示测试
* 输入参数:无
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
void OLED_DIsp_Test(void)
{
int i;
OLED_DIsp_String(0, 0, "wiki.100ask.net");
OLED_DIsp_String(0, 2, "book.100ask.net");
OLED_DIsp_String(0, 4, "bbs.100ask.net");
for(i = 0; i < 3; i++)
{ //显示汉字 百问网
OLED_DIsp_CHinese(32+i*16, 6, i);
}
}
/* spi_oled /dev/100ask_oled */
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s /dev/100ask_oled\n", argv[0]);
return -1;
}
fd_spidev = open(argv[1], O_RDWR);
if (fd_spidev < 0) {
printf("open %s err\n", argv[1]);
return -1;
}
ioctl(fd_spidev, OLED_IOC_INIT);
OLED_DIsp_Clear();
OLED_DIsp_Test();
return 0;
}

View File

@@ -0,0 +1,17 @@
#ifndef _OLED_H_
#define _OLED_H_
void oled_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd);
int oled_init(void);
int oled_fill_data(unsigned char fill_Data);
void OLED_DIsp_Clear(void);
void OLED_DIsp_All(void);
void OLED_DIsp_Set_Pos(int x, int y);
void OLED_DIsp_Char(int x, int y, unsigned char c);
void OLED_DIsp_String(int x, int y, char *str);
void OLED_DIsp_CHinese(unsigned char x,unsigned char y,unsigned char no);
void OLED_DIsp_Test();
#endif