I have custom hardware that consists of an MK22FN512VMP12 processor connected to a sensor through a GPIO for power and four lines for SPI.
I am trying to trigger DMA SPI transfers through a PIT interrupt. The problem I'm seeing is that the DMA transfer happens only on the first PIT interrupt. For subsequent interrupts, nothing happens. At this point, I don't care if the sensor is seeing it or not, I just want to get the DMA transfers working. After I get transmit working, I want to get receive working.
I have the DMA error interrupt handler declared, but it is not currently used. When I had it enabled, I never got any interrupts.
I've been following this example:
https://community.nxp.com/t5/Kinetis-Microcontrollers/使用DMA降低SPI通信过程中内核负荷-Reduce-core-work-load-with...
Here's my code. I've attached the file also.
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdbool.h>
#include "MK22F51212.h"
/*
* Macros
*/
#define SPI_PUSHR_CTAS_CTAR0 (0x0)
/*
*
*/
#define EnableInterrupts __asm(" CPSIE i");
#define DisableInterrupts __asm(" CPSID i");
/*
* Data array - WHOAMI register from sensor
*/
#define SENSOR_FRAME_READ_WHOAMI (0x40000091)
#define SENSOR_TRANSMIT_READ_WHOAMI_COUNT (8)
static uint32_t SENSOR_TRANSMIT_READ_WHOAMI[SENSOR_TRANSMIT_READ_WHOAMI_COUNT] =
{
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> 24) & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> 16) & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI ) & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> 24) & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> 16) & 0xFF),
SPI_PUSHR_CONT_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI >> & 0xFF),
SPI_PUSHR_EOQ_MASK | SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_PCS(1) | SPI_PUSHR_TXDATA((SENSOR_FRAME_READ_WHOAMI ) & 0xFF),
};
uint32_t receive_buffer[128]; // Not currently used
/*
* Transmit
*/
static void spi_transmit_receive(uint32_t* buffer, int count)
{
SPI0->MCR = SPI_MCR_PCSIS(0x01) | SPI_MCR_MSTR_MASK |
SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK |
SPI_MCR_CLR_RXF_MASK | SPI_MCR_CLR_TXF_MASK |
SPI_MCR_HALT_MASK;
DMA0->CR = 0x0;
// Transmit
DMAMUX->CHCFG[0] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(15);
/* Set the Source and destination addresses */
DMA0->TCD[0].SADDR = (uint32_t)buffer;
DMA0->TCD[0].DADDR = (uint32_t)&SPI0->PUSHR;
/* Source source and destination offsets */
DMA0->TCD[0].SOFF = sizeof(uint32_t);
DMA0->TCD[0].DOFF = 0;
/* Modulo off and port sizes */
DMA0->TCD[0].ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2); //source and destination size 0 = 8 bits, 2 = 32 bits
/* Transfer size */
DMA0->TCD[0].NBYTES_MLNO = 4;
/* No link channel, transactions */
DMA0->TCD[0].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(count);
DMA0->TCD[0].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(count);
/* Adjustment to source and destination addresses */
DMA0->TCD[0].SLAST = 0x0;
DMA0->TCD[0].DLAST_SGA = 0x0;
DMA0->TCD[0].CSR = DMA_CSR_DREQ_MASK;
#if 0
// Receive
DMAMUX->CHCFG[1] = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(14);
/* Set the Source and destination addresses */
DMA0->TCD[1].SADDR = (uint32_t)&SPI0->POPR;
DMA0->TCD[1].DADDR = (uint32_t)receive_buffer;
/* Source source and destination offsets */
DMA0->TCD[1].SOFF = 0;
DMA0->TCD[1].DOFF = sizeof(uint32_t);
/* Modulo off and port sizes */
DMA0->TCD[1].ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2); //source and destination size 0 = 8 bits, 2 = 32 bits
/* Transfer size */
DMA0->TCD[1].NBYTES_MLNO = 4;
/* No link channel, transactions */
DMA0->TCD[1].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(count);
DMA0->TCD[1].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(count);
/* Adjustment to source and destination addresses */
DMA0->TCD[1].SLAST = 0x0;
DMA0->TCD[1].DLAST_SGA = 0x0;
DMA0->TCD[1].CSR = DMA_CSR_DREQ_MASK | DMA_CSR_INTMAJOR_MASK;
DMA0->ERQ = DMA_ERQ_ERQ0_MASK | DMA_ERQ_ERQ1_MASK;
#else
DMA0->ERQ = DMA_ERQ_ERQ0_MASK | DMA_ERQ_ERQ1_MASK;
#endif
/*
* Start the SPI -- now configured for DMA
*/
#if 0
SPI0->RSER |= SPI_RSER_TFFF_RE_MASK | SPI_RSER_TFFF_DIRS_MASK | SPI_RSER_RFDF_RE_MASK | SPI_RSER_RFDF_DIRS_MASK;
#else
SPI0->RSER |= SPI_RSER_TFFF_RE_MASK | SPI_RSER_TFFF_DIRS_MASK;
#endif
SPI0->RSER |= SPI_RSER_EOQF_RE_MASK;
SPI0->MCR &= ~SPI_MCR_HALT_MASK;
}
/*
*
*/
void PIT1_IRQHandler(void)
{
/* We should get PIT1 interrupts more often -- check them first */
if (PIT->CHANNEL[1].TFLG & PIT_TFLG_TIF_MASK)
{
spi_transmit_receive(SENSOR_TRANSMIT_READ_WHOAMI, SENSOR_TRANSMIT_READ_WHOAMI_COUNT);
/* Clear interrupt flag */
PIT->CHANNEL[1].TFLG = PIT_TFLG_TIF_MASK;
}
}
void DMA0_IRQHandler(void)
{
SPI0_SR |= SPI_SR_EOQF_MASK | SPI_SR_TCF_MASK | SPI_SR_RFDF_MASK | SPI_SR_TFFF_MASK | SPI_SR_RFDF_MASK;
SPI0_MCR |= SPI_MCR_HALT_MASK;
DMA_CINT |= DMA_CINT_CAIR_MASK;
}
void DMA_Error_IRQHandler(void)
{
__asm("nop");
}
/*
* None
*/
static void pit_init(void)
{
/* Start PIT module clock */
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;
// Initialize timer
PIT->MCR = PIT_MCR_FRZ_MASK;
PIT->CHANNEL[1].LDVAL = 48000000UL/(2000UL);
PIT->CHANNEL[1].TFLG = PIT_TFLG_TIF_MASK;
PIT->CHANNEL[1].TCTRL = PIT_TCTRL_TIE_MASK;
/* Enable IRQ */
NVIC_EnableIRQ(PIT1_IRQn);
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;
}
/*
*
*/
static void ports_init(void)
{
/* Clocking */
SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK;
/* Power for sensor */
PORTC->PCR[5] = PORT_PCR_MUX(1);
PTC->PDDR = (1 << 5);
PTC->PSOR = (1 << 5);
/* Configure SPI ports */
PORTD->PCR[0] = PORT_PCR_MUX(2);
PORTD->PCR[1] = PORT_PCR_MUX(2);
PORTD->PCR[2] = PORT_PCR_MUX(2);
PORTD->PCR[3] = PORT_PCR_MUX(2);
}
/*
*
*/
static void spi_dma_init(void)
{
/* Clocking */
SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK;
SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
/* Configure SPI */
SPI0->MCR = SPI_MCR_HALT_MASK;
SPI0->CTAR[0] = SPI_CTAR_FMSZ(7);
SPI0->CTAR[1] = SPI_CTAR_FMSZ(7);
NVIC_EnableIRQ(DMA0_IRQn);
}
/*
*
*/
int main(void)
{
EnableInterrupts;
ports_init();
spi_dma_init();
pit_init();
while (true)
{
}
return 0;
}