Circular DMA support for SPI on STM32L4 family

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
User avatar
RWLTOK
Posts: 47
Joined: Thu Dec 14, 2017 7:24 pm

Circular DMA support for SPI on STM32L4 family

Post by RWLTOK » Sun Mar 01, 2020 6:52 am

I would like to propose changes to the SPI.init() pyb module signature in order to add circular DMA functionality to the SPI module. The STM32 family is quite broad. I am working with the STM32L452RE specifically, but what I am discussing should apply to the STM32L4 family as the DMA controller is common. This would be implemented differently on the Pyboard D for instance as its DMA controller has double buffer mode.

Here is what I am proposing:

SPI.init() - Add the parameters:

callback - called when the SPI transfer is completed on a single transfer and repeatedly for circular dma.
callbackhalf - called when half of a transfer is completed on a single transfer and repeatedly for circular dma.
callbackerror - called if there was a transfer error
dmamode - NORMAL or CIRCULAR

I am not sure what to do with send, recv, send_recv. Should these be modified to take a parameter, which specifies whether the function returns immediately after the transfer is started. Otherwise, the default blocking behavior would be performed.

Feedback please as I would like to implement this.

Thanks

Rich

PS: There is some discussion on a similar topic located here https://github.com/micropython/micropython/issues/5053

User avatar
jimmo
Posts: 1440
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Circular DMA support for SPI on STM32L4 family

Post by jimmo » Mon Mar 02, 2020 10:36 am

RWLTOK wrote:
Sun Mar 01, 2020 6:52 am
PS: There is some discussion on a similar topic located here https://github.com/micropython/micropython/issues/5053
I see you've already posted this on that bug too, but perhaps the best way to proceed is to write a documentation PR that explains the new API, and then it can be discussed there.

Note that pyb.SPI is fairly much deprecated in favour of machine.SPI (but not all the functionality is available yet on machine.SPI). But I would probably recommend proposing this for machine.SPI rather than pyb.SPI.

User avatar
RWLTOK
Posts: 47
Joined: Thu Dec 14, 2017 7:24 pm

Re: Circular DMA support for SPI on STM32L4 family

Post by RWLTOK » Tue Mar 03, 2020 2:13 am

Thanks for the reply, jimmo. Okay on the machine.SPI. If you happen to have any thoughts on:
I am not sure what to do with send, recv, send_recv. Should these be modified to take a parameter, which specifies whether the function returns immediately after the transfer is started? Otherwise, the default blocking behavior would be performed.
I am going to be working on this in the mean time. I find rolling up my sleeves and getting my hands dirty will give me more insight on a preferred way of doing this. I think the issue will be implementing it in such a way to be forward compatible with some of the bigger more capable CPUs (with more DMA features).

Thanks again.

Rich
jimmo wrote:
Mon Mar 02, 2020 10:36 am
RWLTOK wrote:
Sun Mar 01, 2020 6:52 am
PS: There is some discussion on a similar topic located here https://github.com/micropython/micropython/issues/5053
I see you've already posted this on that bug too, but perhaps the best way to proceed is to write a documentation PR that explains the new API, and then it can be discussed there.

Note that pyb.SPI is fairly much deprecated in favour of machine.SPI (but not all the functionality is available yet on machine.SPI). But I would probably recommend proposing this for machine.SPI rather than pyb.SPI.

User avatar
jimmo
Posts: 1440
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Circular DMA support for SPI on STM32L4 family

Post by jimmo » Tue Mar 03, 2020 2:52 am

RWLTOK wrote:
Tue Mar 03, 2020 2:13 am
If you happen to have any thoughts on:
I haven't thought about this too much but I guess off the top of my head two high-level thoughts:

- One precedent is sockets which can be blocking or non-blocking. But it's the socket, not the operation that is (non-) blocking. So I guess the equivalent would be that the SPI peripheral is in (non-)DMA mode.

- How do you get notified that the write is complete and it's safe to re-use the buffer?

- You need to be careful with the MicroPython GC and the buffers. Obviously the user has to know not to mess with the buffer they've already passed to a non-blocking write, but also it has to not be GC'ed. e.g. the following example:

Code: Select all

spi = machine.SPI(...DMA mode..)
while True:
 buf = bytearray(1000)
 ... do work to populate buf
 ... wait for previous write to complete?
 spi.write(buf)
(This should be fairly easy to manage with root pointers though).

I think possibly the answer to many of these questions involves asyncio. Designing a nice DMA interface around asyncio would be really need (and a good demonstration of how powerful it is).
This is possibly why DMA has been put off for this long...there's lots of things that need to come together to make it work really well.

User avatar
RWLTOK
Posts: 47
Joined: Thu Dec 14, 2017 7:24 pm

Re: Circular DMA support for SPI on STM32L4 family

Post by RWLTOK » Wed Mar 04, 2020 4:36 am

@jimmo,

I added PR proposal comments for SPI dma modes #5721 (https://github.com/micropython/micropython/pull/5721)

Thanks for prompting me.

Rich

PS: my github handle is rlourette. I should change my handle on this forum to match, but I don't know if I can do that.
RWLTOK wrote:
Tue Mar 03, 2020 2:13 am
Thanks for the reply, jimmo. Okay on the machine.SPI. If you happen to have any thoughts on:
I am not sure what to do with send, recv, send_recv. Should these be modified to take a parameter, which specifies whether the function returns immediately after the transfer is started? Otherwise, the default blocking behavior would be performed.
I am going to be working on this in the mean time. I find rolling up my sleeves and getting my hands dirty will give me more insight on a preferred way of doing this. I think the issue will be implementing it in such a way to be forward compatible with some of the bigger more capable CPUs (with more DMA features).

Thanks again.

Rich
jimmo wrote:
Mon Mar 02, 2020 10:36 am
RWLTOK wrote:
Sun Mar 01, 2020 6:52 am
PS: There is some discussion on a similar topic located here https://github.com/micropython/micropython/issues/5053
I see you've already posted this on that bug too, but perhaps the best way to proceed is to write a documentation PR that explains the new API, and then it can be discussed there.

Note that pyb.SPI is fairly much deprecated in favour of machine.SPI (but not all the functionality is available yet on machine.SPI). But I would probably recommend proposing this for machine.SPI rather than pyb.SPI.

User avatar
RWLTOK
Posts: 47
Joined: Thu Dec 14, 2017 7:24 pm

Re: Circular DMA support for SPI on STM32L4 family

Post by RWLTOK » Wed Mar 18, 2020 4:42 pm

@jimmo,

I have fully implemented my proposal and tested both on the PyBoardv1.1 and the STM32L452RE_P NUCLEO board. As the code is portable across the families, it should work on most STM32 board. It works well. All the code is in my fork. I am having trouble with foreground processing of the data while all the interrupts are going on as I am doing most of the processing with a scheduled function. I may have to try the fastio asynchio library to see if that helps with all the context switching.

Rich

Post Reply