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, // Encoder_a Data
PTE0 = 0, // Encoder_a chip select
PTE2 = 2, // Encoder_a Clk
PTB23 = 23, // Encoder_b Data
PTB20 = 20, // Encoder_b chip select
PTB21 = 21, // Encoder_b Clk
};
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); // SPI0_PCS1
PORT_SetPinMux(PORTE, PTE2, kPORT_MuxAlt2); // SPI1_SCK
PORT_SetPinMux(PORTE, PTE3, kPORT_MuxAlt2); // SPI1_SIN
}
{
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); // preparing SPI commands for DMA to copy to SPI memory
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); // allow the SPI to issue Transmit FIFO Fill DMA request
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); // minorloopmapping_disabled+continouslinkmode_disabled
//+halt_on_error_true+debug_on+roundrobbin
DMA0->SEEI = DMA_SEEI_SEEI(0b0)|DMA_SEEI_SAEE(0b0)|DMA_SEEI_NOP(0b0); // enable error interrupt on channel 0
DMA0->INT |= DMA_INT_INT0(0b0); // disable other interrupts on channel 0
DMA0->SEEI = DMA_SEEI_SEEI(0b1)|DMA_SEEI_SAEE(0b0)|DMA_SEEI_NOP(0b0); // enable error interrupt on channel 1
DMA0->INT |= DMA_INT_INT1(0b1); // enable other interrupts on channel 1
}
{
EDMA_ResetChannel(DMA0,0);
DMA0->TCD[0].SADDR = DMA_SADDR_SADDR(master_data); // address of the first element of the array. which is held in the variable name master_data
DMA0->TCD[0].SOFF = DMA_SOFF_SOFF(0); // what is the sizeof each element of the array. should evaluate to 4 bytes
DMA0->TCD[0].DADDR = DMA_DADDR_DADDR(&(SPI1->PUSHR)); // should evaluate to the address of the PUSHR register
DMA0->TCD[0].DOFF = DMA_DOFF_DOFF(0); // no offset since we are writing to the same register
DMA0->TCD[0].ATTR = DMA_ATTR_DSIZE(0b010)|DMA_ATTR_DMOD(0x0)|DMA_ATTR_SSIZE(0b010)|DMA_ATTR_SMOD(0x00); // we are copying 4 bytes of data per basic transfer
DMA0->TCD[0].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(master_data[0])); // should evaluate to bytesize of element x number of elements to copy per minorloop. should evaluate to 4 bytes
DMA0->TCD[0].CITER_ELINKYES = DMA_CITER_ELINKYES_CITER(0x1)|DMA_CITER_ELINKYES_ELINK(0b1); // setting major loop linking to 1, CITER size is 1
DMA0->TCD[0].BITER_ELINKYES = DMA_BITER_ELINKYES_BITER(0x1)|DMA_BITER_ELINKYES_ELINK(0b1); // setting major loop linking to 1, BITER SIZE is 1
DMA0->TCD[0].SLAST = DMA_SLAST_SLAST(0); // should evaluate to the negative of bytesize of element x number of elements to copy x BITER SIZE
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); // hardware_initiates_start+donot_intpt_on_major_loop_complete+
//donot_disable_channelrequest_afer_majorloop+major_link_enabled+
}
{
EDMA_ResetChannel(DMA0,1);
DMA0->TCD[1].SADDR = DMA_SADDR_SADDR(&(SPI1->POPR)); // address of the SPI1 POPR register
DMA0->TCD[1].SOFF = DMA_SOFF_SOFF(0x0); // 0 bytes.
DMA0->TCD[1].DADDR = DMA_DADDR_DADDR(destination_data); // address of the first element of the array. which is held in the variable name destination_data
DMA0->TCD[1].DOFF = DMA_DOFF_DOFF(sizeof(destination_data[0])); // what is the sizeof each element of the array. should evaluate to 2 bytes
DMA0->TCD[1].ATTR = DMA_ATTR_DSIZE(0b001)|DMA_ATTR_DMOD(0x0)|DMA_ATTR_SSIZE(0b001)|DMA_ATTR_SMOD(0x00); // we are coping 2 bytes of data per basic transfer
DMA0->TCD[1].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(destination_data[0])); // should evaluate to bytesize of element x number of elements to copy per minor loop. should evaluate to 2 bytes
DMA0->TCD[1].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(0x10)|DMA_CITER_ELINKNO_ELINK(0b0); // setting major loop linking to false, CITER size is 4
DMA0->TCD[1].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(0x10)|DMA_BITER_ELINKNO_ELINK(0b0); // setting major loop linking to false, BITER SIZE is 4
DMA0->TCD[1].SLAST = DMA_SLAST_SLAST(0x0); // using the same POPR address. set to 0
DMA0->TCD[1].DLAST_SGA = DMA_DLAST_SGA_DLASTSGA(-1*sizeof(destination_data[0])*0x10); // should evaluate to bytesize of element x BITERSIZE x DOFF. should evaluate to -32 bytes
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); // hardware_initiates_start+intpt_on_major_loop_complete+
//dont_disable_channelrequest_afer_majorloop+major_link_disabled+
}
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) // an error has occurred on the channel
{
DMA0->CERR = DMA_CERR_CERR(0b10)|DMA_CERR_CAEI(0b0)|DMA_CERR_NOP(0b0); // clear the error register
}
if ( DMA0->TCD[1].CSR & DMA_CSR_DONE(0b1) ) // this interrupt is because a major loop has finished
{
EDMA_DisableChannelRequest(DMA0,0); // disable channel 0 so no TFFX is honored. done to enable encoder to rest
EDMA_DisableChannelRequest(DMA0,1); // disable channel 0 so no TFFX is honored. done to enable encoder to rest
xSemaphoreGiveFromISR(DMA_type_mutex,&xHigherPriorityTaskWoken); // give mutex here since the channel has already been disabled
// by hardware
}
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);
}
Solved! Go to Solution.
Hi,
I checked the code, the DMA TCD config with some issues:
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};
The size of master_data[] is 4 bytes;
The size of destination_data[] is 32 bytes;
The DMA0 TCD setting , the CITER and BITER should be value 4.
DMA0->TCD[0].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(master_data[0])); // should evaluate to bytesize of element x number of elements to copy per minorloop. should evaluate to 4 bytes
DMA0->TCD[0].CITER_ELINKYES = DMA_CITER_ELINKYES_CITER(0x1)|DMA_CITER_ELINKYES_ELINK(0b1); // setting major loop linking to 1, CITER size is 1
DMA0->TCD[0].BITER_ELINKYES = DMA_BITER_ELINKYES_BITER(0x1)|DMA_BITER_ELINKYES_ELINK(0b1);
The DMA channel1 TCD setting, the CITER and BITER should be value 0x20.
DMA0->TCD[1].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(destination_data[0])); // should evaluate to bytesize of element x number of elements to copy per minor loop. should evaluate to 2 bytes
DMA0->TCD[1].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(0x10)|DMA_CITER_ELINKNO_ELINK(0b0); // setting major loop linking to false, CITER size is 4
DMA0->TCD[1].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(0x10)|DMA_BITER_ELINKNO_ELINK(0b0);
Wish it helps.
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
I checked the code, the DMA TCD config with some issues:
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};
The size of master_data[] is 4 bytes;
The size of destination_data[] is 32 bytes;
The DMA0 TCD setting , the CITER and BITER should be value 4.
DMA0->TCD[0].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(master_data[0])); // should evaluate to bytesize of element x number of elements to copy per minorloop. should evaluate to 4 bytes
DMA0->TCD[0].CITER_ELINKYES = DMA_CITER_ELINKYES_CITER(0x1)|DMA_CITER_ELINKYES_ELINK(0b1); // setting major loop linking to 1, CITER size is 1
DMA0->TCD[0].BITER_ELINKYES = DMA_BITER_ELINKYES_BITER(0x1)|DMA_BITER_ELINKYES_ELINK(0b1);
The DMA channel1 TCD setting, the CITER and BITER should be value 0x20.
DMA0->TCD[1].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(sizeof(destination_data[0])); // should evaluate to bytesize of element x number of elements to copy per minor loop. should evaluate to 2 bytes
DMA0->TCD[1].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(0x10)|DMA_CITER_ELINKNO_ELINK(0b0); // setting major loop linking to false, CITER size is 4
DMA0->TCD[1].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(0x10)|DMA_BITER_ELINKNO_ELINK(0b0);
Wish it helps.
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------