Hi Mike,
Thanks for your fast reply. Unfortunately the application notes you suggested are for the K series which have enhanced eDMA functionality which I believe my L series does not have, only basic DMA. The only option I have in terms of channel link are:
00 No channel-to-channel linking
01 Perform a link to channel LCH1 after each cycle-steal transfer followed by a link to LCH2 after the BCR decrements to 0.
10 Perform a link to channel LCH1 after each cycle-steal transfer
11 Perform a link to channel LCH1 after the BCR decrements to 0.
At present I have selected the final option which is fine in terms of linking to Buffer B (LCH1 in this case) after Buffer A has exhausted, the only problem being that Buffer B is not active (ERQ bit set to 0).
I have attached my code which works as a ping-pong buffer but i believe that i should not need to intervene in the DMA Callback functions to start and stop buffers, this should be carried out in hardware via the channel link?
Gavin
/*CODE NOTES*******************************************************************
*
* Ping-Pong buffer to sample ADC0 pin 8 using PIT set by user. The size of @
* Buffer 0 and 1 are set manually within code. When red light on board is
* active Buffer 0 is active, when green light is active Buffer 1 is active.
*
******************************************************************************/
/*******************************************************************************
* ADC_DMA_PIT
*******************************************************************************/
// Standard
#include <stdio.h>
#include <stdlib.h>
// Board
#include "board.h"
#include "clock_config.h"
#include "peripherals.h"
#include "pin_mux.h"
// CMSIS
#include "MKL26Z4.h"
// Utilities
#include "fsl_debug_console.h"
// Drivers
#include "fsl_adc16.h"
#include "fsl_dmamux.h"
#include "fsl_dma.h"
#include "fsl_pit.h"
#include "fsl_clock.h"
#include "fsl_gpio.h"
#include "fsl_port.h"
/*******************************************************************************
* Definitions
*******************************************************************************/
#define ADC16_SAMPLE_COUNT 10U // Buffer size
#define PIT_TIMER_IN_MICROSECONDS 500000U // Sample time
#define ADC_BASE_ADDRESS ADC0
#define ADC_CH_GROUP 0U
#define ADC_CH_NUM 8U
#define ADC_RESULTS_REGISTER (uint32_t)(&ADC0->R[0])
#define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_BusClk)
#define DMAMUX_BASE_ADDRESS DMAMUX0
#define DMA_CHANNEL_0 0U
#define DMA_ADC_SOURCE kDmaRequestMux0ADC0
#define DMA_BASE_ADDRESS DMA0
#define ADC_CH_GROUP_2 1U
#define DMA_CHANNEL_1 1U
#define BOARD_REDLED_GPIO BOARD_LED_RED_GPIO
#define BOARD_REDLED_GPIO_PIN BOARD_LED_RED_GPIO_PIN
#define BOARD_GREENLED_GPIO BOARD_LED_GREEN_GPIO
#define BOARD_GREENLED_GPIO_PIN BOARD_LED_GREEN_GPIO_PIN
/*******************************************************************************
* Prototypes
*******************************************************************************/
void BOARDS_ConfigTriggerSource(void);
static void ADC_Configuration(void);
static void periodicIntTimer(void);
static void DMA_Configuration(void);
/*******************************************************************************
* Variables
*******************************************************************************/
adc16_config_t adcUserConfig;
adc16_channel_config_t adcChnConfig;
pit_config_t pitConfig;
dma_handle_t g_DMA_handle_0;
dma_transfer_config_t g_transferConfig_0;
dma_handle_t g_DMA_handle_1;
dma_transfer_config_t g_transferConfig_1;
dma_channel_link_config_t g_dmaChLink_0;
dma_channel_link_config_t g_dmaChLink_1;
static uint32_t g_adc16SampleDataArray_0[ADC16_SAMPLE_COUNT];
static uint32_t g_adc16SampleDataArray_1[ADC16_SAMPLE_COUNT];
volatile bool g_Transfer_Done_0 = false;
volatile bool g_Transfer_Done_1 = false;
gpio_pin_config_t red_led_config;
gpio_pin_config_t green_led_config;
/*******************************************************************************
* Code
*******************************************************************************/
void DMA_Call_0(dma_handle_t *handle, void *param)
{
g_Transfer_Done_1 = false;
g_Transfer_Done_0 = true;
DMA_StopTransfer(&g_DMA_handle_0);
DMA_SubmitTransfer(&g_DMA_handle_1, &g_transferConfig_1, kDMA_EnableInterrupt);
DMA_StartTransfer(&g_DMA_handle_1);
}
void DMA_Call_1(dma_handle_t *handle, void *param)
{
g_Transfer_Done_0 = false;
g_Transfer_Done_1 = true;
DMA_StopTransfer(&g_DMA_handle_1);
DMA_SubmitTransfer(&g_DMA_handle_0, &g_transferConfig_0, kDMA_EnableInterrupt);
DMA_StartTransfer(&g_DMA_handle_0);
}
void BOARDS_ConfigTriggerSource(void)
{
/* ADC hardware trigger configured to use PIT trigger 0*/
SIM->SOPT7 |= SIM_SOPT7_ADC0TRGSEL(4) | SIM_SOPT7_ADC0ALTTRGEN(1);
}
static void ADC_Configuration(void)
{
ADC16_GetDefaultConfig(&adcUserConfig);
// adcUserConfig.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
// adcUserConfig.clockSource = kADC16_ClockSourceAsynchronousClock;
// adcUserConfig.enableAsynchronousClock = true;
// adcUserConfig.clockDivider = kADC16_ClockDivider8;
// adcUserConfig.resolution = kADC16_ResolutionSE12Bit;
// adcUserConfig.longSampleMode = kADC16_LongSampleDisabled;
// adcUserConfig.enableHighSpeed = false;
// adcUserConfig.enableLowPower = false;
// adcUserConfig.enableContinuousConversion = false;
ADC16_Init(ADC_BASE_ADDRESS, &adcUserConfig);
ADC16_DoAutoCalibration(ADC_BASE_ADDRESS);
if (kStatus_Success == ADC16_DoAutoCalibration(ADC_BASE_ADDRESS))
{
PRINTF("ADC CALIBRATION COMPLETE\n");
}else
{
PRINTF("ADC CALIBRATION FAILED\n");
}
adcChnConfig.channelNumber = ADC_CH_NUM;
adcChnConfig.enableDifferentialConversion = false;
adcChnConfig.enableInterruptOnConversionCompleted = false;
ADC16_SetChannelConfig(ADC_BASE_ADDRESS, ADC_CH_GROUP, &adcChnConfig);
ADC16_EnableHardwareTrigger(ADC_BASE_ADDRESS, true);
ADC16_EnableDMA(ADC_BASE_ADDRESS, true);
}
static void periodicIntTimer(void)
{
PIT_GetDefaultConfig(&pitConfig);
PIT_Init(PIT, &pitConfig);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, USEC_TO_COUNT(PIT_TIMER_IN_MICROSECONDS, PIT_SOURCE_CLOCK));
PIT_DisableInterrupts(PIT, kPIT_Chnl_0, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_0);
}
static void DMA_Configuration(void)
{
DMAMUX_Init(DMAMUX_BASE_ADDRESS);
/* DMA MUX config for channel 0 */
DMAMUX_SetSource(DMAMUX_BASE_ADDRESS, DMA_CHANNEL_0, DMA_ADC_SOURCE);
DMAMUX_EnableChannel(DMAMUX_BASE_ADDRESS, DMA_CHANNEL_0);
/* DMA MUX config for channel 1 */
DMAMUX_SetSource(DMAMUX_BASE_ADDRESS, DMA_CHANNEL_1, DMA_ADC_SOURCE);
DMAMUX_EnableChannel(DMAMUX_BASE_ADDRESS, DMA_CHANNEL_1);
DMA_Init(DMA_BASE_ADDRESS);
/* DMA Channel 0 Config */
DMA_CreateHandle(&g_DMA_handle_0, DMA_BASE_ADDRESS, DMA_CHANNEL_0);
DMA_SetCallback(&g_DMA_handle_0, DMA_Call_0, NULL);
DMA_PrepareTransfer(&g_transferConfig_0, (void *)ADC_RESULTS_REGISTER,
sizeof(uint32_t), (void *)g_adc16SampleDataArray_0, sizeof(uint32_t),
sizeof(g_adc16SampleDataArray_0), kDMA_PeripheralToMemory);
DMA_SubmitTransfer(&g_DMA_handle_0, &g_transferConfig_0, kDMA_EnableInterrupt);
/* DMA Channel 1 Config */
DMA_CreateHandle(&g_DMA_handle_1, DMA_BASE_ADDRESS, DMA_CHANNEL_1);
DMA_SetCallback(&g_DMA_handle_1, DMA_Call_1, NULL);
DMA_PrepareTransfer(&g_transferConfig_1, (void *)ADC_RESULTS_REGISTER,
sizeof(uint32_t), (void *)g_adc16SampleDataArray_1, sizeof(uint32_t),
sizeof(g_adc16SampleDataArray_1), kDMA_PeripheralToMemory);
DMA_SubmitTransfer(&g_DMA_handle_1, &g_transferConfig_1, kDMA_EnableInterrupt);
/* DMA LINK Config */
g_dmaChLink_0.linkType = kDMA_ChannelLinkChannel1AfterBCR0;
g_dmaChLink_0.channel1 = DMA_CHANNEL_1;
DMA_SetChannelLinkConfig(DMA_BASE_ADDRESS, DMA_CHANNEL_0, &g_dmaChLink_0);
/* DMA LINK Config */
g_dmaChLink_1.linkType = kDMA_ChannelLinkChannel1AfterBCR0;
g_dmaChLink_1.channel1 = DMA_CHANNEL_0;
DMA_SetChannelLinkConfig(DMA_BASE_ADDRESS, DMA_CHANNEL_1, &g_dmaChLink_1);
DMA_SetTransferConfig(DMA_BASE_ADDRESS, DMA_CHANNEL_0, &g_transferConfig_0);
DMA_SetTransferConfig(DMA_BASE_ADDRESS, DMA_CHANNEL_1, &g_transferConfig_1);
DMA_EnableCycleSteal(DMA_BASE_ADDRESS, DMA_CHANNEL_0, true);
DMA_EnableCycleSteal(DMA_BASE_ADDRESS, DMA_CHANNEL_1, true);
/* Inital Start Transfer on Buffer 0 */
DMA_StartTransfer(&g_DMA_handle_0);
}
void Init_Board_Led(void)
{
CLOCK_EnableClock(kCLOCK_PortE);
/* Red LED */
PORT_SetPinMux(PORTE, 29U, kPORT_MuxAsGpio);
red_led_config.pinDirection = kGPIO_DigitalOutput;
red_led_config.outputLogic = 1U;
GPIO_PinInit(BOARD_REDLED_GPIO, BOARD_REDLED_GPIO_PIN, &red_led_config);
/* Green LED */
PORT_SetPinMux(PORTE, 31U, kPORT_MuxAsGpio);
green_led_config.pinDirection = kGPIO_DigitalOutput;
green_led_config.outputLogic = 1U;
GPIO_PinInit(BOARD_GREENLED_GPIO, BOARD_GREENLED_GPIO_PIN, &green_led_config);
}
/*******************************************************************************
* Main
*******************************************************************************/
int main(void) {
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitBootPeripherals();
BOARD_InitDebugConsole();
Init_Board_Led();
periodicIntTimer();
ADC_Configuration();
DMA_Configuration();
BOARDS_ConfigTriggerSource();
while(1)
{
/* Red LED ON = Buffer 0 active */
GPIO_TogglePinsOutput(BOARD_REDLED_GPIO, 1u << BOARD_REDLED_GPIO_PIN);
while (g_Transfer_Done_0 != true)
{
}
GPIO_TogglePinsOutput(BOARD_REDLED_GPIO, 1u << BOARD_REDLED_GPIO_PIN);
/* Green LED ON = Buffer 1 active */
GPIO_TogglePinsOutput(BOARD_GREENLED_GPIO, 1u << BOARD_GREENLED_GPIO_PIN);
while (g_Transfer_Done_1 != true)
{
}
GPIO_TogglePinsOutput(BOARD_GREENLED_GPIO, 1u << BOARD_GREENLED_GPIO_PIN);
}
}