Merge branch 'master' of mjesec.ffzg.hr:/git/Arduino master
authorDobrica Pavlinusic <dpavlin@rot13.org>
Sun, 19 Jul 2020 11:01:21 +0000 (13:01 +0200)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Sun, 19 Jul 2020 11:01:21 +0000 (13:01 +0200)
26 files changed:
c2_ulx3s_test/adc.cpp [new file with mode: 0644]
c2_ulx3s_test/adc.h [new file with mode: 0644]
c2_ulx3s_test/btn.cpp [new file with mode: 0644]
c2_ulx3s_test/btn.h [new file with mode: 0644]
c2_ulx3s_test/c2_ulx3s_test.ino [new file with mode: 0644]
c2_ulx3s_test/dac.cpp [new file with mode: 0644]
c2_ulx3s_test/dac.h [new file with mode: 0644]
c2_ulx3s_test/edid.cpp [new file with mode: 0644]
c2_ulx3s_test/edid.h [new file with mode: 0644]
c2_ulx3s_test/flash.cpp [new file with mode: 0644]
c2_ulx3s_test/flash.h [new file with mode: 0644]
c2_ulx3s_test/font.h [new file with mode: 0644]
c2_ulx3s_test/oled.cpp [new file with mode: 0644]
c2_ulx3s_test/oled.h [new file with mode: 0644]
c2_ulx3s_test/pcm.cpp [new file with mode: 0644]
c2_ulx3s_test/pcm.h [new file with mode: 0644]
c2_ulx3s_test/ram.cpp [new file with mode: 0644]
c2_ulx3s_test/ram.h [new file with mode: 0644]
c2_ulx3s_test/rds.cpp [new file with mode: 0644]
c2_ulx3s_test/rds.h [new file with mode: 0644]
c2_ulx3s_test/rtc.cpp [new file with mode: 0644]
c2_ulx3s_test/rtc.h [new file with mode: 0644]
c2_ulx3s_test/sd.cpp [new file with mode: 0644]
c2_ulx3s_test/sd.h [new file with mode: 0644]
c2_ulx3s_test/spi.cpp [new file with mode: 0644]
c2_ulx3s_test/spi.h [new file with mode: 0644]

