#include "project.h" #define DMA_BUF_SZ (2 + (SSD1306_VRAM_SIZE)) uint8_t dma_buf[DMA_BUF_SZ]; uint8_t update_buf[DMA_BUF_SZ]; static int dma_in_progress = 0; static int refresh_enabled = 0; static uint32_t refresh_wdt = 0; int ssd1306_cmds (uint8_t * buf, size_t len, int delay) { while (i2c_lock ()); i2cp_start_transaction (SSD1306_I2C_ADDRESS, I2C_WRITE); i2cp_send (SSD1306_COMMAND); while (len--) i2cp_send (*(buf++)); i2cp_stop (); if (delay) delay_us (delay); i2c_unlock (); return 0; } int ssd1306_cmd (uint8_t cmd, int delay) { return ssd1306_cmds (&cmd, 1, delay); } static void start_dma (void) { uint8_t cmds[] = { SSD1306_SET_PAGE_ADDR, 0, 0xff, SSD1306_SET_COLUMN_ADDR, 0, SSD1306_WIDTH - 1 }; if (dma_in_progress) return; refresh_wdt = 0; dma_in_progress = 1; memcpy (dma_buf, update_buf, DMA_BUF_SZ); ssd1306_cmds (cmds, sizeof (cmds), 0); i2cp_start_transaction (SSD1306_I2C_ADDRESS, I2C_WRITE); i2cp_start_dma (dma_buf, DMA_BUF_SZ); } void dma1_channel6_isr (void) { if (dma_in_progress) { i2cp_stop_dma (); i2cp_stop (); dma_in_progress = 0; } if (refresh_enabled) start_dma (); } void oled_refresh_wdt (void) { if (!refresh_enabled) return; refresh_wdt++; if (refresh_wdt < 1000) return; refresh_wdt = 0; /*No refresh for 1s, restart everything */ i2cp_stop_dma (); i2cp_stop (); dma_in_progress = 0; start_dma (); } static void dma_generate_stream (void) { memset (update_buf, 0, DMA_BUF_SZ); update_buf[0] = SSD1306_DATA_CONTINUE; } void oled_enable_refresh (void) { refresh_enabled = 1; start_dma (); } void oled_disable_refresh (void) { refresh_enabled = 0; while (dma_in_progress); } void oled_cls (void) { memset (update_buf + 1, 0, SSD1306_VRAM_SIZE); } void oled_on (void) { ssd1306_cmd (SSD1306_DISPLAY_ON, 0); } void oled_off (void) { ssd1306_cmd (SSD1306_DISPLAY_OFF, 0); } void oled_squirt (void) { unsigned i; uint8_t cmds[] = { SSD1306_SET_PAGE_ADDR, 0, 0xff, SSD1306_SET_COLUMN_ADDR, 0, SSD1306_WIDTH - 1 }; ssd1306_cmds (cmds, sizeof (cmds), 0); while (i2c_lock ()); i2cp_start_transaction (SSD1306_I2C_ADDRESS, I2C_WRITE); for (i = 0; i < DMA_BUF_SZ; ++i) i2cp_send (update_buf[i]); i2cp_stop (); i2c_unlock (); } void oled_reset (void) { uint8_t init[] = { SSD1306_DISPLAY_OFF, SSD1306_SET_DISPLAY_CLOCK_DIV_RATIO, 0x80, SSD1306_SET_MULTIPLEX_RATIO, SSD1306_HEIGHT - 1, SSD1306_SET_DISPLAY_OFFSET, 0x0, SSD1306_SET_START_LINE | 0x0, SSD1306_CHARGE_PUMP, 0x14, SSD1306_MEMORY_ADDR_MODE, 0x00, SSD1306_SET_SEGMENT_REMAP | 0x1, SSD1306_COM_SCAN_DIR_DEC, //SSD1306_SET_COM_PINS, 0x12, SSD1306_SET_COM_PINS, 0x02, //SSD1306_SET_CONTRAST_CONTROL, 0xCF, SSD1306_SET_CONTRAST_CONTROL, 0x8F, SSD1306_SET_PRECHARGE_PERIOD, 0xF1, SSD1306_SET_VCOM_DESELECT, 0x40, SSD1306_DISPLAY_ALL_ON_RESUME, SSD1306_NORMAL_DISPLAY, SSD1306_DISPLAY_ON, }; ssd1306_cmds (init, sizeof (init), 0); } void oled_const_strip (int x, int xe, uint8_t and, uint8_t or) { uint8_t r; for (x++; x <= xe; ++x) { r = update_buf[x] & and; update_buf[x] = r | or; } } void oled_blit_strip (int x, int xe, uint8_t mask, int shift, uint8_t * src) { uint8_t r, s; if (shift > 0) { for (x++; x <= xe; ++x) { s = *(src++); s <<= shift; s &= mask; r = update_buf[x] & ~mask; update_buf[x] = r | s; } } else if (shift < 0) { shift = -shift; for (x++; x <= xe; ++x) { s = *(src++); s >>= shift; s &= mask; r = update_buf[x] & ~mask; update_buf[x] = r | s; } } else { for (x++; x <= xe; ++x) { s = *(src++); s &= mask; r = update_buf[x] & ~mask; update_buf[x] = r | s; } } } void oled_init () { oled_reset (); delay_us (100); dma_generate_stream (); nvic_enable_irq (NVIC_DMA1_CHANNEL6_IRQ); oled_enable_refresh (); } void oled_shutdown (void) { oled_disable_refresh (); oled_off (); }