Hi
In the uTasker project I can generate a 500kHz frequency on one (or more bits on a port) ports when I configure a PIT as follows:
PIT_SETUP pit_setup;
pit_setup.int_type = PIT_INTERRUPT;
pit_setup.int_handler = 0;
pit_setup.int_priority = PIT2_INTERRUPT_PRIORITY;
pit_setup.mode = (PIT_PERIODIC | PIT_OUTPUT_DMA_TRIG);
pit_setup.ulPortBits = PORTA_BIT1;
pit_setup.ucPortRef = PORTA;
pit_setup.ucPIT = 2;
pit_setup.count_delay = PIT_US_DELAY(1);
fnConfigureInterrupt((void *)&pit_setup);
So you can get an idea of the method, this is what the configuration does when PIT_OUTPUT_DMA_TRIG is set (it also sets up the PIT for periodic operation - not shown):
if ((PIT_settings->mode & PIT_OUTPUT_DMA_TRIG) != 0) {
static unsigned long ulPortBits[PITS_AVAILABLE] = {0};
ulPortBits[PIT_settings->ucPIT] = PIT_settings->ulPortBits;
fnConfigDMA_buffer(PIT_settings->ucPIT, (DMAMUX0_DMA0_CHCFG_SOURCE_PIT0 + PIT_settings->ucPIT), sizeof(ulPortBits[PIT_settings->ucPIT]), &ulPortBits[PIT_settings->ucPIT], (unsigned long *)(GPIO_BLOCK + (0x040 * PIT_settings->ucPortRef) + 0x00c), (DMA_DIRECTION_OUTPUT | DMA_LONG_WORDS), 0, 0);
fnDMA_BufferReset(PIT_settings->ucPIT, DMA_BUFFER_START);
}
Note that in the case of a PIT, the PIT can only trigger the DMA channel with the same number as itself.
The real work to set up the DMA for a K part (KL parts have a different DMA controller - the uTasker project supports both in a compatible manner but I only show the relevant K part code here for clarity) is
static void fnConfigDMA_buffer(unsigned char ucDMA_channel, unsigned char ucDmaTriggerSource, unsigned long ulBufLength, void *ptrBufSource, void *ptrBufDest, unsigned long ulRules, void(*int_handler)(void), int int_priority)
{
unsigned char ucSize = (unsigned char)(ulRules & 0x07);
KINETIS_DMA_TDC *ptrDMA_TCD = (KINETIS_DMA_TDC *)eDMA_DESCRIPTORS;
ptrDMA_TCD += ucDMA_channel;
ptrDMA_TCD->DMA_TCD_SOFF = ucSize;
ptrDMA_TCD->DMA_TCD_DOFF = 0;
ptrDMA_TCD->DMA_TCD_DLASTSGA = 0;
ptrDMA_TCD->DMA_TCD_SLAST = (-(signed long)(ulBufLength));
switch (ucSize) {
default:
case 1:
ucSize = 1;
ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_8 | DMA_TCD_ATTR_SSIZE_8);
break;
case 2:
ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_16 | DMA_TCD_ATTR_SSIZE_16);
break;
case 4:
ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_32 | DMA_TCD_ATTR_SSIZE_32);
break;
}
ptrDMA_TCD->DMA_TCD_SADDR = (unsigned long)ptrBufSource;
ptrDMA_TCD->DMA_TCD_NBYTES_ML = ucSize;
_DMA_handler[ucDMA_channel] = int_handler;
ptrDMA_TCD->DMA_TCD_CSR = 0;
ptrDMA_TCD->DMA_TCD_DADDR = (unsigned long)ptrBufDest;
ptrDMA_TCD->DMA_TCD_BITER_ELINK = ptrDMA_TCD->DMA_TCD_CITER_ELINK = (signed short)(ulBufLength / ucSize);
POWER_UP(6, SIM_SCGC6_DMAMUX0);
*(unsigned char *)(DMAMUX0_BLOCK + ucDMA_channel) = (ucDmaTriggerSource | DMAMUX_CHCFG_ENBL);
DMA_ERQ |= (DMA_ERQ_ERQ0 << ucDMA_channel);
}
I have also attached a FRDM-K22F binary that will generate a 1MHz signal on the RED led using the technique (using the code above). It also has USB-CDC device on the USB with a command line menu allowing various functions. One needs to be aware that, although the frequency being generated is high precision with low jitter and doesn't use CPU power, the DMA transfers are loading the bus "slightly" - the frequency continues to be generated when the CPU is halted (eg. with debugger) as long as the PIT continues to run. If the toggling speed is increased to a higher rate there can be an impact with USB operation (which also needs to transfer data via the bus) which can cause USB unreliability - this happens when 20MHz is attempted, for example, but 1MHz is not an issue.
Regards
Mark