streaming server for AM/FM radio via UDP connection.

Dependencies:   mbed EthernetNetIf

ns9542.c

Committer:
soramimi
Date:
2012-08-30
Revision:
2:3b6816fd4ae6
Parent:
0:bd865e5a3df3

File content as of revision 2:3b6816fd4ae6:

#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();
}