diff --git a/c2_ulx3s_test/adc.cpp b/c2_ulx3s_test/adc.cpp
new file mode 100644 (file)
index 0000000..17ad139
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+*/
+#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;
+}
diff --git a/c2_ulx3s_test/adc.h b/c2_ulx3s_test/adc.h
new file mode 100644 (file)
index 0000000..dab61a8
--- /dev/null
@@ -0,0 +1,2 @@
+void adc_init();
+int adc_read(char *a);
diff --git a/c2_ulx3s_test/btn.cpp b/c2_ulx3s_test/btn.cpp
new file mode 100644 (file)
index 0000000..76ece4b
--- /dev/null
@@ -0,0 +1,73 @@
+#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;
+}
diff --git a/c2_ulx3s_test/btn.h b/c2_ulx3s_test/btn.h
new file mode 100644 (file)
index 0000000..8f9a428
--- /dev/null
@@ -0,0 +1,2 @@
+void btn_init();
+int btn_read(char *line);
diff --git a/c2_ulx3s_test/c2_ulx3s_test.ino b/c2_ulx3s_test/c2_ulx3s_test.ino
new file mode 100644 (file)
index 0000000..475319c
--- /dev/null
@@ -0,0 +1,224 @@
+#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);
+}
diff --git a/c2_ulx3s_test/dac.cpp b/c2_ulx3s_test/dac.cpp
new file mode 100644 (file)
index 0000000..7b6272b
--- /dev/null
@@ -0,0 +1,81 @@
+/* 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;
+}
diff --git a/c2_ulx3s_test/dac.h b/c2_ulx3s_test/dac.h
new file mode 100644 (file)
index 0000000..b5c171f
--- /dev/null
@@ -0,0 +1,2 @@
+void dac_init();
+int dac_read(char *a);
diff --git a/c2_ulx3s_test/edid.cpp b/c2_ulx3s_test/edid.cpp
new file mode 100644 (file)
index 0000000..739bdbb
--- /dev/null
@@ -0,0 +1,283 @@
+//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;
+}
diff --git a/c2_ulx3s_test/edid.h b/c2_ulx3s_test/edid.h
new file mode 100644 (file)
index 0000000..2b05066
--- /dev/null
@@ -0,0 +1,3 @@
+int edidreadbytes(char *array);
+byte edidchecksum(char *array);
+int edid_read(char *a);
diff --git a/c2_ulx3s_test/flash.cpp b/c2_ulx3s_test/flash.cpp
new file mode 100644 (file)
index 0000000..f9c6f6e
--- /dev/null
@@ -0,0 +1,27 @@
+#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;
+}
diff --git a/c2_ulx3s_test/flash.h b/c2_ulx3s_test/flash.h
new file mode 100644 (file)
index 0000000..2dd43d6
--- /dev/null
@@ -0,0 +1 @@
+int flash_read(char *a);
diff --git a/c2_ulx3s_test/font.h b/c2_ulx3s_test/font.h
new file mode 100644 (file)
index 0000000..8b1b73c
--- /dev/null
@@ -0,0 +1,1448 @@
+#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 },
+};
diff --git a/c2_ulx3s_test/oled.cpp b/c2_ulx3s_test/oled.cpp
new file mode 100644 (file)
index 0000000..8c2d49b
--- /dev/null
@@ -0,0 +1,139 @@
+#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);
+}
diff --git a/c2_ulx3s_test/oled.h b/c2_ulx3s_test/oled.h
new file mode 100644 (file)
index 0000000..1250b67
--- /dev/null
@@ -0,0 +1,2 @@
+void oled_init();
+void oled_read(char *a);
diff --git a/c2_ulx3s_test/pcm.cpp b/c2_ulx3s_test/pcm.cpp
new file mode 100644 (file)
index 0000000..557ba9e
--- /dev/null
@@ -0,0 +1,51 @@
+#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;
+  }
+}
diff --git a/c2_ulx3s_test/pcm.h b/c2_ulx3s_test/pcm.h
new file mode 100644 (file)
index 0000000..1a2c513
--- /dev/null
@@ -0,0 +1,3 @@
+void pcm_tone();
+void pcm_mute();
+void pcm_init();
diff --git a/c2_ulx3s_test/ram.cpp b/c2_ulx3s_test/ram.cpp
new file mode 100644 (file)
index 0000000..9fe126c
--- /dev/null
@@ -0,0 +1,52 @@
+/* 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
+}
diff --git a/c2_ulx3s_test/ram.h b/c2_ulx3s_test/ram.h
new file mode 100644 (file)
index 0000000..0827784
--- /dev/null
@@ -0,0 +1 @@
+void ram_test(char *a);
diff --git a/c2_ulx3s_test/rds.cpp b/c2_ulx3s_test/rds.cpp
new file mode 100644 (file)
index 0000000..a52be2b
--- /dev/null
@@ -0,0 +1,29 @@
+/* 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)
+}
diff --git a/c2_ulx3s_test/rds.h b/c2_ulx3s_test/rds.h
new file mode 100644 (file)
index 0000000..13476a1
--- /dev/null
@@ -0,0 +1 @@
+void rds_init();
diff --git a/c2_ulx3s_test/rtc.cpp b/c2_ulx3s_test/rtc.cpp
new file mode 100644 (file)
index 0000000..6bc97f5
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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;
+}
diff --git a/c2_ulx3s_test/rtc.h b/c2_ulx3s_test/rtc.h
new file mode 100644 (file)
index 0000000..29fa131
--- /dev/null
@@ -0,0 +1,5 @@
+void rtc_init();
+int rtc_read(char *a);
+void rtc_set_alarm();
+void rtc_set_clock();
+void rtc_clear_interrupts();
diff --git a/c2_ulx3s_test/sd.cpp b/c2_ulx3s_test/sd.cpp
new file mode 100644 (file)
index 0000000..76f1ac1
--- /dev/null
@@ -0,0 +1,73 @@
+#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
diff --git a/c2_ulx3s_test/sd.h b/c2_ulx3s_test/sd.h
new file mode 100644 (file)
index 0000000..0b7e8f1
--- /dev/null
@@ -0,0 +1 @@
+int sd_read(char *a);
diff --git a/c2_ulx3s_test/spi.cpp b/c2_ulx3s_test/spi.cpp
new file mode 100644 (file)
index 0000000..40f76fc
--- /dev/null
@@ -0,0 +1,39 @@
+
+#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
+}
diff --git a/c2_ulx3s_test/spi.h b/c2_ulx3s_test/spi.h
new file mode 100644 (file)
index 0000000..60584e8
--- /dev/null
@@ -0,0 +1,2 @@
+uint8_t spi_start_tx(volatile uint16_t *port);
+uint8_t spi_rxtx(volatile uint16_t *port, uint8_t _data);