Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T4 timer #48

Merged
merged 5 commits into from
Jan 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,4 @@ pip-log.txt
*.cbp
*.layout
*.save-failed
*.cmd
12 changes: 12 additions & 0 deletions ADC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ const uint8_t ADC::sc1a2channelADC0[]= { // new version, gives directly the pin
0, 66, 0, 0, 70, 0, 0, 0, // 22-29
0 // 31 means disabled, but just in case
};
#elif defined(ADC_TEENSY_4)
const uint8_t ADC::sc1a2channelADC0[]= { // new version, gives directly the pin number
21, 24, 25, 0, 0, 19, 18, 14, 15, 0, 0, 17, 16, 22,
23, 20, 0, 0, 0, 0, 0, 0, //14-21
0, 0, 0, 0, 0, 0 //22-27
};
#endif // defined

///////// ADC1
Expand All @@ -204,6 +210,12 @@ const uint8_t ADC::sc1a2channelADC1[]= { // new version, gives directly the pin
0, 67, 0, 0, 0, 0, 0, 0, // 22-29.
0
};
#elif defined(ADC_TEENSY_4)
const uint8_t ADC::sc1a2channelADC1[]= { // new version, gives directly the pin number
21, 0, 0, 26, 27, 19, 18, 14, 15, 0, 0, 17, 16, 22, // 0-13
23, 20, 0, 0, 0, 0, 0, 0, //14-21
0, 0, 0, 0, 0, 0 //22-27
};
#endif


Expand Down
107 changes: 106 additions & 1 deletion ADC_Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ ADC_Module::ADC_Module(uint8_t ADC_number,
, PDB0_CHnC1(ADC_num? PDB0_CH1C1 : PDB0_CH0C1)
#endif
#if defined(ADC_TEENSY_4)
, IRQ_ADC(ADC_num? IRQ_NUMBER_t::IRQ_ADC2 : IRQ_NUMBER_t::IRQ_ADC1)
, XBAR_IN(ADC_num? XBARA1_IN_QTIMER4_TIMER3 : XBARA1_IN_QTIMER4_TIMER0)
, XBAR_OUT(ADC_num? XBARA1_OUT_ADC_ETC_TRIG10 : XBARA1_OUT_ADC_ETC_TRIG00)
, QTIMER4_INDEX(ADC_num? 3 : 0)
, ADC_ETC_TRIGGER_INDEX(ADC_num? 4 : 0)
, IRQ_ADC(ADC_num? IRQ_NUMBER_t::IRQ_ADC2 : IRQ_NUMBER_t::IRQ_ADC1)
#elif ADC_NUM_ADCS==2
// IRQ_ADC0 and IRQ_ADC1 aren't consecutive in Teensy 3.6
// fix by SB, https://github.com/pedvide/ADC/issues/19
Expand Down Expand Up @@ -1473,3 +1477,104 @@ uint32_t ADC_Module::getPDBFrequency() {
}

#endif

#if ADC_USE_TIMER && !ADC_USE_PDB
#if defined(ADC_TEENSY_4) // only supported by Teensy 4...
// try to use some teensy core functions...
// mainly out of pwm.c
extern "C" {
extern void xbar_connect(unsigned int input, unsigned int output);
extern void quadtimer_init(IMXRT_TMR_t *p);
extern void quadtimerWrite(IMXRT_TMR_t *p, unsigned int submodule, uint16_t val);
extern void quadtimerFrequency(IMXRT_TMR_t *p, unsigned int submodule, float frequency);
}

void ADC_Module::startTimer(uint32_t freq) {
// First lets setup the XBAR
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON); //turn clock on for xbara1
xbar_connect(XBAR_IN, XBAR_OUT);

// Update the ADC
uint8_t adc_pin_channel = adc_regs.HC0 & 0x1f; // remember the trigger that was set
setHardwareTrigger(); // set the hardware trigger
adc_regs.HC0 = (adc_regs.HC0 & ~0x1f) | 16; // ADC_ETC channel remember other states...
singleMode(); // make sure continuous is turned off as you want the trigger to di it.

// setup adc_etc - BUGBUG have not used the preset values yet.
if ( IMXRT_ADC_ETC.CTRL & ADC_ETC_CTRL_SOFTRST) {// SOFTRST
// Soft reset
atomic::clearBitFlag(IMXRT_ADC_ETC.CTRL, ADC_ETC_CTRL_SOFTRST);
delay(5); // give some time to be sure it is init
}
if (ADC_num == 0) { // BUGBUG - in real code, should probably know we init ADC or not..
IMXRT_ADC_ETC.CTRL |=
(ADC_ETC_CTRL_TSC_BYPASS | ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1 << ADC_ETC_TRIGGER_INDEX)); // 0x40000001; // start with trigger 0
IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(0); // chainlength -1 only us
IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 =
ADC_ETC_TRIG_CHAIN_IE0(1) /*| ADC_ETC_TRIG_CHAIN_B2B0 */
| ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(adc_pin_channel) ;

if (interrupts_enabled) {
// Not sure yet?
}
if (adc_regs.GC && ADC_GC_DMAEN) {
IMXRT_ADC_ETC.DMA_CTRL |= ADC_ETC_DMA_CTRL_TRIQ_ENABLE(ADC_ETC_TRIGGER_INDEX);
}
} else {
// This is our second one... Try second trigger?
// Remove the BYPASS?
IMXRT_ADC_ETC.CTRL &= ~(ADC_ETC_CTRL_TSC_BYPASS); // 0x40000001; // start with trigger 0
IMXRT_ADC_ETC.CTRL |= ADC_ETC_CTRL_DMA_MODE_SEL | ADC_ETC_CTRL_TRIG_ENABLE(1 << ADC_ETC_TRIGGER_INDEX); // Add trigger
IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(0); // chainlength -1 only us
IMXRT_ADC_ETC.TRIG[ADC_ETC_TRIGGER_INDEX].CHAIN_1_0 =
ADC_ETC_TRIG_CHAIN_IE0(1) /*| ADC_ETC_TRIG_CHAIN_B2B0 */
| ADC_ETC_TRIG_CHAIN_HWTS0(1) | ADC_ETC_TRIG_CHAIN_CSEL0(adc_pin_channel) ;

if (adc_regs.GC && ADC_GC_DMAEN) {
IMXRT_ADC_ETC.DMA_CTRL |= ADC_ETC_DMA_CTRL_TRIQ_ENABLE(ADC_ETC_TRIGGER_INDEX);
}
}

