Part Number:MSP432P401R
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 }