Hi,
I want to do a MEM to Periph(SPI) single buffer transfer (no LLI/descriptor usage).
I have read Sam3x datasheet in details (SPI, DMAC & BUS MATRIX sections) but I still don't get the whole thing to work. DMAC is poorly documented
My code SPI is using "hardware Handshaking" mode. What I understood is that SPI is doing that through SPI_SR_TRDE & probably SPI_SR_RDRF as well.
Is it possible to only SEND data over one single DMAC channel (& SPI Transmit HW Interface) or is it required to open a second channel to collect data returned by SPI in SPI_RDR ?
As SPI is doing WRITE/READ through in a single transfer, maybe RDR has to be read. I tried both with no success.
It seems that the transfer never starts: (dataLen bytes at dataBlock address in memory)
sysclk_enable_peripheral_clock(ID_DMAC);
DMAC->DMAC_EN = ~DMAC_EN_ENABLE;
DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_ROUND_ROBIN;
DMAC->DMAC_EN = DMAC_EN_ENABLE;
DMAC->DMAC_EBCIER = DMAC_EBCIER_BTC0|DMAC_EBCIER_ERR0; // Enable IRQ on Buffer Transfer Completed or on Access Error
NVIC_SetPriority(DMAC_IRQn, 0x00); // Set IRQ TOP Priority
NVIC_EnableIRQ(DMAC_IRQn); // Enable IRQ for PIOA in NVIC => will trigger DMAC_Handler(void)
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0;
// Set the channel DMAC_CTRL A/B, CFG, ADDR ... (SRC:dataBlock, DST:@SPI0->SPI_TDR, 8 bits data, dataLen)
DMAC->DMAC_CH_NUM[0].DMAC_SADDR = (uint32_t)dataBlock; // Source Addr
DMAC->DMAC_CH_NUM[0].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR; // Destination Addr (SPI0 TDR address = 0x4000800c)
DMAC->DMAC_CH_NUM[0].DMAC_DSCR = 0; // No Multi-Buffers (No Descriptor required)
DMAC->DMAC_CH_NUM[0].DMAC_CTRLA = DMAC_CTRLA_SRC_WIDTH_BYTE|DMAC_CTRLA_DST_WIDTH_BYTE|dataLen;
DMAC->DMAC_CH_NUM[0].DMAC_CTRLB = DMAC_CTRLB_SRC_INCR_INCREMENTING|DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE|DMAC_CTRLB_DST_INCR_FIXED|DMAC_CTRLB_DST_DSCR_FETCH_DISABLE|DMAC_CTRLB_FC_MEM2PER_DMA_FC;
DMAC->DMAC_CH_NUM[0].DMAC_CFG = DMAC_CFG_DST_H2SEL_HW|DMAC_CFG_DST_PER(SPI0_TX_HWC)|DMAC_CFG_SOD_ENABLE|DMAC_CFG_FIFOCFG_ALAP_CFG; // DST uses SPI0 TX interface, use IRQ (HW handshaking) and disable Channel after transfer ended
// Enable Channel "0"
DMAC->DMAC_CHER = DMAC_CHER_ENA0;
// Transfer supposed to start here ...
while((DMAC->DMAC_CHSR & DMAC_CHSR_ENA0) != 0); <---- stuck here
// ... and be achieved here
Am I missing something to make it work ?
Thanks !