RTT & Renesas high performance CPK-RA6M4 development board review - SPI driven OLED
[Copy link]
1. Hardware
1. OLED pin introduction
OLED pin, is 7-pin SPI mode.
1). GND power ground
2). VCC power supply positive (3~5.5V)
3). D0 OLED's D0 pin is the clock pin in SPI and IIC communication
4). D1 OLED's D1 pin is the data pin in SPI and IIC communication
5). RES OLED's RES# pin is used for reset (low level reset)
6). DC OLED's D/C#E pin, data and command control pin
As shown in the figure: actual pins.
The display principle of OLED will not be introduced here.
2. Wiring
1) VCC is connected to the 3.3V pin on the board and is grounded with the board.
2) Use DuPont wires to connect the corresponding clock SCLK and data MOSI of SPI0 with the clock and data pins of OLED, and then use other pins as common pins to control the chip select CS, reset RES, and DC pins of OLED.
2. Software Operation
1. RA Smart Configurator Operation
1) Use Renesas flexible configuration software to add the clock and MOSI pins related to the multiplexed pins of SPI0. Note that the chip select is configured by software in the program, so the SPI0 hardware chip select pin CS is configured as a normal pin (P703). At the same time, set P406 (corresponding to DC of OLED) and P405 (corresponding to RES of OLED) as normal output pins.
2) Set the three common pin modes to output mode and set them to initialize to high level
3) Add SPI configuration and set the callback function of SPI0 to spi0_callback. Other settings are default. You can set the SPI working mode, rate, phase, polarity, etc. in the corresponding parameter settings. You can also modify the corresponding configuration directly in RTThread.
2. RTThread-Studio Operation
1) Add SPI driver supported by RTThread for RA6M4.
2) Enable SPI0 driver.
3. Code
1) OLED driver code
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-05-01 LD the first version
*/
#include "OLED.h"
#include "oledfont.h"
#include <rtthread.h>
#include <stdio.h>
#include <drv_spi.h>
//static struct rt_spi_device spi_dev_lcd;
/*OLED段码分布
正常
(page0) SEG0-SEG128
COM0
|
COM7
反置
(page0) SEG128-SEG0
COM63
|
COM56
写命令,其实是写寄存器
*/
static struct rt_spi_device spi_dev_oled;
static int rt_hw_oled_config(void)
{
char user_data[] = {1};
if (rt_spi_bus_attach_device(&spi_dev_oled, "oled", "spi0", user_data) != RT_EOK)
return -RT_ERROR;
/* config spi */
{
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
cfg.max_hz = 5 * 1000 * 1000; /* 42M,SPI max 42MHz,lcd 4-wire spi */
rt_spi_configure(&spi_dev_oled, &cfg);
}
rt_pin_mode(OLED_DC, PIN_MODE_OUTPUT);
rt_pin_mode(OLED_RES, PIN_MODE_OUTPUT);
return RT_EOK;
}
/****************************************************************************
* 名 称:void OLED_Init(void)
* 功 能:OLED初始化
* 入口参数:无
* 出口参数:无
* 说 明:参照上电序列初始化(24/40)
****************************************************************************/
int OLED_Init(void)
{
rt_hw_oled_config();
OLED_CS_High;
//复位OLED
OLED_RST_High;
rt_thread_mdelay(200);
OLED_RST_Low;
rt_thread_mdelay(200);
OLED_RST_High;
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置列低位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置列高位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //设置起始行地址及映射RAM显示起始行 (0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0xB0); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x81); //对比度设置
OLED_Write_Operate(OLED_Mode_Cmd,0xCF); //Set SEG Output Current Brightness
OLED_Write_Operate(OLED_Mode_Cmd,0xA1); //Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //
OLED_Write_Operate(OLED_Mode_Cmd,0xA8); //设置驱动路数(1 to 64)
OLED_Write_Operate(OLED_Mode_Cmd,0x3F); //*duty = 1/64*/
OLED_Write_Operate(OLED_Mode_Cmd,0xC8); //0xc0上下反置 0xc8正常
OLED_Write_Operate(OLED_Mode_Cmd,0xD3); //设置显示偏移(0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //not offset
OLED_Write_Operate(OLED_Mode_Cmd,0xD5); //--set Display clock divide ratio/oscillator frequency
OLED_Write_Operate(OLED_Mode_Cmd,0x80); //--set divide ratio, Set Clock as 100 Frames/Sec
OLED_Write_Operate(OLED_Mode_Cmd,0xD9); //*set pre-charge period*/
OLED_Write_Operate(OLED_Mode_Cmd,0Xf1); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_Write_Operate(OLED_Mode_Cmd,0xDA); //*set COM pins*/
OLED_Write_Operate(OLED_Mode_Cmd,0x12); //
OLED_Write_Operate(OLED_Mode_Cmd,0xdb); //*set vcomh*/
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //Set VCOM Deselect Level
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0x20); //设置存储模式(0x00,0x02,0x01)
OLED_Write_Operate(OLED_Mode_Cmd,0x02); //页地址模式
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //*set charge pump disable*/
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //--set(0x10) disable
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0xA4); //显示开启(A4,显示,A5无显示)
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //背景正反向显示(0xa6,正显,0xa7,反显)
OLED_Display_Clear(); //清屏
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开显示
return 0;
}
INIT_COMPONENT_EXPORT(OLED_Init);
/****************************************************************************
* 名 称:u8 SPI1_WriteReadByte(u8 Data)
* 功 能:SPI1读写一个字节
* 入口参数:无
* 出口参数:接收的数据
* 返回值 :0,发送接收超时,1成功
* 说 明:无
****************************************************************************/
uint8_t g_master_rx_buff[6] = {0};
static rt_err_t SPI0_WriteReadByte(const rt_uint8_t Data)
{
rt_size_t len = 0;
rt_spi_transfer(&spi_dev_oled, (const void *)&Data, NULL, 1);
if (len != 1)
{
LOG_I("ssd1306_write_data error. %d", len);
return -RT_ERROR;
}
else
{
return RT_EOK;
}
return RT_EOK;
}
/****************************************************************************
* 名 称:u8 OLED_Write_Byte(u8 data)
* 功 能:OLED写一个字节
* 入口参数:无
* 出口参数:接收的数据
* 返回值 :0失败,1成功
* 说 明:无
****************************************************************************/
u8 OLED_Write_Byte(u8 data)
{
if(SPI0_WriteReadByte(data))
return 0;
else
return 1;
}
/****************************************************************************
* 名 称:void OLED_Write_Operate(u8 mode,u8 data)
* 功 能:OLED写操作
* 入口参数:模式,数据
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Write_Operate(u8 mode,u8 data)
{
OLED_CS_Low;
if(mode)
{
OLED_Write_Data;
}
else
{
OLED_Write_Cmd;
}
OLED_Write_Byte(data);
OLED_CS_High;
}
/****************************************************************************
* 名 称:void OLED_Display_Clear(void)
* 功 能:OLED清屏
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Clear(void)
{
u8 page = 0;
u8 i=0;
OLED_CS_Low;
for(page=0;page < 8; page++)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0+page);//设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置显示位置-列低地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置显示位置-列高地址
for(i = 0;i< 128; i++)
{
OLED_Write_Operate(OLED_Mode_Data,0x00); //清屏
}
}
}
/****************************************************************************
* 名 称:void OLED_Set_Positon(void)
* 功 能:设置显示坐标
* 入口参数:x,y
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Set_Positon(u8 x,u8 y)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0 + y); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,((x & 0xf0) >>4 ) | 0x10); //设置列高四位地址
OLED_Write_Operate(OLED_Mode_Cmd,(x & 0x0f) | 0x01); //设置列低四位地址
}
/****************************************************************************
* 名 称:void OLED_Display_on(void)
* 功 能:显示打开
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_on(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //打开充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_offvoid)
* 功 能:显示关闭
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_off(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //关闭充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_onechar(u8 x,u8 y,u8 character,u8 size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
character 字符
size 字号大小
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_onechar(u8 x,u8 y,u8 character,u8 size)
{
u8 c=0,i=0;
c = character-' ';
if(x > MAX_COLUMN - 1)
{
x= 0;
if(size == SIZE8)
{
y = y+1;
}
if(size == SIZE16)
{
y = y+2;
}
}
if(size == SIZE16)
{
OLED_Set_Positon(x,y);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16[c*16 + i]);
}
OLED_Set_Positon(x,y+1);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16[c*16 + i+8]);
}
}
else
{
OLED_Set_Positon(x,y+1);
for( i =0;i< 6; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F6x8[c]);
}
}
}
/****************************************************************************
* 名 称:void OLED_Display_string(u8 x,u8 y,u8 *str,u8 size)
* 功 能:显示字符串
* 入口参数:
x ,y坐标位置
str 字符串
size 字号大小
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_string(u8 x,u8 y,u8 *str,u8 size)
{
u8 i=0;
while(str!='\0')
{
OLED_Display_onechar(x,y,str,size);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
i++;
}
}
/****************************************************************************
* 名 称:void OLED_Display_Chinese(u8 x,u8 y,u8 Sno)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Chinese(u8 x,u8 y,u8 Sno)
{
u8 adder=0,i=0;
OLED_Set_Positon(x,y);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk[2*Sno]);
adder += 1;
}
OLED_Set_Positon(x,y+1);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk[2*Sno+1]);
adder += 1;
}
}
/****************************************************************************
* 名 称:u32 OLED_POW(u8 m, u8 n)
* 功 能:m的n次方
* 入口参数:
m为底数,n为指数
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
u32 OLED_POW(u8 m, u8 n)
{
u32 result=1;
while(n--)
{
result *= m;
}
return result;
}
/****************************************************************************
* 名 称:void OLED_Display_Num(u8 x,u8 y,u32 num, u8 Len,u8 size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Num(u8 x,u8 y,u32 num, u8 len,u8 size)
{
u8 i=0;
u8 endisplay=0;
u8 temp=0;
for(i = 0;i < len;i++)
{
temp = (num / (OLED_POW(10,len-i-1)))%10;
if(endisplay == 0 && i < len-1)
{
if(temp == 0)
{
OLED_Display_onechar(x + (size / 2) * i,y,' ',size);
continue;
}
else
{
endisplay = 1;
}
}
OLED_Display_onechar(x + (size / 2) * i,y,temp + '0',size);
}
}
/****************************************************************************
* 名 称:void OLED_Display_Picture(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[])
* 功 能:显示一张图片
* 入口参数:
x0 ,y0,x1,y1图片的大小
BMP[] 图片的码
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Picture(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[])
{
u8 i=0;
u8 x,y;
if(y1 == 8)
{
y= y1/ 8;
}
else
{
y = y1/ 8 + 1;
}
for(y = y0;y < y1;y++)
{
OLED_Set_Positon(x0,y);
for(x = x0;x< x1; x++)
{
OLED_Write_Operate(OLED_Mode_Data,BMP[i++]);
}
}
}
2) hal_entry function
void hal_entry(void)
{
rt_kprintf("\nHello RT-Thread!\n");
OLED_Display_string(0,0,"CPK-RA6M4 Board Evaluation",SIZE8);
while (1)
{
rt_thread_mdelay(50);
breathing_light();
}
}
Test phenomenon
Finally, the entire code project will be attached with a git link in the last review.
|