?? exercise-8.c
字號:
/* Exercise 8
The simple voice recorder from exercise 6, modified to use a low-complexity ADPCM codec to
quadruple the storage time.
*/
#include <stdint.h>
#include <msp430xG43x.h>
#define AUDIO_MEM_START 0x2000
#define AUDIO_MEM_END 0xFE00
typedef struct
{
int16_t last;
int16_t step_index;
} adpcm_state_t;
/* ADPCM working data */
adpcm_state_t state;
uint16_t adpcm_val = 0;
int16_t adpcm_nibble = 0;
/* Routines to convert 12 bit linear samples to the ADPCM coding format
originated by Oki, and widely used in CTI. */
static const int16_t step_size[49] =
{
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1408,
1552
};
static const int16_t step_adjustment[8] =
{
-1, -1, -1, -1, 2, 4, 6, 8
};
/* Decode the lower 4 bits of "adpcm" */
int16_t adpcm_decode(uint8_t adpcm)
{
int16_t e;
int16_t ss;
int16_t linear;
ss = step_size[state.step_index];
e = ss >> 3;
if (adpcm & 0x01)
e += (ss >> 2);
/*endif*/
if (adpcm & 0x02)
e += (ss >> 1);
/*endif*/
if (adpcm & 0x04)
e += ss;
/*endif*/
if (adpcm & 0x08)
e = -e;
/*endif*/
linear = state.last + e;
/* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
if (linear > 2047)
linear = 2047;
else if (linear < -2048)
linear = -2048;
/*endif*/
state.last = linear;
state.step_index += step_adjustment[adpcm & 0x07];
if (state.step_index < 0)
state.step_index = 0;
else if (state.step_index > 48)
state.step_index = 48;
/*endif*/
/* Note: the result here is a 12 bit value */
return linear;
}
/* Encode to a 4 bit ADPCM value */
uint8_t adpcm_encode(int16_t linear)
{
int16_t e;
int16_t ss;
uint8_t adpcm;
/* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
if (linear > 2047)
linear = 2047;
else if (linear < -2048)
linear = -2048;
/*endif*/
ss = step_size[state.step_index];
e = linear - state.last;
adpcm = (uint8_t) 0x00;
if (e < 0)
{
adpcm = (uint8_t) 0x08;
e = -e;
}
/*endif*/
if (e >= ss)
{
adpcm |= (uint8_t) 0x04;
e -= ss;
}
/*endif*/
if (e >= (ss >> 1))
{
adpcm |= (uint8_t) 0x02;
e -= ss;
}
/*endif*/
if (e >= (ss >> 2))
adpcm |= (uint8_t) 0x01;
/*endif*/
/* Use the decoder to set the estimate of the last sample. */
/* It also will adjust the step_index for us. */
state.last = adpcm_decode(adpcm);
return adpcm;
}
/* Initialise the ADPCM state */
void adpcm_init(void)
{
state.last = 0;
state.step_index = 0;
}
int16_t *ptr;
void record(void)
{
long int i;
/* Set up timer A to kick the ADC at 6.5536kHz, which will be our audio
* sampling rate. */
TAR = 0;
TACCR0 = 5 - 1;
TACCR1 = 5 - 2;
TACCTL0 = 0;
TACCTL1 = OUTMOD_3;
TACTL = TACLR | MC_1 | TASSEL_1;
/* Make the earpiece pins outputs driven to 0, to power the mic */
P6SEL &= ~(BIT5 | BIT3);
P6DIR |= (BIT5 | BIT3);
P6OUT &= ~(BIT5 | BIT3);
/* Set up the mic amp */
/* Input 0 is the mic signal.
* Output goes to the feedback resistor.
* We want a general purpose amp.
* We want DAC1 to bias the +ve input of the amp.
* We want the amp in high performance mode. */
P6SEL |= (BIT1 | BIT0);
OA0CTL0 = OAN_0 | OAP_3 | OAPM_3 | OAADC1;
OA0CTL1 = OAFC_0;
/* Second amplifier stage */
OA1CTL0 = OAN_2 | OAP_3 | OAPM_3 | OAADC0; // -ve=OA1I0, +ve=DAC1
OA1CTL1 = OAFC_6 | OAFBR_4;
/* Must disable conversion while reprogramming the ADC */
ADC12CTL0 &= ~ENC;
ADC12CTL0 = ADC12ON | SHT0_4 | REFON | REF2_5V; // Turn on the ADC12, and set the sampling time
ADC12CTL1 = SHP | SHS_1 | CONSEQ_2; // Use sampling timer, single sample repeating, TA1 trigger
ADC12MCTL0 = INCH_13 | SREF_1; // ref += Vref, channel = A13 = OA1
ADC12IE = BIT0;
ADC12IFG = 0x00;
/* Configure DAC 1 to provide bias for the mic amplifier */
P6SEL |= BIT7;
DAC12_1CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
DAC12_1DAT = 0x800;
for (ptr = (int16_t *) AUDIO_MEM_START; ptr != (int16_t *) AUDIO_MEM_END; ptr += 0x100)
{
FCTL3 = FWKEY; /* Lock = 0 */
FCTL1 = FWKEY | ERASE;
*ptr = 0; /* Erase flash segment */
FCTL1 = FWKEY; /* Erase, write = 0 */
FCTL3 = FWKEY | LOCK;
}
adpcm_init();
adpcm_val = 0;
adpcm_nibble = 0;
/* Wait for the mic amp to settle */
for (i = 150000; i > 0; i--)
_NOP();
/* Set the recording off, and wait in LPM0 for it to complete */
_EINT();
P1OUT |= BIT0; /* Turn on the LED */
ADC12CTL0 |= ENC;
ptr = (int16_t *) AUDIO_MEM_START;
for (;;)
{
_BIS_SR(LPM0_bits);
_NOP();
if (ptr >= (int16_t *) AUDIO_MEM_END)
break;
}
ADC12CTL0 &= ~ENC;
P1OUT &= ~BIT0; /* Turn off the LED */
_DINT();
}
void play(void)
{
/* Ensure the ADC12 is not running, but is providing the reference
voltage for the DAC12. */
ADC12CTL0 &= ~ENC;
ADC12CTL0 = ADC12ON | REFON | REF2_5V;
ADC12IE = 0;
ADC12CTL0 |= ENC;
/* Set up timer A to kick the DAC at 6.5536kHz, which will be our audio
* sampling rate. */
TAR = 0;
TACCR0 = 5 - 1;
TACCR1 = 5 - 2;
TACCTL0 = CCIE;
TACCTL1 = OUTMOD_3;
TACTL = TACLR | MC_1 | TASSEL_1;
/* Make a differential drive for the earpiece */
P6SEL |= (BIT5 | BIT3);
/* Chain two amps to make an inverting buffer with a gain of one */
OA0CTL0 = OAP_2 | OAPM_3;
OA0CTL1 = OAFC_1;
OA1CTL0 = OAN_2 | OAP_3 | OAPM_3 | OAADC1;
OA1CTL1 = OAFC_6 | OAFBR_2;
/* Use the third amp as a non-inverting buffer with a gain of one */
OA2CTL0 = OAP_2 | OAPM_3 | OAADC1;
OA2CTL1 = OAFC_1;
/* Configure DAC0 to provide the audio signal for the earpiece amp.
The data will be latched by TACCR1 */
DAC12_0CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC | DAC12LSEL_2;
DAC12_0DAT = 0x800;
/* Configure DAC1 to provide a bias signal for the inverting PGA */
DAC12_1CTL = DAC12CALON | DAC12IR | DAC12AMP_7 | DAC12ENC;
DAC12_1DAT = 0x800;
adpcm_init();
adpcm_val = 0;
adpcm_nibble = 0;
_EINT();
ptr = (int16_t *) AUDIO_MEM_START;
for (;;)
{
_BIS_SR(LPM0_bits);
_NOP();
//if (ptr >= (int16_t *) AUDIO_MEM_END)
// break;
}
_DINT();
}
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
SCFI0 = FN_3 | FLLD_4;
FLL_CTL0 = XCAP18PF; // set load capacitance for xtal
SCFQCTL = 64 - 1; // 256*32768Hz = 8.388608MHz
FLL_CTL0 |= DCOPLUS;
P1DIR = 0xE7; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0x00; // All P2.x outputs
P2OUT = 0; // All P2.x reset
P3DIR = 0xFF; // All P3.x outputs
P3OUT = 0; // All P3.x reset
P4DIR = 0xFF; // All P4.x outputs
P4OUT = 0; // All P4.x reset
P5DIR = 0xFF; // All P5.x outputs
P5OUT = 0; // All P5.x reset
P6DIR = 0xFF; // All P6.x outputs
P6OUT = 0; // All P6.x reset
/* Configure UART0 */
UCTL0 = CHAR; /* 8-bit character */
UTCTL0 = SSEL1; /* UCLK = SMCLK */
UBR00 = 72; /* 115200 bps, based on the 256*32768Hz clock */
UBR10 = 0;
UMCTL0 = 0x7F;
P2SEL |= (BIT5 | BIT4);
U0ME |= UTXE0; /* Enable only USART0 TXD */
record();
for (;;)
play();
_NOP();
}
#pragma vector=ADC_VECTOR
__interrupt void adc_interrupt(void)
{
int16_t val;
val = ADC12MEM0;
if (ptr < (int16_t *) AUDIO_MEM_END)
{
adpcm_val <<= 4;
adpcm_val |= adpcm_encode(val - 0x800);
if (++adpcm_nibble == 4)
{
FCTL3 = FWKEY; /* Lock = 0 */
FCTL1 = FWKEY | WRT;
*ptr++ = adpcm_val; /* Write to the flash */
FCTL1 = FWKEY; /* Erase, write = 0 */
FCTL3 = FWKEY | LOCK;
adpcm_nibble = 0;
}
val >>= 4;
TXBUF0 = val;
}
else
{
_BIC_SR_IRQ(LPM3_bits);
}
}
#pragma vector=TIMERA0_VECTOR
__interrupt void timera_interrupt(void)
{
int16_t val;
if (ptr >= (int16_t *) AUDIO_MEM_END)
{
adpcm_init();
ptr = (int16_t *) AUDIO_MEM_START;
}
if (ptr < (int16_t *) AUDIO_MEM_END)
{
if (++adpcm_nibble == 4)
{
adpcm_val = *ptr++;
adpcm_nibble = 0;
}
val = adpcm_decode((adpcm_val >> 12) & 0xF);
adpcm_val <<= 4;
val += 0x800;
DAC12_0DAT = val;
val >>= 4;
TXBUF0 = val;
}
else
{
_BIC_SR_IRQ(LPM3_bits);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -