Serial communication with the codec revived (by flushing RFULL and XEMPTY)
authorRick van Rein <vanrein@hwdev.(none)>
Tue, 11 Oct 2011 09:47:54 +0000 (09:47 +0000)
committerRick van Rein <vanrein@hwdev.(none)>
Tue, 11 Oct 2011 09:47:54 +0000 (09:47 +0000)
bin/i2cp/README
doc/bottom/SKELETON.rst [new file with mode: 0644]
doc/porting.rst
include/0cpm/snd.h
include/bottom/grandstream.h
include/bottom/tic55x.h
src/driver/tic55x/grandstream-bt20x.c
src/driver/tlv320aic2x.c
src/function/develtest/echo.c

index 524716b..229be3d 100644 (file)
@@ -39,8 +39,8 @@ To send built firmware to the EEPROM for the next boot::
 
 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
diff --git a/doc/bottom/SKELETON.rst b/doc/bottom/SKELETON.rst
new file mode 100644 (file)
index 0000000..1333ed7
--- /dev/null
@@ -0,0 +1 @@
+TODO
index f452e34..762068b 100644 (file)
@@ -122,6 +122,27 @@ the PCB's silk screen for every fifth pin.  Always do this work in
 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.
index e0153b7..a6988b7 100644 (file)
@@ -76,4 +76,37 @@ int16_t bottom_codec_record (uint8_t chan, codec_t codec, uint8_t *coded_samples
 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
index dada9b8..f77511e 100644 (file)
@@ -91,6 +91,9 @@ inline void ksz_memset16 (uint16_t ksz, uint8_t *mem) {
 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
index 29c64b7..64b141e 100644 (file)
@@ -276,6 +276,9 @@ asm ("_MCR2_1 .set 0x2c0d");
 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
index f6c08c4..f01b8c8 100644 (file)
@@ -356,13 +356,32 @@ int16_t codec_encode (codec_t codec, uint16_t *in, uint16_t inlen, uint8_t *out,
 
 /* 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
@@ -373,10 +392,12 @@ interrupt void tic55x_dmac0_isr (void) {
        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);
@@ -391,10 +412,13 @@ interrupt void tic55x_dmac1_isr (void) {
        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;
@@ -410,9 +434,13 @@ void dmahint_record (void) {
        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);
                }
@@ -426,7 +454,9 @@ void dmahint_play (void) {
        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);
 }
@@ -970,6 +1000,7 @@ void main (void) {
        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
@@ -1037,7 +1068,7 @@ void main (void) {
                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 ();
index b0215dd..0d81e6d 100644 (file)
@@ -45,6 +45,7 @@
 #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
@@ -121,10 +122,10 @@ void bottom_soundchannel_device (uint8_t chan, sounddev_t dev) {
                // (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:
@@ -264,19 +265,24 @@ void bottom_codec_play_skip (codec_t codec, uint16_t samples) {
  */
 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 */
        }
 }
+
index 19b1526..1746e28 100644 (file)
@@ -55,9 +55,9 @@ timing_t top_timer_expiration (timing_t timeout) {
 
 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);
        }
 }
 
@@ -78,7 +78,25 @@ void top_network_can_recv (void) {
 }
 
 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) {
@@ -98,8 +116,15 @@ void top_can_record (uint16_t samples) {
 }
 
 
-// #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 ********/
@@ -109,18 +134,54 @@ uint8_t sinewave [8] = {
 };
 
 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
+
        }
 }
 
@@ -136,29 +197,24 @@ uint16_t sampled = 0;
 /* 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++) {
@@ -183,6 +239,7 @@ bottom_printf ("TLV_%d = %02x, %02x, %02x, %02x\n", (intptr_t) reg, (intptr_t) v
                        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;
@@ -242,6 +299,12 @@ 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
        }
 }