2016-12-05 14:56:09 +01:00
|
|
|
#include "st7735.h"
|
|
|
|
|
|
|
|
#include <util/delay.h>
|
|
|
|
#include <avr/pgmspace.h>
|
|
|
|
|
|
|
|
#include "spi.h"
|
|
|
|
#include "st7735initcmds.h"
|
|
|
|
|
2016-12-06 19:51:07 +01:00
|
|
|
uint8_t st7735_row_start = 0;
|
|
|
|
uint8_t st7735_column_start = 0;
|
|
|
|
uint8_t st7735_width = 0;
|
|
|
|
uint8_t st7735_height = 0;
|
|
|
|
enum ST7735_ORIENTATION st7735_orientation = ST7735_LANDSCAPE;
|
2016-12-05 14:56:09 +01:00
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
static inline void st7735_set_rs(void) {
|
2016-12-06 19:51:07 +01:00
|
|
|
PORTD |= (1 << PD6);
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
static inline void st7735_unset_rs(void) {
|
2016-12-06 19:51:07 +01:00
|
|
|
PORTD &= ~(1 << PD6);
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
static inline void st7735_set_rst(void) {
|
2016-12-06 19:51:07 +01:00
|
|
|
PORTD |= (1 << PD7);
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
static inline void st7735_unset_rst(void) {
|
2016-12-06 19:51:07 +01:00
|
|
|
PORTD &= ~(1 << PD7);
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void st7735_write_cmd(enum ST7735_COMMANDS cmd) {
|
|
|
|
st7735_unset_rs();
|
|
|
|
|
|
|
|
spi_unset_cs();
|
|
|
|
spi_write(cmd);
|
|
|
|
spi_set_cs();
|
|
|
|
}
|
|
|
|
|
2016-12-05 16:33:58 +01:00
|
|
|
static inline void st7735_write_data(uint8_t data) {
|
2016-12-05 14:56:09 +01:00
|
|
|
st7735_set_rs();
|
|
|
|
|
|
|
|
spi_unset_cs();
|
2016-12-05 16:33:58 +01:00
|
|
|
spi_write(data);
|
2016-12-05 14:56:09 +01:00
|
|
|
spi_set_cs();
|
|
|
|
}
|
|
|
|
|
2016-12-05 23:18:40 +01:00
|
|
|
static inline void st7735_write_color(uint16_t color) {
|
|
|
|
spi_write(color >> 8);
|
|
|
|
spi_write(color);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
static inline void st7735_reset(void) {
|
2016-12-05 14:56:09 +01:00
|
|
|
spi_unset_cs();
|
|
|
|
st7735_set_rst();
|
|
|
|
_delay_ms(500);
|
|
|
|
st7735_unset_rst();
|
|
|
|
_delay_ms(500);
|
|
|
|
st7735_set_rst();
|
|
|
|
_delay_ms(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void st7735_run_command_list(const uint8_t *addr) {
|
|
|
|
uint8_t cmd_count, arg_count, has_delay;
|
|
|
|
|
|
|
|
cmd_count = pgm_read_byte(addr++); // Number of commands to follow
|
|
|
|
for(uint8_t cmd_pos = 0; cmd_pos < cmd_count; cmd_pos++) {
|
|
|
|
st7735_write_cmd(pgm_read_byte(addr++)); // Read, send command
|
|
|
|
arg_count = pgm_read_byte(addr++); // Number of args to follow
|
|
|
|
has_delay = arg_count & DELAY_FLAG; // If set, delay follows args
|
|
|
|
arg_count &= ~DELAY_FLAG; // Number of args
|
|
|
|
for(uint8_t arg_pos = 0; arg_pos < arg_count; arg_pos++) { // For each argument...
|
|
|
|
st7735_write_data(pgm_read_byte(addr++)); // Read, send argument
|
|
|
|
}
|
|
|
|
|
|
|
|
if(has_delay) {
|
|
|
|
uint8_t ms;
|
|
|
|
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
|
|
|
|
if(ms == 255) { // If 255, delay for 500 ms
|
|
|
|
_delay_ms(500);
|
|
|
|
}
|
|
|
|
else {
|
2016-12-06 19:51:07 +01:00
|
|
|
for(int i = 0; i < ms; i += 5) {
|
|
|
|
_delay_ms(5);
|
|
|
|
}
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void st7735_init() {
|
|
|
|
// Set rs and rst output
|
2016-12-06 19:51:07 +01:00
|
|
|
DDRD |= (1 << PD6) | (1 << PD7);
|
2016-12-05 14:56:09 +01:00
|
|
|
|
|
|
|
st7735_reset();
|
|
|
|
|
|
|
|
switch(st7735_type) {
|
|
|
|
case ST7735_BLUE:
|
|
|
|
st7735_run_command_list(st7735_blue_init);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST7735_RED_18_GREENTAB:
|
|
|
|
st7735_run_command_list(st7735_red_init1);
|
|
|
|
st7735_run_command_list(st7735_red_init_green2);
|
|
|
|
st7735_run_command_list(st7735_red_init3);
|
|
|
|
st7735_column_start = 2;
|
|
|
|
st7735_row_start = 1;
|
2016-12-06 19:51:07 +01:00
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
st7735_height = st7735_default_height_18;
|
2016-12-05 14:56:09 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ST7735_RED_18_REDTAB:
|
|
|
|
st7735_run_command_list(st7735_red_init1);
|
|
|
|
st7735_run_command_list(st7735_red_init_red2);
|
|
|
|
st7735_run_command_list(st7735_red_init3);
|
2016-12-06 19:51:07 +01:00
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
st7735_height = st7735_default_height_18;
|
2016-12-05 14:56:09 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ST7735_RED_18_BLACKTAB:
|
|
|
|
st7735_run_command_list(st7735_red_init1);
|
|
|
|
st7735_run_command_list(st7735_red_init_red2);
|
|
|
|
st7735_run_command_list(st7735_red_init3);
|
|
|
|
// Change MADCTL color filter for black
|
|
|
|
st7735_write_cmd(ST7735_MADCTL);
|
|
|
|
st7735_write_data(0xC0);
|
2016-12-06 19:51:07 +01:00
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
st7735_height = st7735_default_height_18;
|
2016-12-05 14:56:09 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ST7735_RED144_GREENTAB:
|
|
|
|
st7735_run_command_list(st7735_red_init1);
|
|
|
|
st7735_run_command_list(st7735_red_init_green1442);
|
|
|
|
st7735_run_command_list(st7735_red_init3);
|
2016-12-05 16:33:58 +01:00
|
|
|
st7735_height = st7735_default_height_144;
|
2016-12-05 14:56:09 +01:00
|
|
|
st7735_column_start = 2;
|
|
|
|
st7735_row_start = 3;
|
2016-12-06 19:51:07 +01:00
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
st7735_height = st7735_default_height_144;
|
2016-12-05 14:56:09 +01:00
|
|
|
break;
|
|
|
|
}
|
2016-12-05 16:33:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum ST7735_MADCTL_ARGS {
|
|
|
|
MADCTL_MY = 0x80, // Mirror Y
|
|
|
|
MADCTL_MX = 0x40, // Mirrror x
|
|
|
|
MADCTL_MV = 0x20, // Swap XY
|
|
|
|
MADCTL_ML = 0x10, // Scan address order
|
|
|
|
MADCTL_RGB = 0x00,
|
|
|
|
MADCTL_BGR = 0x08,
|
|
|
|
MADCTL_MH = 0x04 // Horizontal scan oder
|
|
|
|
};
|
|
|
|
|
|
|
|
void st7735_set_orientation(enum ST7735_ORIENTATION orientation) {
|
|
|
|
st7735_write_cmd(ST7735_MADCTL);
|
|
|
|
|
|
|
|
switch (orientation) {
|
2016-12-06 19:51:07 +01:00
|
|
|
case ST7735_PORTRAIT:
|
2016-12-05 16:33:58 +01:00
|
|
|
if(st7735_type == ST7735_RED_18_BLACKTAB) {
|
|
|
|
st7735_write_data(MADCTL_MX | MADCTL_MY | MADCTL_RGB);
|
|
|
|
} else {
|
|
|
|
st7735_write_data(MADCTL_MX | MADCTL_MY | MADCTL_BGR);
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
|
|
|
|
if(st7735_type == ST7735_RED144_GREENTAB) {
|
|
|
|
st7735_height = st7735_default_height_144;
|
|
|
|
} else {
|
|
|
|
st7735_height = st7735_default_height_18;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2016-12-06 19:51:07 +01:00
|
|
|
case ST7735_LANDSCAPE:
|
2016-12-05 16:33:58 +01:00
|
|
|
if(st7735_type == ST7735_RED_18_BLACKTAB) {
|
|
|
|
st7735_write_data(MADCTL_MY | MADCTL_MV | MADCTL_RGB);
|
|
|
|
} else {
|
|
|
|
st7735_write_data(MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(st7735_type == ST7735_RED144_GREENTAB) {
|
|
|
|
st7735_width = st7735_default_height_144;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
st7735_width = st7735_default_height_18;
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_height = st7735_default_width;
|
|
|
|
break;
|
|
|
|
|
2016-12-06 19:51:07 +01:00
|
|
|
case ST7735_PORTRAIT_INV:
|
2016-12-05 16:33:58 +01:00
|
|
|
if (st7735_type == ST7735_RED_18_BLACKTAB) {
|
|
|
|
st7735_write_data(MADCTL_RGB);
|
|
|
|
} else {
|
|
|
|
st7735_write_data(MADCTL_BGR);
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_width = st7735_default_width;
|
|
|
|
|
|
|
|
if(st7735_type == ST7735_RED144_GREENTAB) {
|
|
|
|
st7735_height = st7735_default_height_144;
|
|
|
|
} else {
|
|
|
|
st7735_height = st7735_default_height_18;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-12-06 19:51:07 +01:00
|
|
|
case ST7735_LANDSCAPE_INV:
|
2016-12-05 16:33:58 +01:00
|
|
|
if (st7735_type == ST7735_RED_18_BLACKTAB) {
|
|
|
|
st7735_write_data(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
|
|
|
|
} else {
|
|
|
|
st7735_write_data(MADCTL_MX | MADCTL_MV | MADCTL_BGR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (st7735_type == ST7735_RED144_GREENTAB) {
|
|
|
|
st7735_width = st7735_default_height_144;
|
|
|
|
} else {
|
|
|
|
st7735_width = st7735_default_height_18;
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_height = st7735_default_width;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void st7735_set_addr_win(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
|
|
|
|
st7735_write_cmd(ST7735_CASET); // Column addr set
|
|
|
|
st7735_write_data(0x00);
|
2016-12-06 19:51:07 +01:00
|
|
|
st7735_write_data(x0 + st7735_column_start); // XSTART
|
2016-12-05 16:33:58 +01:00
|
|
|
st7735_write_data(0x00);
|
|
|
|
st7735_write_data(x1 + st7735_column_start); // XEND
|
|
|
|
|
|
|
|
st7735_write_cmd(ST7735_RASET); // Row addr set
|
|
|
|
st7735_write_data(0x00);
|
|
|
|
st7735_write_data(y0 + st7735_row_start); // YSTART
|
|
|
|
st7735_write_data(0x00);
|
|
|
|
st7735_write_data(y1 + st7735_row_start); // YEND
|
|
|
|
|
|
|
|
st7735_write_cmd(ST7735_RAMWR); // write to RAM
|
|
|
|
}
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
void st7735_draw_pixel(uint8_t x, uint8_t y, uint16_t color) {
|
2016-12-05 23:18:40 +01:00
|
|
|
if(x < 0 || x >= st7735_width || y < 0 || y >= st7735_height){
|
2016-12-05 16:33:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-12-05 23:18:40 +01:00
|
|
|
|
2016-12-05 16:33:58 +01:00
|
|
|
st7735_set_addr_win(x, y, x+1, y+1);
|
|
|
|
|
|
|
|
st7735_set_rs();
|
|
|
|
spi_unset_cs();
|
2016-12-05 14:56:09 +01:00
|
|
|
|
2016-12-05 23:18:40 +01:00
|
|
|
st7735_write_color(color);
|
2016-12-05 14:56:09 +01:00
|
|
|
|
2016-12-05 16:33:58 +01:00
|
|
|
spi_set_cs();
|
2016-12-05 14:56:09 +01:00
|
|
|
}
|
2016-12-05 23:18:40 +01:00
|
|
|
|
|
|
|
|
2016-12-07 00:26:43 +01:00
|
|
|
void st7735_fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) {
|
2016-12-05 23:18:40 +01:00
|
|
|
if(x >= st7735_width || y >= st7735_height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((x + w - 1) >= st7735_width) {
|
|
|
|
w = st7735_width - x;
|
|
|
|
}
|
|
|
|
if((y + h - 1) >= st7735_height) {
|
|
|
|
h = st7735_height - y;
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_set_addr_win(x, y, x + w - 1, y + h - 1);
|
|
|
|
|
|
|
|
st7735_set_rs();
|
|
|
|
spi_unset_cs();
|
|
|
|
|
|
|
|
for(uint8_t i = 0; i < h; i++) {
|
|
|
|
for(uint8_t j = 0; j < w; j++) {
|
|
|
|
st7735_write_color(color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
spi_set_cs();
|
|
|
|
}
|
2016-12-07 00:26:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
void st7735_draw_bitmap(uint8_t x, uint8_t y, PGM_P bitmap) {
|
|
|
|
if(x >= st7735_width || y >= st7735_height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t w = pgm_read_word(bitmap);
|
|
|
|
bitmap += 2;
|
|
|
|
uint8_t h = pgm_read_word(bitmap);
|
|
|
|
bitmap += 2;
|
|
|
|
|
|
|
|
if((x + w - 1) >= st7735_width) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if((y + h - 1) >= st7735_height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_set_addr_win(x, y, x + w - 1, y + h - 1);
|
|
|
|
|
|
|
|
st7735_set_rs();
|
|
|
|
spi_unset_cs();
|
|
|
|
|
|
|
|
for(uint8_t i = 0; i < h; i++) {
|
|
|
|
for(uint8_t j = 0; j < w; j++) {
|
|
|
|
uint16_t color = pgm_read_word(bitmap);
|
|
|
|
st7735_write_color(color);
|
|
|
|
bitmap += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
spi_set_cs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void st7735_draw_mono_bitmap(uint8_t x, uint8_t y, PGM_P bitmap, uint16_t color_set, uint16_t color_unset) {
|
|
|
|
uint8_t w = pgm_read_byte(bitmap++);
|
|
|
|
uint8_t h = pgm_read_byte(bitmap++);
|
|
|
|
|
|
|
|
if(x >= st7735_width || y >= st7735_height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((x + w - 1) >= st7735_width) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if((y + h - 1) >= st7735_height) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
st7735_set_addr_win(x, y, x + w - 1, y + h - 1);
|
|
|
|
|
|
|
|
st7735_set_rs();
|
|
|
|
spi_unset_cs();
|
|
|
|
|
|
|
|
uint16_t bit_pos = 0;
|
|
|
|
uint8_t byte = 0;
|
|
|
|
for(uint8_t i = 0; i < h; i++) {
|
|
|
|
for(uint8_t j = 0; j < w; j++) {
|
|
|
|
if(bit_pos % 8 == 0) {
|
|
|
|
byte = pgm_read_byte(bitmap++);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(byte & (1 << (bit_pos % 8))) {
|
|
|
|
st7735_write_color(color_set);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
st7735_write_color(color_unset);
|
|
|
|
}
|
|
|
|
bit_pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
spi_set_cs();
|
|
|
|
|
|
|
|
}
|