/* * DisplayBoardFirmware.c * * Created: 08.01.2019 19:46:33 * Author : julian */ #include #include #include #include // for size_t #define DISPLAY_PORT PORTA #define DISPLAY_PIN PINA #define DISPLAY_DDR DDRA #define DISPLAY_SCL (1<>i)) DISPLAY_PIN_CLEAR(DISPLAY_SDA); else DISPLAY_SET(DISPLAY_SDA); _delay_us(1); DISPLAY_PIN_CLEAR(DISPLAY_SCL); _delay_us(DISPLAY_HALFCLK); DISPLAY_SET(DISPLAY_SCL); _delay_us(DISPLAY_HALFCLK-2); i++; } DISPLAY_PIN_CLEAR(DISPLAY_SDA); _delay_us(DISPLAY_HALFCLK); DISPLAY_PIN_CLEAR(DISPLAY_SCL); _delay_us(DISPLAY_HALFCLK); // look for ACK int result = DISPLAY_PIN & DISPLAY_SDA; DISPLAY_SET(DISPLAY_SCL); // ack means 0 during clk period return result != 0; } int display_ncmd(uint8_t *cmd, uint8_t len) { int result = 1; display_start(); if (display_send(display_addr)) goto fail; uint8_t prefix = 0x80; while(len--) { if (display_send(prefix) || display_send(*cmd)) goto fail; if (len-1) { prefix = 0x00; } ++cmd; } result = 0; fail: display_stop(); return result; } int display_cmd(uint8_t cmd) { return display_ncmd(&cmd, 1); } int display_data_chunk(uint8_t ** data, size_t *len) { int result = 1; uint8_t count = 16; display_start(); if (display_send(display_addr)) { goto fail; } if (display_send(0x40)) goto fail; while(count && *len && !display_send(**data)) { count--; (*len)--; (*data)++; } result = 0; fail: display_stop(); return result; } int display_data(uint8_t * data, size_t len) { int result = 1; while(len && !(result = display_data_chunk(&data, &len))) {} return result; } void display_copy(int x, int y, int w, int h, uint8_t *data, size_t len) { display_cmd(DISPLAY_CMD_COLUMN_ADDR); display_cmd(y); display_cmd(y + h); display_cmd(DISPLAY_CMD_PAGE_ADDR); display_cmd(x + 4*display.current_buffer); display_cmd(x + w + 4*display.current_buffer -1); display_data(data, len); } void display_clear() { static uint8_t chunk[8] = {0xFF}; size_t len = 0; size_t c = 8; display_cmd(DISPLAY_CMD_COLUMN_ADDR); display_cmd(0); display_cmd(127); display_cmd(DISPLAY_CMD_PAGE_ADDR); display_cmd(display.current_buffer*4); display_cmd(display.current_buffer*4+3); uint8_t * current = chunk; while(len < 128*4) { display_start(); display_send(display_addr); display_send(0x40); for (uint8_t i = 0; i < 16; i++) { display_send(0x00); } display_stop(); len += 16; } } #include "font.h" static inline void pgm_memcpy(uint8_t * dest, const uint8_t * src, size_t s) { while(s--) { *dest = pgm_read_byte(src); ++src; ++dest; } } void display_font_copy(char c, int x, int y) { static uint8_t buffer[FONT_HEIGHT*2]; if (c < FONT_START || c > FONT_START + FONT_END) return; int offset = c - FONT_START; uint16_t index = pgm_read_word(Fonttable + offset); uint8_t w = pgm_read_byte(Fonttable + offset +2); uint8_t h = pgm_read_byte(Fonttable + offset +3); const uint8_t * current = Fonttable + index + FONT_END; uint8_t linebuffer = pgm_read_byte(current++); uint8_t count = 8; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { count--; if (!count) { count = 8; linebuffer = pgm_read_byte(current++); } } } // pgm_memcpy((uint8_t*)&glyph_buffer, (const uint8_t*)Glyphtable, sizeof(glyph_buffer)); // pgm_memcpy(buffer, Fonttable + glyph_buffer.index, glyph_buffer.w); // display_copy(x, y, 1, FONT_HEIGHT, buffer, FONT_HEIGHT); } // initializes display // setup parameters for normal operation void display_init() { display.current_buffer = 1; DISPLAY_PIN_CLEAR(DISPLAY_SCL | DISPLAY_SDA); display_cmd(DISPLAY_CMD_ENABLE); display_cmd(DISPLAY_CMD_CLK_DIV); display_cmd(0x80); display_cmd(DISPLAY_CMD_MULTIPLEX); display_cmd(63); display_cmd(DISPLAY_CMD_CHARGEPUMP); display_cmd(0x14); display_cmd(0xDA); display_cmd(0x02); display_cmd(DISPLAY_CMD_LINE_OFFSET); display_cmd(0); display_cmd(DISPLAY_CMD_LINE_START | 0); display_cmd(DISPLAY_CMD_COMM_VOLTAGE_DETECT); display_cmd(0x40); display_cmd(DISPLAY_CMD_ADDR_MODE); display_cmd(0x01); display_cmd(DISPLAY_CMD_SCANMODE_POS); display_cmd(DISPLAY_CMD_TEST); // no testing mode display_clear(); display_cmd(DISPLAY_CMD_ENABLE|1); } void display_swap() { display.current_buffer = !display.current_buffer; display_cmd(DISPLAY_CMD_LINE_START | 32*display.current_buffer); } // TODO: find out what display is capable of void display_write(const char * str) { } // should be called after every change to display content is made // TODO: check if this is possible to implement void display_present() { } /* encoder driver */ typedef enum { ENC_DIR_NONE, ENC_DIR_CW, ENC_DIR_CCW, } encoder_dir_t; struct encoder; typedef void (*encoder_callback_t)(struct encoder * encoder); typedef struct encoder { encoder_dir_t dir; uint16_t velo; int16_t pos; encoder_callback_t callback; } encoder_t; encoder_t encoder; // encoder can only be at the INT0/INT1 lines // maybe pushbutton on pinchange void encoder_init(encoder_t * encoder) { *encoder = (encoder_t){}; // TODO: configure PCINT0 interrupt for direction // TODO: configure PCINT1 interrupt for push button } volatile encoder_dir_t first; #include // turning interrupt ISR(PCINT0_vect) { // find edge type if (first == ENC_DIR_NONE) { first = ENC_DIR_CCW; return; } encoder.dir = first; encoder.pos -= 1; if (encoder.callback) encoder.callback(&encoder); first = ENC_DIR_NONE; } // push interrupt ISR(PCINT1_vect) { // TODO } /* main application */ typedef struct menuitem { struct menuitem * root; const char * text; struct menuitem * children; uint8_t children_count; } menuitem; #include menuitem root = {.root = NULL, .text = NULL, }; int main(void) { //_delay_ms(100); display_init(); uint8_t face[8] = { 0b11111111, 0b11111110, 0b11111100, 0b11111000, 0b11110000, 0b11100000, 0b11000000, 0b10000000, }; for (int j = 0; j< 16; j++) for (int i = 0; i<4; i++) { display_copy(i,j*8, 1,8, face, 8); display_font_copy('a', i,j*8); } display_swap(); /* Replace with your application code */ while (1) { } }