SPI with DMA not working (using mmap)

Moderator: nferre

rgouget
Posts: 3
Joined: Tue May 14, 2019 4:57 pm

SPI with DMA not working (using mmap)

Tue May 14, 2019 5:56 pm

Hello,

First of all, i am using memory map to modify directly register of SPI and XDMAC so i don't use driver made by Microchip.
I'm trying to send SPI data using FLEXSPI3, it's working without DMA but when i'm trying to use DMA nothing happens.
Moreover memory to memory transfer with DMA is working but not memory to peripherals or peripheral to memory.

I have followed the instructions from datasheet p777 "37.5.5.1 Single Block Transfer With Single Microblock", you can find my code bellow.

XDMAC0 (channel 0 and 1) is used for UART linux console. Others channels are free.

In the code example in the softpack they use some mutex i don't know if it could be the problem.

SPI is working independently and DMA also (i can do a memory to memory transfer) so i don't know what is the problem...

Code: Select all


#define SPI_CONFIG_DAC_MR (SPI_MR_LLB | SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_BRSRCCLK_PERIPH_CLK | SPI_MR_DLYBCS(28))

#define SPI_CONFIG_DAC_CSR (SPI_CSR_BITS_16_BIT | SPI_CSR_CSAAT | SPI_CSR_CPOL | SPI_CSR_NCPHA)

#define XDMAC_CONFIG_DAC 	( XDMAC_CC_TYPE_PER_TRAN | XDMAC_CC_MBSIZE_SIXTEEN | XDMAC_CC_SAM_FIXED_AM \
							| XDMAC_CC_DAM_FIXED_AM | XDMAC_CC_DSYNC_MEM2PER | XDMAC_CC_PROT_UNSEC \
							| XDMAC_CC_CSIZE_CHK_1 | XDMAC_CC_DWIDTH_HALFWORD | XDMAC_CC_SIF_AHB_IF0 \
							| XDMAC_CC_DIF_AHB_IF1 | XDMAC_CC_SWREQ_HWR_CONNECTED )
							
void main (void)
{
	// some code for init and PMC configuration -> this is not the problem
	
	/*
	 * FLEXCOM3 = FLEXSPI = DAC
	 */
	flexcom_select(pAT91_FLEXCOM3_BASE, ID_FLEXCOM3, FLEX_MR_OPMODE_SPI);
	spi_configure(pAT91_FLEXSPI3_BASE, SPI_CONFIG_DAC_MR);
	spi_enable_it(pAT91_FLEXSPI3_BASE, SPI_IER_TDRE | SPI_IER_TXEMPTY | SPI_IER_TXFEF | SPI_IER_TXFFF | SPI_IER_TXFTHF | SPI_IER_TXFPTEF);
	spi_configure_cs(pAT91_FLEXSPI3_BASE, ID_FLEXCOM3, 0, 738, 0, 0, SPI_CONFIG_DAC_CSR);
	spi_select_cs(pAT91_FLEXSPI3_BASE, 0);
	spi_enable(pAT91_FLEXSPI3_BASE);

	_dma_channel dma_dac =
	{
			.hw = pAT91_XDMAC1_BASE,
			.chan = 0,
			.config = XDMAC_CONFIG_DAC | XDMAC_CC_PERID(17),
			.nb_data = 128,
			.src_add = PHYS_TX_SSC_BUFF1_ADDR, // physical address of pTxMemSSC
			.dst_add = 0xFC01440CU // physical address of pAT91_FLEXSPI3_BASE->SPI_TDR
	};
	
	for (temp = 0; temp < 128; temp++)
	{
		pTxMemSSC[temp] = 0x1234;
	}
	
	if(!dma_init(&dma_dac))
	{
		printf("Cannot allocate dma_dac\n");
	}
	
	while(1)
	{
		printf("%08X\n", pAT91_FLEXSPI3_BASE->SPI_RDR); // in spi configuration i use loopback for test
	}
}

/*
 * Single block transfer with single microblock p.777
 */
