Commit 235f660d79ed077ed8f001d024bd86a780147bf4
authorTorbjorn Tyridal <ttyridal@cisco.com>
Fri, 15 Sep 2017 12:52:06 +0000 (14:52 +0200)
committerMichel Pollet <github.com@pollet.net>
Tue, 19 Sep 2017 09:02:21 +0000 (10:02 +0100)
2 files changed:
examples/parts/ssd1306_virt.c
examples/parts/ssd1306_virt.h

index fe4c4c8d8cf766bcac4695cf7ccee4e57ea42214..7021d73b4a02f4da12e37a4d7b14c90a874e2924 100644 (file)
@@ -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
                 ] = "<ssd1306.RS", [IRQ_SSD1306_DATA_INSTRUCTION
                 ] = "<ssd1306.RW", [IRQ_SSD1306_ENABLE] = "<ssd1306.E",
-                [IRQ_SSD1306_ADDR] = "7>hd44780.ADDR" };
+                [IRQ_SSD1306_ADDR] = "7>hd44780.ADDR",
+                [IRQ_SSD1306_TWI_OUT] = "32<sdd1306.TWI.out",
+                [IRQ_SSD1306_TWI_IN] = "8>sdd1306.TWI.in",
+};
 
 void
 ssd1306_connect (ssd1306_t * part, ssd1306_wiring_t * wiring)
@@ -373,6 +442,25 @@ ssd1306_connect (ssd1306_t * part, ssd1306_wiring_t * wiring)
                        part->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));
index ab5edbe88f4e20af8506f5ce5da3f631d2fd6f37..fdf810379f53618a30ce714402e57877db968868 100644 (file)
@@ -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