Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Post here first, or if you can't find a relevant section!
User avatar
RogerClark
Posts: 5615
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby RogerClark » Sun Feb 26, 2017 12:40 am

I Totally agree.

Its not worth adding that level of complexity as hardly any one will use it.

victor_pv
Posts: 1249
Joined: Mon Apr 27, 2015 12:12 pm

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby victor_pv » Sun Feb 26, 2017 1:23 am

First shot at separating the setting up of the DMA transfer, and the firing of the transfer.
Basically I just separated the code that was previously in dmaSend in two parts, dmaSensdSet configured the transfer, except for the length, and enabling the channel. Next you call dmaSendRepeat (I dont really like that name, but can't think on other appropriate one that I like) with the length of the transfer, and that sets the DMACNDTR register, which needs to be reloaded for a new transfer, and enables the channel. If a callback function has been set previously, doesn't block and return 0 for success. If a callback function was not set, it will block.
SPI.dmaSend has the exact same functionality as before, so any code using it should not break in any way, but now it uses the other 2 functions to do the work.

This way if you want to send a number of bytes from the same buffer pointer, you only call SPI.dmaSendRepeat with 1 parameter, the number of bytes to send, everything else stays the same as the last transfer, so you only need to fill the buffer and fire the transfer.

What do you guys think? This still doesn't implement the internal buffer Steven had been testing, but code that repeat transmissions from the same buffer should get less overhead.

EDIT: I realize it may be good to add checks to confirm whether there is a transmission already in progress before changing settings. It depends if we prefer that little overhead for safety.


Code: Select all

uint8 SPIClass::dmaSendRepeat(uint16 length)
{
   if (length == 0) return 1;
   dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
   dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
   if (_currentSetting->TXcallback){
        return 0;
   }
   uint32_t m = millis();
   uint8 b = 0;
   while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
      if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
   }
   dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);

   while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
   while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
   dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
   spi_tx_dma_disable(_currentSetting->spi_d);
   //uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
   return b;
}

