Hi all,
I have a doubt about using DMA and SSP (SPI) to get data from an ADC.
I have a version working that uses SSP (SPI), and reads the data from the ADC. The data that comes from the ADC consists of two 16 bits (4 status + 12 data), so 32 bits. The CS select should be 0 (enabled) during those 32 incoming bits.
The reason I am doing SPI with DMA is that I am seeing there is a lag between consecutive spi.write(0x00) calls, so I wanted to shorten it and use a DMA with interrupts.
Right now I am configuring the DMA as follows:
- DMA Channel 0 as a Memory to Peripheral, sending a buffer of 4 bytes (0x00) to the SPI (Data Register)
- DMA Channel 1 as a Peripheral to Memory, sending from the DR (Data Register) to another 4 bytes buffer.
The problem is that the processor stops responding after enabling the DMA_CH_1.
Do you guys have any thoughts? Below you'll find the configuration.
And thanks in advance :)
config_dma
void setupDma() {
setupDmaTx();
setupDmaRx();
LPC_SSP0->DMACR |=
(1UL << 0) // Enable RX DMA
| (1UL << 1) // Enable TX DMA)
;
NVIC_SetVector(DMA_IRQn, (uint32_t)irqDma);
NVIC_EnableIRQ(DMA_IRQn);
}
config_dma_tx
void setupDmaTx() {
int channel = DMA_CHANNEL_TX; // DMA_CHANNEL_TX = 0
// Initialize the GPDMA corresponding channel
dmaChannelTx = (LPC_GPDMACH_TypeDef *) LPC_GPDMACH0;
// reset GPDMA interrupts for the specific channel
LPC_GPDMA->DMACIntTCClear = (1UL << channel) & 0xFF;
LPC_GPDMA->DMACIntErrClr = (1UL << channel) & 0xFF;
// Clear channel control and configuration registers
dmaChannelTx->DMACCControl = 0x00;
dmaChannelTx->DMACCConfig = 0x00;
// set source address to the buffer of 0x00
dmaChannelTx->DMACCSrcAddr = (uint32_t)&spi_to_send;
// set the destination address as the SSP0 (SPI) Data Register
dmaChannelTx->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
// LLI
dmaChannelTx->DMACCLLI = 0;
// Setup the Control Register
dmaChannelTx->DMACCControl =
(sizeof(spi_to_send) & 0xFFF) // Transfer size (11:0)
| ((0x00 & 0x7) << 12) // Source burst size (SPI is 4)
| ((0x00 & 0x7) << 15) // Destination burst size (SPI is 4)
| ((0x00 & 0x7) << 18) // Source transfer width (SPI is byte)
| ((0x00 & 0x7) << 21) // Destination transfer width (SPI is byte)
| (1UL << 26) // Source increment after each transfer
| (1UL << 31) // Terminal count interrupt enable
;
// Enable GPDMA channel
LPC_GPDMA->DMACConfig |= 1UL;
// while (!(LPC_GPDMA->DMACConfig & 1UL));
// Calculate the absolute value for connection number
uint32_t tmpDst = 0UL;
tmpDst = ((tmpDst > 15) ? (tmpDst - 8) : tmpDst);
dmaChannelTx->DMACCConfig =
((0x00 & 0x1F) << 1) // Connection of source peripheral (0)
| ((tmpDst & 0x1F) << 6) // Connection of destination peripheral (0) SSP0 TX
| ((0x01 & 0x03) << 11) // Transfer type: Memory to Peripheral
| (1UL << 14) // Enable interrupt mask
| (1UL << 15) // Enable Interrupt error mask
;
}
config_dma_rx
void setupDmaRx() {
int channel = DMA_CHANNEL_RX; // DMA_CHANNEL_RX = 1
// Initialize the GPDMA corresponding channel
LPC_GPDMACH_TypeDef *dmaChannelRx = (LPC_GPDMACH_TypeDef *) LPC_GPDMACH1;
// reset GPDMA interrupts for the specific channel
LPC_GPDMA->DMACIntTCClear |= (1UL << channel) & 0xFF;
LPC_GPDMA->DMACIntErrClr |= (1UL << channel) & 0xFF;
// Clear channel control and configuration registers
dmaChannelRx->DMACCControl = 0x00;
dmaChannelRx->DMACCConfig = 0x00;
// set source address as the SSP0 (SPI) Data Register
dmaChannelRx->DMACCSrcAddr = (uint32_t)&LPC_SSP0->DR;
// set the destination address to the buffer
dmaChannelRx->DMACCDestAddr = (uint32_t)&buffer;
// LLI
dmaChannelRx->DMACCLLI = 0;
// Setup the Control Register
dmaChannelRx->DMACCControl =
(sizeof(buffer) & 0xFFF) // Transfer size (11:0)
| ((0x00 & 0x7) << 12) // Source burst size (SPI is 4) // TODO: 0x01 & 0x7 for source burst
| ((0x00 & 0x7) << 15) // Destination burst size (SPI is 4)
| ((0x00 & 0x7) << 18) // Source transfer width (SPI is byte)
| ((0x00 & 0x7) << 21) // Destination transfer width (SPI is byte)
| (1UL << 27) // Destination increment after each transfer
| (1UL << 31) // Terminal count interrupt enable
;
// Enable DMA channel
LPC_GPDMA->DMACConfig |= 1;
// while (!(LPC_GPDMA->DMACConfig & 1UL));
dmaChannelRx->DMACCConfig =
((0x01 & 0x1F) << 1) // Connection of source peripheral (1) SSP0_Rx
| ((0x00 & 0x1F) << 6) // Connection of destination peripheral (0)
| ((0x02 & 0x03) << 11) // Transfer type: Peripheral to Memory
| (1UL << 14) // Enable interrupt mask
| (1UL << 15) // Enable Interrupt error mask
;
}
Hi all,
I have a doubt about using DMA and SSP (SPI) to get data from an ADC. I have a version working that uses SSP (SPI), and reads the data from the ADC. The data that comes from the ADC consists of two 16 bits (4 status + 12 data), so 32 bits. The CS select should be 0 (enabled) during those 32 incoming bits.
The reason I am doing SPI with DMA is that I am seeing there is a lag between consecutive spi.write(0x00) calls, so I wanted to shorten it and use a DMA with interrupts.
Right now I am configuring the DMA as follows: - DMA Channel 0 as a Memory to Peripheral, sending a buffer of 4 bytes (0x00) to the SPI (Data Register) - DMA Channel 1 as a Peripheral to Memory, sending from the DR (Data Register) to another 4 bytes buffer.
The problem is that the processor stops responding after enabling the DMA_CH_1.
Do you guys have any thoughts? Below you'll find the configuration. And thanks in advance :)
config_dma
config_dma_tx
config_dma_rx