I am using timer in up-down mode to generate a PWM with dead time. I would like to control the timer period and also the pulse width with a pot which is read by the ADC. So far I got the PWM working, and the ADC is reading the POT (I also have a little TIMER1_A0 ISR to blink a LED to assure me the system is still running). I have not yet been able to link the ADC with the timer CCR register. I would appreciate any suggestions. I am trying to exclusively use the driverlib utilities for the purpose of code maintainability. Here is the code, which is split up into three files. The first one is main.c:
#include "driverlib.h"
#include "shaker.h"
#define COMPARE_VALUE 50000
volatile uint16_t frequency_input;
volatile uint16_t acceleration_input;
void setup_continual_ADC(void);
void main(void)
{
uint16_t toggle_set = 20000;
uint16_t toggle_reset = 4000;
uint16_t timer_period = 24000;
//Stop WDT
WDT_A_hold(WDT_A_BASE);
//Set P1.0 to output direction
GPIO_setAsOutputPin(GPIO_PORT_P1,GPIO_PIN0);
//P1.2 and P1.3 output
//P1.2 and P1.3 options select
GPIO_setAsPeripheralModuleFunctionOutputPin(
GPIO_PORT_P1,GPIO_PIN2 + GPIO_PIN3); //TA0.1, TA0.2
//Start Timer A0
Timer_A_initUpDownModeParam initUpDownParam = {0};
initUpDownParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
initUpDownParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
initUpDownParam.timerPeriod = timer_period;
initUpDownParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
initUpDownParam.captureCompareInterruptEnable_CCR0_CCIE =
TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
initUpDownParam.timerClear = TIMER_A_DO_CLEAR;
initUpDownParam.startTimer = false;
Timer_A_initUpDownMode(TIMER_A0_BASE, &initUpDownParam);
Timer_A_startCounter(TIMER_A0_BASE,TIMER_A_UPDOWN_MODE);
//Initialze compare registers of timer A0 to generate PWM1
Timer_A_initCompareModeParam initComp1Param = {0};
initComp1Param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
initComp1Param.compareInterruptEnable =
TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
initComp1Param.compareOutputMode = TIMER_A_OUTPUTMODE_TOGGLE_SET;
initComp1Param.compareValue = toggle_set;
Timer_A_initCompareMode(TIMER_A0_BASE, &initComp1Param);
//Initialze compare registers of timer A0 to generate PWM2
Timer_A_initCompareModeParam initComp2Param = {0};
initComp2Param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;
initComp2Param.compareInterruptEnable =
TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
initComp2Param.compareOutputMode = TIMER_A_OUTPUTMODE_TOGGLE_RESET;
initComp2Param.compareValue = toggle_reset;
Timer_A_initCompareMode(TIMER_A0_BASE, &initComp2Param);
//Start timerA1 in continuous mode sourced by SMCLK
Timer_A_initContinuousModeParam initContParam = {0};
initContParam.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
initContParam.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
initContParam.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
initContParam.timerClear = TIMER_A_DO_CLEAR;
initContParam.startTimer = false;
Timer_A_initContinuousMode(TIMER_A1_BASE, &initContParam);
//Initiaze compare mode
Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_0);
Timer_A_initCompareModeParam initCompParam = {0};
initCompParam.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_0;
initCompParam.compareInterruptEnable =
TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
initCompParam.compareOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
initCompParam.compareValue = COMPARE_VALUE;
Timer_A_initCompareMode(TIMER_A1_BASE, &initCompParam);
Timer_A_startCounter(TIMER_A1_BASE,TIMER_A_CONTINUOUS_MODE);
ADC12_A_disableConversions(ADC12_A_BASE, ADC12_A_COMPLETECONVERSION);
setup_continual_ADC();
while(1)
{
ADC12_A_startConversion(ADC12_A_BASE,
ADC12_A_MEMORY_0,
ADC12_A_SEQOFCHANNELS);
timer_period = (frequency_input + 100) * 4;
toggle_set = (timer_period - acceleration_input * 4);
toggle_reset = acceleration_input * 4;
if (toggle_reset > (timer_period/2 - 100)){
toggle_reset = timer_period/2 - 100;
toggle_set = toggle_reset;
}
// __bis_SR_register(LPM4_bits + GIE);
__bis_SR_register(GIE);
//For debugger
__no_operation();
}
}
//******************************************************************************
//
//This is the TIMER1_A0 interrupt vector service routine.
//
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER1_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(TIMER1_A0_VECTOR)))
#endif
void TIMER1_A0_ISR(void)
{
uint16_t compVal = Timer_A_getCaptureCompareCount(TIMER_A1_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_0)
+ COMPARE_VALUE;
//Toggle P1.0
GPIO_toggleOutputOnPin(GPIO_PORT_P1,GPIO_PIN0);
}
The second file is adc12_a_ex7_sequence_otto.c:
/*
* adc12_a_ex7_sequence_otto.c
*
* Created on: Apr 21, 2015
* Author: Otto, based on example 7
*/
#include "driverlib.h"
#include "shaker.h"
//Needs to be global in this example
//Otherwise, the compiler removes it
//because it is not used for anything.
volatile uint16_t frequency_input;
volatile uint16_t acceleration_input;
volatile uint16_t velocity_max_output;
volatile uint16_t velocity_relative_to_CIM;
void setup_continual_ADC(void)
{
//Stop Watchdog Timer
WDT_A_hold(WDT_A_BASE);
//Enable A/D channel inputs
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,
GPIO_PIN0 + GPIO_PIN1 + GPIO_PIN2 +
GPIO_PIN3 + GPIO_PIN4 + GPIO_PIN5 +
GPIO_PIN6 + GPIO_PIN7
);
//Initialize the ADC12_A Module
/*
* Base address of ADC12_A Module
* Use internal ADC12_A bit as sample/hold signal to start conversion
* USE MODOSC 5MHZ Digital Oscillator as clock source
* Use default clock divider of 1
*/
ADC12_A_init(ADC12_A_BASE,
ADC12_A_SAMPLEHOLDSOURCE_SC,
ADC12_A_CLOCKSOURCE_ADC12OSC,
ADC12_A_CLOCKDIVIDER_1);
ADC12_A_enable(ADC12_A_BASE);
/*
* Base address of ADC12_A Module
* For memory buffers 0-7 sample/hold for 16 clock cycles
* For memory buffers 8-15 sample/hold for 4 clock cycles (default)
* Enable Multiple Sampling
*/
ADC12_A_setupSamplingTimer(ADC12_A_BASE,
ADC12_A_CYCLEHOLD_16_CYCLES,
ADC12_A_CYCLEHOLD_4_CYCLES,
ADC12_A_MULTIPLESAMPLESENABLE);
//Configure Memory Buffers
/*
* Base address of the ADC12_A Module
* Configure memory buffer 0
* Map input A0 to memory buffer 0
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 0 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param0 = {0};
param0.memoryBufferControlIndex = ADC12_A_MEMORY_0;
param0.inputSourceSelect = ADC12_A_INPUT_A0;
param0.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param0.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param0.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE,¶m0);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 1
* Map input A1 to memory buffer 1
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 1 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param1 = {0};
param1.memoryBufferControlIndex = ADC12_A_MEMORY_1;
param1.inputSourceSelect = ADC12_A_INPUT_A1;
param1.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param1.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param1.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE,¶m1);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 2
* Map input A2 to memory buffer 2
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 2 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param2 = {0};
param2.memoryBufferControlIndex = ADC12_A_MEMORY_2;
param2.inputSourceSelect = ADC12_A_INPUT_A2;
param2.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param2.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param2.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE,¶m2);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 3
* Map input A3 to memory buffer 3
* Vr+ = AVcc
* Vr- = AVss
* Memory buffer 3 IS the end of a sequence
*/
ADC12_A_configureMemoryParam param3 = {0};
param3.memoryBufferControlIndex = ADC12_A_MEMORY_3;
param3.inputSourceSelect = ADC12_A_INPUT_A3;
param3.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param3.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param3.endOfSequence = ADC12_A_ENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE,¶m3);
//Enable memory buffer 3 interrupt
ADC12_A_clearInterrupt(ADC12_A_BASE,
ADC12IE3);
ADC12_A_enableInterrupt(ADC12_A_BASE,
ADC12IE3);
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC12_VECTOR)))
#endif
void ADC12ISR(void)
{
switch(__even_in_range(ADC12IV,34))
{
case 0: break; //Vector 0: No interrupt
case 2: break; //Vector 2: ADC overflow
case 4: break; //Vector 4: ADC timing overflow
case 6: break; //Vector 6: ADC12IFG0
case 8: break; //Vector 8: ADC12IFG1
case 10: break; //Vector 10: ADC12IFG2
case 12: //Vector 12: ADC12IFG3
//Move results, IFG is cleared
velocity_max_output =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_0);
//Move results, IFG is cleared
velocity_relative_to_CIM =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_1);
//Move results, IFG is cleared
frequency_input =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_2);
//Move results, IFG is cleared
acceleration_input =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_3);
//Exit active CPU, SET BREAKPOINT HERE
// __bic_SR_register_on_exit(LPM4_bits);
case 14: break; //Vector 14: ADC12IFG4
case 16: break; //Vector 16: ADC12IFG5
case 18: break; //Vector 18: ADC12IFG6
case 20: break; //Vector 20: ADC12IFG7
case 22: break; //Vector 22: ADC12IFG8
case 24: break; //Vector 24: ADC12IFG9
case 26: break; //Vector 26: ADC12IFG10
case 28: break; //Vector 28: ADC12IFG11
case 30: break; //Vector 30: ADC12IFG12
case 32: break; //Vector 32: ADC12IFG13
case 34: break; //Vector 34: ADC12IFG14
default: break;
}
}
And finally there is the third file which is shaker.h:
extern volatile uint16_t frequency_input; extern volatile uint16_t acceleration_input; extern uint16_t toggle_set; extern uint16_t toggle_reset; extern uint16_t timer_period;