Der_Frosti
Member
Hello,
i want to use a library to generate XY"-100 Signals to control a galvometer.
It uses the Flex timer module to trigger the dma to write the data.
The library has two implementation, flor the Teensy LC and the Teensy 3.2. This is the link to the library.
https://github.com/Tuet/XY2_100
The problem is that inly the implementation for the Teensy 3.2 works.
The only difference between the 2 implementation ist in the FTM timer setup/ control and the trigger setting fot the dma.
Here are both code pieces where the difference is. The define for the Teensy LC is __MKL26Z64__.
I tried making it work and i also found this thread
https://forum.pjrc.com/threads/54949-Teensy-LC-Trigger-DMA-with-timer
and tried implementing the solution from the comment, but it didnt work really well.
This is my version.
The main programm i used is the "BasicTest.ino" found in the example from the library.
To check my results i used the pin9 in the ISR wich is called after the dma and also the clock pin2.
With some FTM1_MOD values it seems to kind of work a with a very low freqency.
Maybe i am understanding the code or timer wrong.
Im am using a Teensy LC, the Arduino IDE version 1.8.19 with Teensyduino version 1.56.
The test for the Teensy 3.2 implementation was done by someone from this forum.
https://forum.pjrc.com/threads/70516-Need-help-with-testing-a-Library-for-signal-generation
I would greatly appreciate it if someone could tell me what is wrong with the implemtation for the Teensy LC.
Thanks
i want to use a library to generate XY"-100 Signals to control a galvometer.
It uses the Flex timer module to trigger the dma to write the data.
The library has two implementation, flor the Teensy LC and the Teensy 3.2. This is the link to the library.
https://github.com/Tuet/XY2_100
The problem is that inly the implementation for the Teensy 3.2 works.
The only difference between the 2 implementation ist in the FTM timer setup/ control and the trigger setting fot the dma.
Here are both code pieces where the difference is. The define for the Teensy LC is __MKL26Z64__.
Code:
void XY2_100::begin(void)
{
uint32_t bufsize, frequency;
bufsize = 40;
// set up the buffers
memset(pingBuffer, 0, bufsize);
memset(pongBuffer, 0, bufsize);
// configure the 8 output pins
GPIOD_PCOR = 0xFF;
GPIOD_PDOR = 0x0F;
pinMode(2, OUTPUT); // bit 0
pinMode(14, OUTPUT); // bit 1
pinMode(7, OUTPUT); // bit 2
pinMode(8, OUTPUT); // bit 3
pinMode(6, OUTPUT); // bit 4
pinMode(20, OUTPUT); // bit 5
pinMode(21, OUTPUT); // bit 6
pinMode(5, OUTPUT); // bit 7
frequency = 4000000;
// DMA channel writes the data
dma.sourceBuffer((uint8_t *)pingBuffer, bufsize);
dma.destination(GPIOD_PDOR);
dma.transferSize(1);
dma.transferCount(bufsize);
dma.disableOnCompletion();
dma.interruptAtCompletion();
pinMode(9, OUTPUT); // testing: oscilloscope trigger
#if defined(__MK20DX256__)
// TEENSY 3.1/3.2
FTM2_SC = 0;
FTM2_CNT = 0;
uint32_t mod = (F_BUS + frequency / 2) / frequency;
FTM2_MOD = mod - 1; // 11 @96Mhz, 8 @72MHz
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); // increment on every TPM clock, prescaler 1
// need ISR also
FTM2_C0SC = 0x69; // MSB:MSA 10, ELSB:ELSA 10, DMA on
FTM2_C0V = (mod * 128) >> 8; // 256 = 100% of the time
// route the timer interrupt to trigger the dma channel
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_FTM2_CH0);
// enable a done interrupts when channel completes
dma.attachInterrupt(isr);
FTM2_C0SC = 0x28;
noInterrupts();
FTM2_SC = 0; // stop FTM2 timer (hopefully before it rolls over)
FTM2_CNT = 0;
//PORTB_ISFR = (1<<18); // clear any prior rising edge
uint32_t tmp __attribute__((unused));
FTM2_C0SC = 0x28;
tmp = FTM2_C0SC; // clear any prior timer DMA triggers
FTM2_C0SC = 0x69;
dma.enable();
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); // restart FTM2 timer
#elif defined(__MKL26Z64__)
// TEENSY LC
FTM2_SC = 0;
FTM2_CNT = 0;
uint32_t mod = F_CPU / frequency;
FTM2_MOD = mod - 1;
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); // increment on every TPM clock, prescaler 1
// route the timer interrupt to trigger the dma channel
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_FTM2_OV);
// enable a done interrupts when channel completes
dma.attachInterrupt(isr);
uint32_t sc __attribute__((unused)) = FTM2_SC;
noInterrupts();
FTM2_SC = 0; // stop FTM2 timer (hopefully before it rolls over)
dma.clearComplete();
dma.transferCount(bufsize);
dma.sourceBuffer((uint8_t *)pingBuffer, bufsize);
// clear any pending event flags
FTM2_SC = FTM_SC_TOF;
dma.enable(); // enable DMA channel
FTM2_CNT = 0; // writing any value resets counter
FTM2_SC = FTM_SC_DMA | FTM_SC_CLKS(1) | FTM_SC_PS(0);
#endif
//digitalWriteFast(9, LOW);
interrupts();
}
Code:
void XY2_100::isr(void)
{
//digitalWriteFast(9, LOW);
dma.clearInterrupt();
if(txPing & 2) {
txPing &= ~2;
if(txPing & 1) {
dma.sourceBuffer((uint8_t *)pongBuffer, 40);
} else {
dma.sourceBuffer((uint8_t *)pingBuffer, 40);
}
}
//txPing |= 128;
#if defined(__MK20DX256__)
FTM2_SC = 0;
FTM2_SC = FTM_SC_TOF;
uint32_t tmp __attribute__((unused));
FTM2_C0SC = 0x28;
tmp = FTM2_C0SC; // clear any prior timer DMA triggers
FTM2_C0SC = 0x69;
FTM2_CNT = 0;
dma.enable(); // enable DMA channel
FTM2_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); // restart FTM2 timer
#elif defined(__MKL26Z64__)
FTM2_SC = 0;
FTM2_SC = FTM_SC_TOF;
dma.enable(); // enable DMA channel
FTM2_CNT = 0; // writing any value resets counter
FTM2_SC = FTM_SC_DMA | FTM_SC_CLKS(1) | FTM_SC_PS(0);
#endif
//digitalWriteFast(9, HIGH); // oscilloscope trigger
}
I tried making it work and i also found this thread
https://forum.pjrc.com/threads/54949-Teensy-LC-Trigger-DMA-with-timer
and tried implementing the solution from the comment, but it didnt work really well.
This is my version.
Code:
void XY2_100::begin(void)
{
uint32_t bufsize, frequency;
bufsize = 40;
// set up the buffers
memset(pingBuffer, 0, bufsize);
memset(pongBuffer, 0, bufsize);
// configure the 8 output pins
GPIOD_PCOR = 0xFF;
GPIOD_PDOR = 0x0F;
pinMode(2, OUTPUT); // bit 0
pinMode(14, OUTPUT); // bit 1
pinMode(7, OUTPUT); // bit 2
pinMode(8, OUTPUT); // bit 3
pinMode(6, OUTPUT); // bit 4
pinMode(20, OUTPUT); // bit 5
pinMode(21, OUTPUT); // bit 6
pinMode(5, OUTPUT); // bit 7
frequency = 100000;
// DMA channel writes the data
dma.begin(true);
dma.sourceBuffer((uint8_t *)pingBuffer, bufsize);
dma.destination(GPIOD_PDOR);
dma.transferSize(1);
dma.transferCount(bufsize);
dma.disableOnCompletion();
dma.interruptAtCompletion();
pinMode(9, OUTPUT); // testing: oscilloscope trigger
#if defined(testmode)
// TEENSY LC
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_FTM1_CH1);
dma.attachInterrupt(isr);
dma.enable(); // enable DMA channel
SIM_SCGC6 |= SIM_SCGC6_TPM1;
FTM1_SC = 0; delay(1);
FTM1_CNT = 0;
FTM1_MOD = 0x3F00;//F_CPU/frequency - 1;
//FTM1_MOD = (F_PLL/2)/frequency - 1;
FTM1_C1V = 0x3F00;
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0) ;
FTM1_C1SC |= FTM_CSC_DMA;
#endif
Code:
void XY2_100::isr(void)
{
digitalWriteFast(9, LOW);
dma.clearInterrupt();
if(txPing & 2) {
txPing &= ~2;
if(txPing & 1) {
dma.sourceBuffer((uint8_t *)pongBuffer, 40);
} else {
dma.sourceBuffer((uint8_t *)pingBuffer, 40);
}
}
//txPing |= 128;
#if defined(testmode)
FTM1_C1SC &= ~FTM_CSC_DMA;
dma.enable();
FTM1_CNT = 0;
FTM1_C1SC |= FTM_CSC_DMA;
#endif
digitalWriteFast(9, HIGH); // oscilloscope trigger
}
The main programm i used is the "BasicTest.ino" found in the example from the library.
To check my results i used the pin9 in the ISR wich is called after the dma and also the clock pin2.
With some FTM1_MOD values it seems to kind of work a with a very low freqency.
Maybe i am understanding the code or timer wrong.
Im am using a Teensy LC, the Arduino IDE version 1.8.19 with Teensyduino version 1.56.
The test for the Teensy 3.2 implementation was done by someone from this forum.
https://forum.pjrc.com/threads/70516-Need-help-with-testing-a-Library-for-signal-generation
I would greatly appreciate it if someone could tell me what is wrong with the implemtation for the Teensy LC.
Thanks