To instruct a TLV320AIC20K to start producing some noise sent to it::
- ./aic2x-setup /dev/i2c-2 0x40 1=0x49 2=0x20 3a=0x00 3b=0x40 3c=0x88 3d=0xc0 4=0x00 5a=0x1f 5b=0x45 5c=0x80 5d=0xc0 6a=0x20 6b=0x83
+ ./bin/i2cp/aic2x-setup /dev/i2c-2 0x40 1=0x49 2=0x20 3a=0x00 3b=0x40 3c=0x88 3d=0xc0 4=0x00 5a=0x1f 5b=0x45 5c=0x80 5d=0xc0 6a=0x20 6b=0x83
or, since all registers are written anyway::
- ./aic2x-config /dev/i2c-2 0x40 0x49 0x20 0x00 0x40 0x88 0xc0 0x00 0x1f 0x45 0x80 0xc0 0x20 0x83
+ ./bin/i2cp/aic2x-config /dev/i2c-2 0x40 0x49 0x20 0x00 0x40 0x88 0xc0 0x00 0x1f 0x45 0x80 0xc0 0x20 0x83
broad daylight; nothing can beat the Sun for proper illumination.
Closing one eye may help, and using a magnifying glass may help too.
+No matter how well you do it, you will short-circuit parts of the
+circuitry. When you pull a probe along pins you are inevitably going
+to connect neighbouring pins. You should realise that this is a risk,
+albeit a modest one -- most electronic circuitry will survive such
+a beating without much more trouble than some spurious behaviour, such
+as a spontaneous reset. More surprisingly perhaps, you may also create
+a lasting connection between neighbouring pins. This can happen if you
+use very sharp (and thus useful) probes to measure a pin for some time.
+In fixating on the pin, you can easily apply too much force, causing
+the pin to split apart and cover a bit more area. With the small sizes
+of surface mount technology, this may lead to a short-circuit with
+the neighbouring pins! Most circuitry will even survive such a harsh
+treatment, and you can resolve it by taking a needle (not a sewing pin,
+as those will bend) and scratching carefully between the pins that got
+connected. A strong sign of such unwanted connectivity is if the
+original firmware starts to behave strangely and it appears as though
+you destroyed a piece of its hardware. Still, it will take quite a bit
+of your intuition and ingenuity to determine the error spot, but on the
+other hand it is simple to check by measuring, once you have a
+suspicion.
+
And yes... I would love to have probes with one conductive side and
one isolated side, so I could poke it in between two pins instead
of balancing it on top of one while moving something else around.
void bottom_codec_play_skip (codec_t codec, uint16_t samples);
+/* Definitions for sound channels and devices.
+ * These can be overridden by setting them in device-dependent includes.
+ */
+
+#ifndef PHONE_CHANNEL_TELEPHONY
+#define PHONE_CHANNEL_TELEPHONY 0
+#endif
+
+#ifndef PHONE_CHANNEL_SOUNDCARD
+#define PHONE_CHANNEL_SOUNDCARD 0
+#endif
+
+#ifndef PHONE_SOUNDDEV_NONE
+#define PHONE_SOUNDDEV_NONE SOUNDDEV_NONE
+#endif
+
+#ifndef PHONE_SOUNDDEV_HANDSET
+#define PHONE_SOUNDDEV_HANDSET SOUNDDEV_HANDSET
+#endif
+
+#ifndef PHONE_SOUNDDEV_HEADSET
+#define PHONE_SOUNDDEV_HEADSET SOUNDDEV_HEADSET
+#endif
+
+#ifndef PHONE_SOUNDDEV_SPEAKER
+#define PHONE_SOUNDDEV_SPEAKER SOUNDDEV_SPEAKER
+#endif
+
+#ifndef PHONE_SOUNDDEV_LINE
+#define PHONE_SOUNDDEV_LINE SOUNDDEV_LINE
+#endif
+
+
#endif
extern volatile uint32_t flash_16 [];
asm ("_flash_16 .set 0x200000");
+/* Override the SPEAKER as the HEADSET sound device */
+#define PHONE_SOUNDDEV_SPEAKER SOUNDDEV_HEADSET
+
#endif /* CONFIG_TARGET_GRANDSTREAM_BT20x || CONFIG_TARGET_GRANDSTREAM_BT10x */
#if defined CONFIG_TARGET_GRANDSTREAM_BT20x
asm ("_DXR1_1 .set 0x2c02");
asm ("_DRR1_1 .set 0x2c00");
+#define REGVAL_SPCR1_CLKSTP_DISABLED 0x0000
+#define REGVAL_SPCR1_CLKSTP_NODELAY 0x1000
+#define REGVAL_SPCR1_CLKSTP_NODELAY 0x1000
#define REGVAL_SPCR1_CLKSTP_WITHDELAY 0x1800
#define REGVAL_SPCR1_RRST_NOTRESET 0x0001
#define REGVAL_SPCR2_FRST_NOTRESET 0x0080
/* Set a frequency divisor for the intended sample rate */
void tlv320aic2x_set_samplerate (uint32_t samplerate) {
+#ifndef TODO_FS_ONLY_DURING_SOUND_IO
+ SPCR2_1 &= ~ ( REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET );
+#endif
samplerate = 12288000 / samplerate;
if (samplerate >= 4096) {
samplerate = 4096;
} else if (samplerate == 0) {
samplerate = 1;
}
- SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | ((samplerate - 1) & 0x0fff);
+ SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | (samplerate - 1);
+#ifndef TODO_FS_ONLY_DURING_SOUND_IO
+ SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
+ SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
+ SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
+#endif
+ // Now, if not done yet, unreset and setup the TLV320AIC20K codec
+ if ((IODATA & (1 << 7)) == 0) {
+ volatile uint8_t ctr;
+ IODATA |= (1 << 7);
+ for (ctr=0; ctr < 132; ctr++) {
+ asm (" nop"); /* Wait at least 132 MCLK cycles */
+ asm (" nop");
+ asm (" nop");
+ asm (" nop");
+ }
+ }
}
/* A full frame of 64 samples has been recorded. See if space exists for
tic55x_top_has_been_interrupted = true;
if ((available_record += 64) > (BUFSZ - 64)) {
DMACCR_0 &= ~REGVAL_DMACCR_EN;
+#ifdef TODO_FS_ONLY_DURING_SOUND_IO
SPCR1_1 &= ~REGVAL_SPCR1_RRST_NOTRESET;
if ((SPCR2_1 & REGVAL_SPCR2_XRST_NOTRESET) == 0) {
SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
}
+#endif
}
if (available_record >= threshold_record) {
top_can_record (available_record);
uint16_t toplay;
tic55x_top_has_been_interrupted = true;
if ((available_play -= 64) < 64) {
+#ifdef TODO_FS_ONLY_DURING_SOUND_IO
SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
if ((SPCR1_1 & REGVAL_SPCR1_RRST_NOTRESET) == 0) {
SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
}
+#endif
+ DXR1_1 = DXR1_1; // Flag down XEMPTY
DMACCR_1 &= ~REGVAL_DMACCR_EN;
}
toplay = BUFSZ - available_play;
if (! (DMACCR_0 & REGVAL_DMACCR_EN)) {
if (available_record <= (BUFSZ - 64)) {
if (!(DMACCR_0 & REGVAL_DMACCR_EN)) {
+ (void) DRR1_1; // Flag down RFULL
+ (void) DRR1_1;
DMACCR_0 |= REGVAL_DMACCR_EN;
+#ifdef TODO_FS_ONLY_DURING_SOUND_IO
SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
+#endif
}
// bottom_printf ("dmahint_record() enabled DMA from %d bytes out of %d\n", (intptr_t) available_record, (intptr_t) BUFSZ);
}
if ((available_play >= 64) && ! (DMACCR_1 & REGVAL_DMACCR_EN)) {
DMACCR_1 |= REGVAL_DMACCR_EN;
bottom_printf ("dmahint_play() started playing DMA\n");
+#ifdef TODO_FS_ONLY_DURING_SOUND_IO
SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET | REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
+#endif
}
//TODO:DEBUG// else bottom_printf ("dmahint_play() did not start playing -- available_play = %d\n", (intptr_t) available_play);
}
SRGR1_1 = REGVAL_SRGR1_FWID_1 | REGVAL_SRGR1_CLKGDIV_4;
SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | REGVAL_SRGR2_FPER_1535;
PCR1 = /*TODO: (1 << REGBIT_PCR_IDLEEN) | */ (1 << REGBIT_PCR_FSXM) | (1 << REGBIT_PCR_FSRM) | (1 << REGBIT_PCR_CLKXM) | (1 << REGBIT_PCR_CLKRM) /* TODO:WRONG? | (1 << REGBIT_PCR_CLKXP) | (1 << REGBIT_PCR_CLKRP) */;
+ SPCR1_1 |= REGVAL_SPCR1_CLKSTP_NODELAY;
//
// Setup I2C for communication with the TLV320AIC20K codec
// Prescale SYSCLK2 down from 61.44 MHz to 10.24 MHz so it falls
bt200_level_active [idx] = false;
}
IODIR |= (1 << 7) | (1 << 1);
- IODATA |= (1 << 7) | (1 << 1);
+ IODATA |= (1 << 1);
asm (" bclr xf"); // Switch off MESSAGE LED
{ uint16_t ctr = 250; while (ctr > 0) { ctr--; } }
bottom_critical_region_begin (); // _disable_interrupts ();
#include <config.h>
#include <0cpm/snd.h>
#include <0cpm/cons.h>
+#include <0cpm/led.h>
/* The code below distinguishes the two directions of using the
// (but for now just powerdown the codec)
tlv320aic2x_setreg (chan, 6, 0x00 | 0x04);
tlv320aic2x_setreg (chan, 6, 0x80 | 0x00);
- //TODO:TMP_NO_POWERDOWN// tlv320aic2x_setreg (chan, 3, 0x00 | 0x31); /* power down */
+ tlv320aic2x_setreg (chan, 3, 0x00 | 0x31); /* power down */
break;
case SOUNDDEV_HANDSET:
- tlv320aic2x_setreg (chan, 6, 0x00 | 0x02);
+ tlv320aic2x_setreg (chan, 6, 0x00 | 0x22);
tlv320aic2x_setreg (chan, 6, 0x80 | 0x02);
break;
case SOUNDDEV_HEADSET:
*/
void tlv320aic2x_setup_sound (void) {
uint8_t chan;
+ tlv320aic2x_set_samplerate (8000);
// Setup the various registers in the TLV320AIC2x
for (chan = 0; chan < 2; chan++) {
tlv320aic2x_setreg (chan, 1, 0x49); /* Continuous 16-bit, 2.35V bias */
tlv320aic2x_setreg (chan, 2, 0xa0); /* Turbo mode */
/* Setup to SOUNDDEV_NONE below will power down the device */
- tlv320aic2x_setreg (chan, 3, 0x40 | 0x20); /* Arrange mute with volume 0 */
- /* Ignore register 3C */
- tlv320aic2x_setreg (chan, 3, 0xc0 | 0x00); /* Switch off LCD DAC */
- /* Bypass MNP setup, it is phone-speficic */
- tlv320aic2x_setreg (chan, 5, 0x00 | 0x20); /* ADC gain 27 dB -- ok? */
- bottom_soundchannel_setvolume (chan, 16); /* DAC gain -24 dB initially */
+ /* Register 3A resets ok to 0x01: no sleep, FS/fs == 1 */
+ tlv320aic2x_setreg (chan, 3, 0x40 | 0x20); /* Setup 8 kHz filter, no mute */
+ /* Register 3C resets ok to 0x80 | (chip_id << 2) */
+ /* Register 3D resets ok to 0xc0: no LCD DAC */
+ /* Skip MNP setup, but samplerate-setup per phone may override */
+ tlv320aic2x_setreg (chan, 5, 0x00 | 0x12); /* ADC gain 27 dB -- ok? */
+ bottom_soundchannel_setvolume (chan, 15); /* DAC gain -24 dB initially */
tlv320aic2x_setreg (chan, 5, 0x80 | 0x00); /* No sidetones */
- tlv320aic2x_setreg (chan, 5, 0xc0 | 0x30); /* SPKR gain +3 dB -- ok? */
+ /* Register 5D resets ok to 0xc0: No speaker gain */
+ tlv320aic2x_setreg (chan, 6, 0x00 | 0x20); /* Handset feedback, no input */
+ /* Register 6B resets ok to 0x80: No output selected */
bottom_soundchannel_device (chan, SOUNDDEV_NONE);/* No input/output, powerdown */
}
}
+
void top_hook_update (bool offhook) {
if (offhook) {
- bottom_soundchannel_device (0, SOUNDDEV_HANDSET);
+ bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_HANDSET);
} else {
- bottom_soundchannel_device (0, SOUNDDEV_SPEAKER);
+ bottom_soundchannel_device (PHONE_CHANNEL_TELEPHONY, PHONE_SOUNDDEV_SPEAKER);
}
}
}
void top_button_press (buttonclass_t bcl, buttoncode_t cde) {
- /* Keep the linker happy */
+ if (bcl != BUTCLS_FIXED_FUNCTION) {
+ return;
+ }
+ switch (cde) {
+#ifdef HAVE_BUTTON_UP
+ case HAVE_BUTTON_UP:
+ bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY,
+ bottom_soundchannel_getvolume (PHONE_CHANNEL_TELEPHONY) + 1);
+ break;
+#endif
+#ifdef HAVE_BUTTON_DOWN
+ case HAVE_BUTTON_DOWN:
+ bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY,
+ bottom_soundchannel_getvolume (PHONE_CHANNEL_TELEPHONY) - 1);
+ break;
+#endif
+ default:
+ break;
+ }
}
void top_button_release (void) {
}
-// #define top_main_delay_1sec top_main
-#define top_main_sine_1khz top_main
+#define top_main_delay_1sec top_main
+// #define top_main_sine_1khz top_main
+
+
+#ifdef CONFIG_FUNCTION_NETCONSOLE
+uint8_t netinput [1000];
+uint16_t netinputlen;
+void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
+#endif
/******** TOP_MAIN FOR A 1 KHZ SINE WAVE OUTPUT ********/
};
void top_main_sine_1khz (void) {
+ uint16_t oldirqs = 0;
+extern volatile uint16_t available_play;
top_hook_update (bottom_phone_is_offhook ());
bottom_codec_play_samplerate (0, 8000);
bottom_codec_record_samplerate (0, 8000); // Both MUST be called for now
+ bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_RINGING); // TODO: Not really necessary
+ bottom_printf ("Playing 1 kHz tone to speaker or handset\n");
tobeplayed = 64;
while (true) {
- if (tobeplayed > 8) {
+ uint16_t newplayed = tobeplayed;
+ uint16_t oldplayed = newplayed;
+ if (oldirqs != plyirqs) {
+ bottom_printf ("New playing IRQs detected\n");
+ oldirqs = plyirqs;
+ }
+ while (newplayed >= 8) {
bottom_codec_play (0, CODEC_L8, sinewave, 8, 8);
- bottom_critical_region_begin ();
- tobeplayed -= 8;
+ newplayed -= 8;
bottom_critical_region_end ();
}
+#if 0
+ if (oldplayed != newplayed) {
+ bottom_printf ("available_play := %d\n", (intptr_t) available_play);
+ bottom_printf ("Playbuffer reduced from %d to %d\n", (intptr_t) oldplayed, (intptr_t) newplayed);
+ }
+#endif
+
+#ifdef CONFIG_FUNCTION_NETCONSOLE
+ trysend ();
+bottom_led_set (LED_IDX_BACKLIGHT, 1);
+ netinputlen = sizeof (netinput);
+ if (bottom_network_recv (netinput, &netinputlen)) {
+ nethandler_llconly (netinput, netinputlen);
+ { uint32_t ctr = 10000; while (ctr--) ; }
+bottom_led_set (LED_IDX_BACKLIGHT, 0);
+ }
+ trysend ();
+#endif
+
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+ bottom_keyboard_scan ();
+#endif
+
+#if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
+ bottom_hook_scan ();
+#endif
+
}
}
/* 1 second at 8000 samples per second, plus 25% extra */
uint8_t samples [10000];
-#ifdef CONFIG_FUNCTION_NETCONSOLE
-uint8_t netinput [1000];
-uint16_t netinputlen;
-#endif
-
void top_main_delay_1sec (void) {
uint16_t prevsampled = 0;
uint16_t prevrecirqs = 0;
uint16_t prevplyirqs = 0;
+uint16_t oldspcr1 = 0xffff;
uint16_t loop = 0;
- void nethandler_llconly (uint8_t *pkt, uint16_t pktlen);
bottom_critical_region_end ();
top_hook_update (bottom_phone_is_offhook ());
- bottom_codec_play_samplerate (0, 8000);
- bottom_codec_record_samplerate (0, 8000);
- bottom_soundchannel_setvolume (0, 127);
+ bottom_codec_play_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
+ bottom_codec_record_samplerate (PHONE_CHANNEL_TELEPHONY, 8000);
+ bottom_soundchannel_setvolume (PHONE_CHANNEL_TELEPHONY, 127);
bottom_show_fixed_msg (APP_LEVEL_ZERO, FIXMSG_READY); // TODO: Not really necessary
bottom_printf ("Running the development function \"echo\" (Test sound)\n");
while (true) {
-#ifndef TODO_DONT_PRINT_I2C_REGISTERS_AFTER_SETTING_THEM
+#if 0
if (loop++ == 0) {
uint8_t reg, subreg;
-uint8_t chan = 0;
+uint8_t chan = PHONE_CHANNEL_TELEPHONY;
for (reg = 1; reg <= 6; reg++) {
uint8_t val0, val1, val2, val3;
for (subreg = 0; subreg <=3 ; subreg++) {
prevplyirqs = plyirqs;
}
#endif
+{uint16_t xor = oldspcr1 ^ SPCR1_1; if (xor) { oldspcr1 ^= xor; bottom_printf ("SPCR1_1 := 0x%04x\n", oldspcr1); } }
if (sampled != prevsampled) {
bottom_printf ("Buffered %d samples\n", (intptr_t) sampled);
prevsampled = sampled;
}
trysend ();
#endif
+#if defined NEED_KBD_SCANNER_BETWEEN_KEYS || defined NEED_KBD_SCANNER_DURING_KEYPRESS
+ bottom_keyboard_scan ();
+#endif
+#if defined NEED_HOOK_SCANNER_WHEN_ONHOOK || defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
+ bottom_hook_scan ();
+#endif
}
}