Skip to content

Commit

Permalink
software i2c
Browse files Browse the repository at this point in the history
  • Loading branch information
olikraus committed Dec 5, 2015
1 parent bf03441 commit 357b1c5
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 63 deletions.
12 changes: 10 additions & 2 deletions csrc/u8x8.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ struct u8x8_display_info_struct
uint8_t sda_setup_time_ns; /* UC1601: 12ns */
/* the pulse width of the the clock signal, cycle time is twice this value */
/* max freq is 1/(2*sck_pulse_width_ns) */
uint8_t sck_pulse_width_ns; /* UC1601: 15ns */
/* AVR: below 70: DIV2, 8 MHz, >= 70 --> 4MHz clock (DIV4) */
uint8_t sck_pulse_width_ns; /* UC1701: 50ns */

/* data takeover edge: 0=falling edge, 1=rising edge*/
/* initial default value for sck is low (0) for falling edge and high for rising edge */
Expand Down Expand Up @@ -205,7 +206,7 @@ struct u8x8_struct
const uint8_t *font;
u8x8_char_cb char_cb; /* procedure, which will be used to get the next char from the string */
uint8_t x_offset; /* copied from info struct, can be modified in flip mode */

uint8_t i2c_started; /* for i2c interface */
#ifdef U8X8_USE_PINS
uint8_t pins[U8X8_PIN_CNT]; /* defines a pinlist: Mainly a list of pins for the Arduino Envionment, use U8X8_PIN_xxx to access */
#endif
Expand Down Expand Up @@ -417,6 +418,7 @@ uint8_t u8x8_byte_SendByte(u8x8_t *u8x8, uint8_t byte) U8X8_NOINLINE;
uint8_t u8x8_byte_SendBytes(u8x8_t *u8x8, uint8_t cnt, uint8_t *data) U8X8_NOINLINE;

uint8_t u8x8_byte_8bit_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_byte_ssd13xx_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);


/*==========================================*/
Expand All @@ -436,8 +438,13 @@ uint8_t u8x8_byte_8bit_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
#define U8X8_MSG_DELAY_10MICRO 42
#define U8X8_MSG_DELAY_100NANO 43
#define U8X8_MSG_DELAY_NANO 44
/* delay of one i2c unit, should be 5us for 100K, and 1.25us for 400K */
#define U8X8_MSG_DELAY_I2C 45

#define U8X8_MSG_GPIO(x) (64+(x))
#ifdef U8X8_USE_PINS
#define u8x8_GetPinValue(u8x8, msg) ((u8x8)->pins[(msg)&0x3f])
#endif

#define U8X8_MSG_GPIO_D0 U8X8_MSG_GPIO(U8X8_PIN_D0)
#define U8X8_MSG_GPIO_CLOCK U8X8_MSG_GPIO(U8X8_PIN_CLOCK)
Expand All @@ -457,6 +464,7 @@ uint8_t u8x8_byte_8bit_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *

#define u8x8_gpio_Init(u8x8) ((u8x8)->gpio_and_delay_cb((u8x8), U8X8_MSG_GPIO_AND_DELAY_INIT, 0, NULL ))


/*
#define u8x8_gpio_SetDC(u8x8, v) ((u8x8)->gpio_and_delay_cb((u8x8), U8X8_MSG_GPIO_DC, (v), NULL ))
#define u8x8_gpio_SetCS(u8x8, v) ((u8x8)->gpio_and_delay_cb((u8x8), U8X8_MSG_GPIO_CS, (v), NULL ))
Expand Down
188 changes: 188 additions & 0 deletions csrc/u8x8_byte.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,191 @@ uint8_t u8x8_byte_8bit_sw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
return 1;
}

/*=========================================*/


/*
software i2c,
ignores ACK response (which is anyway not provided by some displays)
also does not allow reading from the device
*/
static void i2c_delay(u8x8_t *u8x8) U8X8_NOINLINE;
static void i2c_delay(u8x8_t *u8x8)
{
//u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_10MICRO, u8x8->display_info->i2c_bus_clock_100kHz);
u8x8_gpio_Delay(u8x8, U8X8_MSG_DELAY_I2C, u8x8->display_info->i2c_bus_clock_100kHz);
}

static void i2c_init(u8x8_t *u8x8)
{
u8x8_gpio_SetClock(u8x8, 1);
u8x8_gpio_SetData(u8x8, 1);

i2c_delay(u8x8);
}

/* actually, the scl line is not observed, so this procedure does not return a value */

static void i2c_read_scl_and_delay(u8x8_t *u8x8)
{
/* set as input (line will be high) */
u8x8_gpio_SetClock(u8x8, 1);

i2c_delay(u8x8);
}

static void i2c_clear_scl(u8x8_t *u8x8)
{
u8x8_gpio_SetClock(u8x8, 0);
}

static void i2c_read_sda(u8x8_t *u8x8)
{
/* set as input (line will be high) */
u8x8_gpio_SetData(u8x8, 1);
}

static void i2c_clear_sda(u8x8_t *u8x8)
{
/* set open collector and drive low */
u8x8_gpio_SetData(u8x8, 0);
}

