static int ssd1306_setpower(FAR struct lcd_dev_s *dev, int power) { struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev; DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER); lcdvdbg("power: %d [%d]\n", power, priv->on ? CONFIG_LCD_MAXPOWER : 0); /* Lock and select device */ ssd1306_select(priv, true); if (power <= 0) { /* Turn the display off */ (void)ssd1306_sendbyte(priv, SSD1306_DISPOFF); priv->on = false; } else { /* Turn the display on */ (void)ssd1306_sendbyte(priv, SSD1306_DISPON); priv->on = true; } /* De-select and unlock the device */ ssd1306_select(priv, false); return OK; }
void ssd1306_fill(FAR struct lcd_dev_s *dev, uint8_t color) { FAR struct ssd1306_dev_s *priv = &g_oleddev; unsigned int page; /* Make an 8-bit version of the selected color */ if (color & 1) { color = 0xff; } else { color = 0; } /* Initialize the framebuffer */ memset(priv->fb, color, SSD1306_DEV_FBSIZE); /* Lock and select device */ ssd1306_select(priv, true); /* Visit each page */ for (page = 0; page < SSD1306_DEV_PAGES; page++) { /* Select command transfer */ ssd1306_cmddata(priv, true); /* Set the column address to the XOFFSET value */ ssd1306_sendbyte(priv, SSD1306_SETCOLL(SSD1306_DEV_XOFFSET)); ssd1306_sendbyte(priv, SSD1306_SETCOLH(0)); /* Set the page address */ ssd1306_sendbyte(priv, SSD1306_PAGEADDR(page)); /* Select data transfer */ ssd1306_cmddata(priv, false); /* Transfer one page of the selected color */ ssd1306_sendblk(priv, &priv->fb[page * SSD1306_DEV_XRES], SSD1306_DEV_XRES); } /* De-select and unlock the device */ ssd1306_select(priv, false); }
static int ssd1306_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) { struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev; unsigned int scaled; lcdvdbg("contrast: %d\n", contrast); DEBUGASSERT(priv); /* Verify the contrast value */ #ifdef CONFIG_DEBUG if (contrast > CONFIG_LCD_MAXCONTRAST) { return -EINVAL; } #endif /* Scale contrast: newcontrast = 255 * contrast / CONFIG_LCD_MAXCONTRAST * Where contrast is in the range {1,255} */ #if CONFIG_LCD_MAXCONTRAST != 255 scaled = ((contrast << 8) - 1) / CONFIG_LCD_MAXCONTRAST; #else scaled = contrast; #endif /* Lock and select device */ ssd1306_select(priv, true); /* Select command transfer */ ssd1306_cmddata(priv, true); /* Set the contrast */ (void)ssd1306_sendbyte(priv, SSD1306_CONTRAST_MODE); /* Set contrast control register */ (void)ssd1306_sendbyte(priv, SSD1306_CONTRAST(scaled)); /* Data 1: Set 1 of 256 contrast steps */ priv->contrast = contrast; /* De-select and unlock the device */ ssd1306_select(priv, false); return OK; }
unsigned char ssd1306_data(unsigned char data) { unsigned char buf[2]; buf[0] = 0x40; // [7] : continuation bit // [6] : data / command selection bit buf[1] = data; ssd1306_select(); return HalI2CWrite(sizeof(buf), buf); }
FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev, unsigned int devno) #endif { FAR struct ssd1306_dev_s *priv = &g_oleddev; lcdvdbg("Initializing\n"); DEBUGASSERT(spi && devno == 0); #ifdef CONFIG_LCD_SSD1306_SPI priv->spi = dev; /* Configure the SPI */ ssd1306_configspi(priv->spi); #else /* Remember the I2C configuration */ priv->i2c = dev; priv->addr = CONFIG_SSD1306_I2CADDR; #endif /* Lock and select device */ ssd1306_select(priv, true); /* Select command transfer */ ssd1306_cmddata(priv, true); /* Configure OLED SPI or I/O, must be delayed 1-10ms */ up_mdelay(5); /* Configure the device */ ssd1306_sendbyte(priv, SSD1306_DISPOFF); /* Display off 0xae */ ssd1306_sendbyte(priv, SSD1306_SETCOLL(0)); /* Set lower column address 0x00 */ ssd1306_sendbyte(priv, SSD1306_SETCOLH(0)); /* Set higher column address 0x10 */ ssd1306_sendbyte(priv, SSD1306_STARTLINE(0)); /* Set display start line 0x40 */ //ssd1306_sendbyte(priv, SSD1306_PAGEADDR(0)); /* Set page address (Can ignore) */ ssd1306_sendbyte(priv, SSD1306_CONTRAST_MODE); /* Contrast control 0x81 */ ssd1306_sendbyte(priv, SSD1306_CONTRAST(SSD1306_DEV_CONTRAST)); /* Default contrast 0xCF */ ssd1306_sendbyte(priv, SSD1306_REMAPPLEFT); /* Set segment remap left 95 to 0 | 0xa1 */ //ssd1306_sendbyte(priv, SSD1306_EDISPOFF); /* Normal display off 0xa4 (Can ignore) */ ssd1306_sendbyte(priv, SSD1306_NORMAL); /* Normal (un-reversed) display mode 0xa6 */ ssd1306_sendbyte(priv, SSD1306_MRATIO_MODE); /* Multiplex ratio 0xa8 */ ssd1306_sendbyte(priv, SSD1306_MRATIO(SSD1306_DEV_DUTY)); /* Duty = 1/64 or 1/32 */ //ssd1306_sendbyte(priv, SSD1306_SCANTOCOM0); /* Com scan direction: Scan from COM[n-1] to COM[0] (Can ignore) */ ssd1306_sendbyte(priv, SSD1306_DISPOFFS_MODE); /* Set display offset 0xd3 */ ssd1306_sendbyte(priv, SSD1306_DISPOFFS(0)); ssd1306_sendbyte(priv, SSD1306_CLKDIV_SET); /* Set clock divider 0xd5 */ ssd1306_sendbyte(priv, SSD1306_CLKDIV(8, 0)); /* 0x80 */ ssd1306_sendbyte(priv, SSD1306_CHRGPER_SET); /* Set pre-charge period 0xd9 */ ssd1306_sendbyte(priv, SSD1306_CHRGPER(0x0f, 1)); /* 0xf1 or 0x22 Enhanced mode */ ssd1306_sendbyte(priv, SSD1306_CMNPAD_CONFIG); /* Set common pads / set com pins hardware configuration 0xda */ ssd1306_sendbyte(priv, SSD1306_CMNPAD(SSD1306_DEV_CMNPAD)); /* 0x12 or 0x02 */ ssd1306_sendbyte(priv, SSD1306_VCOM_SET); /* set vcomh 0xdb */ ssd1306_sendbyte(priv, SSD1306_VCOM(0x40)); ssd1306_sendbyte(priv, SSD1306_CHRPUMP_SET); /* Set Charge Pump enable/disable 0x8d ssd1306 */ ssd1306_sendbyte(priv, SSD1306_CHRPUMP_ON); /* 0x14 close 0x10 */ //ssd1306_sendbyte(priv, SSD1306_DCDC_MODE); /* DC/DC control mode: on (SSD1306 Not supported) */ //ssd1306_sendbyte(priv, SSD1306_DCDC_ON); ssd1306_sendbyte(priv, SSD1306_DISPON); /* Display ON 0xaf */ /* De-select and unlock the device */ ssd1306_select(priv, false); /* Clear the display */ up_mdelay(100); ssd1306_fill(&priv->dev, SSD1306_Y1_BLACK); return &priv->dev; }
static int ssd1306_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, size_t npixels) { /* Because of this line of code, we will only be able to support a single UG device */ FAR struct ssd1306_dev_s *priv = (FAR struct ssd1306_dev_s *)&g_oleddev; FAR uint8_t *fbptr; FAR uint8_t *ptr; uint8_t devcol; uint8_t fbmask; uint8_t page; uint8_t usrmask; int pixlen; uint8_t i; lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); DEBUGASSERT(buffer); /* Clip the run to the display */ pixlen = npixels; if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)SSD1306_DEV_XRES) { pixlen = (int)SSD1306_DEV_XRES - (int)col; } /* Verify that some portion of the run remains on the display */ if (pixlen <= 0 || row > SSD1306_DEV_YRES) { return OK; } /* Perform coordinate conversion for reverse landscape mode. * If the rows are reversed then rows are are a mirror reflection of * top to bottom. */ #ifdef SSD1306_DEV_REVERSEY row = (SSD1306_DEV_YRES-1) - row; #endif /* If the column is switched then the start of the run is the mirror of * the end of the run. * * col+pixlen-1 * col | * 0 | | XRES * . S>>>>>>E . * . E<<<<<<S . * | | * | `-(XRES-1)-col * ` (XRES-1)-col-(pixlen-1) */ #ifdef SSD1306_DEV_REVERSEX col = (SSD1306_DEV_XRES-1) - col; col -= (pixlen - 1); #endif /* Get the page number. The range of 64 lines is divided up into eight * pages of 8 lines each. */ page = row >> 3; /* Update the shadow frame buffer memory. First determine the pixel * position in the frame buffer memory. Pixels are organized like * this: * * --------+---+---+---+---+-...-+-----+ * Segment | 0 | 1 | 2 | 3 | ... | 131 | * --------+---+---+---+---+-...-+-----+ * D0 | | X | | | | | * D1 | | X | | | | | * D2 | | X | | | | | * D3 | | X | | | | | * D4 | | X | | | | | * D5 | | X | | | | | * D6 | | X | | | | | * D7 | | X | | | | | * --------+---+---+---+---+-...-+-----+ * * So, in order to draw a white, horizontal line, at row 45. we * would have to modify all of the bytes in page 45/8 = 5. We * would have to set bit 45%8 = 5 in every byte in the page. */ fbmask = 1 << (row & 7); fbptr = &priv->fb[page * SSD1306_DEV_XRES + col]; #ifdef SSD1306_DEV_REVERSEX ptr = fbptr + (pixlen - 1); #else ptr = fbptr; #endif #ifdef CONFIG_NX_PACKEDMSFIRST usrmask = MS_BIT; #else usrmask = LS_BIT; #endif for (i = 0; i < pixlen; i++) { /* Set or clear the corresponding bit */ #ifdef SSD1306_DEV_REVERSEX if ((*buffer & usrmask) != 0) { *ptr-- |= fbmask; } else { *ptr-- &= ~fbmask; } #else if ((*buffer & usrmask) != 0) { *ptr++ |= fbmask; } else { *ptr++ &= ~fbmask; } #endif /* Inc/Decrement to the next source pixel */ #ifdef CONFIG_NX_PACKEDMSFIRST if (usrmask == LS_BIT) { buffer++; usrmask = MS_BIT; } else { usrmask >>= 1; } #else if (usrmask == MS_BIT) { buffer++; usrmask = LS_BIT; } else { usrmask <<= 1; } #endif } /* Offset the column position to account for smaller horizontal * display range. */ devcol = col + SSD1306_DEV_XOFFSET; /* Lock and select device */ ssd1306_select(priv, true); /* Select command transfer */ ssd1306_cmddata(priv, true); /* Set the starting position for the run */ /* Set the column address to the XOFFSET value */ ssd1306_sendbyte(priv, SSD1306_SETCOLL(devcol & 0x0f)); ssd1306_sendbyte(priv, SSD1306_SETCOLH(devcol >> 4)); /* Set the page address */ ssd1306_sendbyte(priv, SSD1306_PAGEADDR(page)); /* Select data transfer */ ssd1306_cmddata(priv, false); /* Then transfer all of the data */ ssd1306_sendblk(priv, fbptr, pixlen); /* De-select and unlock the device */ ssd1306_select(priv, false); return OK; }