Last active
September 18, 2020 07:27
-
-
Save four0four/e9b38a3839706d2fb342c2975c0c6757 to your computer and use it in GitHub Desktop.
NA202MD08BC driver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <string.h> | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
/* | |
* NA202MD08BC pinout: | |
* 1 2 | |
* [-----|-----] | |
* [ vcc | vcc ] | |
* [ vcc | vcc ] | |
* [ ck0 | vcc ] | |
* [ vss | vss ] | |
* [ d_1 | vss ] | |
* [ #CL | vss ] | |
* [ d_0 | vss ] | |
* [ ck1 | vss ] | |
* [ vss | vss ] | |
* [ vcc | vcc ] | |
* 10 20 | |
* | |
* ck0/d_0: 40-bit shift register connected to pixels | |
* ck1/d_1: 40-bit shift register connected to digits | |
* #CL: global blanking strobe | |
* | |
* | |
* apparently ck1 is attached to LS?! | |
* so we can -not- blank, and shift in during low clk | |
*/ | |
#define DIGIT_PORT PORTB | |
#define DIGIT_PIN PINB | |
#define DIGIT_DDR DDRB | |
// idk same port as OC1A | |
#define DIGIT_DATA_BIT (1<<0) | |
// OC1A | |
#define DIGIT_CLOCK_BIT (1<<1) | |
#define BLANK_PORT PORTD | |
#define BLANK_DDR DDRD | |
#define BLANK_BIT (1<<2) | |
#define PX_PORT PORTB | |
#define PX_PIN PINB | |
#define PX_DDR DDRB | |
// SPI on PORTB | |
#define PX_DATA_BIT (1<<3) | |
#define PX_CLOCK_BIT (1<<5) | |
#define BAUD 9600 | |
// 40 px per 40 digits | |
volatile uint8_t framebuf[40][5]; | |
volatile uint8_t flags = 2; | |
// pixel pointer | |
volatile uint8_t px_idx = 0; | |
// digit pointer | |
volatile uint16_t digit_idx = 0; | |
// uart write pos | |
// these are 16 bit because I think | |
// there is a silicon bug which corrupts | |
// them if they're bytes. the flash | |
// buf is 16 bits so it's believable | |
// iow: "works in my emulator" | |
volatile uint16_t write_ptr = 0; | |
volatile uint16_t write_px = 0; | |
// fires twice per 200hz period | |
ISR(TIMER1_COMPA_vect) { | |
// just moved a digit forward, update pixels: | |
if(flags & 1) { | |
flags |= 2; | |
px_idx=0; | |
} | |
else { | |
digit_idx+=1; | |
// do we need to clock in our scanning bit? | |
if (digit_idx == 40) { | |
DIGIT_PORT |= DIGIT_DATA_BIT; | |
digit_idx = 0; | |
} | |
else DIGIT_PORT &= ~DIGIT_DATA_BIT; | |
} | |
flags = flags ^ 1; | |
} | |
// there is some timing slack here | |
// so just defer to the main loop | |
ISR(SPI_STC_vect) { | |
flags |= 4; | |
} | |
// lol whatever | |
ISR(USART_RX_vect) { | |
char t = UDR0; | |
/* | |
if(t == 0x41) { | |
write_px = 0; | |
write_ptr = 0; | |
framebuf[0][0]=0x00; | |
framebuf[0][1]=0xff; | |
framebuf[0][2]=0; | |
framebuf[0][3]=0; | |
framebuf[0][4]=0; | |
framebuf[1][0]=0x1f; | |
framebuf[1][1]=0x00; | |
framebuf[1][2]=0xff; | |
framebuf[1][3]=0xff; | |
framebuf[1][4]=0xff; | |
} | |
else if (t == 0x42) { | |
write_px = 0; | |
write_ptr = 0; | |
framebuf[1][0]=0x00; | |
framebuf[1][1]=0xff; | |
framebuf[1][2]=0; | |
framebuf[1][3]=0; | |
framebuf[1][4]=0; | |
framebuf[0][0]=0x1f; | |
framebuf[0][1]=0x00; | |
framebuf[0][2]=0xff; | |
framebuf[0][3]=0xff; | |
framebuf[0][4]=0xff; | |
} | |
*/ | |
if (t == 0x1b) { | |
write_ptr = write_px = 0; | |
} | |
else { | |
framebuf[write_ptr][write_px] = t; | |
++write_px; | |
if(write_px >= 5){ | |
write_px = 0; | |
if(++write_ptr >= 40) write_ptr = 0; | |
} | |
} | |
} | |
void init_periph() { | |
cli(); | |
SPCR = 0x50; | |
SPSR = 0x00; | |
// ugly io shit | |
DIGIT_DDR |= (DIGIT_CLOCK_BIT | DIGIT_DATA_BIT); | |
DIGIT_PORT &= ~(DIGIT_CLOCK_BIT); | |
DIGIT_PORT |= DIGIT_DATA_BIT; | |
PX_DDR |= (PX_CLOCK_BIT | PX_DATA_BIT); | |
PX_PORT &= ~(PX_CLOCK_BIT | PX_DATA_BIT); | |
// fuck #SS | |
DDRB |= (1<<2); | |
PORTB |= (1<<2); | |
// timer1: | |
// toggle OC1A on compare | |
// prescalar 8 | |
// match 125 for 200hz update | |
const uint16_t digit_count = 75; | |
TCCR1A = 0x40; | |
TCCR1B = 0x0a; | |
OCR1AH = digit_count >> 8; | |
OCR1AL = digit_count & 0xff; | |
TIMSK1 = 0x02; | |
// uart, rx/tx, rx irq, 115200 baud | |
UCSR0A = 0x00; | |
UCSR0B = 0x98; | |
UCSR0C = 0x06; | |
const uint16_t ubrr = F_CPU/16/BAUD-1; | |
UBRR0H = ubrr>>8; | |
UBRR0L = ubrr&0xff; | |
memset((void*)framebuf, 0, 200); | |
// fucking around: | |
framebuf[0][0]=0xFF; | |
framebuf[0][1]=0x00; | |
framebuf[0][2]=0xff; | |
framebuf[0][3]=0xff; | |
framebuf[0][4]=0xff; | |
framebuf[2][4]=0xff; | |
framebuf[3][3]=0xff; | |
framebuf[39][4] = 0x00; | |
// framebuf[39][3] = 0xff; | |
write_px = 0; | |
write_ptr = 0; | |
// interrupts and shit on | |
sei(); | |
} | |
int main() { | |
init_periph(); | |
while(1) { | |
if (flags & 2) { | |
flags = flags & ~2; | |
// enable spi interrupt and kick out initial byte | |
cli(); | |
SPCR |= (1<<SPIE); | |
SPDR = framebuf[digit_idx][0]; | |
sei(); | |
} | |
if(flags&4) { | |
cli(); | |
flags &= ~4; | |
px_idx += 1; | |
SPDR = framebuf[digit_idx][px_idx]; | |
sei(); | |
// completed writing a digit: | |
// release #blank and turn off the irq | |
if (px_idx == 4){ | |
SPCR &= ~(1<<SPIE); | |
//BLANK_PORT |= BLANK_BIT; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment