streaming server for AM/FM radio via UDP connection.

Dependencies:   mbed EthernetNetIf

Revision:
0:bd865e5a3df3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ns9542.c	Mon Feb 28 11:49:39 2011 +0000
@@ -0,0 +1,452 @@
+#include "mbed.h"
+
+//I2C i2c(p9, p10);        // sda, scl
+
+DigitalInOut i2c_sda(p9);
+DigitalInOut i2c_scl(p10);
+
+void wait10us()
+{
+  wait(0.000001);
+}
+
+void wait10ms()
+{
+  wait(0.001);
+}
+
+void wait100ms()
+{
+  wait(0.01);
+}
+
+
+
+#if 1
+
+// i2c
+
+void i2c_cl_0()
+{
+    i2c_scl.output();
+}
+
+void i2c_cl_1()
+{
+    i2c_scl.input();
+}
+
+void i2c_da_0()
+{
+    i2c_sda.output();
+}
+
+void i2c_da_1()
+{
+    i2c_sda.input();
+}
+
+int i2c_get_da()
+{
+  return i2c_sda.read();
+}
+
+void i2c_start()
+{
+  i2c_da_0();
+  wait10us();
+  i2c_cl_0();
+  wait10us();
+}
+
+void i2c_stop()
+{
+  i2c_cl_1();
+  wait10us();
+  i2c_da_1();
+  wait10us();
+}
+
+void i2c_repeat()
+{
+  i2c_cl_1();
+  wait10us();
+  i2c_da_0();
+  wait10us();
+  i2c_cl_0();
+  wait10us();
+}
+
+bool i2c_write(int c)
+{
+  int i;
+  bool nack;
+
+  wait10us();
+
+  for (i = 0; i < 8; i++) {
+    if (c & 0x80) {
+      i2c_da_1();
+    } else {
+      i2c_da_0();
+    }
+    c <<= 1;
+    wait10us();
+    i2c_cl_1();
+    wait10us();
+    i2c_cl_0();
+    wait10us();
+  }
+
+  i2c_da_1();
+  wait10us();
+
+  i2c_cl_1();
+  wait10us();
+  nack = i2c_get_da();
+  i2c_cl_0();
+
+  return nack;
+}
+
+int i2c_read(bool nack)
+{
+  int i, c;
+
+  i2c_da_1();
+  wait10us();
+
+  c = 0;
+
+  for (i = 0; i < 8; i++) {
+    i2c_cl_1();
+    wait10us();
+    c <<= 1;
+    if (i2c_get_da()) {
+      c |= 1;
+    }
+    i2c_cl_0();
+    wait10us();
+  }
+
+  if (nack) {
+    i2c_da_1();
+  } else {
+    i2c_da_0();
+  }
+  wait10us();
+  i2c_cl_1();
+  wait10us();
+  i2c_cl_0();
+  wait10us();
+
+  return c;
+}
+
+#endif
+
+
+// ns9542
+
+void ns9542_write(int a, int c)
+{
+#if 01
+  i2c_start();
+  i2c_write(0xc8);
+  i2c_write(a);
+  i2c_write(c);
+  i2c_stop();
+#else
+    char tmp[2];
+    i2c.start();
+    tmp[0] = a;
+    tmp[1] = c;
+    i2c.write(0xc8, tmp, 2);
+    i2c.stop();
+#endif
+}
+
+int ns9542_read(int a)
+{
+#if 01
+  int c;
+  i2c_start();
+  i2c_write(0xc8);
+  i2c_write(a);
+  i2c_repeat();
+  i2c_write(0xc9);
+  c = i2c_read(true);
+  i2c_stop();
+  return c;
+#else
+    char tmp[2];
+    i2c.start();
+    tmp[0] = a;
+    tmp[1] = 0xc9;
+    i2c.write(0xc8, tmp, 1);
+    i2c.write(0xc8, tmp + 1, 1, true);
+    unsigned char c = i2c.read(1);
+    i2c.stop();
+    return c;
+#endif
+}
+
+void ns9542_imf_adjust()
+{
+  int bF, imf, fhm, g_fhm;
+  bF = 0;
+  g_fhm = 0xf0;
+  ns9542_write(0x15, 0x0e);
+  ns9542_write(0x3d, 0x27);
+  for (fhm = 0; fhm < 4; fhm++) {
+    bF = 0;
+    for (imf = 0; imf < 3; imf++) {
+      ns9542_write(0x37, fhm);
+      ns9542_write(0x16, 22 + imf);
+      wait10ms();
+      if ((ns9542_read(0x70) & 0x0c) == 0x0c) {
+        bF++;
+        if (imf == 1 && g_fhm == 0xf0) {
+          g_fhm = fhm;
+        }
+      }
+    }
+    if (bF == 3) {
+      g_fhm = fhm;
+      break;
+    }
+  }
+  ns9542_write(0x37, 0x80 | g_fhm);
+  ns9542_write(0x16, 23);
+  ns9542_write(0x3d, 0x37);
+  wait100ms();
+}
+
+void ns9542_best_iml(int iml)
+{
+  ns9542_write(0x32, 0x00);
+  while (iml < 16) {
+    ns9542_write(0x17, 0xc0 | iml);
+    wait10ms();
+    if (!(ns9542_read(0x70) & 0x08)) {
+      break;
+    }
+    iml++;
+  }
+  iml--;
+  ns9542_write(0x17, 0xc0 | iml);
+  ns9542_write(0x32, 0x80);
+  wait10ms();
+  ns9542_write(0xfe, 0x0a);
+  wait10ms();
+  wait10ms();
+}
+
+void ns9542_find_pg(int ialgn, int *fine_phase, int *fine_gain, int *result_pg)
+{
+  int i, j;
+  for (i = 0; i < 16; i++) {
+    ns9542_write(0x15, 0x0a | (ialgn << 4));
+    ns9542_write(0x15, 0x0b | (ialgn << 4));
+    if (ns9542_read(0x05) & 0x08) {
+      for (j = 0; j < 20; j++) {
+        if (!(ns9542_read(0x05) & 0x08)) {
+          int g = ns9542_read(0x65);
+          int p = ns9542_read(0x66);
+          if (g >= 103 && g <= 138 && 2 >= p && p <= 14) {
+            *fine_gain = g;
+            *fine_phase = p;
+            *result_pg = 1;
+            return;
+          }
+        }
+        wait10ms();
+      }
+    }
+  }
+  *result_pg = 0;
+}
+
+void ns9542_table_write(int *fine_p, int *fine_g)
+{
+  int i, j, k, result;
+  result = 0;
+  for (i = 0; i < 4; i++) {
+    ns9542_write(0x38, fine_g[i]);
+    ns9542_write(0x39, fine_p[i] << 4);
+    for (j = 0; j < 10; j++) {
+      ns9542_write(0x15, 0x0e | (i << 4));
+      ns9542_write(0x15, 0x03 | (i << 4));
+      if (ns9542_read(0x05) & 0x08) {
+        wait100ms();
+        for (k = 0; k < 10; k++) {
+          if (!(ns9542_read(0x05) & 0x08)) {
+            result++;
+            goto L1;
+          }
+          wait10ms();
+        }
+        break;
+      }
+    }
+L1:;
+    if (result != i + 1) {
+      break;
+    }
+  }
+}
+
+void ns9542_dsp_align_body()
+{
+  int iml, imf, ialgn, cnt, fp, fg;
+  int fine_p[5] = { 0, 0, 0, 0, 0 };
+  int fine_g[5] = { 0, 0, 0, 0, 0 };
+  iml = 5;
+  for (ialgn = 0; ialgn < 4; ialgn++) {
+    ns9542_write(0x15, 0x0a | (ialgn << 4));
+    wait100ms();
+    wait100ms();
+    ns9542_best_iml(iml);
+    imf = 0;
+    cnt = 0;
+    fp = 0;
+    fg = 0;
+    for (cnt = 0; cnt < 5; cnt++) {
+      int fine_phase, fine_gain, result_pg;
+      ns9542_find_pg(ialgn, &fine_phase, &fine_gain, &result_pg);
+      if (result_pg == 0) {
+        return;
+      }
+      fp = fp + fine_phase;
+      fg = fg + fine_gain;
+      if (cnt == 2 && ialgn < 2) {
+        cnt++;
+        break;
+      }
+    }
+    fine_p[ialgn] = fp / cnt;
+    fine_g[ialgn] = fg / cnt;
+  }
+  ns9542_table_write(fine_p, fine_g);
+}
+
+void ns9542_mute(bool mute)
+{
+  if (mute) {
+    ns9542_write(0x00, ns9542_read(0x00) | 0x02);
+  } else {
+    ns9542_write(0x00, ns9542_read(0x00) & ~0x02);
+  }
+}
+
+void ns9542_tune_am9(int freq) // freq = kHz
+{
+  unsigned short psy;
+
+  psy = freq;
+
+  ns9542_write(0x00, 0x23);
+
+  wait10ms();
+  wait10ms();
+
+  ns9542_write(0x04, 0x80);
+  ns9542_write(0x0c, 0xf0);
+
+  ns9542_write(0x10, 0x10);
+
+  ns9542_write(0x02, psy & 0xff);
+  ns9542_write(0x03, psy >> 8);
+
+  ns9542_write(0x00, 0x21);
+}
+
+void ns9542_tune_fm(int freq) // freq = MHz * 100
+{
+  unsigned short psy;
+
+  psy = freq / 5;
+
+  ns9542_write(0x00, 0x03);
+
+  ns9542_write(0x10, 0x10);
+
+  ns9542_write(0x02, psy & 0xff);
+  ns9542_write(0x03, psy >> 8);
+
+  ns9542_write(0x00, 0x01);
+}
+
+void ns9542_reset()
+{
+  ns9542_write(0xfe, 0xaa);
+}
+
+void ns9542_power_on()
+{
+  static unsigned char power_on[] = {
+    0x01, 0x30,
+    0x0c, 0x80,
+    0x0e, 0x34,
+    0x15, 0xc4,
+    0x20, 0x3c,
+    0x21, 0x03,
+    0x22, 0x0a,
+    0x23, 0x0a,
+    0x30, 0xff,
+    0x3d, 0x07,
+    0x40, 0x1a,
+    0x41, 0x9a,
+    0x50, 0xe1,
+    0x54, 0xb0,
+    0x55, 0x36,
+    0x5c, 0xc8,
+    0x5d, 0x61,
+    0x5e, 0x88,
+    0x5f, 0xa5,
+    0x71, 0x2c,
+    0x72, 0x06,
+  };
+  int i;
+  for (i = 0; i < sizeof(power_on); i += 2) {
+    ns9542_write(power_on[i], power_on[i + 1]);
+  }
+
+  ns9542_write(0x00, ns9542_read(0x00) | 0x03);
+}
+
+void ns9542_dsp_alignment()
+{
+  ns9542_write(0x0e, ns9542_read(0x0e) & ~0x60 | 0x40);
+  ns9542_write(0x01, 0x08);
+  ns9542_write(0x15, 0x0c);
+  ns9542_write(0x16, 0x17);
+  ns9542_write(0x37, 0x82);
+  ns9542_write(0x3d, 0x37);
+  wait100ms();
+
+  ns9542_imf_adjust();
+  ns9542_dsp_align_body();
+
+  ns9542_write(0x01, 0x38);
+  ns9542_write(0x0e, ns9542_read(0x0e) & ~0x60 | 0x20);
+  ns9542_write(0x15, 0xc0);
+  ns9542_write(0x17, 0x20);
+  ns9542_write(0x32, 0x00);
+  ns9542_write(0x37, 0x01);
+}
+
+void ns9542_init()
+{                
+    i2c_sda.mode(PullUp);
+    i2c_scl.mode(PullUp);
+    i2c_sda.input();
+    i2c_scl.input();
+    i2c_sda.write(0);
+    i2c_scl.write(0);
+
+    ns9542_reset();
+    ns9542_power_on();
+    ns9542_dsp_alignment();
+}
+