void PulsePositionOutput::isrTimer4()
{
digitalWriteFast(2, HIGH);
if (list[0] && (IMXRT_TMR4.CH[1].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR4.CH[1].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[0]->isr();}
if (list[1] && (IMXRT_TMR4.CH[2].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR4.CH[2].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[1]->isr();}
asm volatile ("dsb"); // wait for clear memory barrier
digitalWriteFast(2, LOW);
}
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;
PulsePositionOutput myOut1;
PulsePositionOutput myOut2;
void setup()
{
Serial.begin(115200);
delay(2000);
myOut.begin(12);
myOut1.begin(13);
myOut2.begin(11);
myOut.write(1, 600.03);
myOut.write(2, 1500);
myOut.write(3, 759.24);
// slots 4 and 5 will default to 1500 us
myOut.write(6, 1234.56);
myOut1.write(1, 2234.56);
myOut2.write(1, 634.56);
}
void loop() {
}
#include <PulsePosition_t4.h>
// Simple loopback test: create 1 output to transmit
// test pulses, and 1 input to receive the pulses
PulsePositionInput myIn;
void setup() {
myIn.begin(11);
}
int count=0;
void loop() {
int i, num;
// Every time new data arrives, simply print it
// to the Arduino Serial Monitor.
num = myIn.available();
if (num > 0) {
count = count + 1;
Serial.print(count);
Serial.print(" : ");
for (i=1; i <= num; i++) {
float val = myIn.read(i);
Serial.print(val);
Serial.print(" ");
}
Serial.println();
}
}
class PulsePositionBase
{
public:
protected:
static PulsePositionBase *list[10];
typedef struct {
uint8_t pin;
uint8_t channel;
volatile IMXRT_TMR_t* tmr;
volatile uint32_t *clock_gate_register;
uint32_t clock_gate_mask;
IRQ_NUMBER_t interrupt;
void (*isr)();
} TMR_Hardware_t;
static const TMR_Hardware_t hardware[];
// member variables...
virtual void isr();
// static class functions
static void isrTimer1();
static void isrTimer2();
static void isrTimer3();
static void isrTimer4();
};
Just a visual inspection, in Input begin() you need@KurtE,
Ok - I got an initial pass at incorporating PulsePositionInput class into the lib. Did a quick test but have something is off. It is receiving data on the pin but the values are wrong - have some debugging to do - pretty sure my ISRs wrong for the this setup - have some debugging to do unless you beat me too it.
write_index = 255;
available_flag = false;
if (write_index < PULSEPOSITION_MAXCHANNELS) {
should be
if (write_index <= PULSEPOSITION_MAXCHANNELS) {
if (list[5] && (IMXRT_TMR2.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR2.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[5]->isr();}
if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) { list[2]->isr();}
3284 : [COLOR="#FF0000"]2347.71[/COLOR]
3285 : 600.08
3286 : 600.08
3287 : [COLOR="#FF0000"]2347.71[/COLOR]
3288 : 600.08
3289 : 600.08
3290 : 2347.71
3291 : 600.08
3292 : 600.08
I don't think it will affect what you are seeing, but upon further review, i think the Input pulse buffer logic and buffer sizes are OK
//TMR1_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_OPS to make falling
if(outPolarity == 0){
tmr_ch->SCTRL = TMR_SCTRL_OEN | TMR_SCTRL_OPS;
} else {
tmr_ch->SCTRL = TMR_SCTRL_OEN ;
}
tmr_ch->CSCTRL = TMR_CSCTRL_CL1(1);
attachInterruptVector(hardware[idx_channel].interrupt, hardware[idx_channel].isr);
tmr_ch->CSCTRL &= ~(TMR_CSCTRL_TCF1); // clear
tmr_ch->CSCTRL |= TMR_CSCTRL_TCF1EN; // enable interrupt
tmr_ch->SCTRL |= TMR_SCTRL_IEFIE; // enable compare interrupt
tmr_ch->CSCTRL = TMR_CSCTRL_TCF1EN; // enable capture interrupt
if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[2]->isr();}
if (list[2] && (IMXRT_TMR1.CH[0].CSCTRL & TMR_CSCTRL_TCF1)) {IMXRT_TMR1.CH[0].CSCTRL &= ~(TMR_CSCTRL_TCF1); list[2]->isr();}
Have to digest this one.Excellent. There are 10 quadtimer pins on T4. One problem requiring additional logic with both quadtimer PPM out and in in the same lib is that I never could get quadtimer Overflow interrupt to work (??). Counter in overflow interrupt is used to generate 32-bit counter for capture values. I had to use compare-value interrupt (0xffff) to count overflows, BUT compare-value interrupt is used in PPM out. So you'd need to know which pin is in capture mode and which pin is in compare mode to follow the proper path in the ISR -- maybe just look at timer's compare value register, if it has 0xffff then it is just counting overflows. For PPM out, lib's logic never allows value > 60000 in compare register.
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;
PulsePositionInput myIn;
uint32_t count = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(115200);
delay(2000);
// Make sure on different timers...
myOut.begin(9);
myIn.begin(11);
myOut.write(1, 750);
}
uint32_t last_in_avail_time = 0;
void loop() {
int i, num;
// Every time new data arrives, simply print it
// to the Arduino Serial Monitor.
num = myIn.available();
if (num > 0) {
uint32_t cur_time = micros;
count = count + 1;
Serial.print(count);
Serial.print("(");
Serial.print(cur_time-last_in_avail_time, DEC);
last_in_avail_time = cur_time;
Serial.print("): ");
for (i=1; i <= num; i++) {
float val = myIn.read(i);
Serial.print(val);
Serial.print(" ");
}
Serial.println();
}
}
796(0): 926.72
797(0): 1026.75
798(0): 1026.75
799(0): 1026.75
800(0): 926.72
801(0): 1026.75
802(0): 1026.75
803(0): 926.72
804(0): 1026.75
805(0): 1026.75
806(0): 926.72
807(0): 1026.75
808(0): 1026.75
// PPM in, report pulse widths
// test with PulsePosition output pin 9 to T4 pin 11
// QTIMER1 pin capture test qtmr 1 ch 2 pin 11 B0_02, ch 52
// free-running 16-bit timer
// QTIMER oflow interrupt no workee, use 0xffff compare for 32-bit
// polarity TMR_SCTRL_IPS
#define PRREG(x) Serial.printf(#x" 0x%x\n",x);
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;
#define PULSEPOSITION_MAXCHANNELS 16
uint32_t pulse_width[PULSEPOSITION_MAXCHANNELS+1];
uint32_t pulse_buffer[PULSEPOSITION_MAXCHANNELS+1];
uint32_t write_index, prev, total_channels;
#define CLOCKS_PER_MICROSECOND (150./4) // pcs 8+2
#define RX_MINIMUM_SPACE 3500.0
#define RX_MINIMUM_SPACE_CLOCKS (uint32_t)(RX_MINIMUM_SPACE * CLOCKS_PER_MICROSECOND)
volatile uint32_t ticks, overflow_count;
volatile bool overflow_inc, available_flag;
void my_isr() { // capture and compare
if (TMR1_CSCTRL2 & TMR_CSCTRL_TCF1) { // compare rollover
TMR1_CSCTRL2 &= ~(TMR_CSCTRL_TCF1); // clear
overflow_count++;
overflow_inc = true;
}
if (TMR1_SCTRL2 & TMR_SCTRL_IEF) { // capture
uint32_t val, count;
TMR1_SCTRL2 &= ~(TMR_SCTRL_IEF); // clear
val = TMR1_CAPT2;
count = overflow_count;
if (val > 0xE000 && overflow_inc) count--;
val |= (count << 16);
count = val - prev;
prev = val;
if (count >= RX_MINIMUM_SPACE_CLOCKS) {
if (write_index < 255) {
for (int i = 0; i < write_index; i++) {
pulse_buffer[i] = pulse_width[i];
}
total_channels = write_index;
available_flag = true;
}
write_index = 0;
} else {
if (write_index < PULSEPOSITION_MAXCHANNELS) {
pulse_width[write_index++] = count;
}
}
}
ticks++;
asm volatile ("dsb"); // wait for clear memory barrier
overflow_inc = false;
}
void capture_init() {
CCM_CCGR6 |= CCM_CCGR6_QTIMER1(CCM_CCGR_ON);
TMR1_CTRL2 = 0; // stop
TMR1_LOAD2 = 0;
TMR1_CSCTRL2 = 0;
TMR1_LOAD2 = 0; // start val after compare
TMR1_COMP12 = 0xffff; // count up to this val, interrupt, and start again
TMR1_CMPLD12 = 0xffff;
TMR1_SCTRL2 = TMR_SCTRL_CAPTURE_MODE(1); //rising
attachInterruptVector(IRQ_QTIMER1, my_isr);
TMR1_SCTRL2 |= TMR_SCTRL_IEFIE; // enable compare interrupt
TMR1_CSCTRL2 = TMR_CSCTRL_TCF1EN; // enable capture interrupt
NVIC_SET_PRIORITY(IRQ_QTIMER1, 32);
NVIC_ENABLE_IRQ(IRQ_QTIMER1);
TMR1_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2) | TMR_CTRL_LENGTH ; // prescale
*(portConfigRegister(11)) = 1; // ALT 1
}
int ppmIn_available() {
uint32_t total;
bool flag;
__disable_irq();
flag = available_flag;
total = total_channels;
__enable_irq();
if (flag) return total;
return -1;
}
float ppmIn_read(uint8_t channel) {
uint32_t total, index, value = 0;
if (channel == 0) return 0.0;
index = channel - 1;
__disable_irq();
total = total_channels;
if (index < total) value = pulse_buffer[index];
if (channel >= total) available_flag = false;
__enable_irq();
return (float)value / (float)CLOCKS_PER_MICROSECOND;
}
void setup() {
Serial.begin(9600);
while (!Serial);
delay(1000);
myOut.begin(9); // connect pins 9 and 10 together...
myOut.write(1, 600.03);
write_index = 255;
available_flag = false;
capture_init();
PRREG(TMR1_SCTRL2);
PRREG(TMR1_CSCTRL2);
PRREG(TMR1_CTRL2);
PRREG(TMR1_LOAD2);
PRREG(TMR1_COMP12);
PRREG(TMR1_CMPLD12);
PRREG(TMR1_COMP22);
PRREG(TMR1_CMPLD22);
}
void loop() {
int i, num;
static int count = 0;
// Every time new data arrives, simply print it
// to the Arduino Serial Monitor.
num = ppmIn_available();
if (num > 0) {
count = count + 1;
Serial.print(count);
Serial.print(" : ");
for (i = 1; i <= num; i++) {
float val = ppmIn_read(i);
Serial.print(val);
Serial.print(" ");
}
Serial.println();
}
}
I get sort of confused in these cases the relationship here between CSCTRL and SCTRL:
That is setting the TMR_SCTRL_IEFIE, looks like it would be doing the interrupt and setting the IEF flag in SCTRL regegister... Not sure what the TMR_CSCTRL_TCF1EN register/bit is doing?
tmr_ch->CTRL = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | [COLOR="#FF0000"]TMR_CTRL_SCS(2[/COLOR]) | TMR_CTRL_LENGTH ; // prescale
TMR1_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + 2) | TMR_CTRL_SCS(2) | TMR_CTRL_LENGTH ; // prescale
{11,2, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1 },
{12,1, &IMXRT_TMR1, &CCM_CCGR6, CCM_CCGR6_QTIMER1(CCM_CCGR_ON), IRQ_QTIMER1, &PulsePositionInput::isrTimer1 },
if (list[3] && (IMXRT_TMR1.CH[2].CSCTRL & TMR_CSCTRL_TCF1)
|| (IMXRT_TMR1.CH[2].SCTRL & (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE) == (TMR_SCTRL_IEF | TMR_SCTRL_IEFIE))) {
list[3]->isr();
}
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
#include <PulsePosition_t4.h>
PulsePositionOutput myOut;
PulsePositionInput myIn;
uint32_t count = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
Serial.begin(115200);
delay(2000);
// Make sure on different timers...
myOut.begin(9);
myIn.begin(11);
myOut.write(1, 750);
}
uint32_t last_in_avail_time = 0;
void loop() {
int i, num;
// Every time new data arrives, simply print it
// to the Arduino Serial Monitor.
num = myIn.available();
if (num > 0) {
uint32_t cur_time = micros();
count = count + 1;
Serial.print(count);
Serial.print("(");
Serial.print(cur_time-last_in_avail_time, DEC);
last_in_avail_time = cur_time;
Serial.print("): ");
for (i=1; i <= num; i++) {
float val = myIn.read(i);
Serial.print(val);
Serial.print(" ");
}
Serial.println();
}
}
38530(2250): 750.05
38531(18500): 1519.28
38532(19251): 502.45
FYI - I create the base class and made Input and Output based off of it, and my test sketch is still working...
I am probably done for awhile... Need to go to store...
101 : 600.08 176.37 600.08 176.37
102 : 176.37 600.08 176.37
103 : 176.37 600.08 176.37
104 : 176.37 600.08 176.37 600.08
0223 : 600.08
10224 : 1412.35
10225 : 759.28
10226 : 600.05
10227 : 759.28
10228 : 1500.05
10229 : 600.08
10230 : 759.28
10231 : 600.08
10232 : 600.08
10233 : 759.28
10234 : 600.08
10235 : 1412.35
24219 : 600.08 176.37 600.08 176.37
24220 : 176.40 600.08 176.37
24221 : 176.37 600.08 176.37
24222 : 176.37 600.08 176.37 600.08
24223 : 600.08 176.37 600.08 176.37
24224 : 176.37 600.08 176.37
23379 : 634.59 141.87 634.59 141.87
23380 : 141.87 634.59 141.89
23381 : 141.87 634.59 141.87
23382 : 141.87 634.59 141.89 634.59
23383 : 634.59 141.87 634.59 141.87
Don't need the hint - was looking for the daisy chain earlier on but when I did the search I didn't come across it - must be losing it in my old age@mjs513 - I will work on making the inputs work on different pins...
I am pretty sure I know what is going on, and what I need to do to fix...
Hint: Think of other IO pins in other subsystems that did not work...
Hint2: Look at pages like 861 (IOMUXC_QTIMER2_TIMER0_SELECT_INPUT)
IOMUXC_QTIMER2_TIMER0_SELECT_INPUT = 0x01; //pin 13
IOMUXC_QTIMER3_TIMER0_SELECT_INPUT = 0x02; //pin 19
IOMUXC_QTIMER3_TIMER1_SELECT_INPUT = 0x00; //pin 18
IOMUXC_QTIMER3_TIMER2_SELECT_INPUT = 0x01; //pin 14
IOMUXC_QTIMER3_TIMER3_SELECT_INPUT = 0x01; //pin 15