/*
* READ MAGNETIC SENSORS USING TIMER INTERRUPTS
* SAVE DATA TO ARRAY BUFFER
* Dean Smart 2020
*
* Pins: sensor teensy4
* LT 2
* LB 4
* RT 6
* RB 8
*/
void intervalSetup()
{
// calculate PIT interval, PIT Timer p.2971
const float PIT_Clock = 0.041666667; // PIT clock cycle interval (24MHz = 41.666667nS/tick)
const float readRateMicros = 100000000 / (float)(walkingPace * readRate); // convert reads/sec to microseconds/read
const uint32_t PIT_Interval = round(readRateMicros / PIT_Clock) - 1; // PIT interval in clock cycles
CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON); // enable PIT clock, p.1085
PIT_MCR = 0; // activate PIT module, p.2979
PIT_TCTRL1 = 0; // reset timer control, p.2984
PIT_LDVAL1 = PIT_Interval; // load PIT_Interval, p.2982
PIT_TFLG1 = PIT_TFLG_TIF; // reset interrupt flag, p.2985
PIT_TCTRL1 = PIT_TCTRL_TIE; // PIT interrupts enable, p.2984
attachInterruptVector(IRQ_PIT, freqCapture); // attach freqCapture isr
NVIC_ENABLE_IRQ(IRQ_PIT); // enable PIT interrupt
NVIC_SET_PRIORITY(IRQ_PIT, 0); // prioritise freqCapture interrupt
}
struct freqPinStruct { // order of variables in freqPin[]
IMXRT_FLEXPWM_t *Pflexpwm; // pointer for pin flexpwm mode
uint8_t subModule; // pin sub-module number
volatile uint32_t *Pmux; // pointer for pin mux mode
uint8_t muxVal; // value to set mux mode on pin
volatile uint32_t *Pinput; // pointer for pin input select
uint8_t inputVal; // value to set input on pin
};
const struct freqPinStruct freqPin[] =
{
{&IMXRT_FLEXPWM4, 2, &IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_04, 1, &IOMUXC_FLEXPWM4_PWMA2_SELECT_INPUT, 0}, // pin 2 LT
{&IMXRT_FLEXPWM2, 0, &IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_06, 1, &IOMUXC_FLEXPWM2_PWMA0_SELECT_INPUT, 0}, // pin 4 LB
// {&IMXRT_FLEXPWM2, 1, &IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_08, 1, &IOMUXC_FLEXPWM2_PWMA1_SELECT_INPUT, 0}, // pin 5 spare
{&IMXRT_FLEXPWM2, 2, &IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_10, 2, &IOMUXC_FLEXPWM2_PWMA2_SELECT_INPUT, 1}, // pin 6 RT
{&IMXRT_FLEXPWM1, 3, &IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00, 6, &IOMUXC_FLEXPWM1_PWMA3_SELECT_INPUT, 4}, // pin 8 RB
// *Pflexpwm, subModule, Pmux, muxVal, Pinput, inputVal
};
void freqSetup() // set up the 4 pins, runs once, FlexPWM p.3029
{
for (byte i = 0; i < 4; i ++) {
*freqPin[i].Pmux = freqPin[i].muxVal; // select mux mode, p.432
*freqPin[i].Pinput = freqPin[i].inputVal; // select input mode, p.817
IMXRT_FLEXPWM_t *Pflexpwm = freqPin[i].Pflexpwm; // get Pflexpwm
uint8_t subModule = freqPin[i].subModule; // get subModule number
uint8_t subModuleBit = 1 << subModule; // convert subModule to 4 bits
Pflexpwm->MCTRL |= FLEXPWM_MCTRL_CLDOK(subModuleBit); // clear master control, p.3134
Pflexpwm->SM[subModule].CTRL2 = FLEXPWM_SMCTRL2_CLK_SEL(0); // select IPBus clock, 150MHz = 6.66667nS/tick, p.3080
Pflexpwm->SM[subModule].INIT = 0; // initial counter & reset value, p.3079
Pflexpwm->SM[subModule].VAL1 = 65535; // maximum counter value/overflow, p.3087
Pflexpwm->MCTRL |= FLEXPWM_MCTRL_LDOK(subModuleBit) | FLEXPWM_MCTRL_RUN(subModuleBit); // LDOK loads setup into buffer, RUN enable PWM clock, p.3134
Pflexpwm->SM[subModule].CAPTCTRLA &= 0x00; // reset capture control register to zero
Pflexpwm->SM[subModule].CAPTCTRLA = 0xA8;
Pflexpwm->SM[subModule].CAPTCOMPA |= FLEXPWM_SMCAPTCOMPA_EDGCMPA(40); // set edge counter compare value to 40 edges (= 20 pulses), p.3112
}
}
/* Convert readings to magnetic flux (nanoTesla)
* typical readings in computer room = 1000 - 1250 ticks
* 1000 - 1250 ticks = 6666.67 - 8333.34 nS (IPBus = 150MHz, 1 tick = 6.66667 nS)
* 6666.67 - 8333.34 nS = 0.00015 - 0.00012 GHz (= 150000 - 120000 Hz)
* 150000 - 120000 Hz = 90000 - 30000 nT (from Zagidulin 2018)
* 1 Hz change = 2 nT, 1 nT change = 0.5 Hz
* 1 nS change = 36 nT, 1 nT change = 0.028 nS
* 1 tick change = 240 nT, 1 nT change = 0.0042 ticks
* formula y = 2x - 210000
*/
volatile uint32_t freqBuff[] = {0, 0, 0, 0}; // volatile buffer for isr, 0 = LT, 1 = LB, 2 = RT, 3 = RB
volatile uint8_t freqPulseCounter = 0; // counts number of pulses sampled
bool freqAvailable() // check that reading was successful
{
for (byte i = 0; i < 4; i ++) {
noInterrupts();
freqBuffer[i] = freqBuff[i]; // copy volatile to non-volatile
freqBuff[i] = 0; // reset freqBuff[i] to 0
interrupts();
if (freqBuffer[i] == 0) {
return false;
}
}
return true;
}
void freqCapture() // isr to capture frequencies
{
// freqtime1 = PIT_CVAL1; // TESTING use to time isr, 1 tick = 41.666667nS
PIT_TFLG1 = PIT_TFLG_TIF; // reset PIT interrupt flag, p.2985
for (byte i = 0; i < 4; i ++) { // repeat for each sensor
IMXRT_FLEXPWM_t *Pflexpwm = freqPin[i].Pflexpwm; // get Pflexpwm
uint8_t subModule = freqPin[i].subModule; // get subModule number
uint16_t capture1, capture2, captureDiff;
Pflexpwm->SM[subModule].CAPTCTRLA |= 0x01; // ARMA = 1 (start capture), p.3110
while (freqPulseCounter < freqNumberSamples) { // repeat capture for freqNumberSamples
if ((Pflexpwm->SM[subModule].STS) &= 0x800) { // perform capture if values are available
capture1 = Pflexpwm->SM[subModule].CVAL2; // 1st edge capture value (number IPBus ticks), p.3121
capture2 = Pflexpwm->SM[subModule].CVAL3; // 2nd edge capture value (number IPBus ticks), p.3123
captureDiff = capture2 - capture1; // calculate difference between captures
freqBuff[i] = freqBuff[i] + captureDiff; // store readings in buffer
freqPulseCounter ++; // advance pulse counter
// Serial.print(captureDiff);
// Serial.print(" ");
}
}
Pflexpwm->SM[subModule].STS |= 0x0C00; // clear status, CFA1 + CFA0 = 1, p.3099
Pflexpwm->SM[subModule].CAPTCTRLA &= 0xA8; // ARMA = 0 (stop capture), p.3110
freqPulseCounter = 0; // reset pulse counter
// Serial.println();
}
asm volatile ("dsb");
asm volatile ("isb");
// freqtime2 = PIT_CVAL1; // TESTING use to time isr, 250 samples time = c.400000 ticks = 16666667 nS = 16.67 mS
}