/* * SSD1306_oled.c * * Created on: Apr 5, 2021 * Author: bartool */ #include "main.h" #include "SSD1306_oled.h" #include "string.h" I2C_HandleTypeDef *oled_i2c; #ifndef TEST static uint8_t buffer_oled[SSD1306_BUF_SIZE]; #else uint8_t buffer_oled[SSD1306_BUF_SIZE]; #endif void SSD1306_SendCommand(uint8_t cmd) { HAL_I2C_Mem_Write(oled_i2c, SSD1306_ADDRESS<<1, 0x00, 1, &cmd, 1, SSD1306_TIMEOUT); } void SSD1306_SendData(uint8_t *data, uint16_t size) { HAL_I2C_Mem_Write(oled_i2c, SSD1306_ADDRESS<<1, 0x40, 1, data, size, SSD1306_TIMEOUT); } void SSD1306_clear(uint8_t color) { switch(color) { case WHITE: memset(buffer_oled, 0xFF, SSD1306_BUF_SIZE); break; case BLACK: memset(buffer_oled, 0x00, SSD1306_BUF_SIZE); break; } } void SSD1306_display_all(void) { SSD1306_SendCommand(SSD1306_PAGEADDR); SSD1306_SendCommand(0); SSD1306_SendCommand(0xFF); SSD1306_SendCommand(SSD1306_COLUMNADDR); SSD1306_SendCommand(0); SSD1306_SendCommand(SSD1306_LCDWIDTH - 1); SSD1306_SendData(buffer_oled, SSD1306_BUF_SIZE); } uint8_t SSD1306_display_page(void) { static uint8_t page = 0; SSD1306_SendCommand(SSD1306_PAGEADDR); SSD1306_SendCommand(page); SSD1306_SendCommand(page); SSD1306_SendCommand(SSD1306_COLUMNADDR); SSD1306_SendCommand(0); SSD1306_SendCommand(SSD1306_LCDWIDTH - 1); SSD1306_SendData(buffer_oled + (page * SSD1306_LCDWIDTH), SSD1306_LCDWIDTH); // page++; if (++page > 7) { page = 0; return SSD1306_SENDALL; } else { return SSD1306_SENDPAGE; } } void SSD1306_Init(I2C_HandleTypeDef *i2c) { oled_i2c = i2c; SSD1306_SendCommand(SSD1306_DISPLAYOFF); SSD1306_SendCommand(SSD1306_SETDISPLAYCLOCKDIV); SSD1306_SendCommand(0x80); SSD1306_SendCommand(SSD1306_SETMULTIPLEX); SSD1306_SendCommand(SSD1306_LCDHEIGHT - 1); SSD1306_SendCommand(SSD1306_SETDISPLAYOFFSET); SSD1306_SendCommand(0x0); SSD1306_SendCommand(SSD1306_SETSTARTLINE | 0x0); SSD1306_SendCommand(SSD1306_CHARGEPUMP); SSD1306_SendCommand(0x14); SSD1306_SendCommand(SSD1306_MEMORYMODE); SSD1306_SendCommand(0x00); SSD1306_SendCommand(SSD1306_SEGREMAP | 0x1); SSD1306_SendCommand(SSD1306_COMSCANDEC); uint8_t comPins = 0x02; uint8_t contrast = 0x8F; if ((SSD1306_LCDWIDTH == 128) && (SSD1306_LCDHEIGHT == 32)) { comPins = 0x02; contrast = 0x0F; } else if ((SSD1306_LCDWIDTH == 128) && (SSD1306_LCDHEIGHT == 64)) { comPins = 0x12; contrast = 0xCF; } else if ((SSD1306_LCDWIDTH == 96) && (SSD1306_LCDHEIGHT == 16)) { comPins = 0x2; // ada x12 contrast = 0xAF; } SSD1306_SendCommand(SSD1306_SETCOMPINS); SSD1306_SendCommand(comPins); SSD1306_SendCommand(SSD1306_SETCONTRAST); SSD1306_SendCommand(contrast); SSD1306_SendCommand(SSD1306_SETPRECHARGE); // 0xd9 SSD1306_SendCommand(0xF1); SSD1306_SendCommand(SSD1306_SETVCOMDETECT); SSD1306_SendCommand(0x40); SSD1306_SendCommand(SSD1306_DISPLAYALLON_RESUME); SSD1306_SendCommand(SSD1306_NORMALDISPLAY); SSD1306_SendCommand(SSD1306_DEACTIVATE_SCROLL); SSD1306_SendCommand(SSD1306_DISPLAYON); } void ssd1306_set_pixel(uint8_t x, uint8_t y, uint8_t bw) { if (x > SSD1306_LCDWIDTH || y > SSD1306_LCDHEIGHT) return; switch (bw) { case WHITE: buffer_oled[(y/8) * SSD1306_LCDWIDTH + x] |= (1<<(y%8)); break; case BLACK: buffer_oled[(y/8) * SSD1306_LCDWIDTH + x] &= ~(1<<(y%8)); break; case INVERSE: buffer_oled[(y/8) * SSD1306_LCDWIDTH + x] ^= (1<<(y%8)); break; } } void ssd1306_write_to_buffer(const uint8_t* data, uint8_t width, uint8_t height, int8_t pos_x, int8_t pos_y) { int8_t max_x, max_y; uint8_t shift_x = 0, temp, row = 0; uint16_t buf_idx = 0, index = 0; // right boundry if (width + pos_x > SSD1306_LCDWIDTH) max_x = SSD1306_LCDWIDTH; else max_x = width + pos_x; // left boundry if (pos_x < 0) { shift_x = pos_x * -1; pos_x = 0; } // bottom boundry if (height + pos_y > SSD1306_LCDHEIGHT) max_y = SSD1306_LCDHEIGHT; else max_y = height + pos_y; max_y = max_y / 8 + (max_y % 8 == 0 ? 0 : 1); // top boundry if (pos_y < 0) { uint8_t abs_pos_y = pos_y * -1; row = abs_pos_y/8 + (abs_pos_y % 8 == 0 ? 0 : 1); pos_y = (8 - abs_pos_y%8)%8; } uint8_t shift = pos_y % 8; uint8_t mask_lsb = 0xFF >> (8 - shift); uint8_t mask_msb = 0xFF << shift; for (uint8_t y = pos_y / 8; y < max_y; y++) { index = width * row + shift_x; for (uint8_t x = pos_x; x < max_x; x++, index++) { buf_idx = y * SSD1306_LCDWIDTH + x; temp = buffer_oled[buf_idx]; if (index < width * ((height + 7) / 8)) temp = data[index] << shift | (temp & mask_lsb); // else if (height%8 != 0) // mask_msb = 0xFF << ((pos_y + height)%8); if (shift != 0 && index >= width) temp = data[index - width] >> (8 - shift) | (temp & mask_msb); buffer_oled[buf_idx] = temp; } row++; } } void ssd1306_clear_buffer (uint8_t width, uint8_t height, uint8_t pos_x, uint8_t pos_y) { uint16_t max_x, max_y, index = 0, temp, row = 0; if (width + pos_x > SSD1306_LCDWIDTH) max_x = SSD1306_LCDWIDTH; else max_x = width + pos_x; if (height + pos_y > SSD1306_LCDHEIGHT) max_y = SSD1306_LCDHEIGHT; else max_y = height + pos_y; max_y = max_y / 8 + (max_y % 8 == 0 ? 0 : 1); uint8_t shift = pos_y % 8; uint8_t mask_right = 0xFF >> shift; uint8_t mask_left = 0xFF << (8 - shift); for (uint8_t y = pos_y / 8; y < max_y; y++, index = width * row) { for (uint8_t x = pos_x; x < max_x; x++, index++) { temp = buffer_oled[y * SSD1306_LCDWIDTH + x]; if (index < width * height/8) temp &= mask_left; if (index >= width) temp &= mask_right; buffer_oled[y * SSD1306_LCDWIDTH + x] = temp; } row++; } } // //void next(void) //{ // uint16_t tmp; // for(uint8_t col = col_start; col < col_end; col++, bitmap_col++) // { // tmp = buffer_oled[page_start * SSD1306_LCDWIDTH + col] & (0xFF >> (8 - pos_y%8)); // // for( uint8_t page = page_start; page < page_end; page++, bitmap_row++ ) // { // bitmap_idx = bitmap_width * bitmap_row + bitmap_col; // // if (bitmap_idx < bitmap_max_idx) // { //// mask_buf = 0xFF; // // pixels_left = bitmap_height - bitmap_row * 8; //poprawic // if (pixels_left < 8) // { // mask_buf = 0xFF >> pixels_left; // } // // tmp &= ~(mask_buf); // mask_buf zeruje tylko to co zostanie nadpisane // tmp |= bitmap[bitmap_idx] << pos_y%8; // mask_data maskuje tylko starsza czesc bajtu // } // // buffer_oled[page * SSD1306_LCDWIDTH + col] = (uint8_t) tmp; // tmp = tmp >> 8; // } // } // // //} // //