diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f5634bd --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +all : flash + +TARGET:=oled_gol +CH32V003FUN:=../ch32v003fun/ch32v003fun + +include ../ch32v003fun/ch32v003fun/ch32v003fun.mk + +flash : build + gdb-multiarch -x gdbinit -ex 'load' -ex 'detach' -ex 'quit' $(TARGET).elf +clean : cv_clean + diff --git a/gol/funconfig.h b/funconfig.h similarity index 100% rename from gol/funconfig.h rename to funconfig.h diff --git a/gol/Makefile b/gol/Makefile deleted file mode 100644 index 69e3dfd..0000000 --- a/gol/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all : flash - -TARGET:=gol -CH32V003FUN:=../../ch32v003fun/ch32v003fun - -include ../../ch32v003fun/ch32v003fun/ch32v003fun.mk - -flash : build - gdb-multiarch -x ../gdbinit -ex 'load' -ex 'detach' -ex 'quit' $(TARGET).elf -clean : cv_clean - diff --git a/gol/gol.c b/oled_gol.c similarity index 100% rename from gol/gol.c rename to oled_gol.c diff --git a/soweli/Makefile b/soweli/Makefile deleted file mode 100644 index 799aab5..0000000 --- a/soweli/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all : flash - -TARGET:=soweli -CH32V003FUN:=../../ch32v003fun/ch32v003fun - -include ../../ch32v003fun/ch32v003fun/ch32v003fun.mk - -flash : build - gdb-multiarch -x ../gdbinit -ex 'load' -ex 'detach' -ex 'quit' $(TARGET).elf -clean : cv_clean - diff --git a/soweli/data.h b/soweli/data.h deleted file mode 100644 index 4655117..0000000 --- a/soweli/data.h +++ /dev/null @@ -1,80 +0,0 @@ -#define OBSTACLE_TYPES 5 - -const unsigned char soweli_a[8] = { - 0b01111111, - 0b10000000, - 0b10101000, - 0b10101000, - 0b10000000, - 0b01010101, - 0b01010000, - 0b01010000, -}; - -const unsigned char soweli_b[8] = { - 0b01111111, - 0b10000000, - 0b10101000, - 0b10101000, - 0b10000000, - 0b01010101, - 0b00000101, - 0b00000101, -}; - -const unsigned char obstacle_sprites[OBSTACLE_TYPES][8] = { - { - 0b00000000, - 0b00000000, - 0b01010101, - 0b01010100, - 0b11111110, - 0b01010100, - 0b01010101, - 0b00000000, - }, - { - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - - 0b00111100, - 0b01100110, - 0b11000011, - 0b10000001, - }, - { - 0b00000000, - 0b00000000, - 0b00000000, - 0b00000000, - 0b11111111, - 0b01000010, - 0b01000010, - 0b01000010, - }, - { - 0b01000010, - 0b00011000, - 0b00100100, - 0b01111110, - 0b00100100, - 0b01111110, - 0b00100100, - 0b00011000, - }, - { - 0b00000000, - 0b00000000, - 0b00000000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00011000, - 0b00111100, - }, -}; - -const unsigned char obstacle_heights[OBSTACLE_TYPES] = {6, 4, 4, 8, 5}; -const unsigned char obstacle_widths[OBSTACLE_TYPES] = {8, 8, 8, 7, 5}; \ No newline at end of file diff --git a/soweli/funconfig.h b/soweli/funconfig.h deleted file mode 100644 index 998cf76..0000000 --- a/soweli/funconfig.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _FUNCONFIG_H -#define _FUNCONFIG_H - -#define CH32V003 1 - -#endif - diff --git a/soweli/soweli.c b/soweli/soweli.c deleted file mode 100644 index 3e1cad1..0000000 --- a/soweli/soweli.c +++ /dev/null @@ -1,255 +0,0 @@ - -#define SSD1306_128X32 -#include "ch32v003fun.h" -#include -#include "ssd1306_i2c.h" -#include "ssd1306.h" - -#include "data.h" - -#define PIN_LED PC4 -#define PIN_BTN PC7 - -// #define JUMP_POWER 48 -// #define GRAVITY 3 -#define JUMP_POWER 36 -#define GRAVITY 2 -#define SCROLL_SPEED 1 -#define FRAME_DELAY 1000 / 60 -#define SCORE_DIGITS 4 -#define RUN_ANIM_SPEED 4 -#define PLAYER_X 16 -#define Y_PRECISION 4 - -u32 time = 0; -u16 score = 0; -u16 highscore = 0; -s16 player_y = 0; -s16 player_vel = 0; -#define MAX_OBSTACLES 16 -u8 obstacle_positions[MAX_OBSTACLES]; -u8 obstacle_types[MAX_OBSTACLES]; // todo -u8 obstacle_count = 0; -u8 is_running = 1; -u8 time_to_obstacle = 0; - -uint32_t lfsr = 1; // PRNG state - -u8 rand8(); -void update(); -void render(); -void restart(); - -int main() -{ - SystemInit(); - funGpioInitAll(); - funPinMode(PIN_LED, GPIO_CFGLR_OUT_10Mhz_PP); - funPinMode(PIN_BTN, GPIO_CFGLR_IN_PUPD); - - ssd1306_i2c_init(); - ssd1306_init(); - - restart(); - while (1) - { - ssd1306_refresh(); - - if (is_running) - update(); - render(); - time += 1; - - if (funDigitalRead(PIN_BTN)) - { - if (is_running) - { - if (player_y == 0 && player_vel == 0) - { - player_vel = JUMP_POWER; - } - } - else - restart(); - } - if (is_running == 0) - { - funDigitalWrite(PIN_LED, (time >> 2) & 1); - } - else - { - funDigitalWrite(PIN_LED, FUN_LOW); - } - Delay_Ms(FRAME_DELAY); - } -} - -void restart() -{ - lfsr = SysTick->CNT; - is_running = 1; - player_vel = 0; - player_y = 0; - obstacle_count = 0; - time_to_obstacle = 0; - if (highscore < score) - highscore = score; - score = 0; -} - -void remove_obstacle() -{ - if (obstacle_count == 0) - return; - for (u8 i = 1; i < obstacle_count; i++) - { - obstacle_positions[i - 1] = obstacle_positions[i]; - obstacle_types[i - 1] = obstacle_types[i]; - } - obstacle_count--; -} - -void spawn_obstacle(u8 pos) -{ - if (obstacle_count >= MAX_OBSTACLES) - return; - obstacle_positions[obstacle_count] = pos; - obstacle_types[obstacle_count] = rand8() % OBSTACLE_TYPES; - obstacle_count++; -} - -void update() -{ - score += (time & 4) != 0; - if (player_vel != 0 || player_y != 0) - { - player_vel -= GRAVITY; - player_y += player_vel; - if (player_y < 0) - { - player_y = 0; - player_vel = 0; - } - } - for (u8 i = 0; i < obstacle_count; i++) - { - obstacle_positions[i] -= SCROLL_SPEED; - u8 type = obstacle_types[i]; - u8 dist_x = gfx_abs((s16)obstacle_positions[i] - (s16)PLAYER_X); - if (dist_x < obstacle_widths[type] && (player_y >> Y_PRECISION) < obstacle_heights[type]) - { - is_running = 0; - } - } - if (obstacle_count > 0 && obstacle_positions[0] == 0) - { - remove_obstacle(); - } - if (time_to_obstacle < 5) - { - u8 count = 1 + (rand8() & rand8() & 1) + (rand8() & rand8() & rand8() & rand8() & 1); - for (u8 i = 0; i < count; i++) - { - spawn_obstacle(128 + i * 8); - } - time_to_obstacle = (rand8() & 31) + 50; - } - time_to_obstacle -= 1; -} - -void render_digit(u8 digit, u8 x, u8 y) -{ - const u16 digit_font[] = { - 0b111101101101111, // 0 - 0b010110010010111, // 1 - 0b111001111100111, // 2 - 0b111001111001111, // 3 - 0b101101111001001, // 4 - 0b111100111001111, // 5 - 0b111100111101111, // 6 - 0b111001001001001, // 7 - 0b111101111101111, // 8 - 0b111101111001111, // 9 - }; - u16 pixels = digit_font[digit]; - - ssd1306_drawPixel(x + 0, y + 0, (pixels >> 14) & 1); - ssd1306_drawPixel(x + 1, y + 0, (pixels >> 13) & 1); - ssd1306_drawPixel(x + 2, y + 0, (pixels >> 12) & 1); - ssd1306_drawPixel(x + 0, y + 1, (pixels >> 11) & 1); - ssd1306_drawPixel(x + 1, y + 1, (pixels >> 10) & 1); - ssd1306_drawPixel(x + 2, y + 1, (pixels >> 9) & 1); - ssd1306_drawPixel(x + 0, y + 2, (pixels >> 8) & 1); - ssd1306_drawPixel(x + 1, y + 2, (pixels >> 7) & 1); - ssd1306_drawPixel(x + 2, y + 2, (pixels >> 6) & 1); - ssd1306_drawPixel(x + 0, y + 3, (pixels >> 5) & 1); - ssd1306_drawPixel(x + 1, y + 3, (pixels >> 4) & 1); - ssd1306_drawPixel(x + 2, y + 3, (pixels >> 3) & 1); - ssd1306_drawPixel(x + 0, y + 4, (pixels >> 2) & 1); - ssd1306_drawPixel(x + 1, y + 4, (pixels >> 1) & 1); - ssd1306_drawPixel(x + 2, y + 4, (pixels >> 0) & 1); -} - -void render_number(u32 s, u8 x, u8 y, u8 digits) -{ - u8 painter_x = x + digits * 4; - u32 val = s; - - for (int i = 0; i < digits; i++) - { - u8 digit = val % 10; - render_digit(digit, painter_x, y); - val /= 10; - painter_x -= 4; - } -} - -void render() -{ - ssd1306_setbuf(0); - ssd1306_drawFastHLine(0, 31, 128, 1); - - render_number(score, 0, 0, SCORE_DIGITS); - render_number(highscore, 0, 6, SCORE_DIGITS); - // render_number(obstacle_count, 20, 0, 2); - // render_number(abs(player_vel), 30, 0, 2); - // render_number(time_to_obstacle, 20, 6, 3); - - for (u8 i = 0; i < obstacle_count; i++) - { - u8 type = obstacle_types[i]; - ssd1306_drawImage(obstacle_positions[i], 31 - 8, obstacle_sprites[type], 8, 8, 0); - } - - if (time & RUN_ANIM_SPEED && is_running) - ssd1306_drawImage(PLAYER_X, 31 - (player_y >> Y_PRECISION) - 8, soweli_a, 8, 8, 0); - else - ssd1306_drawImage(PLAYER_X, 31 - (player_y >> Y_PRECISION) - 8, soweli_b, 8, 8, 0); -} - -/* White Noise Generator State */ -#define NOISE_BITS 8 -#define NOISE_MASK ((1 << NOISE_BITS) - 1) -#define NOISE_POLY_TAP0 31 -#define NOISE_POLY_TAP1 21 -#define NOISE_POLY_TAP2 1 -#define NOISE_POLY_TAP3 0 -/* - * random byte generator, taken from ch32v003fun examples - */ -uint8_t rand8(void) -{ - uint8_t bit; - uint32_t new_data; - - for (bit = 0; bit < NOISE_BITS; bit++) - { - new_data = ((lfsr >> NOISE_POLY_TAP0) ^ - (lfsr >> NOISE_POLY_TAP1) ^ - (lfsr >> NOISE_POLY_TAP2) ^ - (lfsr >> NOISE_POLY_TAP3)); - lfsr = (lfsr << 1) | (new_data & 1); - } - - return lfsr & NOISE_MASK; -} \ No newline at end of file diff --git a/soweli/ssd1306.h b/soweli/ssd1306.h deleted file mode 100644 index 7fb246d..0000000 --- a/soweli/ssd1306.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Single-File-Header for using SPI OLED - * 05-05-2023 E. Brombaugh - */ - -#ifndef _SSD1306_H -#define _SSD1306_H - -#include -#include - -// comfortable packet size for this OLED -#define SSD1306_PSZ 32 - -// characteristics of each type -#if !defined(SSD1306_64X32) && !defined(SSD1306_128X32) && !defined(SSD1306_128X64) -#error "Please define the SSD1306_WXH resolution used in your application" -#endif - -#ifdef SSD1306_64X32 -#define SSD1306_W 64 -#define SSD1306_H 32 -#define SSD1306_FULLUSE -#define SSD1306_OFFSET 32 -#endif - -#ifdef SSD1306_128X32 -#define SSD1306_W 128 -#define SSD1306_H 32 -#define SSD1306_OFFSET 0 -#endif - -#ifdef SSD1306_128X64 -#define SSD1306_W 128 -#define SSD1306_H 64 -#define SSD1306_FULLUSE -#define SSD1306_OFFSET 0 -#endif - -/* - * send OLED command byte - */ -uint8_t ssd1306_cmd(uint8_t cmd) -{ - ssd1306_pkt_send(&cmd, 1, 1); - return 0; -} - -/* - * send OLED data packet (up to 32 bytes) - */ -uint8_t ssd1306_data(uint8_t *data, uint8_t sz) -{ - ssd1306_pkt_send(data, sz, 0); - return 0; -} - -#define SSD1306_SETCONTRAST 0x81 -#define SSD1306_SEGREMAP 0xA0 -#define SSD1306_DISPLAYALLON_RESUME 0xA4 -#define SSD1306_DISPLAYALLON 0xA5 -#define SSD1306_NORMALDISPLAY 0xA6 -#define SSD1306_INVERTDISPLAY 0xA7 -#define SSD1306_DISPLAYOFF 0xAE -#define SSD1306_DISPLAYON 0xAF -#define SSD1306_SETDISPLAYOFFSET 0xD3 -#define SSD1306_SETCOMPINS 0xDA -#define SSD1306_SETVCOMDETECT 0xDB -#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 -#define SSD1306_SETPRECHARGE 0xD9 -#define SSD1306_SETMULTIPLEX 0xA8 -#define SSD1306_SETLOWCOLUMN 0x00 -#define SSD1306_SETHIGHCOLUMN 0x10 -#define SSD1306_SETSTARTLINE 0x40 -#define SSD1306_MEMORYMODE 0x20 -#define SSD1306_COLUMNADDR 0x21 -#define SSD1306_PAGEADDR 0x22 -#define SSD1306_COMSCANINC 0xC0 -#define SSD1306_COMSCANDEC 0xC8 -#define SSD1306_CHARGEPUMP 0x8D -#define SSD1306_EXTERNALVCC 0x1 -#define SSD1306_SWITCHCAPVCC 0x2 -#define SSD1306_TERMINATE_CMDS 0xFF - -/* choose VCC mode */ -#define SSD1306_EXTERNALVCC 0x1 -#define SSD1306_SWITCHCAPVCC 0x2 -// #define vccstate SSD1306_EXTERNALVCC -#define vccstate SSD1306_SWITCHCAPVCC - -// OLED initialization commands for 128x32 -const uint8_t ssd1306_init_array[] = - { - SSD1306_DISPLAYOFF, // 0xAE - SSD1306_SETDISPLAYCLOCKDIV, // 0xD5 - 0x80, // the suggested ratio 0x80 - SSD1306_SETMULTIPLEX, // 0xA8 -#ifdef SSD1306_64X32 - 0x1F, // for 64-wide displays -#else - 0x3F, // for 128-wide displays -#endif - SSD1306_SETDISPLAYOFFSET, // 0xD3 - 0x00, // no offset - SSD1306_SETSTARTLINE | 0x0, // 0x40 | line - SSD1306_CHARGEPUMP, // 0x8D - 0x14, // enable? - SSD1306_MEMORYMODE, // 0x20 - 0x00, // 0x0 act like ks0108 - SSD1306_SEGREMAP | 0x1, // 0xA0 | bit - SSD1306_COMSCANDEC, - SSD1306_SETCOMPINS, // 0xDA - 0x12, // - SSD1306_SETCONTRAST, // 0x81 - 0x8F, - SSD1306_SETPRECHARGE, // 0xd9 - 0xF1, - SSD1306_SETVCOMDETECT, // 0xDB - 0x40, - SSD1306_DISPLAYALLON_RESUME, // 0xA4 - SSD1306_NORMALDISPLAY, // 0xA6 - SSD1306_DISPLAYON, // 0xAF --turn on oled panel - SSD1306_TERMINATE_CMDS // 0xFF --fake command to mark end -}; - -// the display buffer -uint8_t ssd1306_buffer[SSD1306_W * SSD1306_H / 8]; - -/* - * set the buffer to a color - */ -void ssd1306_setbuf(uint8_t color) -{ - memset(ssd1306_buffer, color ? 0xFF : 0x00, sizeof(ssd1306_buffer)); -} - -#ifndef SSD1306_FULLUSE -/* - * expansion array for OLED with every other row unused - */ -const uint8_t expand[16] = - { - 0x00, - 0x02, - 0x08, - 0x0a, - 0x20, - 0x22, - 0x28, - 0x2a, - 0x80, - 0x82, - 0x88, - 0x8a, - 0xa0, - 0xa2, - 0xa8, - 0xaa, -}; -#endif - -/* - * Send the frame buffer - */ -void ssd1306_refresh(void) -{ - uint16_t i; - - ssd1306_cmd(SSD1306_COLUMNADDR); - ssd1306_cmd(SSD1306_OFFSET); // Column start address (0 = reset) - ssd1306_cmd(SSD1306_OFFSET + SSD1306_W - 1); // Column end address (127 = reset) - - ssd1306_cmd(SSD1306_PAGEADDR); - ssd1306_cmd(0); // Page start address (0 = reset) - ssd1306_cmd(7); // Page end address - -#ifdef SSD1306_FULLUSE - /* for fully used rows just plow thru everything */ - for (i = 0; i < sizeof(ssd1306_buffer); i += SSD1306_PSZ) - { - /* send PSZ block of data */ - ssd1306_data(&ssd1306_buffer[i], SSD1306_PSZ); - } -#else - /* for displays with odd rows unused expand bytes */ - uint8_t tbuf[SSD1306_PSZ], j, k; - for (i = 0; i < sizeof(ssd1306_buffer); i += 128) // for each page - { - /* low nybble */ - for (j = 0; j < 128; j += SSD1306_PSZ) - { - for (k = 0; k < SSD1306_PSZ; k++) - tbuf[k] = expand[ssd1306_buffer[i + j + k] & 0xf]; - - /* send PSZ block of data */ - ssd1306_data(tbuf, SSD1306_PSZ); - } - - /* high nybble */ - for (j = 0; j < 128; j += SSD1306_PSZ) - { - for (k = 0; k < SSD1306_PSZ; k++) - tbuf[k] = expand[(ssd1306_buffer[i + j + k] >> 4) & 0xf]; - - /* send PSZ block of data */ - ssd1306_data(tbuf, SSD1306_PSZ); - } - } -#endif -} - -/* - * plot a pixel in the buffer - */ -void ssd1306_drawPixel(uint8_t x, uint8_t y, uint8_t color) -{ - uint16_t addr; - - /* clip */ - if (x >= SSD1306_W) - return; - if (y >= SSD1306_H) - return; - - /* compute buffer address */ - addr = x + SSD1306_W * (y / 8); - - /* set/clear bit in buffer */ - if (color) - ssd1306_buffer[addr] |= (1 << (y & 7)); - else - ssd1306_buffer[addr] &= ~(1 << (y & 7)); -} - -/* - * fast vert line - */ -void ssd1306_drawFastVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color) -{ - // clipping - if ((x >= SSD1306_W) || (y >= SSD1306_H)) - return; - if ((y + h - 1) >= SSD1306_H) - h = SSD1306_H - y; - while (h--) - { - ssd1306_drawPixel(x, y++, color); - } -} - -/* - * fast horiz line - */ -void ssd1306_drawFastHLine(uint8_t x, uint8_t y, uint8_t w, uint8_t color) -{ - // clipping - if ((x >= SSD1306_W) || (y >= SSD1306_H)) - return; - if ((x + w - 1) >= SSD1306_W) - w = SSD1306_W - x; - - while (w--) - { - ssd1306_drawPixel(x++, y, color); - } -} - -/* - * abs() helper function for line drawing - */ -int16_t gfx_abs(int16_t x) -{ - return (x < 0) ? -x : x; -} - -/* - * swap() helper function for line drawing - */ -void gfx_swap(uint16_t *z0, uint16_t *z1) -{ - uint16_t temp = *z0; - *z0 = *z1; - *z1 = temp; -} - -/* - * Bresenham line draw routine swiped from Wikipedia - */ -void ssd1306_drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t color) -{ - int16_t steep; - int16_t deltax, deltay, error, ystep, x, y; - - /* flip sense 45deg to keep error calc in range */ - steep = (gfx_abs(y1 - y0) > gfx_abs(x1 - x0)); - - if (steep) - { - gfx_swap(&x0, &y0); - gfx_swap(&x1, &y1); - } - - /* run low->high */ - if (x0 > x1) - { - gfx_swap(&x0, &x1); - gfx_swap(&y0, &y1); - } - - /* set up loop initial conditions */ - deltax = x1 - x0; - deltay = gfx_abs(y1 - y0); - error = deltax / 2; - y = y0; - if (y0 < y1) - ystep = 1; - else - ystep = -1; - - /* loop x */ - for (x = x0; x <= x1; x++) - { - /* plot point */ - if (steep) - /* flip point & plot */ - ssd1306_drawPixel(y, x, color); - else - /* just plot */ - ssd1306_drawPixel(x, y, color); - - /* update error */ - error = error - deltay; - - /* update y */ - if (error < 0) - { - y = y + ystep; - error = error + deltax; - } - } -} - -/* - * draws a circle - */ -void ssd1306_drawCircle(int16_t x, int16_t y, int16_t radius, int8_t color) -{ - /* Bresenham algorithm */ - int16_t x_pos = -radius; - int16_t y_pos = 0; - int16_t err = 2 - 2 * radius; - int16_t e2; - - do - { - ssd1306_drawPixel(x - x_pos, y + y_pos, color); - ssd1306_drawPixel(x + x_pos, y + y_pos, color); - ssd1306_drawPixel(x + x_pos, y - y_pos, color); - ssd1306_drawPixel(x - x_pos, y - y_pos, color); - e2 = err; - if (e2 <= y_pos) - { - err += ++y_pos * 2 + 1; - if (-x_pos == y_pos && e2 <= x_pos) - { - e2 = 0; - } - } - if (e2 > x_pos) - { - err += ++x_pos * 2 + 1; - } - } while (x_pos <= 0); -} - -/* - * draws a filled circle - */ -void ssd1306_fillCircle(int16_t x, int16_t y, int16_t radius, int8_t color) -{ - /* Bresenham algorithm */ - int16_t x_pos = -radius; - int16_t y_pos = 0; - int16_t err = 2 - 2 * radius; - int16_t e2; - - do - { - ssd1306_drawPixel(x - x_pos, y + y_pos, color); - ssd1306_drawPixel(x + x_pos, y + y_pos, color); - ssd1306_drawPixel(x + x_pos, y - y_pos, color); - ssd1306_drawPixel(x - x_pos, y - y_pos, color); - ssd1306_drawFastHLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, color); - ssd1306_drawFastHLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, color); - e2 = err; - if (e2 <= y_pos) - { - err += ++y_pos * 2 + 1; - if (-x_pos == y_pos && e2 <= x_pos) - { - e2 = 0; - } - } - if (e2 > x_pos) - { - err += ++x_pos * 2 + 1; - } - } while (x_pos <= 0); -} - -/* - * draw a rectangle - */ -void ssd1306_drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) -{ - ssd1306_drawFastVLine(x, y, h, color); - ssd1306_drawFastVLine(x + w - 1, y, h, color); - ssd1306_drawFastHLine(x, y, w, color); - ssd1306_drawFastHLine(x, y + h - 1, w, color); -} - -/* - * fill a rectangle - */ -void ssd1306_fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) -{ - uint8_t m, n = y, iw = w; - - /* scan vertical */ - while (h--) - { - m = x; - w = iw; - /* scan horizontal */ - while (w--) - { - /* invert pixels */ - ssd1306_drawPixel(m++, n, color); - } - n++; - } -} - -/* - * invert a rectangle in the buffer - */ -void ssd1306_xorrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h) -{ - uint8_t m, n = y, iw = w; - - /* scan vertical */ - while (h--) - { - m = x; - w = iw; - /* scan horizontal */ - while (w--) - { - /* invert pixels */ - ssd1306_xorPixel(m++, n); - } - n++; - } -} - -/* - * initialize I2C and OLED - */ -uint8_t ssd1306_init(void) -{ - // pulse reset - ssd1306_rst(); - - // initialize OLED - uint8_t *cmd_list = (uint8_t *)ssd1306_init_array; - while (*cmd_list != SSD1306_TERMINATE_CMDS) - { - if (ssd1306_cmd(*cmd_list++)) - return 1; - } - - // clear display - ssd1306_setbuf(0); - ssd1306_refresh(); - - return 0; -} - -#endif diff --git a/soweli/ssd1306_i2c.h b/soweli/ssd1306_i2c.h deleted file mode 100644 index 023157f..0000000 --- a/soweli/ssd1306_i2c.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Single-File-Header for SSD1306 I2C interface - * 05-07-2023 E. Brombaugh - */ - -#ifndef _SSD1306_I2C_H -#define _SSD1306_I2C_H - -#include - -// SSD1306 I2C address -#define SSD1306_I2C_ADDR 0x3c - -// I2C Bus clock rate - must be lower the Logic clock rate -#define SSD1306_I2C_CLKRATE 1000000 - -// I2C Logic clock rate - must be higher than Bus clock rate -#define SSD1306_I2C_PRERATE 2000000 - -// uncomment this for high-speed 36% duty cycle, otherwise 33% -#define SSD1306_I2C_DUTY - -// I2C Timeout count -#define TIMEOUT_MAX 100000 - -// uncomment this to enable IRQ-driven operation -//#define SSD1306_I2C_IRQ - -#ifdef SSD1306_I2C_IRQ -// some stuff that IRQ mode needs -volatile uint8_t ssd1306_i2c_send_buffer[64], *ssd1306_i2c_send_ptr, ssd1306_i2c_send_sz, ssd1306_i2c_irq_state; - -// uncomment this to enable time diags in IRQ -//#define IRQ_DIAG -#endif - -/* - * init just I2C - */ -void ssd1306_i2c_setup(void) -{ - uint16_t tempreg; - - // Reset I2C1 to init all regs - RCC->APB1PRSTR |= RCC_APB1Periph_I2C1; - RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1; - - // set freq - tempreg = I2C1->CTLR2; - tempreg &= ~I2C_CTLR2_FREQ; - tempreg |= (FUNCONF_SYSTEM_CORE_CLOCK/SSD1306_I2C_PRERATE)&I2C_CTLR2_FREQ; - I2C1->CTLR2 = tempreg; - - // Set clock config - tempreg = 0; -#if (SSD1306_I2C_CLKRATE <= 100000) - // standard mode good to 100kHz - tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(2*SSD1306_I2C_CLKRATE))&SSD1306_I2C_CKCFGR_CCR; -#else - // fast mode over 100kHz -#ifndef SSD1306_I2C_DUTY - // 33% duty cycle - tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(3*SSD1306_I2C_CLKRATE))&SSD1306_I2C_CKCFGR_CCR; -#else - // 36% duty cycle - tempreg = (FUNCONF_SYSTEM_CORE_CLOCK/(25*SSD1306_I2C_CLKRATE))&I2C_CKCFGR_CCR; - tempreg |= I2C_CKCFGR_DUTY; -#endif - tempreg |= I2C_CKCFGR_FS; -#endif - I2C1->CKCFGR = tempreg; - -#ifdef SSD1306_I2C_IRQ - // enable IRQ driven operation - NVIC_EnableIRQ(I2C1_EV_IRQn); - - // initialize the state - ssd1306_i2c_irq_state = 0; -#endif - - // Enable I2C - I2C1->CTLR1 |= I2C_CTLR1_PE; - - // set ACK mode - I2C1->CTLR1 |= I2C_CTLR1_ACK; -} - -/* - * error descriptions - */ -char *errstr[] = -{ - "not busy", - "master mode", - "transmit mode", - "tx empty", - "transmit complete", -}; - -/* - * error handler - */ -uint8_t ssd1306_i2c_error(uint8_t err) -{ - // report error - printf("ssd1306_i2c_error - timeout waiting for %s\n\r", errstr[err]); - - // reset & initialize I2C - ssd1306_i2c_setup(); - - return 1; -} - -// event codes we use -#define SSD1306_I2C_EVENT_MASTER_MODE_SELECT ((uint32_t)0x00030001) /* BUSY, MSL and SB flag */ -#define SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */ -#define SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED ((uint32_t)0x00070084) /* TRA, BUSY, MSL, TXE and BTF flags */ - -/* - * check for 32-bit event codes - */ -uint8_t ssd1306_i2c_chk_evt(uint32_t event_mask) -{ - /* read order matters here! STAR1 before STAR2!! */ - uint32_t status = I2C1->STAR1 | (I2C1->STAR2<<16); - return (status & event_mask) == event_mask; -} - -#ifdef SSD1306_I2C_IRQ -/* - * packet send for IRQ-driven operation - */ -uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz) -{ - int32_t timeout; - -#ifdef IRQ_DIAG - GPIOC->BSHR = (1<<(3)); -#endif - - // error out if buffer under/overflow - if((sz > sizeof(ssd1306_i2c_send_buffer)) || !sz) - return 2; - - // wait for previous packet to finish - while(ssd1306_i2c_irq_state); - -#ifdef IRQ_DIAG - GPIOC->BSHR = (1<<(16+3)); - GPIOC->BSHR = (1<<(4)); -#endif - - // init buffer for sending - ssd1306_i2c_send_sz = sz; - ssd1306_i2c_send_ptr = ssd1306_i2c_send_buffer; - memcpy((uint8_t *)ssd1306_i2c_send_buffer, data, sz); - - // wait for not busy - timeout = TIMEOUT_MAX; - while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(0); - - // Set START condition - I2C1->CTLR1 |= I2C_CTLR1_START; - - // wait for master mode select - timeout = TIMEOUT_MAX; - while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(1); - - // send 7-bit address + write flag - I2C1->DATAR = addr<<1; - - // wait for transmit condition - timeout = TIMEOUT_MAX; - while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(2); - - // Enable TXE interrupt - I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN; - ssd1306_i2c_irq_state = 1; - -#ifdef IRQ_DIAG - GPIOC->BSHR = (1<<(16+4)); -#endif - - // exit - return 0; -} - -/* - * IRQ handler for I2C events - */ -void I2C1_EV_IRQHandler(void) __attribute__((interrupt)); -void I2C1_EV_IRQHandler(void) -{ - uint16_t STAR1, STAR2 __attribute__((unused)); - -#ifdef IRQ_DIAG - GPIOC->BSHR = (1<<(4)); -#endif - - // read status, clear any events - STAR1 = I2C1->STAR1; - STAR2 = I2C1->STAR2; - - /* check for TXE */ - if(STAR1 & I2C_STAR1_TXE) - { - /* check for remaining data */ - if(ssd1306_i2c_send_sz--) - I2C1->DATAR = *ssd1306_i2c_send_ptr++; - - /* was that the last byte? */ - if(!ssd1306_i2c_send_sz) - { - // disable TXE interrupt - I2C1->CTLR2 &= ~(I2C_CTLR2_ITBUFEN | I2C_CTLR2_ITEVTEN); - - // reset IRQ state - ssd1306_i2c_irq_state = 0; - - // wait for tx complete - while(!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)); - - // set STOP condition - I2C1->CTLR1 |= I2C_CTLR1_STOP; - } - } - -#ifdef IRQ_DIAG - GPIOC->BSHR = (1<<(16+4)); -#endif -} -#else -/* - * low-level packet send for blocking polled operation via i2c - */ -uint8_t ssd1306_i2c_send(uint8_t addr, uint8_t *data, uint8_t sz) -{ - int32_t timeout; - - // wait for not busy - timeout = TIMEOUT_MAX; - while((I2C1->STAR2 & I2C_STAR2_BUSY) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(0); - - // Set START condition - I2C1->CTLR1 |= I2C_CTLR1_START; - - // wait for master mode select - timeout = TIMEOUT_MAX; - while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_MODE_SELECT)) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(1); - - // send 7-bit address + write flag - I2C1->DATAR = addr<<1; - - // wait for transmit condition - timeout = TIMEOUT_MAX; - while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(2); - - // send data one byte at a time - while(sz--) - { - // wait for TX Empty - timeout = TIMEOUT_MAX; - while(!(I2C1->STAR1 & I2C_STAR1_TXE) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(3); - - // send command - I2C1->DATAR = *data++; - } - - // wait for tx complete - timeout = TIMEOUT_MAX; - while((!ssd1306_i2c_chk_evt(SSD1306_I2C_EVENT_MASTER_BYTE_TRANSMITTED)) && (timeout--)); - if(timeout==-1) - return ssd1306_i2c_error(4); - - // set STOP condition - I2C1->CTLR1 |= I2C_CTLR1_STOP; - - // we're happy - return 0; -} -#endif - -/* - * high-level packet send for I2C - */ -uint8_t ssd1306_pkt_send(uint8_t *data, uint8_t sz, uint8_t cmd) -{ - uint8_t pkt[33]; - - /* build command or data packets */ - if(cmd) - { - pkt[0] = 0; - pkt[1] = *data; - } - else - { - pkt[0] = 0x40; - memcpy(&pkt[1], data, sz); - } - return ssd1306_i2c_send(SSD1306_I2C_ADDR, pkt, sz+1); -} - -/* - * init I2C and GPIO - */ -uint8_t ssd1306_i2c_init(void) -{ - // Enable GPIOC and I2C - RCC->APB2PCENR |= RCC_APB2Periph_GPIOC; - RCC->APB1PCENR |= RCC_APB1Periph_I2C1; - - // PC1 is SDA, 10MHz Output, alt func, open-drain - GPIOC->CFGLR &= ~(0xf<<(4*1)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1); - - // PC2 is SCL, 10MHz Output, alt func, open-drain - GPIOC->CFGLR &= ~(0xf<<(4*2)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2); - -#ifdef IRQ_DIAG - // GPIO diags on PC3/PC4 - GPIOC->CFGLR &= ~(0xf<<(4*3)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*3); - GPIOC->BSHR = (1<<(16+3)); - GPIOC->CFGLR &= ~(0xf<<(4*4)); - GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - GPIOC->BSHR = (1<<(16+4)); -#endif - - // load I2C regs - ssd1306_i2c_setup(); - -#if 0 - // test if SSD1306 is on the bus by sending display off command - uint8_t command = 0xAF; - return ssd1306_pkt_send(&command, 1, 1); -#else - return 0; -#endif -} - -/* - * reset is not used for SSD1306 I2C interface - */ -void ssd1306_rst(void) -{ -} -#endif diff --git a/gol/ssd1306.h b/ssd1306.h similarity index 99% rename from gol/ssd1306.h rename to ssd1306.h index 7fb246d..e613481 100644 --- a/gol/ssd1306.h +++ b/ssd1306.h @@ -480,7 +480,7 @@ uint8_t ssd1306_init(void) } // clear display - ssd1306_setbuf(0); + // ssd1306_setbuf(0); ssd1306_refresh(); return 0; diff --git a/gol/ssd1306_i2c.h b/ssd1306_i2c.h similarity index 100% rename from gol/ssd1306_i2c.h rename to ssd1306_i2c.h