I am trying to program a Teensy LC to link two DMA channels so that they copy data sequentially, clocked by one of the timer-counters. The eventual goal is to use the DMA to reprogram the timer-counter, but this test program just copies memory-to-memory.
The test program is below. I want it to copy the string "01234567890123456789" to the output buffer, one byte per timer overflow (2.7 msec). I want DMA channel 0 to copy the first 10 bytes, and channel 1 to copy the other 10.
What actually happens, see the log below, is that channel 0 copies the first 10 bytes, then channel 1 copies one byte and stops.
If I set the ERQ bit in DMA channel 1 at setup time, both channels run in parallel.
What am I doing wrong? Thanks.
Test program.
Serial output.
The test program is below. I want it to copy the string "01234567890123456789" to the output buffer, one byte per timer overflow (2.7 msec). I want DMA channel 0 to copy the first 10 bytes, and channel 1 to copy the other 10.
What actually happens, see the log below, is that channel 0 copies the first 10 bytes, then channel 1 copies one byte and stops.
If I set the ERQ bit in DMA channel 1 at setup time, both channels run in parallel.
What am I doing wrong? Thanks.
Test program.
Code:
#include <DMAChannel.h>
#ifndef __MKL26Z64__
#error "for Teensy LC only"
#endif
#define BUF_CNT 10
#define OUT_CNT (3 * BUF_CNT)
DMAChannel chan0, chan1; // Reserve two DMA channels.
uint8_t buf[BUF_CNT];
uint8_t out[OUT_CNT];
uint32_t start_time, report_time, stop_time;
#define assert(c) ((c) || assertion_failed(#c, __LINE__))
void start_DMA()
{
assert(chan0.channel == 0);
assert(chan1.channel == 1);
// Configure DMA channel 0
DMAMUX0_CHCFG0 = DMAMUX_ENABLE | DMAMUX_SOURCE_FTM1_OV;
DMA_SAR0 = buf;
DMA_DAR0 = out;
DMA_DSR_BCR0 = sizeof buf;
DMA_DCR0 = 0 |
DMA_DCR_ERQ |
DMA_DCR_CS |
DMA_DCR_SINC |
DMA_DCR_SSIZE(0b01) |
DMA_DCR_DINC |
DMA_DCR_DSIZE(0b01) |
DMA_DCR_D_REQ |
DMA_DCR_LINKCC(0b11) |
DMA_DCR_LCH1(1) |
0;
// Configure DMA channel 1
DMAMUX0_CHCFG1 = DMAMUX_ENABLE | DMAMUX_SOURCE_FTM1_OV;
DMA_SAR1 = buf;
DMA_DAR1 = out + BUF_CNT;
DMA_DSR_BCR1 = sizeof buf;
DMA_DCR1 = 0 |
// DMA_DCR_ERQ |
DMA_DCR_CS |
DMA_DCR_SINC |
DMA_DCR_SSIZE(0b01) |
DMA_DCR_DINC |
DMA_DCR_DSIZE(0b01) |
DMA_DCR_D_REQ |
DMA_DCR_LINKCC(0b11) |
DMA_DCR_LCH1(0) |
0;
dump_registers("Ready to start");
FTM1_SC |= 0x100; // FTM_SC_DMA bit not defined in kinetis.h
dump_registers("Started");
}
void dump_registers(const char *label)
{
#define PREG(r) (Serial.print(#r " "), \
Serial.println((uint32_t)(r), HEX))
Serial.println(label);
PREG(DMAMUX0_CHCFG0);
PREG(DMA_SAR0);
PREG(DMA_DAR0);
PREG(DMA_DSR_BCR0);
PREG(DMA_DCR0);
Serial.println();
PREG(DMAMUX0_CHCFG1);
PREG(DMA_SAR1);
PREG(DMA_DAR1);
PREG(DMA_DSR_BCR1);
PREG(DMA_DCR1);
Serial.println();
PREG(FTM1_SC);
Serial.println();
#undef PREG
}
void report()
{
for (int i = 0; i < OUT_CNT; i++) {
uint16_t v = out[i];
if ('0' <= v && v <= '9')
Serial.print((char)v);
else if (v == 0xFF)
Serial.print('.');
else
Serial.print('?');
}
Serial.println();
}
void setup()
{
Serial.begin(115200);
for (int i = 0; i < BUF_CNT; i++)
buf[i] = '0' + i;
for (int i = 0; i < OUT_CNT; i++)
out[i] = 0xFF;
analogWrite(17, 127); // ensure the timer-counter is running
start_time = millis() + 1000;
report_time = start_time;
stop_time = start_time + 50;
}
void loop()
{
uint32_t t0 = millis();
if (t0 < start_time)
return;
start_DMA();
while (millis() < stop_time) {
if (millis() >= report_time) {
report();
report_time += 5;
}
}
dump_registers("Stop");
while (1) // Sit. Stay.
continue;
}
bool assertion_failed(const char *c, int line)
{
Serial.println();
Serial.print("Assertion failed at line ");
Serial.print(line);
Serial.print(": ");
Serial.println(c);
while (1)
continue;
return false;
}
Serial output.
Code:
Ready to start
DMAMUX0_CHCFG0 B7
DMA_SAR0 1FFFFE64
DMA_DAR0 1FFFFE3C
DMA_DSR_BCR0 A
DMA_DCR0 605A00B4
DMAMUX0_CHCFG1 B7
DMA_SAR1 1FFFFE64
DMA_DAR1 1FFFFE46
DMA_DSR_BCR1 A
DMA_DCR1 205A00B0
FTM1_SC 89
Started
DMAMUX0_CHCFG0 B7
DMA_SAR0 1FFFFE65
DMA_DAR0 1FFFFE3D
DMA_DSR_BCR0 2000009
DMA_DCR0 605A00B4
DMAMUX0_CHCFG1 B7
DMA_SAR1 1FFFFE64
DMA_DAR1 1FFFFE46
DMA_DSR_BCR1 A
DMA_DCR1 205A00B0
FTM1_SC 109
0.............................
012...........................
01234.........................
01234567......................
01234567890...................
01234567890...................
01234567890...................
01234567890...................
01234567890...................
01234567890...................
01234567890...................
Stop
DMAMUX0_CHCFG0 B7
DMA_SAR0 1FFFFE6E
DMA_DAR0 1FFFFE46
DMA_DSR_BCR0 1000000
DMA_DCR0 205A00B4
DMAMUX0_CHCFG1 B7
DMA_SAR1 1FFFFE65
DMA_DAR1 1FFFFE47
DMA_DSR_BCR1 2000009
DMA_DCR1 205A00B0
FTM1_SC 189