static void i2c_start(u8x8_t *u8x8)
{
if ( u8x8->i2c_started != 0 )
{
/* if already started: do restart */
i2c_read_sda(u8x8); /* SDA = 1 */
i2c_delay(u8x8);
i2c_read_scl_and_delay(u8x8);
}
i2c_read_sda(u8x8);
/* send the start condition, both lines go from 1 to 0 */
i2c_clear_sda(u8x8);
i2c_delay(u8x8);
i2c_clear_scl(u8x8);
u8x8->i2c_started = 1;
}


static void i2c_stop(u8x8_t *u8x8)
{
/* set SDA to 0 */
i2c_clear_sda(u8x8);
i2c_delay(u8x8);

/* now release all lines */
i2c_read_scl_and_delay(u8x8);

/* set SDA to 1 */
i2c_read_sda(u8x8);
i2c_delay(u8x8);
u8x8->i2c_started = 0;
}

static void i2c_write_bit(u8x8_t *u8x8, uint8_t val)
{
if (val)
i2c_read_sda(u8x8);
else
i2c_clear_sda(u8x8);

i2c_delay(u8x8);
i2c_read_scl_and_delay(u8x8);
i2c_clear_scl(u8x8);
}

static void i2c_read_bit(u8x8_t *u8x8)
{
//uint8_t val;
/* do not drive SDA */
i2c_read_sda(u8x8);
i2c_delay(u8x8);
i2c_read_scl_and_delay(u8x8);
i2c_read_sda(u8x8);
i2c_delay(u8x8);
i2c_clear_scl(u8x8);
//return val;
}

static void i2c_write_byte(u8x8_t *u8x8, uint8_t b)
{
i2c_write_bit(u8x8, b & 128);
i2c_write_bit(u8x8, b & 64);
i2c_write_bit(u8x8, b & 32);
i2c_write_bit(u8x8, b & 16);
i2c_write_bit(u8x8, b & 8);
i2c_write_bit(u8x8, b & 4);
i2c_write_bit(u8x8, b & 2);
i2c_write_bit(u8x8, b & 1);

/* read ack from client */
/* 0: ack was given by client */
/* 1: nothing happend during ack cycle */
i2c_read_bit(u8x8);
}




uint8_t u8x8_byte_ssd13xx_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t *data;
static uint8_t last_dc = 0;
static uint8_t is_send_dc = 0;

switch(msg)
{
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;

if ( is_send_dc != 0 )
{

i2c_start(u8x8);
i2c_write_byte(u8x8, 0x078); /* write slave adr and read/write bit */

if ( last_dc == 0 )
i2c_write_byte(u8x8, 0);
else
i2c_write_byte(u8x8, 0x040);
is_send_dc = 0;
}

while( arg_int > 0 )
{
i2c_write_byte(u8x8, *data);
data++;
arg_int--;
}

break;

case U8X8_MSG_BYTE_INIT:
i2c_init(u8x8);
break;
case U8X8_MSG_BYTE_SET_DC:
if ( last_dc != arg_int )
{
last_dc = arg_int;
is_send_dc = 1;
}
break;
case U8X8_MSG_BYTE_START_TRANSFER:
last_dc = 0;
is_send_dc = 1;
break;
case U8X8_MSG_BYTE_END_TRANSFER:
i2c_stop(u8x8);
break;
case U8X8_MSG_BYTE_SET_I2C_ADR:
break;
case U8X8_MSG_BYTE_SET_DEVICE:
break;
default:
return 0;
}
return 1;
}

2 changes: 1 addition & 1 deletion csrc/u8x8_d_ssd1306_128x64_noname.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static const u8x8_display_info_t u8x8_ssd1306_128x64_noname_display_info =
/* reset_pulse_width_ms = */ 100, /* SSD1306: 3 us */
/* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
/* sda_setup_time_ns = */ 50, /* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
/* sck_pulse_width_ns = */ 50, /* SSD1306: 20ns, but cycle time is 100ns, so use 100/2 */
/* sck_pulse_width_ns = */ 50, /* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
/* sck_takeover_edge = */ 1, /* rising edge */
/* i2c_bus_clock_100kHz = */ 4,
/* data_setup_time_ns = */ 40,
Expand Down
4 changes: 2 additions & 2 deletions csrc/u8x8_d_uc1701_dogs102.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ static const u8x8_display_info_t u8x8_uc1701_display_info =
/* pre_chip_disable_wait_ns = */ 5,
/* reset_pulse_width_ms = */ 1,
/* post_reset_wait_ms = */ 6,
/* sda_setup_time_ns = */ 15, /* if this is smaller than sck_pulse_width_ns, use sck_pulse_width_ns, so use 15 instead of 12*/
/* sck_pulse_width_ns = */ 15,
/* sda_setup_time_ns = */ 12,
/* sck_pulse_width_ns = */ 75, /* half of cycle time (100ns according to datasheet), AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
/* sck_takeover_edge = */ 1, /* rising edge */
/* i2c_bus_clock_100kHz = */ 37,
/* data_setup_time_ns = */ 30,
Expand Down
Loading

0 comments on commit 357b1c5

Please sign in to comment.