Lecture 26: Timer_A recap 10:10 First half of the lecture - refer to slides 10:40 Second half of the lecture - discuss msp432-recorder-demo-2 Architecture of the program: - An ISR runs at 8KHz - The ISR has two different modes: Recording: storing samples from ADC in memory Playback: retrieving samples from ADC in memory - Playback is based on PWM modulation of 64KHz carrier - Timer A0 is used for PWM generation - Timer A1 is used for ISR rate generation The program illustrates several interesting features - Calibration of samples coming from the ADC - Configuration record for upmode config - Configuration record for PWM config - ISR tied to Timer_A upmode counter - PWM generation with varying duty cycle 10:43 Calibration of ADC samples char scaleSample(unsigned vx) { // microphone sample is 0x1000 to 0x2FFF midpoint 0x1FFF // output is 0x00 to 0xFF midpoint 0x80 // set gain to 4 int c = (vx - 0x1FFF) * 0x100 * 4 / 0x2000 + 0x80; return (char) c; } The program requires 8-bit samples, since we don't want to store the lower LSBs (to save memory). This means we have to scale samples. ADC CHAR 0x2fff -------- 0xFF || || || || 0x1fff -------- 0x80 || || || || 0x1000 -------- 0x00 This leads to the following formula: (vx - 0x1FFF) * 0x100 / 0x2000 + 0x80 10:46 PWM configuration of a 64 KHz Carrier #define CARRIER ((int) (SYSTEMCLOCK / 64000)) Timer_A_PWMConfig pwmConfig = { TIMER_A_CLOCKSOURCE_SMCLK, TIMER_A_CLOCKSOURCE_DIVIDER_1, // 3 MHz CARRIER, // 64 Khz Carrier TIMER_A_CAPTURECOMPARE_REGISTER_4, TIMER_A_OUTPUTMODE_RESET_SET, CARRIER / 2 }; Note the macro CARRIER. If you know the system clock, and the divider is 1, then you can generate a period value for a give frequency f by computing (int) (SYSTEMCLOCK / f) 10:48 Upmode counting with interrupt #define SAMPLERATE ((int) (SYSTEMCLOCK / 8000)) Timer_A_UpModeConfig upConfig = { TIMER_A_CLOCKSOURCE_SMCLK, TIMER_A_CLOCKSOURCE_DIVIDER_1, // 3 MHz SAMPLERATE, TIMER_A_TAIE_INTERRUPT_DISABLE, TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE, TIMER_A_SKIP_CLEAR }; In this case, we enable interrupts on the upmode config counter. The interrupts will be vectored into: void TA1_0_IRQHandler() { ... Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0); } 10:50 Initialization Note the initialization routines: Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig); Interrupt_enableInterrupt(INT_TA1_0); Interrupt_enableMaster(); Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE); You first have to set Timer_A in upmode, then enable interrupts from source INT_TA1_0 (which includes CCR0 interrupts from TA1), and finally start the Timer_A A1 counter.