My end goal for this project is to sample audio from an amplified electret microphone, and store it in SRAM (short sample, I know) using DMA.
Currently, the output of my microphone circuit looks perfect through an oscilloscope. I'm running my MSP432 at 48 MHz; so I should be able to sample at 44.1 kHz without a problem, though I will probably sample slower just to save RAM.
My ideal scenario is as follows:
- Automatically trigger ADC conversions at a rate of 44.1 kHz using Timer_A0.
- When each conversion is completed, automatically transfer sample to memory.
The problem I am running into is that I can't get the ADC to trigger automatically using a timer. I can't find any example code that doesn't use the DriverLib API.
So FOR NOW, I am trying to manually trigger a conversion at 44.1 kHz using a timer interrupt. I configured Timer_A0 in UP mode, with a CCR0 value that triggers a timer overflow interrupt at a rate of 44.1 kHz. So my timer is working perfectly, but when I start a conversion inside my timer interrupt function (and manually store the data inside a conversion complete interrupt), I get wonky ADC results when I look at the data after pausing the program.
Here is my code as of now:
#include "msp.h"
#define A0 BIT5
#define num_samples 100
#define startConversion() ADC14->CTL0 |= ADC14_CTL0_ENC | ADC14_CTL0_SC
#define startSampling() TIMER_A0->CCR[0] = 271 // Corresponds to 44.1 kHz sampling rate
#define stopSampling() TIMER_A0->CCR[0] = 0;
void VCORE1();
void FLASH_init();
void CLK_init();
void ADC_init();
void TIMER_init();
volatile uint16_t audio[num_samples];
volatile uint16_t i = 0;
void main(void)
{
WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD; // stop watchdog timer
//P2->DIR |= BIT7;
//Enable MCLK clock output on P4.3
//P4->DIR |= BIT3;
//P4->SEL0 |= BIT3;
VCORE1(); //Go to VCORE1 mode before setting clock to 48 MHz
FLASH_init();
CLK_init(); //Set clock to 48 MHz
ADC_init(); //Initializes ADC, waiting for Timer to start conversions
TIMER_init();
NVIC_EnableIRQ(ADC14_IRQn);
NVIC_EnableIRQ(TA0_0_IRQn);
__enable_irq();
startSampling();
while(1);
}
void ADC14_IRQHandler(void)
{
audio[i] = ADC14->MEM[0]; //Save sample, clears flag
}
void TA0_0_IRQHandler(void)
{
TIMER_A0->CCTL[0] &= ~TIMER_A_CCTLN_CCIFG; //Clear timer flag
//P2->OUT |= BIT7; //For testing timer
startConversion();
}
void VCORE1()
{
while(PCM->CTL1 & PCM_CTL1_PMR_BUSY);
PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR__AM_LDO_VCORE1;
while(PCM->CTL1 & PCM_CTL1_PMR_BUSY);
}
void FLASH_init()
{
//Configure Flash wait-state to 1 for both banks 0 & 1
FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) |
FLCTL_BANK0_RDCTL_WAIT_1;
FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) |
FLCTL_BANK1_RDCTL_WAIT_1;
}
void CLK_init()
{
//Set clock to 48 MHz
CS->KEY = CS_KEY_VAL; //Unlock CS registers
CS->CTL0 = CS_CTL0_DCOEN |
CS_CTL0_DCORSEL_5; //Choose 24MHz MHz clock speed
CS->CTL1 = CS_CTL1_SELS_3 |
CS_CTL1_SELM_3; //Use DCOCLK as source for MCLK, SMCLK + HSMCLK
CS->KEY = 0; //Re-lock CS registers
}
void ADC_init()
{
P5->DIR &= ~(A0); //Set ADC pin as input
P5->SEL0 |= A0; //Choose ADC as port function
P5->SEL1 |= A0;
ADC14->CTL0 = //ADC14_CTL0_SHS_1 | //Use TA0 to start conversion
ADC14_CTL0_SHP | //??
ADC14_CTL0_ON; //Turn ADC module on
ADC14->CTL1 = ADC14_CTL1_RES__14BIT; //Set 14-bit resolution
ADC14->IER0 = ADC14_IER0_IE0; //Enable interrupt when conversion on A0 is complete
}
void TIMER_init()
{
TIMER_A0->CCTL[0] = TIMER_A_CCTLN_CCIE; //Enable CC interrupt
TIMER_A0->CTL = TIMER_A_CTL_TASSEL_2 | //Select SMCLK as source for timer
TIMER_A_CTL_ID_2 | //Divide clock by 4 (this yields 6 MHz for the timer clock)
TIMER_A_CTL_MC_1 | //Up mode
TIMER_A_CTL_CLR ; //Clear timer count
}

