Hello, can someone help me to get this project to work. I have been trying for several days to get SPI to trasfer data using DMA controller on MK22FN512 microcontroller without success. I am using MCUxpresso IDE and SDK 2.5 and I have read the manual for SPI, DMA and DMAMUX . My idea is to get the spi to issue a Transmit FIFO fill request when the program begins,the DMA should respond by coping Command+Data from memory into the PUSHR register of the SPI. then the SPI should send that data. I am using a Major loop count of 1 and channel linking on major loop complete. What i want to do is to have the first channel transfer control to an Always on channel which should be responsible for copying the received data from SPI_POPR register to memory. After 16 data copies into memory, I want the second channel to generate an interrupt. I have managed to get the spi to send the data, put the interrupts are not firing. Can someone guide me what I am doing wrong.
#include "clock_config.h"
#include "MK22F51212.h"
#include "fsl_dspi.h"
#include "fsl_gpio.h"
#include "fsl_port.h"
#include "fsl_clock.h"
#include "fsl_edma.h"
#include "fsl_dmamux.h"
#include "fsl_pit.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"
#include "queue.h"
enum PINS {
PTE3 = 3,
PTE0 = 0,
PTE2 = 2,
PTB23 = 23,
PTB20 = 20,
PTB21 = 21,
};
void Delay(volatile uint32_t k) {
while (k > 0) {
k--;
asm("");
}
}
volatile uint32_t masterCommand0;
uint32_t master_data[1] = {0};
uint16_t destination_data[16] = {100,100,100,100,200,300,15,20,100,600,900,100,500,100,600,20};
void ActuatorControl(void* parameters);
TaskHandle_t ActuatorAhandle = NULL;
SemaphoreHandle_t DMA_type_mutex = NULL;
int main(void) {
{
BOARD_BootClockHSRUN();
CLOCK_EnableClock(kCLOCK_PortE);
PORT_SetPinMux(PORTE, PTE0, kPORT_MuxAlt2);
PORT_SetPinMux(PORTE, PTE2, kPORT_MuxAlt2);
PORT_SetPinMux(PORTE, PTE3, kPORT_MuxAlt2);
}
{
dspi_command_data_config_t commandData;
commandData.isPcsContinuous = false;
commandData.whichCtar = kDSPI_Ctar0;
commandData.whichPcs = kDSPI_Pcs1;
commandData.isEndOfQueue = false;
commandData.clearTransferCount = false;
masterCommand0 = DSPI_MasterGetFormattedCommand(&commandData);
master_data[0] = masterCommand0|SPI_PUSHR_TXDATA(300);
dspi_master_config_t master_config;
master_config.whichCtar = kDSPI_Ctar0;
master_config.ctarConfig.bitsPerFrame = 13;
master_config.ctarConfig.baudRate = 800000;
master_config.ctarConfig.direction = kDSPI_MsbFirst;
master_config.ctarConfig.cpol = kDSPI_ClockPolarityActiveLow;
master_config.ctarConfig.cpha = kDSPI_ClockPhaseSecondEdge;
master_config.ctarConfig.pcsToSckDelayInNanoSec = 700;
master_config.ctarConfig.lastSckToPcsDelayInNanoSec = 700;
master_config.ctarConfig.betweenTransferDelayInNanoSec = 700;
master_config.enableRxFifoOverWrite = false;
master_config.enableContinuousSCK = false;
master_config.whichPcs = kDSPI_Pcs1;
master_config.pcsActiveHighOrLow = kDSPI_PcsActiveLow;
master_config.samplePoint = kDSPI_SckToSin0Clock;
master_config.enableModifiedTimingFormat = false;
DSPI_MasterInit(SPI1,&master_config,CLOCK_GetBusClkFreq());
DSPI_SetFifoEnable(SPI1,false,false);
DSPI_StopTransfer(SPI1);
DSPI_EnableDMA(SPI1,kDSPI_TxDmaEnable);
DSPI_StartTransfer(SPI1);
}
{
DMAMUX_Init(DMAMUX);
DMAMUX_SetSource(DMAMUX,0,(uint8_t)kDmaRequestMux0SPI1);
DMAMUX_SetSource(DMAMUX,1,(uint8_t)kDmaRequestMux0AlwaysOn60);
DMAMUX_DisablePeriodTrigger(DMAMUX,0);
DMAMUX_DisablePeriodTrigger(DMAMUX,1);
DMAMUX_EnableChannel(DMAMUX,0);
DMAMUX_EnableChannel(DMAMUX,1);
}
{
CLOCK_EnableClock(kCLOCK_Dma0);
DMA0->CR = DMA_CR_EMLM(0b0)|DMA_CR_CLM(0b0)|DMA_CR_ERCA(0b1)|DMA_CR_EDBG(0b1)|DMA_CR_HOE(0b1);
DMA0->SEEI = DMA_SEEI_SEEI(0b0)|DMA_SEEI_SAEE(0b0)|DMA_SEEI_NOP(0b0);
DMA0->INT |= DMA_INT_INT0(0b0);
DMA0->SEEI = DMA_SEEI_SEEI(0b1)|DMA_SEEI_SAEE(0b0)|DMA_SEEI_NOP(0b0);
DMA0->INT |= DMA_INT_INT1(0b1);
}
{
EDMA_ResetChannel(DMA0,0);
DMA0->TCD[0].SADDR = DMA_SADDR_SADDR(master_data);
DMA0->TCD[0].SOFF = DMA_SOFF_SOFF(0);
DMA0->TCD[0].DADDR = DMA_DADDR_DADDR(&(SPI1->PUSHR));
DMA0->TCD[0].DOFF = DMA_DOFF_DOFF(0);
DMA0->TCD[0].ATTR = DMA_ATTR_DSIZE(0b010)|DMA_ATTR_DMOD(0x0)|DMA_ATTR_SSIZE(0b010)|DMA_ATTR_SMOD(0x00);
DMA0->TCD[0].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(master_data[0]));
DMA0->TCD[0].CITER_ELINKYES = DMA_CITER_ELINKYES_CITER(0x1)|DMA_CITER_ELINKYES_ELINK(0b1);
DMA0->TCD[0].BITER_ELINKYES = DMA_BITER_ELINKYES_BITER(0x1)|DMA_BITER_ELINKYES_ELINK(0b1);
DMA0->TCD[0].SLAST = DMA_SLAST_SLAST(0);
DMA0->TCD[0].DLAST_SGA = DMA_DLAST_SGA_DLASTSGA(0x0);
DMA0->CDNE = DMA_CDNE_CDNE(0b00)|DMA_CDNE_CADN(0b0)|DMA_CDNE_NOP(0b0);
DMA0->TCD[0].CSR = DMA_CSR_START(0b0)|DMA_CSR_INTMAJOR(0b0)|DMA_CSR_DREQ(0b0)|DMA_CSR_MAJORELINK(0b1)|DMA_CSR_MAJORLINKCH(0b1);
}
{
EDMA_ResetChannel(DMA0,1);
DMA0->TCD[1].SADDR = DMA_SADDR_SADDR(&(SPI1->POPR));
DMA0->TCD[1].SOFF = DMA_SOFF_SOFF(0x0);
DMA0->TCD[1].DADDR = DMA_DADDR_DADDR(destination_data);
DMA0->TCD[1].DOFF = DMA_DOFF_DOFF(sizeof(destination_data[0]));
DMA0->TCD[1].ATTR = DMA_ATTR_DSIZE(0b001)|DMA_ATTR_DMOD(0x0)|DMA_ATTR_SSIZE(0b001)|DMA_ATTR_SMOD(0x00);
DMA0->TCD[1].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(destination_data[0]));
DMA0->TCD[1].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(0x10)|DMA_CITER_ELINKNO_ELINK(0b0);
DMA0->TCD[1].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(0x10)|DMA_BITER_ELINKNO_ELINK(0b0);
DMA0->TCD[1].SLAST = DMA_SLAST_SLAST(0x0);
DMA0->TCD[1].DLAST_SGA = DMA_DLAST_SGA_DLASTSGA(-1*sizeof(destination_data[0])*0x10);
DMA0->CDNE = DMA_CDNE_CDNE(0b1)|DMA_CDNE_CADN(0b0)|DMA_CDNE_NOP(0b0);
DMA0->TCD[1].CSR = DMA_CSR_START(0b0)|DMA_CSR_INTMAJOR(0b1)|DMA_CSR_DREQ(0b0)|DMA_CSR_MAJORELINK(0b0)|DMA_CSR_MAJORLINKCH(0b1);
}
NVIC_SetPriority(DMA1_IRQn, 7);
NVIC_ClearPendingIRQ(DMA1_IRQn);
NVIC_EnableIRQ(DMA1_IRQn);
if (xTaskCreate(ActuatorControl, "Actuator_A", 2000, NULL, 4,
&ActuatorAhandle) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
exit(-1);
vTaskStartScheduler();
while(true)
{
}
return 0 ;
}
void DMA1_IRQHandler()
{
static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if ( (DMA0->ERR) & 0b10)
{
DMA0->CERR = DMA_CERR_CERR(0b10)|DMA_CERR_CAEI(0b0)|DMA_CERR_NOP(0b0);
}
if ( DMA0->TCD[1].CSR & DMA_CSR_DONE(0b1) )
{
EDMA_DisableChannelRequest(DMA0,0);
EDMA_DisableChannelRequest(DMA0,1);
xSemaphoreGiveFromISR(DMA_type_mutex,&xHigherPriorityTaskWoken);
}
NVIC_ClearPendingIRQ(DMA1_IRQn);
NVIC_DisableIRQ(DMA1_IRQn);
}
void ActuatorControl(void* parameters)
{
portTickType xBoardLastWakeTime;
xBoardLastWakeTime = xTaskGetTickCount();
uint8_t blocktime = 1;
DMA_type_mutex = xSemaphoreCreateBinary();
EDMA_EnableChannelRequest(DMA0,0);
EDMA_EnableChannelRequest(DMA0,1);
for(;;)
{
if (xSemaphoreTake(DMA_type_mutex,0))
{
EDMA_EnableChannelRequest(DMA0,1);
EDMA_EnableChannelRequest(DMA0,0);
NVIC_EnableIRQ(DMA1_IRQn);
}
vTaskDelayUntil(&xBoardLastWakeTime, blocktime / portTICK_RATE_MS);
}
vTaskDelete( NULL);
}