cmake_cpputest_template/inc/extralibs/ssd1306_spi.h
2025-12-23 14:33:54 -08:00

156 lines
3.4 KiB
C

/*
* Single-File-Header for SSD1306 SPI interface
* 05-05-2023 E. Brombaugh
*/
#ifndef _SSD1306_SPI_H
#define _SSD1306_SPI_H
// control pins
#ifndef SSD1306_RST_PIN
#define SSD1306_RST_PIN PC2
#endif
#ifndef SSD1306_CS_PIN
#define SSD1306_CS_PIN PC3
#endif
#ifndef SSD1306_DC_PIN
#define SSD1306_DC_PIN PC4
#endif
#ifndef SSD1306_MOSI_PIN
#define SSD1306_MOSI_PIN PC6
#endif
#ifndef SSD1306_SCK_PIN
#define SSD1306_SCK_PIN PC5
#endif
#ifndef SSD1306_BAUD_RATE_PRESCALER
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_2
#endif
#ifndef SSD1306_SOFT_SPI
#define SSD1306_SOFT_SPI 0
#endif
/*
* init SPI and GPIO for SSD1306 OLED
*/
uint8_t ssd1306_spi_init(void)
{
// Enable GPIOC and SPI
#ifdef CH5xx
#else
RCC->APB2PCENR |= RCC_APB2Periph_SPI1;
#endif
funGpioInitAll();
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode( SSD1306_CS_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode( SSD1306_DC_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
#if defined( CH5xx ) || SSD1306_SOFT_SPI
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_PP );
#else
funPinMode( SSD1306_MOSI_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
funPinMode( SSD1306_SCK_PIN, GPIO_CFGLR_OUT_50Mhz_AF_PP );
#endif
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
// Configure SPI
#if SSD1306_SOFT_SPI
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH );
#elif defined( CH5xx )
R8_SPI0_CLOCK_DIV = FUNCONF_SYSTEM_CORE_CLOCK / 12000000; // 16MHz is the fastest I want to go - though it does seem to work up to ~60MHz.
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_2WIRE_MOD | RB_SPI_SCK_OE;
R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
// | RB_SPI_MST_SCK_MOD; // Mode 3 / mode 0
R8_SPI0_CTRL_CFG = RB_MST_CLK_SEL;
#else
SPI1->CTLR1 =
SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_8b |
SPI_Mode_Master | SPI_Direction_1Line_Tx |
SSD1306_BAUD_RATE_PRESCALER;
// enable SPI port
SPI1->CTLR1 |= CTLR1_SPE_Set;
#endif
// always succeed
return 0;
}
/*
* toggle reset line
*/
void ssd1306_rst(void)
{
funDigitalWrite( SSD1306_RST_PIN, FUN_LOW );
Delay_Ms(10);
funDigitalWrite( SSD1306_RST_PIN, FUN_HIGH );
}
/*
* packet send for blocking polled operation via spi
*/
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
{
if(cmd)
{
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
}
else
{
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
}
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
// send data
while(sz--)
{
#if SSD1306_SOFT_SPI
uint8_t c = *data++;
int i = 8;
do
{
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
funDigitalWrite( SSD1306_MOSI_PIN, !!(c & 0x80) ); ADD_N_NOPS(1)
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH ); ADD_N_NOPS(1)
c<<=1;
} while( --i );
#elif defined( CH5xx )
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
R8_SPI0_BUFFER = *data++;
#else
// wait for TXE
while(!(SPI1->STATR & SPI_STATR_TXE));
// Send byte
SPI1->DATAR = *data++;
#endif
}
// wait for not busy before exiting
#if SSD1306_SOFT_SPI
// Nothing needed here.
#elif defined( CH5xx )
while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE)) { }
#else
while(SPI1->STATR & SPI_STATR_BSY) { }
#endif
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
// we're happy
return 0;
}
#endif