本次来试试SPI功能。使用手上SPI接口的oled来试一试。
首先还是打开STM32CUBEMX来配置SPI接口。
OLED接口使用SPI1,PA5,PA6,PA7。
片选使用PB6,DC脚使用PC7,复位脚使用PA9。
下面是编写代码,OLED的spi接口驱动如下
#include "main.h"
#include "drv_spi.h"
void drv_spi_gpio_init( void )
{
}
/**
* SSIOF callback function
*
* @param[in] dataCnt Count of writing
* @param[in] errStatus Status of operation result
* [url=home.php?mod=space&uid=784970]@return[/url] None
*/
typedef void (*CallbackHook)(void);
volatile uint32_t spi_transmit_ok;
CallbackHook spi_cmpl_fn = NULL;
extern SPI_HandleTypeDef hspi1;
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi->Instance == SPI1)
{
}
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
if(hspi->Instance == SPI1)
{
spi_transmit_ok = 1;
if(spi_cmpl_fn != NULL) spi_cmpl_fn();
}
}
///////////////////////////////////////////////////////////////////////////////////////
uint8_t spi_transmit_byte(void *spibus,uint8_t ch)
{
uint8_t txbuf,rxbuf;
txbuf = ch;
rxbuf = 0xff;
spi_transmit_ok = 0;
spi_cmpl_fn = NULL;
HAL_SPI_TransmitReceive(&hspi1,(void *)&txbuf, (void *)&rxbuf, 1, 10);
return rxbuf;
}
uint8_t spi_transmit_buff(void *spibus,uint8_t * wbuf,uint8_t * rbuf,uint32_t len,void(* callback)(void))
{
spi_transmit_ok = 0;
spi_cmpl_fn = callback;
HAL_SPI_TransmitReceive_DMA(&hspi1,wbuf, rbuf, len);
if(callback == NULL)
{
while(!spi_transmit_ok);
}
return 0;
}
void spi_write_read_buff(void *spibus,uint8_t * wbuf,uint32_t wl,uint8_t * rbuf,uint32_t rl)
{
if((wbuf != NULL) && (wl != 0))
{
spi_transmit_ok = 0;
spi_cmpl_fn = NULL;
HAL_SPI_Transmit(&hspi1,wbuf, wl, 100);
}
if((rbuf != NULL) && (rl != 0))
{
memset(rbuf,0,rl);
spi_transmit_ok = 0;
spi_cmpl_fn = NULL;
HAL_SPI_Receive(&hspi1,rbuf, rl, 100);
}
}
#include <main.h>
// Choose a bus
//#define SSD1306_USE_I2C
#define SSD1306_USE_SPI
#ifdef SSD1306_USE_I2C
#include "drv_i2c.h"
#define SSD1306_I2C_NUM 0
#define SSD1306_I2C_ADDR (0x3C)
#endif
#ifdef SSD1306_USE_SPI
#include "drv_spi.h"
#define SSD1306_SPI_NUM 0
#define SSD1306_RST_Set() HAL_GPIO_WritePin(LCD_BLK_GPIO_Port,LCD_BLK_Pin,GPIO_PIN_SET)
#define SSD1306_RST_Reset() HAL_GPIO_WritePin(LCD_BLK_GPIO_Port,LCD_BLK_Pin,GPIO_PIN_RESET)
#define SSD1306_DC_Set() HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_SET)
#define SSD1306_DC_Reset() HAL_GPIO_WritePin(LCD_DC_GPIO_Port,LCD_DC_Pin,GPIO_PIN_RESET)
#define SSD1306_SPI_CS_Set() HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET)
#define SSD1306_SPI_CS_Reset() HAL_GPIO_WritePin(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET)
#endif
#define ssd1306_mdelay(x) delay_ms(x)
#if defined(SSD1306_USE_SPI)
void ssd1306_Reset(void)
{
SSD1306_SPI_CS_Set();
// Reset the OLED
SSD1306_RST_Reset();
ssd1306_mdelay(10);
SSD1306_RST_Set();
ssd1306_mdelay(10);
}
// Send a byte to the command register
void ssd1306_WriteCommand(uint8_t byte)
{
SSD1306_SPI_CS_Reset(); // select OLED
SSD1306_DC_Reset(); // command
spi_transmit_byte(SSD1306_SPI_NUM, byte);
SSD1306_SPI_CS_Set(); // un-select OLED
}
// Send data
void ssd1306_WriteData(uint8_t* buffer, size_t buff_size)
{
SSD1306_SPI_CS_Reset(); // select OLED
SSD1306_DC_Set(); // command
spi_write_read_buff(SSD1306_SPI_NUM, buffer, buff_size,NULL,0);
SSD1306_SPI_CS_Set(); // un-select OLED
}
#else
#error "You should define SSD1306_USE_SPI or SSD1306_USE_I2C macro"
#endif
uint8_t SSD1306_Buffer[SSD1306_BUFFER_SIZE];
void ssd1306_SetContrast(const uint8_t value)
{
const uint8_t kSetContrastControlRegister = 0x81;
ssd1306_WriteCommand(kSetContrastControlRegister);
ssd1306_WriteCommand(value);
}
uint32_t ssd1306_SetDisplayOn(uint8_t light)
{
if (light)
{
ssd1306_WriteCommand(0x8D); //--set DC-DC enable
ssd1306_WriteCommand(0x14); //
ssd1306_WriteCommand(0xAF);// Display on
}else
{
ssd1306_WriteCommand(0x8D); //--set DC-DC enable
ssd1306_WriteCommand(0x10); //
ssd1306_WriteCommand(0xAE);// Display off
}
return 0;
}
// Initialize the oled screen
uint32_t ssd1306_Init(void *args)
{
#if defined(SSD1306_USE_I2C)
I2C_BUS_DEV = I2C_FindDevice(I2C_NAME);
if (I2C_BUS_DEV == NULL)
{
return -1;
}
#endif
#if defined(SSD1306_USE_SPI)
#endif
// Reset OLED
ssd1306_Reset();
// Wait for the screen to boot
ssd1306_mdelay(100);
// Init OLED
ssd1306_SetDisplayOn(0); //display off
ssd1306_WriteCommand(0x20); //Set Memory Addressing Mode
ssd1306_WriteCommand(0x00); // 00b,Horizontal Addressing Mode; 01b,Vertical Addressing Mode;
// 10b,Page Addressing Mode (RESET); 11b,Invalid
ssd1306_WriteCommand(0xB0); //Set Page Start Address for Page Addressing Mode,0-7
#ifdef SSD1306_MIRROR_VERT
ssd1306_WriteCommand(0xC0); // Mirror vertically
#else
ssd1306_WriteCommand(0xC8); //Set COM Output Scan Direction
#endif
ssd1306_WriteCommand(0x00); //---set low column address
ssd1306_WriteCommand(0x10); //---set high column address
ssd1306_WriteCommand(0x40); //--set start line address - CHECK
ssd1306_SetContrast(0xFF);
#ifdef SSD1306_MIRROR_HORIZ
ssd1306_WriteCommand(0xA0); // Mirror horizontally
#else
ssd1306_WriteCommand(0xA1); //--set segment re-map 0 to 127 - CHECK
#endif
#ifdef SSD1306_INVERSE_COLOR
ssd1306_WriteCommand(0xA7); //--set inverse color
#else
ssd1306_WriteCommand(0xA6); //--set normal color
#endif
// Set multiplex ratio.
#if (SSD1306_HEIGHT == 128)
// Found in the Luma Python lib for SH1106.
ssd1306_WriteCommand(0xFF);
#else
ssd1306_WriteCommand(0xA8); //--set multiplex ratio(1 to 64) - CHECK
#endif
#if (SSD1306_HEIGHT == 32)
ssd1306_WriteCommand(0x1F); //
#elif (SSD1306_HEIGHT == 64)
ssd1306_WriteCommand(0x3F); //
#elif (SSD1306_HEIGHT == 128)
ssd1306_WriteCommand(0x3F); // Seems to work for 128px high displays too.
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif
ssd1306_WriteCommand(0xA4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_WriteCommand(0xD3); //-set display offset - CHECK
ssd1306_WriteCommand(0x00); //-not offset
ssd1306_WriteCommand(0xD5); //--set display clock divide ratio/oscillator frequency
ssd1306_WriteCommand(0xF0); //--set divide ratio
ssd1306_WriteCommand(0xD9); //--set pre-charge period
ssd1306_WriteCommand(0x22); //
ssd1306_WriteCommand(0xDA); //--set com pins hardware configuration - CHECK
#if (SSD1306_HEIGHT == 32)
ssd1306_WriteCommand(0x02);
#elif (SSD1306_HEIGHT == 64)
ssd1306_WriteCommand(0x12);
#elif (SSD1306_HEIGHT == 128)
ssd1306_WriteCommand(0x12);
#else
#error "Only 32, 64, or 128 lines of height are supported!"
#endif
ssd1306_WriteCommand(0xDB); //--set vcomh
ssd1306_WriteCommand(0x20); //0x20,0.77xVcc
ssd1306_SetDisplayOn(1); //--turn on SSD1306 panel
return 0;
}
整个工程如图:
最终编译下载之后就可以看到oled显示字符。
这里顺便移植了一个qrcode显示。
工程代码: