#include <util/delay.h>
#include <avr/sleep.h>
#include <stdbool.h>
+#include <string.h>
#include "atmega168_clock_7seg.h"
// for linker, emulator, and programmer's sake
#include "avr_mcu_section.h"
AVR_MCU(F_CPU, "atmega168");
-#define N_DIGITS 17
-#define USE_17SEG 1
-#if USE_17SEG
-#define BYTES_PER_DIGIT 3
-#else
-#define BYTES_PER_DIGIT 1
-#endif
+#define N_DIGIT 14
+#define N_ALPHA 3
+#define N_BYTES (N_DIGIT + N_ALPHA * 3)
+#define DIGIT_SEG_DP 0b10000000
+#define ALPHA_SEG_DP 0b10000000000000000L
PIN_DEFINE(SRESET, D, PD4, 1);
//PIN_DEFINE(SOE, D, PD6, 1); // pwm AIN0/OC0A
} ;
uint8_t state = state_ShowTime | state_IncrementTime;
-#if USE_17SEG
-uint32_t digits[N_DIGITS];
-#else
-uint8_t digits[N_DIGITS];
-#endif
+uint8_t data[N_BYTES];
enum EDecimal {
D_SECOND = 0, D_MINUTE, D_HOUR, D_DAY, D_MONTH, D_YEAR, D_MAX
}
uint8_t weekDay(uint8_t day, uint8_t month, uint8_t year) {
+ uint8_t y0 = year & 3;
+ year >>= 3;
+ uint8_t y1 = year % 25;
+ year /= 25;
return (
day +
month_weekday[month] +
- (month >= 2 && isLeap(year)) +
- (year >> 2) -
- year / 100
+ (365 % 7) * y0 +
+ ((365 * 4 + 1) % 7) * y1 +
+ (uint8_t)((365L * 100 + 24) % 7) * year +
+ (y1 && (y0 || month >= 2))
) % 7;
}
void decimalInc()
{
-#if 1 // for testing day/month/year increments
+#if 0 // for testing day/month/year increments
for (uint8_t in = D_DAY; in < D_MAX; in++)
#else
for (uint8_t in = 0; in < D_MAX; in++)
}
}
-#if USE_17SEG
+#if 0 // not used anymore
// A1 A2
// F H J K B
// G1 G2
// E N M L C
// D1 D2 DP
-const uint16_t digit_to_segments[10] = {
+const uint16_t digit_to_data[10] = {
//NMLKJHGGFEDDCBAA
// 21 21 21
0b0000000011111111, // 0
0b0000001111111111, // 8
0b0000001110001111, // 9
};
-#define SEG_DP 0b10000000000000000L
-#define SEG_h 0b0000001111001000
#else
// A
// F B
// G
// E C
// D DP
-const uint8_t digit_to_segments[10] = {
+const uint8_t digit_to_data[10] = {
// GFEDCBA
0b00111111, // 0
0b00000110, // 1
0b01111111, // 8
0b01100111, // 9
};
-#define SEG_DP 0b10000000
-#define SEG_h 0b01110100
#endif
// A1 A2
// E N M L C
// D1 D2 DP
// note: table starts with Saturday for 1/1/2000
-const uint16_t weekday_to_segments[7][3] = {
+const uint8_t weekday_to_data[7][3][3] = {
// NMLKJHGGFEDDCBAA
// 21 21 21
{
- 0b0000001110111011, // S
- 0b0000001111001111, // A
- 0b0100100000000011, // T
+ {0b00000000, 0b00000011, 0b10111011}, // S
+ {0b00000000, 0b00000011, 0b11001111}, // A
+ {0b00000000, 0b01001000, 0b00000011}, // T
},
{
- 0b0000001110111011, // S
- 0b0000000011111100, // U
- 0b0010010011001100, // N
+ {0b00000000, 0b00000011, 0b10111011}, // S
+ {0b00000000, 0b00000000, 0b11111100}, // U
+ {0b00000000, 0b00100100, 0b11001100}, // N
},
{
- 0b0001010011001100, // M
- 0b0000000011111111, // O
- 0b0010010011001100, // N
+ {0b00000000, 0b00010100, 0b11001100}, // M
+ {0b00000000, 0b00000000, 0b11111111}, // O
+ {0b00000000, 0b00100100, 0b11001100}, // N
},
{
- 0b0100100000000011, // T
- 0b0000000011111100, // U
- 0b0000001111110011, // E
+ {0b00000000, 0b01001000, 0b00000011}, // T
+ {0b00000000, 0b00000000, 0b11111100}, // U
+ {0b00000000, 0b00000011, 0b11110011}, // E
},
{
- 0b1010000011001100, // W
- 0b0000001111110011, // E
- 0b0100100000111111, // D
+ {0b00000000, 0b10100000, 0b11001100}, // W
+ {0b00000000, 0b00000011, 0b11110011}, // E
+ {0b00000000, 0b01001000, 0b00111111}, // D
},
{
- 0b0100100000000011, // T
- 0b0000001111001100, // H
- 0b0000000011111100, // U
+ {0b00000000, 0b01001000, 0b00000011}, // T
+ {0b00000000, 0b00000011, 0b11001100}, // H
+ {0b00000000, 0b00000000, 0b11111100}, // U
},
{
- 0b0000001111000011, // F
- 0b0010001111000111, // R
- 0b0100100000110011, // I
+ {0b00000000, 0b00000011, 0b11000011}, // F
+ {0b00000000, 0b00100011, 0b11000111}, // R
+ {0b00000000, 0b01001000, 0b00110011}, // I
},
};
struct {
- uint8_t b[N_DIGITS * BYTES_PER_DIGIT];
- uint8_t in;
- uint8_t out;
+ uint8_t b[N_BYTES];
+ uint8_t ptr;
} spi;
void spi_init()
{
- spi.in = spi.out = 0;
+ spi.ptr = 0;
SPCR = (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) |
(0 << CPOL) | (0 << CPHA) | (0 << SPR0);
void spi_start()
{
uint8_t b;
- if (spi.in != spi.out) {
- b = spi.b[spi.in++];
+ if (spi.ptr != N_BYTES) {
+ b = spi.b[spi.ptr++];
SPDR = b;
}
}
ISR(SPI_STC_vect)
{
uint8_t b;
- if (spi.in != spi.out) {
- b = spi.b[spi.in++];
+ if (spi.ptr != N_BYTES) {
+ b = spi.b[spi.ptr++];
SPDR = b;
} else {
// fifo is empty, tell the 74hc595 to latch the shift register
if (!(state & state_IncrementTime) || timer[delay_Second].delay <= 2) {
switch (state & ~state_IncrementTime) {
case state_ShowTime:
- digits[0] |= SEG_DP; // mapped to colon
+ data[N_ALPHA * 3] |= DIGIT_SEG_DP; // mapped to colon
break;
}
}
cli();
// interupts are stopped here, so there is no race condition
- //int restart = spi.out == spi.in;
- spi.in = 0;
- spi.out = 0;
- for (uint8_t bi = 0; bi < N_DIGITS; bi++)
-#if USE_17SEG
- {
- spi.b[spi.out++] = (uint8_t)(digits[bi] >> 16);
- spi.b[spi.out++] = (uint8_t)(digits[bi] >> 8);
- spi.b[spi.out++] = (uint8_t)digits[bi];
- }
-#else
- spi.b[spi.out++] = digits[bi];
-#endif
- //if (restart)
- spi_start();
+ spi.ptr = 0;
+ memcpy(spi.b, data, N_BYTES);
+ spi_start();
sei();
}
{
switch (state & ~state_IncrementTime) {
case state_ShowTime: {
+ uint8_t weekday =
+ weekDay(decimal[D_DAY], decimal[D_MONTH], decimal[D_YEAR]);
+ for (uint8_t i = 0; i < N_ALPHA; ++i)
+ for (uint8_t j = 0; j < 3; ++j)
+ data[i * 3 + j] = weekday_to_data[weekday][N_ALPHA - 1 - i][j];
+
uint16_t year = decimal[D_YEAR] + 2000;
- digits[0] = digit_to_segments[year % 10];
+ data[N_ALPHA * 3] = digit_to_data[year % 10];
year /= 10;
- digits[1] = digit_to_segments[year % 10];
+ data[N_ALPHA * 3 + 1] = digit_to_data[year % 10];
year /= 10;
- digits[2] = digit_to_segments[year % 10];
- year /= 10;
- digits[3] = digit_to_segments[year];
+ data[N_ALPHA * 3 + 2] = digit_to_data[year % 10];
+ data[N_ALPHA * 3 + 3] = digit_to_data[year / 10];
+
+ uint8_t month = decimal[D_MONTH] + 1;
+ data[N_ALPHA * 3 + 4] = digit_to_data[month % 10] | DIGIT_SEG_DP;
+ month /= 10;
+ data[N_ALPHA * 3 + 5] = month ? digit_to_data[month / 10] : 0;
- uint8_t temp = decimal[D_MONTH] + 1;
- digits[4] = digit_to_segments[temp % 10] | SEG_DP;
- digits[5] = digit_to_segments[temp / 10];
+ uint8_t day = decimal[D_DAY] + 1;
+ data[N_ALPHA * 3 + 6] = digit_to_data[day % 10] | DIGIT_SEG_DP;
+ day /= 10;
+ data[N_ALPHA * 3 + 7] = day ? digit_to_data[day] : 0;
- /*uint8_t*/ temp = decimal[D_DAY] + 1;
- digits[6] = digit_to_segments[temp % 10] | SEG_DP;
- digits[7] = digit_to_segments[temp / 10];
+ data[N_ALPHA * 3 + 8] = digit_to_data[decimal[D_SECOND] % 10];
+ data[N_ALPHA * 3 + 9] = digit_to_data[decimal[D_SECOND] / 10];
- temp = weekDay(decimal[D_DAY], decimal[D_MONTH], decimal[D_YEAR]);
- digits[8] = weekday_to_segments[temp][2];
- digits[9] = weekday_to_segments[temp][1];
- digits[10] = weekday_to_segments[temp][0];
+ data[N_ALPHA * 3 + 10] = digit_to_data[decimal[D_MINUTE] % 10];
+ data[N_ALPHA * 3 + 11] = digit_to_data[decimal[D_MINUTE] / 10];
- digits[11] = digit_to_segments[decimal[D_SECOND] % 10];
- digits[12] = digit_to_segments[decimal[D_SECOND] / 10];
- digits[13] = digit_to_segments[decimal[D_MINUTE] % 10];
- digits[14] = digit_to_segments[decimal[D_MINUTE] / 10];
- digits[15] = digit_to_segments[decimal[D_HOUR] % 10];
- digits[16] = digit_to_segments[decimal[D_HOUR] / 10];
+ uint8_t hour = decimal[D_HOUR];
+ data[N_ALPHA * 3 + 12] = digit_to_data[hour % 10];
+ hour /= 10;
+ data[N_ALPHA * 3 + 13] = hour ? digit_to_data[hour] : 0;
if (!(state & state_IncrementTime))
- digits[0] |= SEG_DP; // mapped to colon
+ data[N_ALPHA * 3] |= DIGIT_SEG_DP; // mapped to colon
} break;
//case state_Sleep: {
// /* nothing to do */
#include "button.h"
#include "hc595.h"
-#define N_DIGITS 17
+#define N_DIGIT 14
+#define N_ALPHA 3
+#define N_BYTES (N_DIGIT + N_ALPHA * 3)
#define ORIGIN_X 50.f
#define ORIGIN_Y 50.f
#define DIGIT_WIDTH 320.f
#define WINDOW_X (ORIGIN_X + 5.5f * DIGIT_WIDTH + .5f * COLON_WIDTH)
#define WINDOW_Y (ORIGIN_Y + 1.5f * LINE_HEIGHT)
-#define USE_17SEG 1
-#if USE_17SEG
-#define BYTES_PER_DIGIT 3
-#define SEGMENTS_PER_DIGIT 17
-#define SEG_DP 0x10000
-#else
-#define BYTES_PER_DIGIT 1
-#define SEGMENTS_PER_DIGIT 8
-#define SEG_DP 0x80
-#endif
+#define DIGIT_SEG_DP 0x80
+#define DIGIT_N_SEG 8
+
+#define ALPHA_SEG_DP 0x10000
+#define ALPHA_N_SEG 17
enum {
B_START = 0, B_STOP, B_RESET,
volatile int do_button_press[B_MAX] = {0};
avr_t * avr = NULL;
avr_vcd_t vcd_file;
-#define N_SHIFTERS (N_DIGITS * BYTES_PER_DIGIT)
-hc595_t shifters[N_SHIFTERS];
+hc595_t shifters[N_BYTES];
-const float digit_pos[N_DIGITS][3] = {
+const float digit_pos[N_DIGIT][3] = {
// first row
{ORIGIN_X, ORIGIN_Y + .6f * LINE_HEIGHT, 1.f},
{ORIGIN_X + DIGIT_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, 1.f},
{ORIGIN_X + 4.f * DIGIT_WIDTH + 1.5f * COLON_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, .5f},
{ORIGIN_X + 4.5f * DIGIT_WIDTH + 1.5f * COLON_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, .5f},
// second row
- {ORIGIN_X, ORIGIN_Y, .5f},
- {ORIGIN_X + .5f * DIGIT_WIDTH, ORIGIN_Y, .5f},
- {ORIGIN_X + 1.f * DIGIT_WIDTH, ORIGIN_Y, .5f},
{ORIGIN_X + 1.5f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
{ORIGIN_X + 2.f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
{ORIGIN_X + 2.5f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
{ORIGIN_X + 5.f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
};
+const float alpha_pos[N_ALPHA][3] = {
+ // second row
+ {ORIGIN_X, ORIGIN_Y, .5f},
+ {ORIGIN_X + .5f * DIGIT_WIDTH, ORIGIN_Y, .5f},
+ {ORIGIN_X + 1.f * DIGIT_WIDTH, ORIGIN_Y, .5f},
+};
+
int display_flag = 0;
-volatile uint32_t display_bits[N_DIGITS];
+volatile uint8_t display_data[N_BYTES];
volatile uint8_t display_pwm = 0;
int window;
*/
void hc595_changed_hook(struct avr_irq_t * irq, uint32_t value, void * param)
{
-#if 0
- printf("shifters:\n");
- for (int i = 0; i < N_SHIFTERS; ++i)
- printf("%02x: %08x\n", i, shifters[i].value);
- printf("\n");
-#endif
- for (int i = 0; i < N_DIGITS; ++i)
- display_bits[i] = shifters[i * BYTES_PER_DIGIT].value;
-#if 0
- printf("digits:\n");
- for (int i = 0; i < N_DIGITS; ++i)
- printf("%02x: %08x\n", i, display_bits[i]);
- printf("\n");
-#endif
+ for (int i = 0; i < N_BYTES; ++i)
+ display_data[i] = shifters[i].value;
display_flag++;
}
color_on = color_off;
uint32_t bits;
- for (int di = 0; di < N_DIGITS; di++) {
- bits = display_bits[di];
+ for (int di = 0; di < N_DIGIT; di++) {
+ bits = display_data[di];
float x = digit_pos[di][0];
float y = digit_pos[di][1];
float scale = digit_pos[di][2];
- for (int i = 0; i < SEGMENTS_PER_DIGIT; i++) {
- bool segment = (bits & (1 << i)) != 0;
- if (di == N_DIGITS - 1 && i == SEGMENTS_PER_DIGIT - 1)
- segment = false; // mapped to colon instead (but still shown dark)
- glColor3f(0.f, segment ? color_on : color_off, 0.f);
+ for (int i = 0; i < DIGIT_N_SEG; i++) {
+ bool bit = (bits & (1 << i)) != 0;
+ if (di == N_DIGIT - 1 && i == DIGIT_N_SEG - 1)
+ bit = false; // mapped to colon instead (but still shown dark)
+ glColor3f(0.f, bit ? color_on : color_off, 0.f);
glBegin(GL_POLYGON); //GL_LINE_STRIP);
-#if USE_17SEG
- int end = led_17seg_ptr[i + 1];
- for (int j = led_17seg_ptr[i]; j < end; ++j)
- glVertex2f(x + led_17seg[j][0] * scale, y + led_17seg[j][1] * scale);
-#else
int end = led_8seg_ptr[i + 1];
for (int j = led_8seg_ptr[i]; j < end; ++j)
glVertex2f(x + led_8seg[j][0] * scale, y + led_8seg[j][1] * scale);
-#endif
glEnd();
}
}
// colon
- glColor3f(0.f, bits & SEG_DP ? color_on : color_off, 0.f);
+ glColor3f(0.f, bits & DIGIT_SEG_DP ? color_on : color_off, 0.f);
for (int i = 0; i < 2; ++i) {
glBegin(GL_POLYGON); //GL_LINE_STRIP);
int end = led_colon_ptr[i + 1];
glEnd();
}
+ for (int di = 0; di < N_ALPHA; di++) {
+ bits =
+ (uint32_t)display_data[N_DIGIT + di * 3] |
+ ((uint32_t)display_data[N_DIGIT + di * 3 + 1] << 8) +
+ ((uint32_t)display_data[N_DIGIT + di * 3 + 2] << 16);
+
+ float x = alpha_pos[di][0];
+ float y = alpha_pos[di][1];
+ float scale = alpha_pos[di][2];
+
+ for (int i = 0; i < ALPHA_N_SEG; i++) {
+ bool bit = (bits & (1 << i)) != 0;
+ glColor3f(0.f, bit ? color_on : color_off, 0.f);
+ glBegin(GL_POLYGON); //GL_LINE_STRIP);
+ int end = led_17seg_ptr[i + 1];
+ for (int j = led_17seg_ptr[i]; j < end; ++j)
+ glVertex2f(x + led_17seg[j][0] * scale, y + led_17seg[j][1] * scale);
+ glEnd();
+ }
+ }
+
glutSwapBuffers();
//glFlush(); /* Complete any pending operations */
}
//
// initialize our 'peripherals'
//
- for (int i = 0; i < N_SHIFTERS; ++i)
+ for (int i = 0; i < N_BYTES; ++i)
hc595_init(avr, shifters + i);
button_init(avr, &button[B_START], "button.start");
* i_reset = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 4),
* i_latch = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 7);
avr_irq_t * i_data = i_mosi;
- for (int i = 0; i < N_SHIFTERS; ++i) {
+ for (int i = 0; i < N_BYTES; ++i) {
avr_connect_irq(i_data, shifters[i].irq + IRQ_HC595_SPI_BYTE_IN);
avr_connect_irq(i_reset, shifters[i].irq + IRQ_HC595_IN_RESET);
avr_connect_irq(i_latch, shifters[i].irq + IRQ_HC595_IN_LATCH);