From 235f660d79ed077ed8f001d024bd86a780147bf4 Mon Sep 17 00:00:00 2001 From: Torbjorn Tyridal Date: Fri, 15 Sep 2017 14:52:06 +0200 Subject: [PATCH] parts/ssd1306: add twi interface --- examples/parts/ssd1306_virt.c | 92 ++++++++++++++++++++++++++++++++++- examples/parts/ssd1306_virt.h | 13 ++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/examples/parts/ssd1306_virt.c b/examples/parts/ssd1306_virt.c index fe4c4c8..7021d73 100644 --- a/examples/parts/ssd1306_virt.c +++ b/examples/parts/ssd1306_virt.c @@ -27,6 +27,7 @@ #include "ssd1306_virt.h" #include "avr_spi.h" +#include "avr_twi.h" #include "avr_ioport.h" /* @@ -262,6 +263,71 @@ ssd1306_write_command (ssd1306_t *part) } } +/* + * Called when a TWI byte is sent + */ +static void +ssd1306_twi_hook (struct avr_irq_t * irq, uint32_t value, void * param) +{ + ssd1306_t * p = (ssd1306_t*) param; + avr_twi_msg_irq_t v; + v.u.v = value; + + if (v.u.twi.msg & TWI_COND_STOP) + p->twi_selected = 0; + + if (v.u.twi.msg & TWI_COND_START) { + p->twi_selected = 0; + p->twi_index = 0; + if (((v.u.twi.addr>>1) & SSD1306_I2C_ADDRESS_MASK) == SSD1306_I2C_ADDRESS) { + p->twi_selected = v.u.twi.addr; + avr_raise_irq(p->irq + IRQ_SSD1306_TWI_IN, + avr_twi_irq_msg(TWI_COND_ACK, p->twi_selected, 1)); + } + } + + if (p->twi_selected) { + if (v.u.twi.msg & TWI_COND_WRITE) { + avr_raise_irq(p->irq + IRQ_SSD1306_TWI_IN, + avr_twi_irq_msg(TWI_COND_ACK, p->twi_selected, 1)); + + if (p->twi_index == 0) { // control byte + if ((v.u.twi.data & (~(1<<6))) != 0) { + printf("%s COND_WRITE %x\n", __FUNCTION__, v.u.twi.data); + printf("%s ALERT: unhandled Co bit\n", __FUNCTION__); + abort(); + } + p->di_pin = v.u.twi.data ? SSD1306_VIRT_DATA : SSD1306_VIRT_INSTRUCTION; + } else { + p->spi_data = v.u.twi.data; + + switch (p->di_pin) + { + case SSD1306_VIRT_DATA: + ssd1306_write_data (p); + break; + case SSD1306_VIRT_INSTRUCTION: + ssd1306_write_command (p); + break; + default: + // Invalid value + break; + } + } + p->twi_index++; + } + + // SSD1306 doesn't support read on serial interfaces + // just return 0 + if (v.u.twi.msg & TWI_COND_READ) { + uint8_t data = 0; + avr_raise_irq(p->irq + IRQ_SSD1306_TWI_IN, + avr_twi_irq_msg(TWI_COND_READ, p->twi_selected, data)); + p->twi_index++; + } + } +} + /* * Called when a SPI byte is sent */ @@ -341,7 +407,10 @@ static const char * irq_names[IRQ_SSD1306_COUNT] = { [IRQ_SSD1306_SPI_BYTE_IN] = "=ssd1306.SDIN", [IRQ_SSD1306_RESET ] = "irq + IRQ_SSD1306_RESET); } +void +ssd1306_connect_twi (ssd1306_t * part, ssd1306_wiring_t * wiring) +{ + avr_connect_irq ( + avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_OUTPUT), + part->irq + IRQ_SSD1306_TWI_OUT); + + avr_connect_irq ( + part->irq + IRQ_SSD1306_TWI_IN, + avr_io_getirq (part->avr, AVR_IOCTL_TWI_GETIRQ(0), TWI_IRQ_INPUT)); + + avr_connect_irq ( + avr_io_getirq (part->avr, + AVR_IOCTL_IOPORT_GETIRQ( + wiring->reset.port), + wiring->reset.pin), + part->irq + IRQ_SSD1306_RESET); +} + void ssd1306_init (struct avr_t *avr, struct ssd1306_t * part, int width, int height) { @@ -399,6 +487,8 @@ ssd1306_init (struct avr_t *avr, struct ssd1306_t * part, int width, int height) ssd1306_cs_hook, part); avr_irq_register_notify (part->irq + IRQ_SSD1306_DATA_INSTRUCTION, ssd1306_di_hook, part); + avr_irq_register_notify (part->irq + IRQ_SSD1306_TWI_OUT, + ssd1306_twi_hook, part); printf ("SSD1306: %duS is %d cycles for your AVR\n", 37, (int) avr_usec_to_cycles (avr, 37)); diff --git a/examples/parts/ssd1306_virt.h b/examples/parts/ssd1306_virt.h index ab5edbe..fdf8103 100644 --- a/examples/parts/ssd1306_virt.h +++ b/examples/parts/ssd1306_virt.h @@ -45,6 +45,9 @@ #define SSD1306_VIRT_DATA 1 #define SSD1306_VIRT_INSTRUCTION 0 +#define SSD1306_I2C_ADDRESS 0x3C +#define SSD1306_I2C_ADDRESS_MASK 0xfe + #define SSD1306_VIRT_PAGES 8 #define SSD1306_VIRT_COLUMNS 128 @@ -105,6 +108,8 @@ enum IRQ_SSD1306_DATA_INSTRUCTION, //IRQ_SSD1306_INPUT_COUNT, IRQ_SSD1306_ADDR, // << For VCD + IRQ_SSD1306_TWI_IN, + IRQ_SSD1306_TWI_OUT, IRQ_SSD1306_COUNT //TODO: Add IRQs for VCD: Internal state etc. }; @@ -155,6 +160,9 @@ typedef struct ssd1306_t uint8_t spi_data; uint8_t reg_write_sz; enum ssd1306_addressing_mode_t addr_mode; + + uint8_t twi_selected; + uint8_t twi_index; } ssd1306_t; typedef struct ssd1306_pin_t @@ -190,4 +198,7 @@ ssd1306_get_flag (ssd1306_t *b, uint16_t bit) void ssd1306_connect (ssd1306_t * part, ssd1306_wiring_t * wiring); -#endif +void +ssd1306_connect_twi (ssd1306_t * part, ssd1306_wiring_t * wiring); + +#endif -- 2.39.5