void SPIClass::dmaSendSet(void * transmitBuf, bool minc)
{
   uint32 flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
   dma_init(_currentSetting->spiDmaDev);
   // TX
   spi_tx_dma_enable(_currentSetting->spi_d);
   dma_xfer_size dma_bit_size = (_currentSetting->dataSize==SPI_DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
   dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
                       transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
}

uint8 SPIClass::dmaSend(void * transmitBuf, uint16 length, bool minc)
{
    dmaSendSet(transmitBuf, minc);
    return dmaRepeat(length);
}

User avatar
RogerClark
Posts: 5615
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby RogerClark » Sun Feb 26, 2017 2:34 am

Thanks Victor

The blocking / non blocking selection via the callback argument being non null is what Nordic semi do in their SDK / API, so if its good enough for them, I think its good enough for us.

Also

dmaSendRepeat() seems a prefectly good name to me, as its descriptive and concise

stevestrong
Posts: 1019
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby stevestrong » Sun Feb 26, 2017 7:04 am

That's nice so far.
It should be non-blocking if a non-null CB function is passed as parameter.
I would really tend to reserve the DMA channels for SPI, if configured by the user, in order to remove the overhead calling dmaSend/Set each time if only the buffer pointer and its length have changed. This way one could quickly switch between two buffers, one being filled while the previous one being sent.
I think it is very unlikely to use same DMA channel for other purposes if one use the DMA for SPI, which means the SPI is constantly working, and then with DMA, like display-related applications.

Ollie
Posts: 151
Joined: Thu Feb 25, 2016 7:27 pm

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby Ollie » Sun Feb 26, 2017 4:07 pm

If/when you are preparing to port the F1xx architecture to F4xx/F7xx/H7xx, the DMA allocation management has to be addressed. With multiple alternative DMA streams available for the peripherals and more peripherals requiring DMA, the visibility of this mapping matrix is important. In long run, it will not work if the peripheral libraries are assuming that certain DMA streams are available for them.

We either need to have on demand DMA stream request/release or static allocations with conflict detection.

stevestrong
Posts: 1019
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby stevestrong » Sun Feb 26, 2017 4:25 pm

Ollie wrote:If/when you are preparing to port the F1xx architecture to F4xx/F7xx/H7xx, the DMA allocation management has to be addressed. With multiple alternative DMA streams available for the peripherals and more peripherals requiring DMA, the visibility of this mapping matrix is important. In long run, it will not work if the peripheral libraries are assuming that certain DMA streams are available for them.

We either need to have on demand DMA stream request/release or static allocations with conflict detection.

I think it is a bit too soon to think on such complex systems. I don't think we will port the Arduino_F1 to F4 core very quickly.
I am happy with reserving DMA for SPI.

victor_pv
Posts: 1249
Joined: Mon Apr 27, 2015 12:12 pm

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby victor_pv » Sun Feb 26, 2017 4:30 pm

How do you guys suggest to manage the DMA channels allocation?
As far as I know currently the core doesn't keep any kind of data on what channels are enabled and for what peripheral, I guess that would require an additional library, that keeps that data, and manage allocation and releasing channels.

About the F4 porting, I think the first effort we should probably try is changing to the "tubes" API that leaflabs added to manage the F4 DMA streams. I haven't used it in the F1, but I have seen code using it, so probably works.

Now, I am of the opinion of changing things one at a time when they are already working, so not to break anything.
Personally I will finish with what I started, adding the part to manage a callback, and repeated transfers. I will add another function to cover changing the source address and length at once as Steve suggested, that will help manage doublebuffering.

If someone can start working on code that manage DMA channels reservations, we can work in parallel. Once I'm finished with the extra functions and they work, I'll try to see if I can get it working with tubes so it works for the F4.

EDIT: One way could be try to build some table like the PIN_MAP one, that maps the DMA channels with the peripherals that can use them, and add a bool indicating if that peripheral DMA requests have been enabled in that channel.

User avatar
RogerClark
Posts: 5615
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby RogerClark » Sun Feb 26, 2017 9:00 pm

Is it going to take much space to store the reservations ? e.g. do we need to just store something for each DMA channel e.g. whether its reserved or do we need to store a struct per channel ?

Is there just a way read back the information from the hardware. From what I recall it was possible to effectively parse the DMA registers to figure out quite a lot of information about their setup.

victor_pv
Posts: 1249
Joined: Mon Apr 27, 2015 12:12 pm

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby victor_pv » Mon Feb 27, 2017 1:36 am

RogerClark wrote:Is it going to take much space to store the reservations ? e.g. do we need to just store something for each DMA channel e.g. whether its reserved or do we need to store a struct per channel ?

Is there just a way read back the information from the hardware. From what I recall it was possible to effectively parse the DMA registers to figure out quite a lot of information about their setup.


The registers can be read to check which peripherals have DMA requests enabled, but I dont think there is a function in the core for that.
Maybe as easy as writing functions that check if any peripheral has DMA requests enabled before enabling them for another peripheral.

What I do not remember of the top of my head, is if the peripherals requests are enabled in a peripheral register, or a DMA controller register. In the second case those the functions would have to check one by one all the peripherals that can possibly use that DMA channel.
If that's the case, may be better to set our own table. With a single byte per DMA channel is probably enough, there are 7+5 channels, so 12 total.
We could also just use 1 byte per DMA controller, and simply indicate if the channel is already in use or not with a bit.

Ollie
Posts: 151
Joined: Thu Feb 25, 2016 7:27 pm

Re: Planning to add callback to the SPI DMA functions (dmaSend, dmaTransfer...)

Postby Ollie » Mon Feb 27, 2017 4:41 am

I agree, that we will have many moons before we will use Arduino IDE for serious or semiserious F4/F7/H7 programming. In that frontier, the developers need to be aware of the capabilities and restrictions of different peripheral buses and the DMA channels in them.

I do propose that we are using STM terminology for these concepts. In that sense we need to identify that there are only few DMA channels and each of them have multiple streams. The streams in different channels can be active at the same time, but for the streams in a channel only one can be active at any point of time.


Return to “General discussion”

Who is online

Users browsing this forum: No registered users and 1 guest