cmake_cpputest_template/src/extralibs/ssd1306_i2c_bitbang.h

136 lines
3 KiB
C

/*
* Single-File-Header for SSD1306 emulated I2C interface
* 02-12-2025 cnlohr
*/
#ifndef _SSD1306_I2C_BITBANG_H
#define _SSD1306_I2C_BITBANG_H
#include <string.h>
// SSD1306 I2C address
#ifndef SSD1306_I2C_ADDR
#define SSD1306_I2C_ADDR 0x3c
#endif
#ifndef SSD1306_I2C_BITBANG_SDA
#define SSD1306_I2C_BITBANG_SDA PC1
#endif
#ifndef SSD1306_I2C_BITBANG_SCL
#define SSD1306_I2C_BITBANG_SCL PC2
#endif
/*
* init just I2C
*/
void ssd1306_i2c_setup(void)
{
funGpioInitAll();
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
funPinMode( SSD1306_I2C_BITBANG_SCL, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
}
#define SDA_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 1 );
#define SCL_HIGH funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 1 );
#define SDA_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SDA, 0 );
#define SCL_LOW funDigitalWrite( SSD1306_I2C_BITBANG_SCL, 0 );
#define SDA_IN funDigitalRead( SSD1306_I2C_BITBANG_SDA );
#define I2CSPEEDBASE 1
#define I2CDELAY_FUNC(x) ADD_N_NOPS(x*1)
//Delay_Us(x*1);
static void ssd1306_i2c_sendstart()
{
SCL_HIGH
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_LOW
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
}
void ssd1306_i2c_sendstop()
{
SDA_LOW
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_HIGH
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
}
//Return nonzero on failure.
unsigned char ssd1306_i2c_sendbyte( unsigned char data )
{
unsigned int i;
for( i = 0; i < 8; i++ )
{
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
if( data & 0x80 )
{ SDA_HIGH; }
else
{ SDA_LOW; }
data<<=1;
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH
I2CDELAY_FUNC( 2 * I2CSPEEDBASE );
SCL_LOW
}
//Immediately after sending last bit, open up DDDR for control.
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_IN_PUPD );
SDA_HIGH
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_HIGH
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
i = SDA_IN;
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SCL_LOW
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
SDA_HIGH // Maybe?
funPinMode( SSD1306_I2C_BITBANG_SDA, GPIO_CFGLR_OUT_10Mhz_PP );
I2CDELAY_FUNC( 1 * I2CSPEEDBASE );
return !!i;
}
uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
{
ssd1306_i2c_sendstart();
int r = ssd1306_i2c_sendbyte( SSD1306_I2C_ADDR<<1 );
if( r ) return r;
//ssd1306_i2c_sendstart(); For some reason displays don't want repeated start
if(cmd)
{
if( ssd1306_i2c_sendbyte( 0x00 ) )
return 1; // Control
}
else
{
if( ssd1306_i2c_sendbyte( 0x40 ) )
return 1; // Data
}
for( int i = 0; i < sz; i++ )
{
if( ssd1306_i2c_sendbyte( data[i] ) )
return 1;
}
ssd1306_i2c_sendstop();
return 0;
}
void ssd1306_rst(void)
{
funPinMode( SSD1306_RST_PIN, GPIO_CFGLR_OUT_10Mhz_PP );
funDigitalWrite( SSD1306_RST_PIN, 0 );
Delay_Ms(10);
funDigitalWrite( SSD1306_RST_PIN, 1 );
Delay_Us(10);
}
#endif