// Now init the QTimer.
// Extracted from quadtimer_init in pwm.c but only the one channel...
// Maybe see if we have to do this every time we call this. But how often is that?
IMXRT_TMR4.CH[QTIMER4_INDEX].CTRL = 0; // stop timer
IMXRT_TMR4.CH[QTIMER4_INDEX].CNTR = 0;
IMXRT_TMR4.CH[QTIMER4_INDEX].SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS | TMR_SCTRL_VAL | TMR_SCTRL_FORCE;
IMXRT_TMR4.CH[QTIMER4_INDEX].CSCTRL = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_ALT_LOAD;
// COMP must be less than LOAD - otherwise output is always low
IMXRT_TMR4.CH[QTIMER4_INDEX].LOAD = 24000; // low time (65537 - x) -
IMXRT_TMR4.CH[QTIMER4_INDEX].COMP1 = 0; // high time (0 = always low, max = LOAD-1)
IMXRT_TMR4.CH[QTIMER4_INDEX].CMPLD1 = 0;
IMXRT_TMR4.CH[QTIMER4_INDEX].CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) |
TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(6);

quadtimerFrequency(&IMXRT_TMR4, QTIMER4_INDEX, freq);
quadtimerWrite(&IMXRT_TMR4, QTIMER4_INDEX, 5);

}

//! Stop the PDB
void ADC_Module::stopTimer() {
quadtimerWrite(&IMXRT_TMR4, QTIMER4_INDEX, 0);
setSoftwareTrigger();


}

//! Return the PDB's frequency
uint32_t ADC_Module::getTimerFrequency() {
// Can I reverse the calculations of quad timer set frequency?
uint32_t high = IMXRT_TMR4.CH[QTIMER4_INDEX].CMPLD1;
uint32_t low = 65537 - IMXRT_TMR4.CH[QTIMER4_INDEX].LOAD;
uint32_t highPlusLow = high + low; //
if (highPlusLow == 0) return 0; //

uint8_t pcs = (IMXRT_TMR4.CH[QTIMER4_INDEX].CTRL >> 9) & 0x7;
uint32_t freq = (F_BUS_ACTUAL >> pcs)/highPlusLow;
//Serial.printf("ADC_Module::getTimerFrequency H:%u L:%u H+L=%u pcs:%u freq:%u\n", high, low, highPlusLow, pcs, freq);
return freq;
}

#endif // Teensy 4
#endif // ADC_USE_TIMER
40 changes: 38 additions & 2 deletions ADC_Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ class ADC_Module {


//////////// PDB ////////////////
//// Only works for Teensy 3.0 and 3.1, not LC (it doesn't have PDB)
//// Only works for Teensy 3.x not LC nor tensy 4.0 (they don't have PDB)
#if ADC_USE_PDB

//! Start PDB triggering the ADC at the frequency
Expand All @@ -518,6 +518,37 @@ class ADC_Module {
uint32_t getPDBFrequency();
#endif

//////////// TIMER ////////////////
//// Only works for Teensy T3.x and T4 (not LC) on T3.x (If USE_PDB is defined just calls back to PDB)
#if ADC_USE_TIMER
#if ADC_USE_PDB
void startTimer(uint32_t freq) __attribute__((always_inline)) { startPDB(freq); }

//! Stop the PDB
void stopTimer() __attribute__((always_inline)) { stopPDB(); }

//! Return the PDB's frequency
uint32_t getTimerFrequency() __attribute__((always_inline)) { return getPDBFrequency(); }


#else
//! Start a timer to trigger the ADC at the frequency
/** Call startSingleRead or startSingleDifferential on the pin that you want to measure before calling this function.
* See the example adc_pdb.ino.
* \param freq is the frequency of the ADC conversion, it can't be lower that 1 Hz
*/
void startTimer(uint32_t freq);

//! Stop the timer
void stopTimer();

//! Return the timer's frequency
uint32_t getTimerFrequency();
#endif

#endif



//////// OTHER STUFF ///////////

Expand Down Expand Up @@ -670,7 +701,12 @@ class ADC_Module {
#if ADC_USE_PDB
reg PDB0_CHnC1; // PDB channel 0 or 1
#endif

#ifdef ADC_TEENSY_4
uint8_t XBAR_IN;
uint8_t XBAR_OUT;
uint8_t QTIMER4_INDEX;
uint8_t ADC_ETC_TRIGGER_INDEX;
#endif
const IRQ_NUMBER_t IRQ_ADC; // IRQ number

protected:
Expand Down
Loading