Files
TweinStein/inc/ADCTimer.c
2026-06-12 02:55:04 -07:00

215 lines
8.2 KiB
C

/* ADCTimer.c
* Jonathan Valvano
* December 8, 2025
* Derived from adc12_single_conversion_vref_internal_LP_MSPM0G3507_nortos_ticlang
* adc12_single_conversion_LP_MSPM0G3507_nortos_ticlang
* adc12_triggered_by_timer_event_LP_MSPM0G3507_nortos_ticlang
*/
// ****note to students****
// the data sheet says the ADC does not work when clock is 80 MHz
// however, the ADC seems to work on my boards at 80 MHz
// I suggest you try 80MHz, but if it doesn't work, switch to 40MHz
#include <ti/devices/msp/msp.h>
#include "../inc/ADCTimer.h"
#include "../inc/Clock.h"
// Assumes 80 MHz bus
// power Domain PD0
// for 80MHz bus clock, Timer G0 clock is ULPCLK 40MHz
// frequency = TimerClock/prescale/period
// e.g., period=5000,prescale=8 is 40MHz/5000/8 = 1kHz
void ADC0_TimerG0_Init(uint32_t channel, uint32_t reference,uint16_t period, uint32_t prescale, uint32_t priority){
// Reset ADC Timer G0 and VREF
// RSTCLR
// bits 31-24 unlock key 0xB1
// bit 1 is Clear reset sticky bit
// bit 0 is reset ADC
ADC0->ULLMEM.GPRCM.RSTCTL = 0xB1000003;
if(reference == ADCVREF_INT){
VREF->GPRCM.RSTCTL = 0xB1000003;
}
TIMG0->GPRCM.RSTCTL = 0xB1000003;
// Enable power ADC G0 and VREF
// PWREN
// bits 31-24 unlock key 0x26
// bit 0 is Enable Power
ADC0->ULLMEM.GPRCM.PWREN = 0x26000001;
if(reference == ADCVREF_INT){
VREF->GPRCM.PWREN = 0x26000001;
}
TIMG0->GPRCM.PWREN = 0x26000001;
Clock_Delay(24); // time for ADC Vref G0 to power up
TIMG0->CLKSEL = 0x08; // bus clock
TIMG0->CLKDIV = 0x00; // divide by 1
TIMG0->COMMONREGS.CPS = prescale-1; // divide by prescale,
TIMG0->COUNTERREGS.LOAD = period-1; // set reload register
TIMG0->FPUB_0 = 1; // publish on channel 1
// bits 29-28 CVAE 00 (set to LOAD value)
TIMG0->COUNTERREGS.CTRCTL = 0x02;
// bits 5-4 CM =0, down
// bits 3-1 REPEAT =001, continue
// bit 0 EN enable (0 for disable, 1 for enable)
TIMG0->GEN_EVENT0.IMASK = 1; // hardware event published on Chan1
TIMG0->COMMONREGS.CCLKCTL = 1;
ADC0->ULLMEM.GPRCM.CLKCFG = 0xA9000000; // ULPCLK
// bits 31-24 key=0xA9
// bit 5 CCONSTOP= 0 not continuous clock in stop mode
// bit 4 CCORUN= 0 not continuous clock in run mode
// bit 1-0 0=ULPCLK,1=SYSOSC,2=HFCLK
ADC0->ULLMEM.CLKFREQ = 7; // 40 to 48 MHz
ADC0->ULLMEM.CTL0 = 0x03010000;
// bits 26-24 = 011 divide by 8
// bit 16 PWRDN=1 for manual, =0 power down on completion, if no pending trigger
// bit 0 ENC=1 enable (1 to 0 will end conversion)
ADC0->ULLMEM.CTL1 = 0x00000001;
// bits 30-28 =0 no shift
// bits 26-24 =0 no averaging
// bit 20 SAMPMODE=0 timer triggers
// bits 17-16 CONSEQ=01 ADC at start will be sampled once, 10 for repeated sampling
// bit 8 SC=0 for stop, =1 to software start
// bit 0 TRIGSRC=1 timer trigger
ADC0->ULLMEM.CTL2 = 0x00000000;
// bits 28-24 ENDADD (which MEMCTL to end)
// bits 20-16 STARTADD (which MEMCTL to start)
// bits 15-11 SAMPCNT (for DMA)
// bit 10 FIFOEN=0 disable FIFO
// bit 8 DMAEN=0 disable DMA
// bits 2-1 RES=0 for 12 bit (=1 for 10bit,=2for 8-bit)
// bit 0 DF=0 unsigned formant (1 for signed, left aligned)
ADC0->ULLMEM.MEMCTL[0] = reference+channel;
// bit 28 WINCOMP=0 disable window comparator
// bit 24 TRIG trigger policy, =0 for auto next, =1 for next requires trigger
// bit 20 BCSEN=0 disable burn out current
// bit 16 = AVGEN =0 for no averaging
// bit 12 = STIME=0 for SCOMP0
// bits 9-8 VRSEL = 10 for internal VREF,(00 for VDDA)
// bits 4-0 channel = 0 to 7 available
ADC0->ULLMEM.SCOMP0 = 0x64; // sample clocks
ADC0->ULLMEM.SCOMP1 = 0x32; // sample clocks
if(reference == ADCVREF_INT){
VREF->CLKSEL = 0x00000008; // bus clock
VREF->CLKDIV = 0; // divide by 1
VREF->CTL0 = 0x0001;
// bit 8 SHMODE = off
// bit 7 BUFCONFIG=0 for 2.4 (=1 for 1.4)
// bit 0 is enable
VREF->CTL2 = 0;
// bits 31-16 HCYCLE=0
// bits 15-0 SHCYCLE=0
while((VREF->CTL1&0x01)==0){}; // wait for VREF to be ready
}
ADC0->ULLMEM.FSUB_0 = 0x00000001; // subscribe to chan 1
ADC0->ULLMEM.CPU_INT.IMASK = 0x00000100; //MEMRESIFG0
ADC0->ULLMEM.CTL0 |= 1; // start
NVIC->ISER[0] = 1 << 4; // ADC0 interrupt
NVIC->IP[1] = (NVIC->IP[1]&(~0x000000FF))|(priority<<6); // set priority (bits 7,6) IRQ 4
TIMG0->COUNTERREGS.CTRCTL |= 0x01;
}
// Assumes 80 MHz bus
// power Domain PD0
// for 80MHz bus clock, Timer G8 clock is ULPCLK 40MHz
// frequency = TimerClock/prescale/period
// e.g., period=5000,prescale=8 is 40MHz/5000/8 = 1kHz
void ADC1_TimerG8_Init(uint32_t channel, uint32_t reference,uint16_t period, uint32_t prescale, uint32_t priority){
// Reset ADC Timer G8 and VREF
// RSTCLR
// bits 31-24 unlock key 0xB1
// bit 1 is Clear reset sticky bit
// bit 0 is reset ADC
ADC1->ULLMEM.GPRCM.RSTCTL = 0xB1000003;
if(reference == ADCVREF_INT){
VREF->GPRCM.RSTCTL = 0xB1000003;
}
TIMG8->GPRCM.RSTCTL = 0xB1000003;
// Enable power ADC G0 and VREF
// PWREN
// bits 31-24 unlock key 0x26
// bit 0 is Enable Power
ADC1->ULLMEM.GPRCM.PWREN = 0x26000001;
if(reference == ADCVREF_INT){
VREF->GPRCM.PWREN = 0x26000001;
}
TIMG8->GPRCM.PWREN = 0x26000001;
Clock_Delay(24); // time for ADC Vref G8 to power up
TIMG8->CLKSEL = 0x08; // bus clock
TIMG8->CLKDIV = 0x00; // divide by 1
TIMG8->COMMONREGS.CPS = prescale-1; // divide by prescale,
TIMG8->COUNTERREGS.LOAD = period-1; // set reload register
TIMG8->FPUB_0 = 1; // publish on channel 1
// bits 29-28 CVAE 00 (set to LOAD value)
TIMG8->COUNTERREGS.CTRCTL = 0x02;
// bits 5-4 CM =0, down
// bits 3-1 REPEAT =001, continue
// bit 0 EN enable (0 for disable, 1 for enable)
TIMG8->GEN_EVENT0.IMASK = 1; // hardware event published on Chan1
TIMG8->COMMONREGS.CCLKCTL = 1;
ADC1->ULLMEM.GPRCM.CLKCFG = 0xA9000000; // ULPCLK
// bits 31-24 key=0xA9
// bit 5 CCONSTOP= 0 not continuous clock in stop mode
// bit 4 CCORUN= 0 not continuous clock in run mode
// bit 1-0 0=ULPCLK,1=SYSOSC,2=HFCLK
ADC1->ULLMEM.CLKFREQ = 7; // 40 to 48 MHz
ADC1->ULLMEM.CTL0 = 0x03010000;
// bits 26-24 = 011 divide by 8
// bit 16 PWRDN=1 for manual, =0 power down on completion, if no pending trigger
// bit 0 ENC=1 enable (1 to 0 will end conversion)
ADC1->ULLMEM.CTL1 = 0x00000001;
// bits 30-28 =0 no shift
// bits 26-24 =0 no averaging
// bit 20 SAMPMODE=0 timer triggers
// bits 17-16 CONSEQ=01 ADC at start will be sampled once, 10 for repeated sampling
// bit 8 SC=0 for stop, =1 to software start
// bit 0 TRIGSRC=1 timer trigger
ADC1->ULLMEM.CTL2 = 0x00000000;
// bits 28-24 ENDADD (which MEMCTL to end)
// bits 20-16 STARTADD (which MEMCTL to start)
// bits 15-11 SAMPCNT (for DMA)
// bit 10 FIFOEN=0 disable FIFO
// bit 8 DMAEN=0 disable DMA
// bits 2-1 RES=0 for 12 bit (=1 for 10bit,=2for 8-bit)
// bit 0 DF=0 unsigned formant (1 for signed, left aligned)
ADC1->ULLMEM.MEMCTL[0] = reference+channel;
// bit 28 WINCOMP=0 disable window comparator
// bit 24 TRIG trigger policy, =0 for auto next, =1 for next requires trigger
// bit 20 BCSEN=0 disable burn out current
// bit 16 = AVGEN =0 for no averaging
// bit 12 = STIME=0 for SCOMP0
// bits 9-8 VRSEL = 10 for internal VREF,(00 for VDDA)
// bits 4-0 channel = 0 to 7 available
ADC1->ULLMEM.SCOMP0 = 0x64; // sample clocks
ADC1->ULLMEM.SCOMP1 = 0x32; // sample clocks
if(reference == ADCVREF_INT){
VREF->CLKSEL = 0x00000008; // bus clock
VREF->CLKDIV = 0; // divide by 1
VREF->CTL0 = 0x0001;
// bit 8 SHMODE = off
// bit 7 BUFCONFIG=0 for 2.4 (=1 for 1.4)
// bit 0 is enable
VREF->CTL2 = 0;
// bits 31-16 HCYCLE=0
// bits 15-0 SHCYCLE=0
while((VREF->CTL1&0x01)==0){}; // wait for VREF to be ready
}
ADC1->ULLMEM.FSUB_0 = 0x00000001; // subscribe to chan 1
ADC1->ULLMEM.CPU_INT.IMASK = 0x00000100; //MEMRESIFG0
ADC1->ULLMEM.CTL0 |= 1; // start
NVIC->ISER[0] = 1 << 5; // ADC1 interrupt
NVIC->IP[1] = (NVIC->IP[1]&(~0x0000FF00))|(priority<<14); // set priority (bits 15,14) IRQ 5
TIMG8->COUNTERREGS.CTRCTL |= 0x01;
}