streaming server for AM/FM radio via UDP connection.
Dependencies: mbed EthernetNetIf
Diff: ns9542.c
- 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(); +} +