Hello,
To clarify the timer situation, you will need to utilise a single channel for the TPM module. This is for your short delay, using output compare mode. For the long delay, you would simply count the number of overflows made by the TPM module, by decrementing a counter for each overflow. When the counter reaches zero, the required delay has completed. If the TPM overflow period is made greater than 200 ms, there is a simpler way to generate the short delay than that previously outlined.
I will assume the use of interrupts, rather than polling the TPM flags. You will need to code the following functions -
Read ADC result for each channel
Start long delay
Start short delay
TPM overflow ISR
TPM channel ISR (output compare)
The action required at the completion of each delay period would occur within the respective ISR.
To accommodate your bus frequency of 4.1856 MHz, I might suggest use of prescale factor 16. This will result in the TPM incrementing every 3.82 us, and a TPM overflow period of 3.82 * 65536 us = 250.5 ms. This meets the requirement for the simplified short delay.
For the long delay, the ADC reading will need to be scaled to produce the required initial count setting. For a period of 600 seconds (and an ADC reading of 1023) the initial count value would need to be 600/0.2505 = 2395. This would require a scaling factor for the ADC reading of 2395/1023 = 2.341. However, a floating point calculation is not necessary since the scaling factor can be closely approximated by the integer fraction 7/3. Therefore, integer calculations can be used.
Assuming ADC channel 0 is used for the long delay, the following function would set up the required count value. The addition of 1 to the calculated value will ensure that the count value is non-zero.
long count; /* Global variable */
void long_delay( void)
{
count = getADC(0)*7/3 + 1;
}
The TPM overflow interrupt would need to include the following code -
TPMSC_TOF = 0; /* Clear flag */
if (count) { /* Check for not already zero */
count--;
if (count == 0) {
// Long delay action
}
}
For the short delay, the TPM channel register will need to be set to a value corresponding to the current TPM counter value plus an amount corresponding the required delay. Again the ADC reading will need to be suitably scaled. For a period of 200 ms (and an ADC reading of 1023) increment value would need to be 200000/3.82 = 52356. This would require a scaling factor for the ADC reading of 52356/1023 ~= 51.
Assuming ADC channel 1, and TPM channel 0 is used for the short delay, the following function would set up the TPM channel. The addition of 1 to the calculated value will ensure that the increment value is always non-zero.
void short_delay( void)
{
TPMC0V = TPMCNT + getADC(1)*51 + 1;
TPMC0V_CH0F = 0; /* Ensure flag is clear */
TPMC0V = 0x50; /* Enable OC (software) interrupt */
}
The TPM channel interrupt would need to include the following code -
TPMC0SC_CH0F = 0; /* Clear flag */
TPMC0SC = 0; /* Disable further Ch 0 interrupts */
// Short delay action
The ADC channel read might use the following code -
word getADC( byte chan)
{
AD1SC1 = chan & 0x1F; /* Start conversion */
while (!ADCSC1_COCO); /* Wait for conversion complete */
return ADCR;
}
You will also need to set the ADC clock within your initialisation code.
Regards,
Mac