init
This commit is contained in:
commit
7b006d6f20
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
src/compiled_payload.elf
|
||||
src/compiled_eeprom
|
||||
src/.cache
|
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# AVR WRISTWATCH
|
||||
## What is it?
|
||||
This repository contains the code in development (and soon schematics) for a small wristwatch with a 128x32 OLED display. I'm hoping it will last the whole day, have cool animated visuals, and be pretty to look at.
|
||||
|
||||
## Desired Features and Goals
|
||||
* 128x32 OLED monochrome display
|
||||
* 128kb upgradable external EEPROM for images and short videos
|
||||
* Fancy graphics, display images and videos that can overlay time with inverting filter
|
||||
* Battery that lasts at least a day
|
||||
* USB-C charging (may switch to micro-usb depending on IC prices/availability)
|
||||
* Display the time
|
||||
|
||||
## Parts
|
||||
* Microcontroller: Any ATmega chip with TWI/I2C I can get my hands on
|
||||
* Display: Waveshare 128x32 0.91inch OLED display
|
||||
* RTC clock: PCF85063A
|
||||
* EEPROM: BR24T128-W
|
||||
* Battery Management: TBD
|
||||
|
||||
|
||||
## Why
|
||||
This project is to help me learn how to develop for AVR without Arduino libraries, read datasheets faster, and to prove I can solder small SMD components. It will be my first physical project where I design my own PCB, which has been something I've wanted to do for a long time.
|
||||
|
BIN
docs/Quiescent_Current.pdf
Normal file
BIN
docs/Quiescent_Current.pdf
Normal file
Binary file not shown.
2
docs/README.txt
Normal file
2
docs/README.txt
Normal file
@ -0,0 +1,2 @@
|
||||
This folder is simply for my own refrence for the chips I buy.
|
||||
This is NOT any documentation for the watch.
|
58581
docs/atmega2560.pdf
Normal file
58581
docs/atmega2560.pdf
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/clock.pdf
Normal file
BIN
docs/clock.pdf
Normal file
Binary file not shown.
BIN
docs/display_driver.pdf
Normal file
BIN
docs/display_driver.pdf
Normal file
Binary file not shown.
BIN
docs/eeprom.pdf
Normal file
BIN
docs/eeprom.pdf
Normal file
Binary file not shown.
BIN
docs/i2c_summary.pdf
Normal file
BIN
docs/i2c_summary.pdf
Normal file
Binary file not shown.
62
src/br24t_eeprom_driver.c
Normal file
62
src/br24t_eeprom_driver.c
Normal file
@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include "i2c.h"
|
||||
#include "br24t_eeprom_driver.h"
|
||||
|
||||
#define EEPROM_ADDR 0x57
|
||||
#define EEPROM_PAGE_SIZE 64
|
||||
|
||||
//for burning eeprom
|
||||
#define MAGIC_SYN 0xdeadbeef
|
||||
#define MAGIC_ACK 0xf00dd00d
|
||||
|
||||
#define PAGE_WRITE_OK 0x00
|
||||
#define PAGE_WRITE_CORRUPTED 0x01
|
||||
#define PAGE_WRITE_UNKNOWN_ERROR 0xff
|
||||
|
||||
//we need another function cause it's got a 16 bit register address
|
||||
|
||||
#ifdef FLASH_EEPROM
|
||||
void flash_eeprom() {
|
||||
uint16_t data_len;
|
||||
uint32_t syn = 0;
|
||||
uint8_t on_byte;
|
||||
uint8_t eeprom_buffer_out[EEPROM_PAGE_SIZE];
|
||||
uint8_t eeprom_buffer_in[EEPROM_PAGE_SIZE];
|
||||
|
||||
while(syn != MAGIC_SYN) fread(&syn, 4, 1, stdin); //not sure we _really_ need to do this?
|
||||
|
||||
//this feels ugly
|
||||
syn = MAGIC_ACK;
|
||||
fwrite(&syn, 4, 1, stdout);
|
||||
|
||||
//get amount of data we'll be using
|
||||
data_len = uart_recvbyte();
|
||||
data_len |= (uart_recvbyte() >> 8);
|
||||
|
||||
for(int page = 0; page < (data_len / EEPROM_PAGE_SIZE); data_len -= EEPROM_PAGE_SIZE) {
|
||||
|
||||
fread(eeprom_buffer_out, EEPROM_PAGE_SIZE, 1, stdin);
|
||||
|
||||
i2c_start(EEPROM_I2C_ADDR, I2C_READ);
|
||||
i2c_send((uint8_t)(page * EEPROM_PAGE_SIZE) & 0xff);
|
||||
i2c_send((uint8_t)(page * EEPROM_PAGE_SIZE) >> 8);
|
||||
for(on_byte = 0; on_byte < EEPROM_PAGE_SIZE; on_byte++)
|
||||
i2c_send(eeprom_buffer_out[on_byte]);
|
||||
i2c_stop();
|
||||
|
||||
//verify
|
||||
eeprom_buffer_in[0] = EEPROM_READBYTE(page * EEPROM_PAGE_SIZE);
|
||||
//eeprom_buffer_in[0] = i2c_read_reg_addr16(EEPROM_I2C_ADDR, page * EEPROM_PAGE_SIZE);
|
||||
i2c_start(EEPROM_I2C_ADDR, I2C_READ);
|
||||
for(on_byte = 1; on_byte < EEPROM_PAGE_SIZE; on_byte++)
|
||||
eeprom_buffer_in[on_byte] = i2c_recv();
|
||||
i2c_stop();
|
||||
|
||||
if(memcmp(eeprom_buffer_in, eeprom_buffer_out, EEPROM_PAGE_SIZE)) {
|
||||
fputc(PAGE_WRITE_CORRUPTED, stdout);
|
||||
error();
|
||||
}
|
||||
fputc(PAGE_WRITE_OK, stdout);
|
||||
}
|
||||
}
|
||||
#endif
|
21
src/br24t_eeprom_driver.h
Normal file
21
src/br24t_eeprom_driver.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef __BR24_INC
|
||||
#define __BR24_INC
|
||||
|
||||
#include <stdint.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define EEPROM_I2C_ADDR 0x50 //fix to represent custom address setting
|
||||
|
||||
|
||||
#ifdef FLASH_EEPROM
|
||||
void flash_eeprom();
|
||||
#endif
|
||||
|
||||
typedef uint16_t EEPROM_ADDR;
|
||||
|
||||
#define EEPROM_READBYTE(addr) i2c_read_reg_addr16(EEPROM_I2C_ADDR, addr);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
114
src/compile_commands.json
Normal file
114
src/compile_commands.json
Normal file
@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"directory": "/home/indigo/projects/watch/src",
|
||||
"arguments": [
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/bin/avr-gcc",
|
||||
"-v",
|
||||
"-mmcu=atmega2560",
|
||||
"-I",
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/avr/include",
|
||||
"-o",
|
||||
"compiled_payload",
|
||||
"-DBAUD=9600",
|
||||
"-DF_CPU=16000000",
|
||||
"-Wall",
|
||||
"-O1",
|
||||
"main.c"
|
||||
],
|
||||
"file": "main.c"
|
||||
},
|
||||
{
|
||||
"directory": "/home/indigo/projects/watch/src",
|
||||
"arguments": [
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/bin/avr-gcc",
|
||||
"-lc",
|
||||
"-mmcu=atmega2560",
|
||||
"-I",
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/avr/include",
|
||||
"-o",
|
||||
"compiled_payload.elf",
|
||||
"-DDEBUG_BUILD=1",
|
||||
"-DBAUD=9600",
|
||||
"-DF_CPU=16000000",
|
||||
"-Wall",
|
||||
"-O1",
|
||||
"main.c",
|
||||
"debug_serial.c",
|
||||
"i2c.c",
|
||||
"ssd1306_driver.h"
|
||||
],
|
||||
"file": "i2c.c"
|
||||
},
|
||||
{
|
||||
"directory": "/home/indigo/projects/watch/src",
|
||||
"arguments": [
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/bin/avr-gcc",
|
||||
"-mmcu=atmega2560",
|
||||
"-I",
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/avr/include",
|
||||
"-o",
|
||||
"compiled_payload.elf",
|
||||
"-DDEBUG_BUILD=1",
|
||||
"-DBAUD=9600",
|
||||
"-DF_CPU=16000000",
|
||||
"-Wall",
|
||||
"-O1",
|
||||
"main.c",
|
||||
"debug.c",
|
||||
"i2c.c",
|
||||
"ssd1306_driver.c",
|
||||
"uart.c",
|
||||
"-Wall"
|
||||
],
|
||||
"file": "uart.c"
|
||||
},
|
||||
{
|
||||
"directory": "/home/indigo/projects/watch/src",
|
||||
"arguments": [
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/bin/avr-gcc",
|
||||
"-mmcu=atmega2560",
|
||||
"-I",
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/avr/include",
|
||||
"-o",
|
||||
"compiled_payload.elf",
|
||||
"-DDEBUG_BUILD=1",
|
||||
"-DBAUD=9600",
|
||||
"-DF_CPU=16000000",
|
||||
"-Wall",
|
||||
"-O1",
|
||||
"main.c",
|
||||
"debug.c",
|
||||
"i2c.c",
|
||||
"ssd1306_display_driver.c",
|
||||
"uart.c",
|
||||
"br24t_eeprom_driver.c",
|
||||
"-Wall"
|
||||
],
|
||||
"file": "br24t_eeprom_driver.c"
|
||||
},
|
||||
{
|
||||
"directory": "/home/indigo/projects/watch/src",
|
||||
"arguments": [
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/bin/avr-gcc",
|
||||
"-mmcu=atmega2560",
|
||||
"-I",
|
||||
"/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64/avr/include",
|
||||
"-o",
|
||||
"compiled_payload.elf",
|
||||
"-DDEBUG_BUILD=1",
|
||||
"-DBAUD=9600",
|
||||
"-DF_CPU=16000000",
|
||||
"-Wall",
|
||||
"-O1",
|
||||
"main.c",
|
||||
"debug.c",
|
||||
"i2c.c",
|
||||
"ssd1306_display_driver.c",
|
||||
"uart.c",
|
||||
"br24t_eeprom_driver.c",
|
||||
"paint.c",
|
||||
"-Wall"
|
||||
],
|
||||
"file": "paint.c"
|
||||
}
|
||||
]
|
116
src/compile_eeprom.py
Executable file
116
src/compile_eeprom.py
Executable file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
from PIL import BdfFontFile, Image
|
||||
import os
|
||||
import serial
|
||||
import argparse
|
||||
|
||||
compiled_output_path = 'compiled_eeprom'
|
||||
header_path = 'eeprom_address.h'
|
||||
eeprom_length = 131072 # 128 kib
|
||||
|
||||
data_path = "./eeprom_data"
|
||||
|
||||
output = open(compiled_output_path, 'wb')
|
||||
header = open(header_path, 'w')
|
||||
|
||||
page_bit_width = 128
|
||||
page_bit_height = 8
|
||||
page_cnt = 4
|
||||
|
||||
|
||||
|
||||
#fonts
|
||||
# for some reason BdfFontFile.BdfFontFile.bitmap doesn't have proper spacing
|
||||
# so we'll just manually go through each character ourselves
|
||||
# it's expected I'll rename fonts to how I think they should be refrenced beorehand
|
||||
# also note we have no protection from using unsed chars, I can't let this project
|
||||
# get to big for litteraly no reason
|
||||
|
||||
header.write("/** GENERATED BY EEPROM COMPILER SCRIPT **/\n\n")
|
||||
header.write("// FONTS\n")
|
||||
|
||||
for file in os.listdir("{}/fonts/".format(data_path)):
|
||||
path = "{}/fonts/{}".format(data_path, file)
|
||||
if os.path.isfile(path) and path.split('.')[-1] == 'bdf':
|
||||
with open(path, 'rb') as font_fd:
|
||||
font_bdf = BdfFontFile.BdfFontFile(font_fd)
|
||||
font_name = file.split('.')[0].capitalize()
|
||||
|
||||
header.write("#define FONT_{}_ADDR\t0x{:04x}\n".format(font_name, output.tell()))
|
||||
|
||||
first_char = False
|
||||
for char in enumerate(font_bdf.glyph):
|
||||
if char[1]:
|
||||
if not first_char:
|
||||
first_char = True
|
||||
header.write(("#define FONT_{}_FIRST_CHAR\t{}\n"
|
||||
"#define FONT_{}_WIDTH\t{}\n"
|
||||
"#define FONT_{}_HEIGHT\t{}\n").format(
|
||||
font_name, char[0],
|
||||
font_name, char[1][-1].size[0],
|
||||
font_name, char[1][-1].size[1]))
|
||||
output.write(char[1][-1].tobytes('raw'))
|
||||
|
||||
header.write("\n\n// IMAGES\n#define IMG_BEGIN\t0x{:04x}\n".format(output.tell()))
|
||||
|
||||
image_cnt = 0
|
||||
|
||||
# images
|
||||
for file in os.listdir("{}/images/".format(data_path)):
|
||||
path = "{}/images/{}".format(data_path, file)
|
||||
if os.path.isfile(path) and path.split('.')[-1] == 'png':
|
||||
with open(path, 'rb') as image_fd:
|
||||
image_cnt += 1
|
||||
image_bitmap = []
|
||||
image_bitmap_remapped = []
|
||||
image = Image.open(image_fd)
|
||||
if not image.mode == 'RGB':
|
||||
print("this script only compiles RGB formatted photos! (I'm lazy\n")
|
||||
exit(1)
|
||||
header.write("#define IMG_{}_ADDR\t0x{:04x}\n".format(
|
||||
file.split('.')[0].capitalize(),
|
||||
output.tell()))
|
||||
for byte in range(0, len(image.tobytes()), 3):
|
||||
if (byte / 3) % 8 == 0:
|
||||
image_bitmap.append(0)
|
||||
if sum(image.tobytes()[byte:byte+3]) > 0:
|
||||
image_bitmap[-1] |= (int(byte / 3)) % 8
|
||||
|
||||
# is this supposed to be big endian?
|
||||
image_bitmap_remapped = [0] * len(image_bitmap)
|
||||
for bit in range(0, page_bit_width * page_bit_height * page_cnt):
|
||||
w = page_bit_width
|
||||
h = page_bit_height
|
||||
i = bit
|
||||
#I am so sorry.
|
||||
extract_bit = (((i % w) * page_bit_height) +
|
||||
(int(i / w) % page_bit_height) +
|
||||
(int(i / (w * page_bit_height)) *
|
||||
(w * page_bit_height)))
|
||||
|
||||
if (extract_bit % 8) - (bit % 8) >= 0:
|
||||
image_bitmap_remapped[int(bit / 8)] |= \
|
||||
(image_bitmap[int(extract_bit / 8)] & (extract_bit % 8)) >> \
|
||||
((extract_bit % 8) - (bit % 8))
|
||||
else:
|
||||
image_bitmap_remapped[int(bit / 8)] |= \
|
||||
(image_bitmap[int(extract_bit / 8)] & (extract_bit % 8)) << \
|
||||
((bit % 8) - (extract_bit % 8))
|
||||
[output.write(byte.to_bytes(1, 'big')) for byte in image_bitmap_remapped]
|
||||
|
||||
header.write("#define IMG_COUNT\t{}\n\n".format(image_cnt))
|
||||
|
||||
|
||||
|
||||
print("EEPROM used: {}% ({} out of {} bits)".format(
|
||||
(output.tell() / eeprom_length) * 100,
|
||||
output.tell(), eeprom_length))
|
||||
|
||||
if(output.tell() > eeprom_length):
|
||||
print("WARNING: You've used more eeprom then there is available!\n")
|
||||
|
||||
output.close()
|
||||
header.close()
|
||||
|
||||
|
||||
|
31
src/debug.c
Normal file
31
src/debug.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <avr/io.h>
|
||||
#include <stdio.h>
|
||||
#include <util/delay.h>
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* TCNTn: timer/counter
|
||||
* TCCRnA/B/C: timer/counter control registers
|
||||
*/
|
||||
void timer_init() {
|
||||
TCCR1A = 0; //no waveform generation or something like that
|
||||
TCCR1B = _BV(CS00); //no prescaling; use internal clock
|
||||
TCCR1C = 0;
|
||||
}
|
||||
|
||||
//makes it easier to print time; is an unsigned int and NOT to be used for more then printing
|
||||
unsigned int ticks_to_seconds(uint16_t start, uint16_t end) {
|
||||
return ((unsigned int)(end - start) / F_CPU);
|
||||
}
|
||||
|
||||
void test_timer() {
|
||||
uint16_t start, end;
|
||||
start = TCNT1;
|
||||
_delay_ms(1000);
|
||||
end = TCNT1;
|
||||
printf("1 second is %u ticks\n", end - start);
|
||||
}
|
14
src/debug.h
Normal file
14
src/debug.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __DEBUG_SERIAL_H
|
||||
#define __DEBUG_SERIAL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <avr/io.h>
|
||||
#include "uart.h"
|
||||
|
||||
void timer_init();
|
||||
void test_timer();
|
||||
unsigned int ticks_to_seconds();
|
||||
|
||||
|
||||
|
||||
#endif
|
47
src/eeprom_address.h
Normal file
47
src/eeprom_address.h
Normal file
@ -0,0 +1,47 @@
|
||||
/** GENERATED BY EEPROM COMPILER SCRIPT **/
|
||||
|
||||
// FONTS
|
||||
#define FONT_5thelement_ADDR 0x0000
|
||||
#define FONT_5thelement_FIRST_CHAR 32
|
||||
#define FONT_5thelement_WIDTH 4
|
||||
#define FONT_5thelement_HEIGHT 5
|
||||
#define FONT_4thd_ADDR 0x01db
|
||||
#define FONT_4thd_FIRST_CHAR 32
|
||||
#define FONT_4thd_WIDTH 4
|
||||
#define FONT_4thd_HEIGHT 4
|
||||
#define FONT_Bitocra-13-full_ADDR 0x0357
|
||||
#define FONT_Bitocra-13-full_FIRST_CHAR 32
|
||||
#define FONT_Bitocra-13-full_WIDTH 7
|
||||
#define FONT_Bitocra-13-full_HEIGHT 13
|
||||
#define FONT_Bitocra-13_ADDR 0x0cf0
|
||||
#define FONT_Bitocra-13_FIRST_CHAR 32
|
||||
#define FONT_Bitocra-13_WIDTH 7
|
||||
#define FONT_Bitocra-13_HEIGHT 13
|
||||
#define FONT_Bitocra_ADDR 0x1689
|
||||
#define FONT_Bitocra_FIRST_CHAR 32
|
||||
#define FONT_Bitocra_WIDTH 0
|
||||
#define FONT_Bitocra_HEIGHT 0
|
||||
#define FONT_Bitbuntu_ADDR 0x1b1d
|
||||
#define FONT_Bitbuntu_FIRST_CHAR 32
|
||||
#define FONT_Bitbuntu_WIDTH 0
|
||||
#define FONT_Bitbuntu_HEIGHT 0
|
||||
#define FONT_Bitocra-full_ADDR 0x1fbd
|
||||
#define FONT_Bitocra-full_FIRST_CHAR 32
|
||||
#define FONT_Bitocra-full_WIDTH 6
|
||||
#define FONT_Bitocra-full_HEIGHT 11
|
||||
#define FONT_Bitbuntu-full_ADDR 0x27e7
|
||||
#define FONT_Bitbuntu-full_FIRST_CHAR 32
|
||||
#define FONT_Bitbuntu-full_WIDTH 6
|
||||
#define FONT_Bitbuntu-full_HEIGHT 10
|
||||
#define FONT_Bitocra7_ADDR 0x2f53
|
||||
#define FONT_Bitocra7_FIRST_CHAR 0
|
||||
#define FONT_Bitocra7_WIDTH 4
|
||||
#define FONT_Bitocra7_HEIGHT 7
|
||||
|
||||
|
||||
// IMAGES
|
||||
#define IMG_BEGIN 0x3493
|
||||
#define IMG_Test_image_2_ADDR 0x3493
|
||||
#define IMG_Test_image_1_ADDR 0x3693
|
||||
#define IMG_COUNT 2
|
||||
|
BIN
src/eeprom_data/compiled_eeprom
Normal file
BIN
src/eeprom_data/compiled_eeprom
Normal file
Binary file not shown.
0
src/eeprom_data/eeprom_locations.h
Normal file
0
src/eeprom_data/eeprom_locations.h
Normal file
1070
src/eeprom_data/fonts/4thD.bdf
Normal file
1070
src/eeprom_data/fonts/4thD.bdf
Normal file
File diff suppressed because it is too large
Load Diff
1165
src/eeprom_data/fonts/5thElement.bdf
Normal file
1165
src/eeprom_data/fonts/5thElement.bdf
Normal file
File diff suppressed because it is too large
Load Diff
7567
src/eeprom_data/fonts/bitbuntu-full.bdf
Normal file
7567
src/eeprom_data/fonts/bitbuntu-full.bdf
Normal file
File diff suppressed because it is too large
Load Diff
2550
src/eeprom_data/fonts/bitbuntu.bdf
Normal file
2550
src/eeprom_data/fonts/bitbuntu.bdf
Normal file
File diff suppressed because it is too large
Load Diff
5450
src/eeprom_data/fonts/bitocra-13-full.bdf
Normal file
5450
src/eeprom_data/fonts/bitocra-13-full.bdf
Normal file
File diff suppressed because it is too large
Load Diff
3810
src/eeprom_data/fonts/bitocra-13.bdf
Normal file
3810
src/eeprom_data/fonts/bitocra-13.bdf
Normal file
File diff suppressed because it is too large
Load Diff
8010
src/eeprom_data/fonts/bitocra-full.bdf
Normal file
8010
src/eeprom_data/fonts/bitocra-full.bdf
Normal file
File diff suppressed because it is too large
Load Diff
2538
src/eeprom_data/fonts/bitocra.bdf
Normal file
2538
src/eeprom_data/fonts/bitocra.bdf
Normal file
File diff suppressed because it is too large
Load Diff
2720
src/eeprom_data/fonts/bitocra7.bdf
Normal file
2720
src/eeprom_data/fonts/bitocra7.bdf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/eeprom_data/fonts/bitorca-full.pcf
Normal file
BIN
src/eeprom_data/fonts/bitorca-full.pcf
Normal file
Binary file not shown.
10
src/eeprom_data/fonts/fonts.dir
Normal file
10
src/eeprom_data/fonts/fonts.dir
Normal file
@ -0,0 +1,10 @@
|
||||
9
|
||||
4thD.bdf -aaron-4thd-medium-r-normal--4-40-86-86-c-30-iso8859-1
|
||||
5thElement.bdf -aaron-5thelement-medium-r-normal--5-40-86-86-c-30-iso8859-1
|
||||
bitbuntu-full.bdf -aaron-bitbuntufull-medium-r-normal--10-100-72-72-c-90-utf8-1
|
||||
bitbuntu.bdf -aaron-bitbuntu-medium-r-normal--10-100-72-72-c-90-iso8859-1
|
||||
bitocra-13-full.bdf -aaron-bitocra13full-medium-r-normal--13-130-84-84-c-90-iso8859-1
|
||||
bitocra-13.bdf -aaron-bitocra13-medium-r-normal--13-130-84-84-c-90-iso8859-1
|
||||
bitocra-full.bdf -aaron-bitocrafull-medium-r-normal--11-100-72-72-m-90-iso8859-1
|
||||
bitocra.bdf -aaron-bitocra-medium-r-normal--11-100-72-72-m-90-iso8859-1
|
||||
bitocra7.bdf -aaron-bitocra7-medium-r-normal--7-60-75-75-c-40-iso8859-1
|
1
src/eeprom_data/fonts/fonts.scale
Normal file
1
src/eeprom_data/fonts/fonts.scale
Normal file
@ -0,0 +1 @@
|
||||
0
|
BIN
src/eeprom_data/fonts/test.bmp
Normal file
BIN
src/eeprom_data/fonts/test.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 B |
BIN
src/eeprom_data/fonts/test.pbm
Normal file
BIN
src/eeprom_data/fonts/test.pbm
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
src/eeprom_data/fonts/test.pil
Normal file
BIN
src/eeprom_data/fonts/test.pil
Normal file
Binary file not shown.
BIN
src/eeprom_data/images/test_image_1.png
Normal file
BIN
src/eeprom_data/images/test_image_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 887 B |
BIN
src/eeprom_data/images/test_image_2.png
Normal file
BIN
src/eeprom_data/images/test_image_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
src/eeprom_data/sketches/test_image_1.png
Normal file
BIN
src/eeprom_data/sketches/test_image_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 887 B |
BIN
src/eeprom_data/sketches/test_image_1.xcf
Normal file
BIN
src/eeprom_data/sketches/test_image_1.xcf
Normal file
Binary file not shown.
BIN
src/eeprom_data/sketches/test_image_2.xcf
Normal file
BIN
src/eeprom_data/sketches/test_image_2.xcf
Normal file
Binary file not shown.
BIN
src/eeprom_data/test.bmp
Normal file
BIN
src/eeprom_data/test.bmp
Normal file
Binary file not shown.
130
src/i2c.c
Normal file
130
src/i2c.c
Normal file
@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
#include <util/delay.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#ifdef DEBUG_BUILD
|
||||
#include "debug.h"
|
||||
#endif
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
|
||||
/** I2C notes
|
||||
* TWDR: data address shift register
|
||||
* contians address or data bytes to be transmitted/recieved
|
||||
* ACK bit not accesible
|
||||
* TWAR: matches recieved addresses
|
||||
* TWCR: control register, sets settings
|
||||
* TWINT: tw interrupt flag
|
||||
* also is dependent on GIE in SREG
|
||||
* TWSR: TWI status register (only matters if TWI interurupt flag asserted)
|
||||
|
||||
* Steps simplified:
|
||||
* SEND START
|
||||
* Send START with TWCR
|
||||
* Set TWINT in TWCR to 1; as this clears the flag
|
||||
* TWSR will then say start has begun
|
||||
* Load SLA+W into TWDR (what is this? TODO)
|
||||
* Write something to TWCR to initiate send? (make sure twint is set after)
|
||||
* poll TWSR interrupt bit to see if we recieve a message (or figure out interrupts)
|
||||
*
|
||||
* Note: You may be wondering why I'm not handling i2c errors.
|
||||
* I have limited time, and I don't think it's nessesary unless I start running into them.
|
||||
*
|
||||
* Some I may work on handling later.
|
||||
*
|
||||
*/
|
||||
|
||||
void error() {}
|
||||
|
||||
void i2c_init() {
|
||||
TWBR = 12;
|
||||
TWSR &= 0b11111100;
|
||||
}
|
||||
|
||||
|
||||
void i2c_start(uint8_t addr, bool rw) {
|
||||
TWCR = (_BV(TWSTA) | _BV(TWEN) | _BV(TWINT)); //send start signal
|
||||
loop_until_bit_is_set(TWCR, TWINT);
|
||||
if((TWSR & 0xf8) != TW_START) {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("Couldn't set start condition?\n");
|
||||
#endif
|
||||
error();
|
||||
}
|
||||
|
||||
TWDR = (addr << 1) | rw;
|
||||
TWCR = _BV(TWINT) | _BV(TWEN);
|
||||
loop_until_bit_is_set(TWCR, TWINT);
|
||||
|
||||
if((TWSR & 0xf8) != TW_MT_SLA_ACK) {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("unhandled NACK in address transmission\
|
||||
TWCR: 0x%x\
|
||||
TWSR: 0x%x\n", TWCR, (TWSR & ~(0b11)));
|
||||
#endif
|
||||
error();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void i2c_stop() { TWCR = (_BV(TWSTO) | _BV(TWEN) | _BV(TWINT)); }
|
||||
|
||||
void i2c_send(uint8_t byte) {
|
||||
TWDR = byte; //fist packet is address
|
||||
TWCR = _BV(TWINT) | _BV(TWEN); //send over the byte
|
||||
loop_until_bit_is_set(TWCR, TWINT);
|
||||
|
||||
if((TWSR & 0xf8) != TW_MT_DATA_ACK) {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("unhandled NACK in data transmission\
|
||||
TWCR: 0x%x\
|
||||
TWSR: 0x%x\n", TWCR, (TWSR & ~(0b11)));
|
||||
#endif
|
||||
error();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_recv() {
|
||||
uint8_t value;
|
||||
loop_until_bit_is_set(TWCR, TWINT);
|
||||
value = TWDR;
|
||||
if((TWSR & 0xf8) != TW_MR_SLA_ACK) {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("Error recieving byte from i2c device\n");
|
||||
#endif
|
||||
error();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
//does NOT control start/stop, simply reads TWDR
|
||||
|
||||
uint8_t i2c_read_reg_addr16(uint8_t device, uint16_t addr) {
|
||||
uint8_t value;
|
||||
|
||||
i2c_start(device, I2C_WRITE);
|
||||
i2c_send((uint8_t)addr & 0xff);
|
||||
i2c_send((uint8_t)addr >> 8);
|
||||
i2c_start(device, I2C_READ);
|
||||
value = i2c_recv();
|
||||
i2c_stop();
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
void i2c_write_reg(uint8_t device_addr, uint8_t device_reg, uint8_t value) {
|
||||
i2c_start(device_addr, I2C_WRITE);
|
||||
i2c_send(device_reg);
|
||||
i2c_send(value);
|
||||
i2c_stop();
|
||||
}
|
||||
|
||||
void i2c_write_reg_multi(uint8_t device_addr, uint8_t device_reg, size_t len, uint8_t *values) {
|
||||
i2c_start(device_addr, I2C_WRITE);
|
||||
i2c_send(device_reg);
|
||||
for(size_t on_byte = 0; on_byte < len; on_byte++) i2c_send(values[on_byte]);
|
||||
i2c_stop();
|
||||
}
|
25
src/i2c.h
Normal file
25
src/i2c.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __I2C_H
|
||||
#define __I2C_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define I2C_WRITE 0
|
||||
#define I2C_READ 1
|
||||
|
||||
//higher level functions write registers
|
||||
//TODO rename if we end up only using for screen
|
||||
void i2c_write_reg(uint8_t device_addr, uint8_t device_reg, uint8_t value);
|
||||
void i2c_write_reg_multi(uint8_t device_addr, uint8_t device_reg, size_t len, uint8_t *values);
|
||||
|
||||
//for drivers with weird i2c processes
|
||||
void i2c_send(uint8_t byte);
|
||||
uint8_t i2c_recv();
|
||||
void i2c_stop();
|
||||
void i2c_start(uint8_t addr, bool rw);
|
||||
uint8_t i2c_read_reg_addr16(uint8_t device, uint16_t addr);
|
||||
|
||||
void i2c_init();
|
||||
|
||||
|
||||
#endif
|
57
src/main.c
Normal file
57
src/main.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <stdio.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include "i2c.h"
|
||||
#include "ssd1306_display_driver.h"
|
||||
#include "debug.h" //TODO move to timer
|
||||
#include "br24t_eeprom_driver.h"
|
||||
/**
|
||||
* TODO
|
||||
* make sure desired functions are static (it's just good practice)
|
||||
* crashing, stack tracing, if that ever matters
|
||||
* see if stdio is ever needed in non debug builds
|
||||
* Battery factors to test:
|
||||
* OLED clock (command 0xd5)
|
||||
* OLED stay on/off
|
||||
* organize i2c eeprom/timer code
|
||||
*/
|
||||
|
||||
|
||||
#if defined(DEBUG_BUILD) || defined(EEPROM_INSTALL)
|
||||
#include "uart.h" //TODO remove if needed
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
//initlizes i2c, right now only speed //TODO don't delegate a whole function if desired
|
||||
i2c_init();
|
||||
screen_init();
|
||||
#if defined(DEBUG_BUILD) || defined(EEPROM_INSTALL)
|
||||
//initlizes usart registers
|
||||
uart_init();
|
||||
FILE stdout_replacement = FDEV_SETUP_STREAM((void *)uart_sendbyte, NULL, _FDEV_SETUP_WRITE);
|
||||
FILE stdin_replacement = FDEV_SETUP_STREAM(NULL, (void *)uart_recvbyte, _FDEV_SETUP_READ);
|
||||
stdout = &stdout_replacement;
|
||||
stdin = &stdin_replacement;
|
||||
screen_testdraw();
|
||||
#endif
|
||||
|
||||
//initilize timer
|
||||
timer_init();
|
||||
|
||||
#ifdef EEPROM_INSTALL
|
||||
flash_eeprom();
|
||||
#endif
|
||||
|
||||
|
||||
//initlizes screen registers with good values since we dont have control over reset functionallity
|
||||
screen_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
48
src/makefile
Normal file
48
src/makefile
Normal file
@ -0,0 +1,48 @@
|
||||
#compile options
|
||||
TOOLCHAIN_DIR=/home/indigo/packs/avr8-gnu-toolchain-linux_x86_64
|
||||
CC=$(TOOLCHAIN_DIR)/bin/avr-gcc
|
||||
LD=$(TOOLCHAIN_DIR)/bin/avr-ld
|
||||
INC=$(TOOLCHAIN_DIR)/avr/include
|
||||
OUT=compiled_payload.elf
|
||||
DEVICE=atmega2560
|
||||
F_CPU=16000000
|
||||
|
||||
DEBUG=1
|
||||
|
||||
#avrdude options
|
||||
PARTNO=ATmega2560
|
||||
PORT=/dev/ttyACM1
|
||||
BAUD=115200
|
||||
|
||||
|
||||
#baudrate
|
||||
RUNTIME_BAUDRATE=9600
|
||||
|
||||
|
||||
make:
|
||||
#$(CC) -mmcu=$(DEVICE) -I $(INC) -c debug_serial.o -DDEBUG_BUILD=$(DEBUG) -DBAUD=$(RUNTIME_BAUDRATE) -DF_CPU=$(F_CPU) -Wall -O1 debug_serial.c
|
||||
#$(CC) -mmcu=$(DEVICE) -I $(INC) -c main.o -DDEBUG_BUILD=$(DEBUG) -DBAUD=$(RUNTIME_BAUDRATE) -DF_CPU=$(F_CPU) -Wall -O1 main.c
|
||||
#$(CC) -mmcu=$(DEVICE) -I $(INC) -c debug_serial.o -DDEBUG_BUILD=$(DEBUG) -DBAUD=$(RUNTIME_BAUDRATE) -DF_CPU=$(F_CPU) -Wall -O1 i2c.c
|
||||
#$(LD) -mavr6 -o $(OUT) -s main.o debug_serial.o #TODO wish I knew how to make -mavr6 dependent on DEVICE
|
||||
#TODO no debug.c if debug disabled
|
||||
$(CC) -mmcu=$(DEVICE) -I $(INC) -o $(OUT) -DDEBUG_BUILD=$(DEBUG) -DBAUD=$(RUNTIME_BAUDRATE) -DF_CPU=$(F_CPU) -Wall -O1 main.c debug.c i2c.c ssd1306_display_driver.c uart.c br24t_eeprom_driver.c paint.c -Wall
|
||||
compiledb make --dry-run > /dev/null
|
||||
|
||||
eeprom:
|
||||
./compile_eeprom.py
|
||||
|
||||
eeprom_install:
|
||||
$(CC) -lc -mmcu=$(DEVICE) -I $(INC) -o $(OUT) -DBAUD=$(RUNTIME_BAUDRATE) -DF_CPU=$(F_CPU) -DEEPROM_INSTALL -Wall -O1 debug.c i2c.c ssd1306_driver.c uart.c main.c -Wall
|
||||
doas avrdude -v -p $(PARTNO) -P $(PORT) -c wiring -b $(BAUD) -D -U flash:w:$(OUT):e
|
||||
doas ./write_eeprom.py $(PORT) $(SPEED)
|
||||
|
||||
|
||||
install: $(OUT)
|
||||
doas avrdude -v -p $(PARTNO) -P $(PORT) -c wiring -b $(BAUD) -D -U flash:w:$(OUT):e
|
||||
|
||||
screen:
|
||||
screen $(PORT) $(RUNTIME_BAUDRATE)
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf compiled_eeprom
|
||||
|
35
src/paint.c
Normal file
35
src/paint.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include <string.h>
|
||||
#include "ssd1306_display_driver.h"
|
||||
#include "paint.h"
|
||||
#include "br24t_eeprom_driver.h"
|
||||
|
||||
#define TWOD_INDEX(x, y) ((y * SCREEN_RES_Y) / 8) + x //TODO rename to insinuate /8
|
||||
//
|
||||
/** I'm not using the screen's buffer as a standard 2d array,
|
||||
* this is because of how pixels are represented in the display's GDRAM.
|
||||
*
|
||||
* While it would be nicer to just resort the array every time it's updated,
|
||||
* keeping driver abstractions in it's own file (like we should),
|
||||
* this way we don't have to resort every time we redraw.
|
||||
*
|
||||
* Some operations may not need a resort, for example, images/videos optmimized
|
||||
* for GDRAM. Doing it in each function helps us prevent unnessesary calculations
|
||||
* while doing real time operations like videos.
|
||||
*/
|
||||
|
||||
void screen_clear() { memset(&screen_buffer, 0, sizeof(screen_buffer)); }
|
||||
|
||||
//images are optimized to follow page formatting
|
||||
void draw_image(EEPROM_ADDR image) {
|
||||
for(int on_pix = 0; on_pix < (SCREEN_RES_X * SCREEN_RES_Y) / 8; on_pix++)
|
||||
screen_buffer[on_pix] = EEPROM_READBYTE(image + on_pix);
|
||||
}
|
||||
|
||||
//however here we need to compensate
|
||||
void draw_hline(int pos_y) {
|
||||
for(int on_pix = 0; on_pix < SCREEN_RES_X; on_pix++)
|
||||
screen_buffer[((pos_y / 8) * 8) + on_pix] |= (1 << (pos_y % 8));
|
||||
}
|
||||
|
||||
void draw_text(char *text, int x, int y, EEPROM_ADDR font) {
|
||||
}
|
13
src/paint.h
Normal file
13
src/paint.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __PAINT_H
|
||||
#define __PAINT_H
|
||||
|
||||
#include "ssd1306_display_driver.h"
|
||||
#include "br24t_eeprom_driver.h"
|
||||
|
||||
void screen_clear();
|
||||
void draw_image(EEPROM_ADDR image);
|
||||
void draw_hline(int pos_y);
|
||||
void draw_text(char *text, int x, int y, EEPROM_ADDR font);
|
||||
|
||||
#endif
|
||||
|
15
src/pcf_clock_driver.c
Normal file
15
src/pcf_clock_driver.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <i2c.h>
|
||||
#define CLOCK_ADDR 0x51
|
||||
|
||||
#ifdef FLASH_EEPROM
|
||||
void flash_clock() {
|
||||
i2c_write_reg(EEPROM_ADDR, 0x00, 0x58); //resets clock
|
||||
i2c_write_reg(CLOCK_ADDR, 0x00, 0x40); //sets to 12 hour time
|
||||
i2c_write_reg(CLOCK_ADDR, 0x01, 0x08); //sets alarm interrupts on
|
||||
|
||||
//recieve time
|
||||
|
||||
|
||||
}
|
||||
i2c_write_reg(CLOCK_ADDR, 0x03, 0x01); //free ram byte; says we've set the time
|
||||
#endif
|
6
src/pcf_clock_driver.h
Normal file
6
src/pcf_clock_driver.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <time.h>
|
||||
|
||||
void clock_init();
|
||||
void set_time(time_t time);
|
||||
time_t get_time();
|
||||
void set_alarm(time_t time);
|
127
src/ssd1306_display_driver.c
Normal file
127
src/ssd1306_display_driver.c
Normal file
@ -0,0 +1,127 @@
|
||||
#include <util/twi.h>
|
||||
#include <stdio.h>
|
||||
#include <util/delay.h>
|
||||
#include <string.h>
|
||||
#include "i2c.h"
|
||||
#include "ssd1306_display_driver.h"
|
||||
|
||||
|
||||
#define SSD1306_ADDR 0x3c
|
||||
#define SSD1306_CMD_REG 0x00
|
||||
#define SSD1306_DATA_REG 0x40
|
||||
|
||||
//on the datasheet we have 32 extra rows (4 more pages) of GDRAM that don't fit on the display; we just ignore them everywhere
|
||||
#define SCREEN_PAGE_CNT SCREEN_RES_Y / 8
|
||||
|
||||
#define I2C_WRITE 0
|
||||
#define I2C_READ 1
|
||||
|
||||
|
||||
|
||||
void screen_init() {
|
||||
#ifdef DEBUG_BUILD
|
||||
printf("initlizing SSD1306 display driver\n");
|
||||
#endif
|
||||
//turn on screen while we configure shit, it might look cooler
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xaf);
|
||||
|
||||
//don't inverse display
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xa6);
|
||||
|
||||
//set contrast to 255 (try chainging?)
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x81, 0xff});
|
||||
|
||||
//set lower nibble of column ptr to 0
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
|
||||
//set upper nibble of column ptr to 0
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
|
||||
|
||||
//memory mode is paging
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x20, 0x02});
|
||||
|
||||
//no vertical shift
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xd3, 0x00});
|
||||
|
||||
//page address is at 0
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0);
|
||||
|
||||
//ram display start register is at 0
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x40);
|
||||
|
||||
//column address 0 is mapped to seg0
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xa0); //a1
|
||||
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xc8);
|
||||
|
||||
|
||||
//set mux ratio to 32 mux
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xa8, 0x1f});
|
||||
|
||||
//alternative COM hardware mapping (stolen from lib)
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xda, 0x02});
|
||||
|
||||
//volage regulator on
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0x8d, 0x14});
|
||||
|
||||
|
||||
//set clock divider to zero, and oscillator frequency as high as it goes
|
||||
//Maybe we save battery to run slower?
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 2, (uint8_t[]){0xd5, 0xf0}); //TODO look
|
||||
|
||||
//deactivate scroll
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x2e);
|
||||
|
||||
}
|
||||
|
||||
void screen_off() { i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xaf); }
|
||||
|
||||
void screen_on() { i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xae); }
|
||||
|
||||
void screen_update() {
|
||||
for(int on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_DATA_REG, sizeof(screen_buffer), screen_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
//ugly code below
|
||||
|
||||
void scroll_test() {
|
||||
//sets scroll area to whole screen
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 3, (uint8_t[]){0xa3, 0x00, 0x20});
|
||||
//set up scroll options
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x29, 0x00, 0x00, 0x00, 0x04, 0x00});
|
||||
//actually activate scroll
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_CMD_REG, 6, (uint8_t[]){0x2f});
|
||||
}
|
||||
|
||||
void screen_testdraw() {
|
||||
unsigned int on_pix;
|
||||
unsigned int on_page;
|
||||
|
||||
printf("running screen time tests\n");
|
||||
printf("generating test image...\n");
|
||||
for(on_pix = 0; on_pix < sizeof(screen_buffer); on_pix++)
|
||||
screen_buffer[on_pix] = ((uint8_t)0xaa << (on_pix % 8));
|
||||
|
||||
printf("page mode, individual byte per i2c call...\n");
|
||||
for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
|
||||
for(on_pix = 0; on_pix < SCREEN_RES_X; on_pix++)
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_DATA_REG, screen_buffer[(on_page * 8) + on_pix]);
|
||||
}
|
||||
printf("page mode, 1 page per i2c call...\n");
|
||||
for(on_page = 0; on_page < SCREEN_PAGE_CNT; on_page++) {
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0xb0 + on_page);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x00);
|
||||
i2c_write_reg(SSD1306_ADDR, SSD1306_CMD_REG, 0x10);
|
||||
i2c_write_reg_multi(SSD1306_ADDR, SSD1306_DATA_REG, SCREEN_RES_X, &screen_buffer[on_page * SCREEN_RES_X]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
17
src/ssd1306_display_driver.h
Normal file
17
src/ssd1306_display_driver.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __SSD1306_H
|
||||
#define __SSD1306_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SCREEN_RES_X 128
|
||||
#define SCREEN_RES_Y 32
|
||||
|
||||
uint8_t screen_buffer[(SCREEN_RES_X * SCREEN_RES_Y) / 8];
|
||||
|
||||
void screen_init();
|
||||
void screen_testdraw();
|
||||
void screen_off();
|
||||
void screen_on();
|
||||
void screen_update();
|
||||
|
||||
#endif
|
74
src/uart.c
Normal file
74
src/uart.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include <avr/io.h>
|
||||
#include <stdio.h>
|
||||
#include <util/setbaud.h>
|
||||
|
||||
/** UART notes
|
||||
* UCSR0A:
|
||||
* 0: MP communication mode
|
||||
* 1: U2X (double trans speed)
|
||||
* 2: USART parity error
|
||||
* 3: Data overrun (udr0 not read before next frame)
|
||||
* 4: Frame error
|
||||
* 5: Data register empty (new data can be transmitted)
|
||||
* 6: USART transmit complete
|
||||
* 7: USART recieve complete
|
||||
* ____________________________________________________________
|
||||
* UCSR0B:
|
||||
* 0: transmit data bit 8
|
||||
* 1: recieve data bit 8
|
||||
* 2: USART char size 0 (used with UCSZ01 and UCSZ00 to set data frame size)
|
||||
* 3: Transmitter enable
|
||||
* 4: Reciever enable
|
||||
* 5: USART data reg empty interrupt table
|
||||
* 6: TX complete int enable
|
||||
* 7: RX complete int enable
|
||||
* ____________________________________________________________
|
||||
* UCSR0C:
|
||||
* 0: Clock polarity (1: falling edge trasmit, recieve rising edge)
|
||||
* 1: USART char size 0
|
||||
* 2: USART char size 1
|
||||
* 3: USART stop bit select (1: 1 stop bit, 0: 2 stop bits)
|
||||
* 4: USART parity mode (00: async, 01: sync)
|
||||
* 5: USART Parity mode (02: master SPI)
|
||||
* 6: USART mode select (00: async 01: sync)
|
||||
* 7: USART mode select (02: master SPI)
|
||||
* ____________________________________________________________
|
||||
* UBRR0(H,L): baudrates
|
||||
*
|
||||
**/
|
||||
|
||||
//TODO replace with static void and just use high level functions?
|
||||
void uart_sendbyte(uint8_t byte) {
|
||||
if(byte == '\n') uart_sendbyte('\r');
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = byte;
|
||||
}
|
||||
|
||||
//TODO replace with static void and just use high level functions?
|
||||
uint8_t uart_recvbyte() {
|
||||
loop_until_bit_is_set(UCSR0A, RXC0);
|
||||
return UDR0;
|
||||
}
|
||||
|
||||
void uart_init() {
|
||||
//set baud rate
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
TODO figure out why USE_2X is enable when it shoudn't be
|
||||
//set baud rate
|
||||
#ifdef USE_2X //is set by header
|
||||
UCSR0A |= _BV(U2X0);
|
||||
#else
|
||||
UCSR0A &= ~(_BV(U2X0));
|
||||
#endif
|
||||
**/
|
||||
|
||||
UCSR0A &= ~(_BV(U2X0));
|
||||
|
||||
UCSR0C = ((_BV(UCSZ01)) | _BV(UCSZ00)); // set 8 bit char size, yes the '=' is intentional
|
||||
UCSR0B = (_BV(RXEN0) | _BV(TXEN0));
|
||||
|
||||
}
|
3
src/uart.h
Normal file
3
src/uart.h
Normal file
@ -0,0 +1,3 @@
|
||||
void uart_init();
|
||||
void uart_sendbyte(uint8_t byte);
|
||||
uint8_t uart_recvbyte();
|
50
src/write_eeprom.py
Executable file
50
src/write_eeprom.py
Executable file
@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
import serial
|
||||
import argparse
|
||||
import os
|
||||
|
||||
#we send syn, recv ack
|
||||
SYN_MAGIC = 0xdeafbeef
|
||||
ACK_MAGIC = 0xf00dd00d
|
||||
|
||||
EEPROM_PAGESIZE = 64
|
||||
EEPROM_FILE = "./compiled_eeprom"
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description="sends binary file over serial so the avr can write it to eeprom")
|
||||
parser.add_argument('port', type=str)
|
||||
parser.add_argument('baud', type=int)
|
||||
args = parser.parse_args()
|
||||
|
||||
eeprom_file = open("./compiled_eeprom", "rb")
|
||||
eeprom_filesize = os.fstat(eeprom_file.fileno()).st_size
|
||||
|
||||
s = serial.Serial(args.port, args.baud, timeout = 0)
|
||||
s.write(SYN_MAGIC)
|
||||
|
||||
def handle_writer_error():
|
||||
if write_status == 1: # verification failed
|
||||
print("Verification failed on page {}!".format(page))
|
||||
elif write_status == 0xff:
|
||||
print("Unknown error writing page {}!".format(page))
|
||||
|
||||
|
||||
while not s.read(4) == ACK_MAGIC:
|
||||
pass
|
||||
|
||||
print("Device detected, writing eeprom...")
|
||||
for page in range(0, int(eeprom_filesize / EEPROM_PAGESIZE)):
|
||||
s.write(eeprom_file.read(EEPROM_PAGESIZE))
|
||||
write_status = s.read(1)
|
||||
if not write_status == 0:
|
||||
handle_writer_error(write_status)
|
||||
|
||||
if eeprom_file.tell() < eeprom_filesize:
|
||||
s.write(eeprom_file.read())
|
||||
[s.write(0) for b in range(0, eeprom_filesize % EEPROM_PAGESIZE)]
|
||||
write_status = s.read(1)
|
||||
if not write_status == 0:
|
||||
handle_writer_error(write_status)
|
||||
|
||||
|
||||
print("Done writing to EEPROM! You are still alone!")
|
8
unison_project_config.prf
Normal file
8
unison_project_config.prf
Normal file
@ -0,0 +1,8 @@
|
||||
root=/home/indigo/projects/watch
|
||||
root=ssh://root@bpcspace.com//unison/watch
|
||||
ignore=Name *.out
|
||||
ignore=Name .tmp*
|
||||
ignore=Name compiled_payload.elf
|
||||
ignore=Name compiled_eeprom
|
||||
ignore=Path bin/*
|
||||
auto=true
|
Loading…
x
Reference in New Issue
Block a user