uint8_t dma_init(_dma_channel* channel)
{
	uint8_t chan;

	for (chan = 0; chan < XDMAC_CHANNELS; chan++)
	{
		if((channel->hw->XDMAC_GS & (1<<chan)) == 0) // if channel chan is free
		{
			channel->chan = chan;
			// 2. Clear the pending Interrupt Status bit(s) by reading the selected XDMAC Channel x Interrupt Status
			// Register (XDMAC_CISx).
			channel->hw->XDMAC_CH[chan].XDMAC_CIS;

			// 3. Write the XDMAC Channel x Source Address Register (XDMAC_CSAx) for channel x.
			channel->hw->XDMAC_CH[chan].XDMAC_CSA = channel->src_add;

			// 4. Write the XDMAC Channel x Destination Address Register (XDMAC_CDAx) for channel x.
			channel->hw->XDMAC_CH[chan].XDMAC_CDA = channel->dst_add;

			// 5. Program field UBLEN in the XDMAC Channel x Microblock Control Register (XDMAC_CUBCx) with
			// the number of data. (max 0xFFFFFF = 16,777,215)
			channel->hw->XDMAC_CH[chan].XDMAC_CUBC = channel->nb_data;

			// 6. Program the XDMAC Channel x Configuration Register (XDMAC_CCx) :
			channel->hw->XDMAC_CH[chan].XDMAC_CC = channel->config;

			// 7. Clear the following five registers.
			// This indicates that the linked list is disabled, there is only one block and striding is disabled.
			channel->hw->XDMAC_CH[chan].XDMAC_CNDC = 0;
			channel->hw->XDMAC_CH[chan].XDMAC_CBC = 0;
			channel->hw->XDMAC_CH[chan].XDMAC_CDS_MSP = 0;
			channel->hw->XDMAC_CH[chan].XDMAC_CSUS = 0;
			channel->hw->XDMAC_CH[chan].XDMAC_CDUS = 0;

			// 8. Enable the Microblock interrupt by writing a ‘1’ to bit BIE in the XDMAC Channel x Interrupt Enable
			// Register (XDMAC_CIEx). Enable the Channel x Interrupt Enable bit by writing a ‘1’ to bit IEx in the
			// XDMAC Global Interrupt Enable Register (XDMAC_GIE).
			channel->hw->XDMAC_CH[chan].XDMAC_CIE = XDMAC_CIE_BIE;
			channel->hw->XDMAC_GIE = 1 << chan;

			// 9. Enable channel x by writing a ‘1’ to bit ENx in the XDMAC Global Channel Enable Register
			// (XDMAC_GE).
			channel->hw->XDMAC_GE = 1 << chan;

			return 1; // channel allocated
		}
	}
	return 0; // cannot allocate channel
}	
	
Thank you to help me i'm desperate with this processor...

Romain
blue_z
Location: USA
Posts: 1943
Joined: Thu Apr 19, 2007 10:15 pm

Re: SPI with DMA not working (using mmap)

Wed May 15, 2019 2:22 am

rgouget wrote: First of all, i am using memory map to modify directly register of SPI and XDMAC so i don't use driver made by Microchip.
First of all, identifying which SoC you are using would be helpful.
You mention "mmap" and "memory map" which is a method used by userspace device drivers. You mention what you are not doing (i.e. not "use driver made by Microchip" which is inherently ambiguous) and neglect to clarify what you are (specifically) doing.

You neglect to mention which version of the Linux kernel is involved (presuming Linux is used).

rgouget wrote: I'm trying to send SPI data using FLEXSPI3, it's working without DMA but when i'm trying to use DMA nothing happens.
If for whatever reasons one does not choose to implement a SPI protocol driver for the slave SPI device, then the Linux kernel supports the spidev driver, which provides access to R/W services by the SPI master controller in the normal userspace I/O framework.

Use of spidev is IMO a hack, and replacement of the kernel driver for a SPI master controller is an implementation that is even more inferior.
Looks like you're also stepping on DMAC registers from userspace, so you're competing with or hijacking registers from the kernel platform driver. Such a method to "modify directly register of XDMAC" is simply wrong.

You cannot fix something that is not going to work.

Regards
rgouget
Posts: 3
Joined: Tue May 14, 2019 4:57 pm

Re: SPI with DMA not working (using mmap)

Wed May 15, 2019 3:34 pm

Thank you for your reply and sorry i am confuse i forgot the most important things...

I am using the evaluation board SAMA5D27-SOM1-EK1 so the proc is SAMA5D27 and the os is linux4SAM 6.0.

I don't use any driver from linux or atmel to control the peripherals like SPI (so i don't use spidev), instead of this i use a pointer to the physical address of the memory (/dev/mem following the datasheet p57) and i modify these registers.
Why? Because i'm looking for optimization (in term of speed processing) and response time (we need a real time application even if linux is not really appropriate for this). We did that for our last project with an AT91RM9200 and it worked well for years.

In your opinion we shouldn't use mmap and "hack" the linux kernel because it's not safe but the drivers are not really optimize for speed so i don't have the choice.

Else do you have any ideas why my DMA is not working?
Do you think there might be some conflicts between my home made driver and the kernel driver?

Regards
blue_z
Location: USA
Posts: 1943
Joined: Thu Apr 19, 2007 10:15 pm

Re: SPI with DMA not working (using mmap)

Wed May 15, 2019 8:55 pm

rgouget wrote: I don't use any driver from linux or atmel to control the peripherals like SPI (so i don't use spidev), instead of this i use a pointer to the physical address of the memory (/dev/mem following the datasheet p57) and i modify these registers.
If you did not follow the UIO guide, then you probably have one big ugly hack.

rgouget wrote: Do you think there might be some conflicts between my home made driver and the kernel driver?
You have only presented a spotty description.
Is there still a Linux platform driver for the XDMAC?
If so, then you have conflict.

Regards
rgouget
Posts: 3
Joined: Tue May 14, 2019 4:57 pm

Re: SPI with DMA not working (using mmap)

Wed Jun 05, 2019 5:52 pm

I have investigated on my problem and I found the solution :
- I’m using FLEXSPI address instead of FLEXCOM address for the TDR and RDR buffer. Using FLEXCOM address make it works.
- I didn’t secure the channel (bit 5 PROT).

regards

Return to “SAMA5-based”

Who is online

Users browsing this forum: No registered users and 3 guests