--- /dev/null
+/*
+*/
+#include <Arduino.h>
+
+// constants won't change. Used here to set a pin number:
+const int ledPin = 17; // the number of the LED pin
+const int pin = 32+20; // first audio pin
+
+const int SPI_MISO = 20;
+const int SPI_MOSI = 8+18;
+const int SPI_CLK = 8+17;
+const int SPI_CSN = 8+16;
+
+// additional gpio for GN lines (not integrated into arduino yet)
+volatile uint32_t *gpio1_out = (uint32_t *) 0xfffff820;
+volatile uint32_t *gpio1_ctl = (uint32_t *) 0xfffff824;
+volatile uint32_t *gpio1_in = (uint32_t *) 0xfffff838;
+const uint32_t gpio1_bits = 0x3C000; // bits/pins 14,15,16,17
+
+// constants won't change:
+const long interval = 100; // min interval at which to blink (milliseconds)
+
+const uint16_t config_setup =
+ (0x10 << 11) | // CONFIG_SETUP
+ (1 << 10) | // REFSEL external single ended (vs REF-).
+ (0 << 9) | // AVGON averaging turned off.
+ (0 << 7) | // NAVG 1 conversion per result.
+ (0 << 5) | // NSCAN scans N and returns 4 results.
+ (0 << 3) | // SPM all circuitry powered all the time.
+ (1 << 2) ; // ECHO 1-enabled 0-disabled.
+
+const uint16_t mode_control =
+ (0 << 15) | // REG_CNTL select ADC mode control.
+ (3 << 11) | // standard_int scan 0-N internal clock w/avg.
+ (7 << 7) | // CHSEL scan up to channel 7.
+ (0 << 5) | // RESET the FIFO only.
+ (0 << 3) | // PM power management normal.
+ (0 << 2) | // CHAN_ID set to 1 in ext mode to get chan id.
+ (1 << 1) ; // SWCNV 1 (rising edge of CS)
+
+const uint16_t sample_set =
+ (B10110 << 11 ) | // SMPL_SET select ADC sample set
+ (4 << 3) ; // SEQ length
+
+uint16_t SPIRW(uint16_t d)
+{
+ uint16_t r = 0, b = 1<<15;
+ uint8_t miso;
+ for(int i = 0; i < 16; i++)
+ {
+ digitalWrite(SPI_CLK, LOW);
+ //digitalWrite(9, LOW);
+ digitalWrite(SPI_MOSI, (d & b) != 0 ? HIGH : LOW);
+ //digitalWrite(10, (d & b) != 0 ? HIGH : LOW);
+ //delay(1);
+ digitalWrite(SPI_CLK, HIGH);
+ //digitalWrite(9, HIGH);
+ // read now
+ if(digitalRead(SPI_MISO))
+ {
+ r |= b;
+ //digitalWrite(11, HIGH);
+ }
+ else
+ {
+ //digitalWrite(11, LOW);
+ }
+ b >>= 1;
+ //delay(1);
+ }
+ return r;
+}
+
+uint16_t SPISend(const unsigned int adc_cbase, uint16_t d)
+{
+ digitalWrite(SPI_CSN, LOW);
+ //digitalWrite(8, LOW);
+ uint16_t retval = SPIRW(d);
+ digitalWrite(SPI_CSN, HIGH);
+ //digitalWrite(8, HIGH);
+ return retval;
+}
+
+void SPIdriveCSN(int cs)
+{
+ digitalWrite(SPI_CSN, cs);
+ //digitalWrite(8, cs);
+}
+
+void SPIstart()
+{
+ // first clock with CSN HI
+ digitalWrite(SPI_CSN, HIGH); // make sure it's high
+ //delay(1);
+ digitalWrite(SPI_CLK, LOW);
+ //delay(1);
+ digitalWrite(SPI_CLK, HIGH);
+ //delay(1);
+ SPISend(0,mode_control); // to the rest 16 bit send normal mode control command
+}
+
+void configureMax1112x()
+{
+ const int adc_cbase = 0;
+ // Config: Reset.
+ SPISend(adc_cbase, (2 << 5)); // RESET reset all registers to defaults.
+
+ // Config: ADC configuration.
+ SPISend(adc_cbase, config_setup);
+
+ // Config: Unipolar.
+ SPISend(adc_cbase, (0x12 << 11)); // All channels unipolar.
+ SPISend(adc_cbase, (0x11 << 11) | // All channels unipolar.
+ (1 << 2)); // Reference all channels to REF-.
+
+ // Config: ADC mode control.
+ SPISend(adc_cbase, mode_control);
+
+ // Defaults are good for:
+ // Config: Bipolar.
+ // Config: RANGE.
+ // Config: Custom scan 0.
+ // Config: Custom scan 1.
+ // Config: Sample set.
+}
+
+
+void adc_init()
+{
+ for(int j = 0; j < 8; j++)
+ {
+ pinMode(8+j, OUTPUT);
+ digitalWrite(8+j, LOW);
+ }
+ // set the digital pin as output:
+ pinMode(ledPin, OUTPUT);
+ configureMax1112x();
+}
+
+int adc_read(char *a)
+{
+ int ret = 0;
+ static uint8_t skip_eval = 5; // skip evaluation for first few readings
+ static uint16_t reading[10], prev_reading[10];
+ // alternating LED state will also alternate
+ // digital output pins shared with ADC
+ // ADC will read digital states
+ static int ledState = LOW;
+ {
+
+ // if the LED is off turn it on and vice-versa:
+ if (ledState == LOW) {
+ ledState = HIGH;
+ } else {
+ ledState = LOW;
+ }
+
+ // set the LED with the ledState of the variable:
+ digitalWrite(ledPin, ledState);
+
+ // copy previous reading for evaluation
+ for(int i = 0; i < 8; i++)
+ prev_reading[i] = reading[i];
+
+ SPIstart();
+ delay(1); // wait conversion
+ for(int i = 0; i < 9; i++)
+ reading[i] = SPISend(0,0);
+ // evaluation for ADC readings: OK/FAIL
+ static char *channel_eval[8];
+ for(uint16_t i = 0; i < 8; i++)
+ {
+ if(skip_eval)
+ channel_eval[i] = "WAIT";
+ else if(ledState)
+ {
+ if(i & 1)
+ {
+ if(reading[i] < ((i << 12) + 0x080) && prev_reading[i] > ((i << 12) + 0xF80) ) {
+ channel_eval[i] = " OK ";
+ ret++;
+ } else
+ channel_eval[i] = "FAIL";
+ }
+ else
+ {
+ if(prev_reading[i] < ((i << 12) + 0x080) && reading[i] > ((i << 12) + 0xF80) ) {
+ channel_eval[i] = " OK ";
+ ret++;
+ } else
+ channel_eval[i] = "FAIL";
+ }
+ }
+ }
+ // skip evaluation for first few readings
+ if(skip_eval)
+ skip_eval--;
+ sprintf(a, "%04x %04x %04x %04x %04x %04x %04x %04x\n%s %s %s %s %s %s %s %s\n",
+ reading[0],
+ reading[1],
+ reading[2],
+ reading[3],
+ reading[4],
+ reading[5],
+ reading[6],
+ reading[7],
+ channel_eval[0],
+ channel_eval[1],
+ channel_eval[2],
+ channel_eval[3],
+ channel_eval[4],
+ channel_eval[5],
+ channel_eval[6],
+ channel_eval[7]
+ );
+ // change GPIO logic levels 0/1, ADC is connected to GPIO
+ // and should convert logic levels
+ pinMode(32+14, OUTPUT);
+ digitalWrite(32+14, ledState);
+ pinMode(32+15, OUTPUT);
+ digitalWrite(32+15, ledState);
+ pinMode(32+16, OUTPUT);
+ digitalWrite(32+16, ledState);
+ pinMode(32+17, OUTPUT);
+ digitalWrite(32+17, ledState);
+ // same as above but with alternat phase for PN pins
+ // those are not implemented in arduino so we
+ // write directly to hardware registers
+ *gpio1_ctl |= gpio1_bits; // outputs
+ if(ledState)
+ *gpio1_out &= ~gpio1_bits;
+ else
+ *gpio1_out |= gpio1_bits;
+ }
+ return ret;
+}
--- /dev/null
+void adc_init();
+int adc_read(char *a);
--- /dev/null
+#include <Arduino.h>
+
+void btn_init()
+{
+ int i;
+ // buttons
+ for(i = 0; i < 6; i++)
+ pinMode(i, INPUT);
+ // switches
+ for(i = 16; i < 20; i++)
+ pinMode(i, INPUT);
+ // leds
+ for(i = 8; i < 16; i++)
+ pinMode(i, OUTPUT);
+}
+
+uint8_t btn[6];
+uint8_t btn_toggle[6] = { 0,0,0,0,0,0 };
+
+int btn_read(char *line)
+{
+ int ret = 0;
+ static uint8_t shiftdata = 0;
+ uint8_t led = B10001 << (shiftdata++ & 3);
+
+ Serial.print("btn_toggle=");
+ for(int i=0; i<=6; i++) {
+ btn[i] = digitalRead(i);
+ if ( i == 0 ) btn[i] = !btn[i];
+ if ( btn[i] ) {
+ digitalWrite(8+i, 1);
+ if ( btn_toggle[i] == 0 ) {
+ btn_toggle[i]++; // press
+ }
+ } else {
+ digitalWrite(8+i, 0);
+ if ( btn_toggle[i] == 1 ) {
+ btn_toggle[i]++; // release
+ }
+ }
+ if (btn_toggle[i] == 2) {
+ ret++;
+ //digitalWrite(8+i, 1);
+ }
+ Serial.print(btn_toggle[i]);
+ }
+ Serial.println();
+
+ sprintf(line, "BTN:%c%c%c%c%c%c%c SW:%c%c%c%c LED:%c%c%c%c%c%c%c%c\n",
+ digitalRead(0) ? '_' : '0',
+ digitalRead(1) ? '1' : '_',
+ digitalRead(2) ? '2' : '_',
+ digitalRead(3) ? '3' : '_',
+ digitalRead(4) ? '4' : '_',
+ digitalRead(5) ? '5' : '_',
+ digitalRead(6) ? '6' : '_',
+ digitalRead(16) ? '1' : '_',
+ digitalRead(17) ? '2' : '_',
+ digitalRead(18) ? '3' : '_',
+ digitalRead(19) ? '4' : '_',
+ led & B10000000 ? '7' : '_',
+ led & B01000000 ? '6' : '_',
+ led & B00100000 ? '5' : '_',
+ led & B00010000 ? '4' : '_',
+ led & B00001000 ? '3' : '_',
+ led & B00000100 ? '2' : '_',
+ led & B00000010 ? '1' : '_',
+ led & B00000001 ? '0' : '_'
+ );
+ //for(int i = 0; i < 8; i++)
+ // digitalWrite(8+i, led & (1<<i) ? 1 : 0);
+ return ret;
+}
--- /dev/null
+void btn_init();
+int btn_read(char *line);
--- /dev/null
+#include <Compositing.h>
+#include "font.h"
+#include "rtc.h"
+#include "adc.h"
+#include "dac.h"
+#include "edid.h"
+#include "btn.h"
+#include "flash.h"
+#include "sd.h"
+#include "oled.h"
+#include "ram.h"
+#include "rds.h"
+#include "pcm.h"
+
+#define N_LETTERS (sizeof(Font)/sizeof(Font[0]))
+
+Compositing c2;
+
+const int Cols = 40;
+const int Rows = 30;
+int Cursor_col = 0, Cursor_row = 0;
+
+void cls()
+{
+ for(int row = 0; row < Rows; row++)
+ for(int col = 0; col < Cols; col++)
+ {
+ int i = N_LETTERS + row*Cols + col;
+ c2.sprite_link_content('@'-'@', i);
+ }
+ Cursor_col = Cursor_row = 0;
+}
+
+void prints(char *a)
+{
+ for(;*a != '\0'; a++)
+ {
+ int i = N_LETTERS + Cursor_row*Cols + Cursor_col;
+ uint8_t letter = 0; // space is default
+ char c = *a;
+ if(c == '\n')
+ {
+ Cursor_col = 0;
+ Cursor_row = (Cursor_row + 1) % Rows;
+ continue;
+ }
+ c = toupper(c);
+ if(c >= ' ' && c <= '_')
+ letter = c - ' ';
+ c2.sprite_link_content(letter, i);
+ if(++Cursor_col >= Cols)
+ {
+ Cursor_col = 0;
+ Cursor_row = (Cursor_row + 1) % Rows;
+ }
+ }
+}
+
+// initialize compositing2 text using sprites
+void video_init()
+{
+ int i;
+ int unique_sprites;
+ c2.init();
+ c2.alloc_sprites(N_LETTERS+Rows*Cols); // it sets c2.sprite_max
+ *c2.videobase_reg = NULL; // disable video during update
+ *c2.cntrl_reg = 0;
+ #if 1
+ for(i = 0; i < c2.sprite_max && i < N_LETTERS; i++)
+ c2.shape_to_sprite(&(Font[i]));
+ unique_sprites = c2.n_sprites;
+ // unique sprites containing alphabet are not displayed, set them off-screen
+ for(i = 0; i < unique_sprites; i++)
+ {
+ c2.Sprite[i]->x = -100;
+ c2.Sprite[i]->y = -100;
+ }
+ // position cloned sprites on display
+ // i = N_LETTERS;
+ for(int row = 0; row < Rows; row++)
+ for(int col = 0; col < Cols; col++)
+ {
+ c2.sprite_clone(0); // by default clone 0-sprite which is space
+ int n = N_LETTERS + row*Cols + col;
+ c2.Sprite[n]->x = col*16;
+ c2.Sprite[n]->y = row*16;
+ i++;
+ }
+ #endif
+ // cls();
+ c2.sprite_refresh();
+ // this is needed for vgatext
+ // to disable textmode and enable bitmap
+ *c2.cntrl_reg = 0b11000000; // enable video, yes bitmap, no text mode, no cursor
+}
+
+void setup()
+{
+ Serial.println("setup start");
+ video_init();
+ rtc_init();
+ adc_init();
+ dac_init();
+ btn_init();
+ oled_init();
+ rds_init();
+ pcm_init();
+ rtc_set_clock();
+ rtc_set_alarm();
+ Serial.println("setup end");
+}
+
+int rtc_ok = 0;
+int edid_ok = 0;
+int adc_ok = 0;
+int dac_ok = 0;
+int btn_ok = 0;
+int flash_ok = 0;
+int sd_ok = 0;
+
+int all_ok = 0;
+int last_all_ok = -1;
+
+int led_beat = 0;
+
+
+void loop()
+{
+ static uint8_t counter = 0;
+ const int nlines = 6;
+ char line[nlines][256];
+
+ digitalWrite(8+7, led_beat);
+ led_beat = !led_beat;
+
+#if 0
+ if(1 & ++counter)
+ pcm_tone();
+ else
+ pcm_mute();
+#endif
+
+ if ( rtc_ok == 0 ) rtc_ok = rtc_read(line[0]);
+ if ( rtc_ok == 1 ) {
+ Serial.println("RTC OK");
+ rtc_ok++;
+ all_ok++;
+ }
+ if ( edid_ok == 0 ) edid_ok = edid_read(line[1]);
+ if ( edid_ok == 1 ) {
+ Serial.println("EDID OK");
+ edid_ok++;
+ all_ok++;
+ }
+ if ( adc_ok < 8 ) adc_ok = adc_read(line[2]);
+ if ( adc_ok == 8 ) {
+ Serial.println("ADC OK");
+ adc_ok++;
+ all_ok++;
+ }
+ if ( dac_ok == 0 ) dac_ok = dac_read(line[3]);
+ if ( dac_ok == 1 ) {
+ Serial.println("DAC OK");
+ dac_ok++;
+ all_ok++;
+ }
+
+ int btn = btn_read(line[4]); // buttons. DIP switches and blink LEDs
+ if ( btn_ok == 0 && btn == 7 ) {
+ Serial.println("BTN OK");
+ btn_ok++;
+ all_ok++;
+ }
+
+#if 0
+ if(line[4][5] == '1') // BTN1 pressed
+ {
+ rtc_set_clock();
+ rtc_set_alarm();
+ oled_init();
+ }
+ if(line[4][6] == '2') // BTN2 pressed - shutdown
+ {
+ volatile uint32_t *simple_out = (uint32_t *)0xFFFFFF10;
+ simple_out[0] |= (1<<13); // bit 13 of simple_out is shutdown
+ }
+#endif
+ char flash_str[64], sd_str[64], oled_str[64];
+ if ( flash_ok == 0 ) flash_ok = flash_read(flash_str);
+ if ( flash_ok == 1 ) {
+ Serial.println("FLASH OK");
+ flash_ok++;
+ all_ok++;
+ }
+
+ if ( sd_ok == 0 ) sd_ok = sd_read(sd_str); // esp32 must be flashed not to access SD card
+ if ( sd_ok == 1 ) {
+ Serial.println("SD OK");
+ sd_ok++;
+ all_ok++;
+ }
+
+#if 0
+ oled_read(oled_str);
+#endif
+
+ Serial.print("all_ok=");
+ Serial.println(all_ok);
+
+ sprintf(line[5], "%s %s %s\n", flash_str, oled_str, sd_str);
+ line[6][0]='\0';
+ //ram_test(line[5]); // works but too slow, need speedup
+ Serial.println("");
+ for(int i = 0; i < nlines; i++)
+ Serial.print(line[i]);
+
+ cls();
+ for(int i = 0; i < nlines; i++)
+ prints(line[i]);
+
+ while((*c2.vblank_reg & 0x80) == 0);
+ c2.sprite_refresh();
+ // delay(1000);
+}
--- /dev/null
+/* Test connectivity of audio jack DAC
+** it will check do all FPGA DAC lines have
+** connection to DAC resistors network.
+** This check cannot detect does signal
+** really appears on audio jack.
+*
+* audio pins should have pull-up enabled in the bitstream
+* pulling down any of the bits on each channel should result in all 4 bits
+* reading in this channel be 0x0, otherwise all bits will 0xF
+* any other value indicates bits connection error
+*
+* Todo: if probe bit is not connected,
+* complete checkword will fail. Construct better boolean
+* algebra so that using another probe bit reveals one disconnected line
+*/
+#include <Arduino.h>
+
+// additional gpio for DAC lines testing (not integrated into arduino yet)
+// this needs special bitstream with gpio 64-75 (bits 0-11) connected to
+// 12 DAC resistor network
+volatile uint32_t *gpio2_out = (uint32_t *) 0xfffff840;
+volatile uint32_t *gpio2_ctl = (uint32_t *) 0xfffff844;
+volatile uint32_t *gpio2_in = (uint32_t *) 0xfffff858;
+const uint32_t gpio2_bits = 0xFFF; // all bits/pins 0-11
+
+void dac_init()
+{
+ *gpio2_ctl &= ~gpio2_bits; // inputs (output disabled)
+ *gpio2_out &= ~gpio2_bits; // output default low when enabled
+}
+
+// 4-bit value converted to 4-byte string "3210"
+void dac_decode(char *a, uint8_t v)
+{
+ for(uint8_t i = 0; i < 4; i++)
+ {
+ a[3-i] = v & 1 ? '_' : '0'+i;
+ v >>= 1;
+ }
+ a[4] = '\0'; // null-string termination
+}
+
+
+int dac_read(char *a)
+{
+ int ret = 0;
+ uint32_t probeword, checkword, difference;
+ // static uint8_t counter = 0; // moving bit for detection state
+ uint32_t i;
+ // testword 32-cycle
+ uint32_t fail = 0; // reset fail flags
+ difference = 0; // reset difference register
+ // this for-loop should find and indentify
+ // disconnected or faulty bits in DAC resistor network
+ for(i = 0; i < 32; i++)
+ {
+ probeword = (((i & B100)<<6) | ((i & B10)<<3) | (i & B1)) << ((i >> 3) & 3);
+ checkword = 0xFFF & ~( (0xF*((i & B100)<<6)) | (0xF*((i & B10)<<3)) | (0xF*(i & B1)) );
+ *gpio2_ctl = (*gpio2_ctl & ~gpio2_bits) | probeword;
+ delay(1); // wait for change to take effect
+ // any difference between checkword and read bits will set a bit in difference register
+ uint32_t error_bits = checkword ^ *gpio2_in;
+ difference |= probeword & error_bits;
+ fail |= error_bits;
+ }
+ difference &= 0xFFF; // final bitmask
+ char dac_l[5], dac_r[5], dac_v[5];
+ dac_decode(dac_l, difference);
+ dac_decode(dac_r, difference >> 4);
+ dac_decode(dac_v, difference >> 8);
+ sprintf(a, "DAC: L%s %s R%s %s V%s %s\n",
+ dac_l,
+ (fail & 0x00F) == 0 ? " OK " : "FAIL",
+ dac_r,
+ (fail & 0x0F0) == 0 ? " OK " : "FAIL",
+ dac_v,
+ (fail & 0xF00) == 0 ? " OK " : "FAIL"
+ );
+ if ((fail & 0xFFF) == 0) ret++;
+ return ret;
+}
--- /dev/null
+void dac_init();
+int dac_read(char *a);
--- /dev/null
+//VGA writer to write eeproms in vga displays
+//Apr 2011 Kieran Levin kiram9@yahoo.com
+//If you want to modify some data scroll down and modify the bytes in command 'c'
+//Then load from display - change custom bytes, generate checksum, write to save values back(r,c,g,w)
+//See also http://en.wikipedia.org/wiki/Extended_display_identification_data
+/*Help Commands:
+ r=read hex
+ b=read binary
+ l=load binary from serial(gets 128 bytes of binary data from serial then returns)
+ w=write
+ d=displaybuffer(binary)
+ e=print detailed info
+ g=generatechecksum
+ t=check checksum
+ c=change custom bytes (compiled in)
+Connection
+Arduino VGA DVI
+Analog 4(Data) 12 7
+Analog 5(Clk) 15 6
+DIO 2 14
+Power5V 9 14
+GND 11 15
+*/
+
+#include <SoftwareWire.h>
+extern SoftwareWire Wire; // defined in RTC
+
+#define BYTE HEX
+
+#define LED2 8
+#define LED18 9
+
+int i;
+int inByte = 0; // incoming serial byte
+int count = 0;
+char edidarray[128];
+
+int edid_setup()
+{
+ Wire.setClock(100000L); // 100000-400000
+ Wire.begin(); // join i2c bus (address optional for master)
+ // Serial.begin(115200); // start serial for output
+
+ //write to vclk pin on pin 2
+ pinMode(LED2, OUTPUT);
+ pinMode(LED18, OUTPUT);
+
+ //This puts i2c eeproms that are also clocked off the vsync into R/W mode
+ digitalWrite(LED18, HIGH); // set the LED off
+ for(i = 0; i < 20; i++){
+ digitalWrite(LED2, HIGH); // set the LED on
+ delay(10); // wait for a second
+ digitalWrite(LED2, LOW); // set the LED off
+ delay(10);
+ }
+ digitalWrite(LED2, HIGH); // set the LED on
+ delay(10);
+ digitalWrite(LED18, LOW); // set the LED off
+ delay(10);
+ digitalWrite(LED2, LOW); // set the LED on
+
+ for(i = 0; i < 10; i++){
+ digitalWrite(LED2, HIGH); // set the LED on
+ delay(10); // wait for a second
+ digitalWrite(LED2, LOW); // set the LED off
+ delay(10);
+ }
+ //disable writing to eeprom
+ digitalWrite(LED2, LOW); // set the LED off
+ Serial.println("EDID Reader Writer C 2011 Kieran Levin kiram9@yahoo.com");
+}
+
+int edidreadbytes(char * array)
+{
+ byte mycount = 0;
+ Wire.beginTransmission(B1010000);
+ Wire.write(byte(mycount));
+ Wire.endTransmission();
+ for(int j = 0; j < 128; j++){
+ Wire.requestFrom(B1010000, 1);
+ if (Wire.available()) // slave may send less than requested
+ {
+ array[j] = Wire.read(); // receive a byte as character
+ mycount++;
+ }
+ delay(10);
+ }
+ return mycount;
+}
+int edidwritebytes(char * array){
+ byte mycount = 0;
+ digitalWrite(LED2, HIGH); // set the LED off
+ delay(10);
+ for(byte j =0; j < 128;j++){
+ Wire.beginTransmission(B1010000);
+ #if 1
+ Wire.write(byte(j));
+ Wire.write(byte(array[j]));
+ Wire.endTransmission();
+ #endif
+ delay(10);
+ }
+ digitalWrite(LED2, LOW); // set the LED off
+ return mycount;
+}
+void printDetailedinfo(){
+Serial.println("Detailed Information:");
+Serial.print("\tManufacture ID \t");
+Serial.println(*((uint16_t *)(edidarray+8)));
+Serial.print("\tProduct ID code \t");
+Serial.println(*((uint16_t *)(edidarray+10)));
+Serial.print("\tSerial Number \t");
+Serial.println(*((uint32_t *)(edidarray+12)));
+Serial.print("\tWeek of Manufacture \t");
+Serial.println(edidarray[16]);
+Serial.print("\tYear of manufacture \t");
+Serial.println(edidarray[17] + 1990);
+Serial.print("\tEdid Version\t");
+Serial.println(edidarray[18]);
+Serial.print("\tEdid Revision \t");
+Serial.println(edidarray[19]);
+Serial.print("\tEstablished Timing 1 \t");
+Serial.println(0x00FF & edidarray[35],BIN);
+Serial.print("\tEstablished Timing 2 \t");
+Serial.println(0x00FF & edidarray[36],BIN);
+ for(int i = 38; i < 53; i +=2){
+ Serial.print("Standard Timing ID \t");
+ Serial.println(i);
+ Serial.print("\tHoriz Res \t");
+ Serial.println(248+8*(0x00FF & edidarray[i]));
+ Serial.print("\tAspect Ratio \t");
+ switch(B11000000 & edidarray[i+1]){
+ case B00000000:
+ if (edidarray[19] < 3)
+ Serial.println("1:1");
+ else
+ Serial.println("16:10");
+ break;
+ case B01000000:
+ Serial.println("4:3");
+ break;
+ case B10000000:
+ Serial.println("5:4");
+ break;
+ case B11000000:
+ Serial.println("16:9");
+ break;
+ }
+ Serial.print("\tVertical Freq \t");
+ Serial.println(60+(B00111111 & edidarray[i+1]));
+ }
+}
+byte edidchecksum(char * array){
+ byte checksum = 0;
+ for (int i = 0; i < 128; i++){
+ checksum += array[i];
+ }
+ return(checksum);
+}
+void checkchecksum(){
+ byte checksum = 0;
+ for (int i = 0; i < 128; i++){
+ checksum += edidarray[i];
+ }
+ Serial.print("\tChecksum (should = 0) \t");
+ Serial.println(checksum,HEX);
+
+}
+void generatechecksum(){
+ Serial.println("Generating Checksum");
+ byte checksum = 0;
+ for (int i = 0; i < 127; i++){
+ checksum += edidarray[i];
+ }
+ edidarray[127] = 256 - checksum;
+ checkchecksum();
+
+}
+void edid_loop()
+{
+
+ if (Serial.available() > 0) {
+ // get incoming byte:
+ inByte = Serial.read();
+ switch (inByte){
+
+ case 'r':
+ count = 0;
+ Serial.println("EEPROM:");
+ count = edidreadbytes(edidarray);
+ for (i = 0; i < count; i++){
+ Serial.print(edidarray[i],HEX);
+ Serial.print(',');
+ delay(1);
+ }
+ Serial.println();
+ Serial.print("Read ");
+ Serial.print(count);
+ Serial.println(" bytes");
+ break;
+ case 'b':
+ count = 0;
+ Serial.println("EEPROM:");
+ count = edidreadbytes(edidarray);
+ for (i = 0; i < count; i++){
+ Serial.print(edidarray[i],BYTE);
+ delay(1);
+ }
+ Serial.println();
+ Serial.print("Read ");
+ Serial.print(count);
+ Serial.println(" bytes");
+ break;
+ case 'l':
+ count = 0;
+ while (count < 128){
+ if (Serial.available() > 0) {
+ // get incoming byte:
+ edidarray[count] = Serial.read();
+ count++;
+ }
+ }
+ Serial.println("Done Loading Bytes press W to write to eeprom ");
+ break;
+ case 'w':
+ edidwritebytes(edidarray);
+ Serial.println("Wrote 128 Bytes to eeprom ");
+ break;
+ case 'd':
+ Serial.println("Contents of buffer");
+ for (i = 0; i < 128; i++){
+ Serial.print(edidarray[i]);
+ delay(1);
+ }
+ break;
+ case 'e':
+ printDetailedinfo();
+ break;
+ case 'g':
+ generatechecksum();
+ break;
+ case 't':
+ checkchecksum();
+ break;
+ case 'c':
+ /******************************************************/
+ //Change custom bytes here
+ edidarray[0] = 0;
+ //edidarray[49] = edidarray[49] | B11000000; //change aspect ratio to 16x9
+ edidarray[48] = 139;
+ edidarray[49] = 0 | B11000000; //change aspect ratio to 16x9 60hz resolution
+ //Add on a few more custom resolutions here
+ edidarray[50] = 129;
+ edidarray[51] = 12 | B11000000; //change aspect ratio to 16x9 72hz resolution
+ edidarray[52] = 129; // change resolution to 1368
+ edidarray[53] = 0 | B11000000; //change aspect ratio to 16x9 60hz resolution
+ break;
+ case 'h':
+// Serial.println("Help:\n\tr=read hex\n\tb=read binary\n\tl=load binary from serial(gets 128 bytes)\n\tw=write\n\td=displaybuffer(binary)\n\te=print detailed info\n\tg=generatechecksum\n\tt=check checksum\n\tc=change custom bytes (compiled in)");
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+int edid_read(char *a)
+{
+ int ret = 0;
+
+ for(byte i = 0; i < 128; i++)
+ edidarray[i] = i;
+ int edid_count = edidreadbytes(edidarray);
+ byte edid_checksum = edidchecksum(edidarray);
+ sprintf(a, "EDID EEPROM:%d CRC=%02x %s\n",
+ edid_count,
+ edid_checksum,
+ edid_checksum == 0 ? "OK" : "FAIL"
+ );
+ if ( edid_checksum == 0 ) ret++;
+ return ret;
+}
--- /dev/null
+int edidreadbytes(char *array);
+byte edidchecksum(char *array);
+int edid_read(char *a);
--- /dev/null
+#include <Arduino.h>
+#include "spi.h"
+
+volatile uint16_t *flash_spi = (uint16_t *)0xFFFFFB40;
+
+uint8_t flash_id(void)
+{
+ spi_start_tx(flash_spi);
+ spi_rxtx(flash_spi, 0xAB);
+ spi_rxtx(flash_spi, 0);
+ spi_rxtx(flash_spi, 0);
+ spi_rxtx(flash_spi, 0);
+ return spi_rxtx(flash_spi, 0);
+}
+
+// set up variables using the SD utility library functions:
+int flash_read(char *a)
+{
+ int ret = 0;
+ uint8_t id = flash_id();
+ if(id >= 0x15 && id <= 0x17) {
+ sprintf(a, "FLASH: %02x OK ", id);
+ ret = 1;
+ } else
+ sprintf(a, "FLASH: %02x FAIL", id);
+ return ret;
+}
--- /dev/null
+int flash_read(char *a);
--- /dev/null
+#include <stdlib.h>
+#include "shape.h"
+
+// ascii-art of the shapes
+const struct charcolors std_colors[] =
+{ // RRGGBB
+ {'O', RGB2PIXEL(0xFF7F00)}, // orange
+ {'R', RGB2PIXEL(0xFF0000)}, // red
+ {'Y', RGB2PIXEL(0xFFFF00)}, // yellow
+ {'C', RGB2PIXEL(0x00FFFF)}, // cyan
+ {'G', RGB2PIXEL(0x00FF00)}, // green
+ {'B', RGB2PIXEL(0x0000FF)}, // blue
+ {'W', RGB2PIXEL(0xFFFFFF)}, // white
+ {' ', RGB2PIXEL(0)}, // transparent
+ {0, 0}
+};
+
+const char *shape_space[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_exclamation[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+" ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_double_quote[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_number[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_dollar[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_percent[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" WWW WW ",
+" WW WW WW ",
+" WW WW WW ",
+" WWW WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW WWW ",
+" WW WW WW ",
+" WW WW WW ",
+" WW WWW ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_single_quote[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_left_parenthesis[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_right_parenthesis[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_asterisk[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" WW ",
+" WW ",
+" WWW WW WWW ",
+" WWW WW WWW ",
+" WWWWWW ",
+" WWWWWW ",
+" WWW WW WWW ",
+" WWW WW WWW ",
+" WW ",
+" WW ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_plus[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_comma[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WW ",
+" WW ",
+NULL
+};
+
+const char *shape_minus[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_dot[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" ",
+NULL
+};
+
+const char *shape_slash[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_0[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WWWW ",
+" WW WWWWW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WWWWW WW ",
+" WWWW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_1[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WWW ",
+" WWWW ",
+" WWWWW ",
+" WWW WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_2[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWW ",
+" WWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWW ",
+" WWW ",
+" WWWW ",
+" WWWW ",
+" WWWW ",
+" WWWW ",
+" WWW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_3[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_4[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWW ",
+" WWWW ",
+" WWWWW ",
+" WWW WW ",
+" WWW WW ",
+" WWW WW ",
+" WWW WW ",
+" WWW WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_5[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_6[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_7[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WWW ",
+" WW WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" ",
+NULL
+};
+
+const char *shape_8[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_9[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_colon[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" ",
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_semicolon[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" ",
+" ",
+" ",
+" ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_less_than[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_equal[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_greater_than[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_question[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_a[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWW ",
+" WWWWWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_b[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_c[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_d[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_e[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_f[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_g[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW WWWWWW ",
+" WW WWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_h[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_i[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_j[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_k[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WWWWWWWWW ",
+" WWWWWWWWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_l[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_m[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WWW WWW ",
+" WWWW WWWW ",
+" WWWWW WWwWW ",
+" WW WWW WWW WW ",
+" WW WWWWWW WW ",
+" WW WWWW WW ",
+" WW WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_n[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WWW WW ",
+" WWWW WW ",
+" WWWWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWWWW ",
+" WW WWWW ",
+" WW WWW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_o[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_p[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_q[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW WW ",
+" WW WWW WW ",
+" WW WWW WW ",
+" WW WWWW ",
+" WW WWW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWW WW ",
+" ",
+NULL
+};
+
+const char *shape_r[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WWW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_s[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWW ",
+" WWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_t[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_u[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_v[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWWWWW ",
+" WWWW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_w[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW ",
+" WW WW WW ",
+" WW WWWW WW ",
+" WW WWWWWW WW ",
+" WW WWW WWW WW ",
+" WWWWW WWWWW ",
+" WWWW WWWW ",
+" WWW WWW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_x[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWWWWW ",
+" WWWW ",
+" WWWW ",
+" WWWWWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WW WW ",
+" ",
+NULL
+};
+
+const char *shape_y[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WW WW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWW WWW ",
+" WWWWWW ",
+" WWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" ",
+NULL
+};
+
+const char *shape_z[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWWWWWWWWWWWWW ",
+" WWWWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_left_bracket[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_backslash[] =
+{/*
+ 01234567890123456789012345678901 */
+"WW ",
+"WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW ",
+" WWW",
+" WW",
+NULL
+};
+
+const char *shape_right_bracket[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WW ",
+" WWWWWWWW ",
+" WWWWWWWW ",
+" ",
+NULL
+};
+
+const char *shape_caret[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" W ",
+" WWW ",
+" WW WW ",
+" WW WW ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+NULL
+};
+
+const char *shape_underscore[] =
+{/*
+ 01234567890123456789012345678901 */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" WWWWWWWWWWWW ",
+" WWWWWWWWWWWW ",
+" ",
+NULL
+};
+
+const struct shape Font[] =
+{
+ [0] = { std_colors, shape_space },
+ [1] = { std_colors, shape_exclamation },
+ [2] = { std_colors, shape_double_quote },
+ [3] = { std_colors, shape_number },
+ [4] = { std_colors, shape_dollar },
+ [5] = { std_colors, shape_percent },
+ [6] = { std_colors, shape_space }, // todo "&"
+ [7] = { std_colors, shape_single_quote },
+ [8] = { std_colors, shape_left_parenthesis },
+ [9] = { std_colors, shape_right_parenthesis },
+ [10] = { std_colors, shape_asterisk },
+ [11] = { std_colors, shape_plus },
+ [12] = { std_colors, shape_comma },
+ [13] = { std_colors, shape_minus },
+ [14] = { std_colors, shape_dot },
+ [15] = { std_colors, shape_slash },
+ [16] = { std_colors, shape_0 },
+ [17] = { std_colors, shape_1 },
+ [18] = { std_colors, shape_2 },
+ [19] = { std_colors, shape_3 },
+ [20] = { std_colors, shape_4 },
+ [21] = { std_colors, shape_5 },
+ [22] = { std_colors, shape_6 },
+ [23] = { std_colors, shape_7 },
+ [24] = { std_colors, shape_8 },
+ [25] = { std_colors, shape_9 },
+ [26] = { std_colors, shape_colon },
+ [27] = { std_colors, shape_semicolon },
+ [28] = { std_colors, shape_less_than },
+ [29] = { std_colors, shape_equal },
+ [30] = { std_colors, shape_greater_than },
+ [31] = { std_colors, shape_question },
+ [32] = { std_colors, shape_space }, // todo "@"
+ [33] = { std_colors, shape_a },
+ [34] = { std_colors, shape_b },
+ [35] = { std_colors, shape_c },
+ [36] = { std_colors, shape_d },
+ [37] = { std_colors, shape_e },
+ [38] = { std_colors, shape_f },
+ [39] = { std_colors, shape_g },
+ [40] = { std_colors, shape_h },
+ [41] = { std_colors, shape_i },
+ [42] = { std_colors, shape_j },
+ [43] = { std_colors, shape_k },
+ [44] = { std_colors, shape_l },
+ [45] = { std_colors, shape_m },
+ [46] = { std_colors, shape_n },
+ [47] = { std_colors, shape_o },
+ [48] = { std_colors, shape_p },
+ [49] = { std_colors, shape_q },
+ [50] = { std_colors, shape_r },
+ [51] = { std_colors, shape_s },
+ [52] = { std_colors, shape_t },
+ [53] = { std_colors, shape_u },
+ [54] = { std_colors, shape_v },
+ [55] = { std_colors, shape_w },
+ [56] = { std_colors, shape_x },
+ [57] = { std_colors, shape_y },
+ [58] = { std_colors, shape_z },
+ [59] = { std_colors, shape_left_bracket },
+ [60] = { std_colors, shape_backslash },
+ [61] = { std_colors, shape_right_bracket },
+ [62] = { std_colors, shape_caret },
+ [63] = { std_colors, shape_underscore },
+};
--- /dev/null
+#include <Arduino.h>
+#include "spi.h"
+
+enum
+{
+ C_OLED_NOP1 = 0xBC,
+ C_OLED_NOP2 = 0xBD, // delay nop
+ C_OLED_NOP3 = 0xE3,
+ C_OLED_SET_DISPLAY_OFF = 0xAE, // 10101110
+ C_OLED_SET_REMAP_COLOR = 0xA0,
+ C_OLED_ULX3S_REMAP = 0b00100010, // A[7:6] = 00; 256 color. A[7:6] = 01; 65k color format rotation for ULX3S, A[1] = 1 scan right to left
+ C_OLED_SET_DISPLAY_START_LINE = 0xA1,
+ C_OLED_SET_DISPLAY_OFFSET = 0xA1,
+ C_OLED_SET_DISPLAY_MODE_NORMAL = 0xA4,
+ C_OLED_SET_MULTIPLEX_RATIO = 0xA8,
+ C_OLED_SET_MASTER_CONFIGURATION = 0xAD,
+ C_OLED_SET_POWER_SAVE_MODE = 0xB0,
+ C_OLED_SET_PHASE_1_AND_2_PERIOD_ADJUSTMENT = 0xB1,
+ C_OLED_SET_DISPLAY_CLOCK_DIVIDER = 0xF0,
+ C_OLED_SET_PRECHARGE_A = 0x8A,
+ C_OLED_SET_PRECHARGE_B = 0x8B,
+ C_OLED_SET_PRECHARGE_C = 0x8C,
+ C_OLED_SET_PRECHARGE_LEVEL = 0xBB,
+ C_OLED_SET_VCOMH = 0xBE,
+ C_OLED_SET_MASTER_CURRENT_CONTROL = 0x87,
+ C_OLED_SET_CONTRAST_COLOR_A = 0x81,
+ C_OLED_SET_CONTRAST_COLOR_B = 0x82,
+ C_OLED_SET_CONTRAST_COLOR_C = 0x83,
+ C_OLED_SET_COLUMN_ADDRESS = 0x15,
+ C_OLED_SET_ROW_ADDRESS = 0x75,
+ C_OLED_SET_DISPLAY_ON = 0xAF,
+};
+
+uint8_t oled_init_sequence[] =
+{
+ C_OLED_NOP1, // 0, 10111100
+ C_OLED_SET_DISPLAY_OFF, // 1, 10101110
+ C_OLED_SET_REMAP_COLOR, C_OLED_ULX3S_REMAP, // 2
+ C_OLED_SET_DISPLAY_START_LINE, 0x00, // 4
+ C_OLED_SET_DISPLAY_OFFSET, 0x00, // 6
+ C_OLED_SET_DISPLAY_MODE_NORMAL, // 8
+ C_OLED_SET_MULTIPLEX_RATIO, 0b00111111, // 9, 15-16
+ C_OLED_SET_MASTER_CONFIGURATION, 0b10001110, // 11, a[0]=0 Select external Vcc supply, a[0]=1 Reserved(reset)
+ C_OLED_SET_POWER_SAVE_MODE, 0x00, // 13, 0-no power save, 0x1A-power save
+ C_OLED_SET_PHASE_1_AND_2_PERIOD_ADJUSTMENT, 0x74, // 15
+ C_OLED_SET_DISPLAY_CLOCK_DIVIDER, 0xF0, // 17
+ C_OLED_SET_PRECHARGE_A, 0x64, // 19
+ C_OLED_SET_PRECHARGE_B, 0x78, // 21
+ C_OLED_SET_PRECHARGE_C, 0x64, // 23
+ C_OLED_SET_PRECHARGE_LEVEL, 0x31, // 25
+ C_OLED_SET_CONTRAST_COLOR_A, 0xFF, // 27, 255
+ C_OLED_SET_CONTRAST_COLOR_B, 0xFF, // 29, 255
+ C_OLED_SET_CONTRAST_COLOR_C, 0xFF, // 31, 255
+ C_OLED_SET_VCOMH, 0x3E,
+ C_OLED_SET_MASTER_CURRENT_CONTROL, 0x06,
+ C_OLED_SET_COLUMN_ADDRESS, 0x00, 0x5F, // 33, 96
+ C_OLED_SET_ROW_ADDRESS, 0x00, 0x3F, // 36, 63
+ C_OLED_SET_DISPLAY_ON, // 39
+ C_OLED_NOP1, // 40 -- during debugging sent as data
+};
+
+volatile uint16_t *oled_spi = (uint16_t *)0xFFFFFB60;
+volatile uint32_t *simple_out = (uint32_t *)0xFFFFFF10;
+
+uint8_t oled_y = 0; // increments y-line to be drawn
+
+void dc(uint8_t state)
+{
+ if(state)
+ *simple_out |= (1<<11);
+ else
+ *simple_out &= ~(1<<11);
+}
+
+
+void resn(uint8_t state)
+{
+ if(state)
+ *simple_out |= (1<<10);
+ else
+ *simple_out &= ~(1<<10);
+}
+
+
+void oled_fill_screen(uint8_t color)
+{
+ dc(0); // command
+ spi_rxtx(oled_spi, C_OLED_SET_COLUMN_ADDRESS);
+ spi_rxtx(oled_spi, 0);
+ spi_rxtx(oled_spi, 0x5F);
+ spi_rxtx(oled_spi, C_OLED_SET_ROW_ADDRESS);
+ spi_rxtx(oled_spi, 0);
+ spi_rxtx(oled_spi, 0x3F);
+ dc(1); // data
+ for(int i = 0; i < 6144; i++)
+ spi_rxtx(oled_spi, color);
+}
+
+void oled_init()
+{
+ dc(0); // commands
+ resn(0);
+ delay(5);
+ resn(1);
+ delay(20);
+ // spi_start_tx(oled_spi);
+ for(int i = 0; i < sizeof(oled_init_sequence)/sizeof(oled_init_sequence[0]); i++)
+ spi_rxtx(oled_spi, oled_init_sequence[i]);
+ oled_fill_screen(0x42);
+ oled_y = 0;
+}
+
+void oled_horizontal_line(uint8_t y, uint8_t color)
+{
+ dc(0); // command
+ spi_rxtx(oled_spi, C_OLED_SET_ROW_ADDRESS);
+ spi_rxtx(oled_spi, y);
+ spi_rxtx(oled_spi, y);
+ dc(1); // data
+ for(int i = 0; i < 96; i++)
+ spi_rxtx(oled_spi, color);
+}
+
+uint8_t oled_color_stripes()
+{
+ oled_horizontal_line((oled_y+ 0) & 63, 0xFF); // white
+ oled_horizontal_line((oled_y+16) & 63, 0x03); // blue
+ oled_horizontal_line((oled_y+32) & 63, 0x1C); // green
+ oled_horizontal_line((oled_y+48) & 63, 0xE0); // red
+ return oled_y++ & 63;
+}
+
+
+// set up variables using the SD utility library functions:
+void oled_read(char *a)
+{
+ uint8_t line = oled_color_stripes();
+ sprintf(a, "OLED: %02x", line);
+}
--- /dev/null
+void oled_init();
+void oled_read(char *a);
--- /dev/null
+#include <Arduino.h>
+#include <math.h>
+#include <PCM.h>
+
+PCM pcm = PCM();
+
+struct sample
+{
+ int16_t ch[2]; // 0:left and 1:right channel, signed 16 bit integers
+};
+
+// crude malloc()
+volatile struct sample *buf = (volatile struct sample *) 0x80080000;
+int buflen = 1<<13; // number of samples, halfdma code easier if power of 2
+int halfdma = buflen*sizeof(struct sample)/2;
+int maxvolume = 20000;
+int stepvolume = 50;
+
+void pcm_tone()
+{
+ for(int i = 0; i <= maxvolume; i += stepvolume)
+ {
+ pcm.volume(i, i);
+ delayMicroseconds(1);
+ }
+}
+
+void pcm_mute()
+{
+ for(int i = maxvolume; i >= 0; i -= stepvolume)
+ {
+ pcm.volume(i, i);
+ delayMicroseconds(1);
+ }
+}
+
+void pcm_init() {
+ // set audio parameters
+ int i, rate = 22050;
+ buf = (struct sample *)malloc(buflen * sizeof(struct sample));
+ pcm.dma((uint32_t *)buf, buflen);
+ pcm.rate(rate);
+ pcm_mute();
+ for(i = 0; i < buflen; i++)
+ {
+ int16_t left = 32767 * sin(2*M_PI/buflen * i * 200);
+ int16_t right = 32767 * sin(2*M_PI/buflen * i * 201);
+ buf[i].ch[0] = left;
+ buf[i].ch[1] = right;
+ }
+}
--- /dev/null
+void pcm_tone();
+void pcm_mute();
+void pcm_init();
--- /dev/null
+/* Test for 32MB RAM
+** Fill RAM with pseudoranom data and read back its content
+*/
+#include <Arduino.h>
+
+volatile uint32_t *ram_begin = (uint32_t *) 0x80100000; // test start
+volatile uint32_t *ram_end = (uint32_t *) 0x82000000; // test end
+
+
+static uint32_t rngseed = 123459876;
+
+uint32_t rng(void)
+{
+ int x, t;
+ uint32_t hi, lo;
+
+ /*
+ * Compute x[n + 1] = (7^5 * x[n]) mod (2^31 - 1).
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ /* Can't be initialized with 0, so use another value. */
+ if ((x = rngseed) == 0)
+ x = 123459876;
+ hi = x / 127773;
+ lo = x % 127773;
+ t = 16807 * lo - 2836 * hi;
+ if (t < 0)
+ t += 0x7fffffff;
+ rngseed = t;
+ return t;
+}
+
+void ram_test(char *a)
+{
+ volatile uint32_t *addr;
+ uint32_t errors = 0;
+ static uint32_t seed = 123459876;
+ rngseed = seed;
+ for(addr = ram_begin; addr < ram_end; addr +=4)
+ *addr = rng();
+ rngseed = seed;
+ for(addr = ram_begin; addr < ram_end; addr +=4)
+ if(*addr != rng())
+ errors++;
+ if(errors)
+ sprintf(a, "RAM: ERRORS:%d FAIL\n", errors);
+ else
+ sprintf(a, "RAM: OK\n");
+ seed++; // change seed each time
+}
--- /dev/null
+void ram_test(char *a);
--- /dev/null
+/* FM antenna test
+ * Tune FM radio to 107.9 MHz
+ * Bring ULX3S within 1 m distance of radio antenna
+ * You should hear silence.
+ * RDS display should show: "TEST1234"
+ * RDS long message (optional on some radios): "@ABCDEFGHIJ.."
+ */
+
+#include <RDS.h>
+
+RDS rds = RDS();
+
+uint16_t pi = 0xCAFE;
+char ps[9] = "TEST1234";
+char rt[65] = "ABCDEFGH";
+
+void rds_init() {
+ int i;
+ for(i = 0; i < sizeof(rt)-1; i++)
+ rt[i] = '@'+i; // ascii map
+ /* Setup initial RDS text */
+ rds.pi(pi); // station numeric ID
+ rds.stereo(0); // 0-Inform over RDS that we send Mono, 1-Stereo
+ rds.ta(0); // 0-No, 1-Traffice Announcements
+ rds.ps(ps); // 8-char text, displayed as station name
+ rds.rt(rt); // 64-char text, not every radio displays it
+ rds.Hz(107900000); // Hz carrier wave frequency
+ rds.length(260); // bytes message length (260 default)
+}
--- /dev/null
+void rds_init();
--- /dev/null
+/* RTC MCP7940N test
+ * Battery required: CR1225 3V
+ * Board v1.7 needs changes: D11=RED LED, R4=4.7k
+ * To enter sleep mode, D18 (GREEN LED) should be OFF
+ * D18 is OFF by default when FT231x usb-serial is not enumerated
+ * Either plug FPGA into 5V USB charger
+ * or reprogram FT231x to drive D18 OFF:
+ * ftx_prog --cbus 3 drive_0
+ * to restore default D18 state:
+ * ftx_prob --cbus 3 sleep
+ */
+
+#include <SoftwareWire.h>
+SoftwareWire Wire(32+29,32+28);
+
+#define I2CADDR 0x6F // Microchip MCP7940N
+
+void regwrite(uint8_t reg, uint8_t value)
+{
+ Wire.beginTransmission(I2CADDR);
+ Wire.write(byte(reg));
+ Wire.write(byte(value));
+ Wire.endTransmission();
+}
+
+int regread(uint8_t reg, int8_t n)
+{
+ Wire.beginTransmission(I2CADDR);
+ Wire.write(byte(reg));
+ Wire.endTransmission();
+
+ Wire.requestFrom(I2CADDR, n);
+ if(Wire.available()) // slave may send less than requested
+ return Wire.read();
+ return -1;
+}
+
+void rtc_clear_interrupts()
+{
+}
+
+void rtc_set_clock()
+{
+ // set clock
+ regwrite(0x06, 0x17); // year
+ regwrite(0x05, 0x12); // month
+ regwrite(0x04, 0x31); // day
+ regwrite(0x03, 0x07 | 8); // weekday | battery_backup
+ regwrite(0x02, 0x23); // hour
+ regwrite(0x01, 0x59); // minute
+ regwrite(0x00, 0x58 | 0x80); // second | start_oscillator
+}
+
+void rtc_set_alarm()
+{
+ // set alarm (in 2 minutes)
+ regwrite(0x10, 0x18); // year
+ regwrite(0x0F, 0x01); // month
+ regwrite(0x0E, 0x01); // day
+ regwrite(0x0D, 0x01 | 0x70); // weekday | match_condition full timedate
+ regwrite(0x0C, 0x00); // hour
+ regwrite(0x0B, 0x00); // minute
+ regwrite(0x0A, 0x00); // seconds
+}
+
+void rtc_init() {
+ Wire.setClock(100000L); // 100000-400000 Hz i2c bus clock
+ Wire.begin(); // join i2c bus (address optional for master)
+
+ // set control register, enable only alarm0
+ regwrite(0x07, 0x10);
+
+ // set oscillator digital trim
+ regwrite(0x08, 0x45);
+}
+
+int rtc_read(char *a)
+{
+ int ret = 0;
+ char *eval;
+ uint8_t yr = regread(0x06,1) & 0x3F;
+ if(yr >= 0x17 && yr <= 0x18) {
+ //eval = regread(0x0D,1) & 8 ? " OK " : "WAIT";
+ if ( regread(0x0D,1) & 8 ) {
+ eval = " OK ";
+ ret = 1;
+ } else {
+ eval = "WAIT";
+ }
+ } else
+ eval = "FAIL";
+ sprintf(a, "20%02x-%02x-%02x %02x:%02x:%02x %s *-%02x %02x:%02x:%02x\n",
+ regread(0x06,1) & 0x3F, // year
+ regread(0x05,1) & 0x7F, // month
+ regread(0x04,1) & 0x7F, // day
+ regread(0x02,1) & 0x3F, // hour
+ regread(0x01,1) & 0x7F, // minute
+ regread(0x00,1) & 0x7F, // second
+ eval, // time evaluation and alarm flag
+ regread(0x0E,1) & 0x3F, // alarm day
+ regread(0x0C,1) & 0x3F, // alarm hour
+ regread(0x0B,1) & 0x7F, // alarm minute
+ regread(0x0A,1) & 0x7F // alarm second
+ );
+ return ret;
+}
--- /dev/null
+void rtc_init();
+int rtc_read(char *a);
+void rtc_set_alarm();
+void rtc_set_clock();
+void rtc_clear_interrupts();
--- /dev/null
+#include <Arduino.h>
+
+#if 0
+#include "spi.h"
+volatile uint16_t *sd_spi = (uint16_t *)0xFFFFFB50;
+uint8_t sd_cmd0()
+{
+ int i, r;
+
+ spi_start_tx(sd_spi);
+ for(i = 0; i < 10; i++)
+ spi_rxtx(sd_spi, 0xFF);
+ spi_rxtx(sd_spi, 0x40);
+ spi_rxtx(sd_spi, 0x00);
+ spi_rxtx(sd_spi, 0x00);
+ spi_rxtx(sd_spi, 0x00);
+ spi_rxtx(sd_spi, 0x95);
+
+ //Polling it to check response to 0x01
+ r = 0xFF;
+ for(int i = 0; i < 1000 && r != 0xFF; i++)
+ r = spi_rxtx(sd_spi, 0xFF);
+ return r;
+}
+
+void sd_read(char *a)
+{
+ uint8_t cmd0_response = sd_cmd0();
+ if(cmd0_response == 1)
+ sprintf(a, "SD: %02x OK ", cmd0_response);
+ else
+ sprintf(a, "SD: %02x FAIL", cmd0_response);
+}
+#endif
+
+#if 1
+#include <SPI.h>
+#include <SD.h>
+// set up variables using the SD utility library functions:
+Sd2Card card;
+SdVolume volume;
+SdFile root;
+// reading sd card type is slow
+int sd_read(char *a)
+{
+ int ret = 0;
+ char *cardtype;
+ if (card.init(SPI_HALF_SPEED, 2))
+ {
+ switch (card.type())
+ {
+ case SD_CARD_TYPE_SD1:
+ cardtype = "1 ";
+ break;
+ case SD_CARD_TYPE_SD2:
+ cardtype = "2 ";
+ break;
+ case SD_CARD_TYPE_SDHC:
+ cardtype = "HC";
+ break;
+ default:
+ cardtype = "? ";
+ }
+ sprintf(a, "SD: %s OK", cardtype);
+ ret = 1;
+ }
+ else
+ {
+ sprintf(a, "SD: FAIL ");
+ }
+ return ret;
+}
+#endif
--- /dev/null
+int sd_read(char *a);
--- /dev/null
+
+#if (_BYTE_ORDER == _LITTLE_ENDIAN)
+#define SPI_READY_MASK (1 << 8)
+#else
+#define SPI_READY_MASK (1 << 16)
+#endif
+
+uint8_t spi_start_tx(volatile uint16_t *port)
+{
+ uint32_t in;
+
+ ((uint8_t *)port)[1] = 0x80;
+ do {
+ in = *port;
+ } while ((in & SPI_READY_MASK) == 0);
+
+#if (_BYTE_ORDER == _LITTLE_ENDIAN)
+ return (in & 0xff);
+#else
+ return (in >> 24);
+#endif
+}
+
+
+uint8_t spi_rxtx(volatile uint16_t *port, uint8_t _data)
+{
+ uint32_t in;
+
+ *(uint8_t *)port = _data;
+ do {
+ in = *port;
+ } while ((in & SPI_READY_MASK) == 0);
+
+#if (_BYTE_ORDER == _LITTLE_ENDIAN)
+ return (in & 0xff);
+#else
+ return (in >> 24);
+#endif
+}
--- /dev/null
+uint8_t spi_start_tx(volatile uint16_t *port);
+uint8_t spi_rxtx(volatile uint16_t *port, uint8_t _data);