I'm persevering with ASF4 for now since the chip I'm using isn't supported in ASF3.
The SERCOM SPI DMA driver prevents simultaneous transmit of a Tx buffer while receiving an Rx buffer due to a silly bug in the function _spi_m_dma_transfer in hpl/sercom/hpl_sercom.c
This function is called with pointers for txbuf and rxbuf. If either of these is NULL, then only the other direction buffer is used, as you would expect.
In theory if you provide buffers for txbuf and rxbuf, it should use both. However in the function it sets up the Rx DMA transaction and then, if there is a Tx buffer specified, immediately disables the Rx transaction it has just set up.
Broken code:
if (rxbuf) { /* Enable spi rx */ _spi_m_dma_rx_enable(dev); _dma_set_source_address(rx_ch, (void *)_spi_m_get_source_for_dma(dev->prvt)); _dma_set_destination_address(rx_ch, rxbuf); _dma_set_data_amount(rx_ch, length); _dma_enable_transaction(rx_ch, false); } if (txbuf) { /* Enable spi tx */ _spi_m_dma_rx_disable(dev); _dma_set_source_address(tx_ch, txbuf); _dma_set_destination_address(tx_ch, (void *)_spi_m_get_destination_for_dma(dev->prvt)); _dma_srcinc_enable(tx_ch, true); _dma_set_data_amount(tx_ch, length); } else { _dma_set_source_address(tx_ch, ®s->dummy_byte); _dma_set_destination_address(tx_ch, (void *)_spi_m_get_destination_for_dma(dev->prvt)); _dma_srcinc_enable(tx_ch, false); _dma_set_data_amount(tx_ch, length); }
At the very least it is present in these driver versions:
Device: ATSAME51J20A
Device Pack: SAME51_DFP
Version: 1.0.65
Device: ATSAMC21E18A
Device Pack: SAMC21_DFP
Version: 1.1.105
It's easy to fix, see one possibility below.
Fixed code:
if (rxbuf) { /* Enable spi rx */ _spi_m_dma_rx_enable(dev); _dma_set_source_address(rx_ch, (void *)_spi_m_get_source_for_dma(dev->prvt)); _dma_set_destination_address(rx_ch, rxbuf); _dma_set_data_amount(rx_ch, length); _dma_enable_transaction(rx_ch, false); } if (txbuf) { /* Enable spi tx */ if (!rxbuf) { /* Rx not used, so disable */ _spi_m_dma_rx_disable(dev); } _dma_set_source_address(tx_ch, txbuf); _dma_set_destination_address(tx_ch, (void *)_spi_m_get_destination_for_dma(dev->prvt)); _dma_srcinc_enable(tx_ch, true); _dma_set_data_amount(tx_ch, length); } else { _dma_set_source_address(tx_ch, ®s->dummy_byte); _dma_set_destination_address(tx_ch, (void *)_spi_m_get_destination_for_dma(dev->prvt)); _dma_srcinc_enable(tx_ch, false); _dma_set_data_amount(tx_ch, length); }
Is there somewhere to report bugs that actually works? I see http://asf.atmel.no/bugzilla/ is broken. I see mention of myAtmel Support Case system but that seems to have gone away too. There doesn't seem to be a ticketing system in myMicrochip.