DMA vs CPU when sending SPI CMD, which one is more CPU efficient? - Page 1
Forum section: electronics / general

author: 3dgeo
author_rank: Frequent Contributor
timestamp: November 17, 2020, 01:07:10 pm
content: Hi,STM32F411 + 1Gbit NAND flash – to do file transfer MCU needs to send many commands (2-4bytes each, see picture below), one of them is to poll flash chip state (is it busy). Also CS pin needs to go low and high between commands else flash just response with same CMD data.My question is – is it worth using DMA on all SPI transfers or I should use it just for actual file data packets?To be specific – is it more CPU intensive to set up DMA and process interrupt or just simply send data and wait for the response.I need to save as much CPU time as possible.I did some DMA testing(pic below), but it does not represent CPU usage.Top row is CMU requests (except last data stream, that one is DMA request).Middle row is DMA requests with complete interrupt calls to send/receive next CMD.Ignore bottom row – it's different type CMU requests (except last data stream, that one is DMA).Bytes "05" and "C0" are "is flash busy" (circled blue) CMD, next byte after ("40" - not busy or "41" - busy) is a response that gets polled till chip responds with "40" (not busy), ignore other CMDs.P.S. for now I'm using STs HAL code, I know – it's not perfect, but it'll have to do for now.

author: Siwastaja
author_rank: Super Contributor
timestamp: November 17, 2020, 02:19:26 pm
content: AFAIK the STM32 HAL code for enabling DMA transfer is excessively slow; the last time I looked at it, it seemed to do a lot more than required for each transfer. If you get rid of the library, initializing the transfer is just some 2-3 register writes, depending on what parameters you need to change. Typically it's: set memory address (M0AR), clear status flags, and enable channel (write the full CR every time, don't do Read-Modify-Write) (3 register writes).This being said, if the particular SPI implementation allows 32-bit data register access, i.e., has FIFOs, not sure about that particular chip but at least the newer high-end MCUs do, so that one bus operation results in four 8-bit SPI words, then doing the transfer without DMA is even more efficient, at least up to some 8-12 bytes (2-3 register writes to the SPI data register). For example, a 4-byte operation would then be 1 register access; 5-, 6-, or 8-byte operations are 2 register accesses, and 7-, 9-, 10- or 12-byte operations are 3 register accesses.Do note though, if you write your command literals to memory first, for DMA to send them, that is also going to take some time. Performance is better if you have all possible commands (const) in memory, then just set M0AR to point to the right one. Then it's 3 register accesses with DMA. The plus side is, if you don't need to look at the reply, you can just let DMA write it to some dummy buffer. If you do non-DMA, you need to actually read out the SPI FIFO with CPU, spending cycles regarless of what you do with the data.So, it depends, but either way you choose, if you do it right, the difference will be negligible enough so do what is easier to do.You may want to try if you can make the STM32 SPI hardware nSS control do its magic; if it works out with that particular flash chip, you can offload toggling that pin on software. But IME, usually you have to resort to manual GPIO for nSS. I have had just one occasion where the STM32 SPI peripheral could do the nSS control in real life.Note, many chips have such low nSS falling edge -> first clock edge delay specification you can just do this:LO(NSS_GPIO);maybe_a_few_NOPs; // blocking delay; just a few clock cycles, not worth using timer interrupt.SPI->TXDR = 0xacdcabba;ISR(SPI_TX_FINISHED):HI(NSS_GPIO);

author: SiliconWizard
author_rank: Super Contributor
timestamp: November 17, 2020, 03:10:16 pm
content: Obviously, it all depends on the block size to transfer. Only you can answer this based on actual cases.And as Siwastaja said, if you're using STM32's HAL, the DMA functions are slow (because they want to cover a lot of cases, and set up registers without assuming their previous state), so they'd be worth it only for large blocks. Otherwise, you better code DMA transfers yourself. It's not that hard: since the HAL source code is provided, you can start from there and extract the minimum necessary for your needs.

author: 3dgeo
author_rank: Frequent Contributor
timestamp: November 17, 2020, 03:50:28 pm
content: Quote from: Siwastaja on November 17, 2020, 02:19:26 pmOh I know HAL libs are bloated, but that's not relevant at the moment – I can replace HAL DMA function with my own when time comes. Now I need to decide on coding strategy – using CPU which is simple or DMA (interrupts) which is in order of magnitude harder.From the test I already made tracking everything will be a nightmare, especially with few SPI devices so ATM I'm leaning towards using CPU for CMDs and DMA for actual data packets.Quote from: Siwastaja on November 17, 2020, 02:19:26 pmSTM32F411 has FIFO and I'm using it (4 bytes if I remember correctly).Quote from: Siwastaja on November 17, 2020, 02:19:26 pmYeah, using constant arrays for CMDs is a logical approach.I'm reading up to 38KB/file wich is 19 flash requests (2Kb per packet), that is I have to replicate sequence in a picture 19 times. Assuming I need to load file like this 20 to 25 times a sec I think that could make a difference... But, as I've said, code becomes waaaay more complicated.Quote from: Siwastaja on November 17, 2020, 02:19:26 pmCS pin toggling is not a problem – doing it via BSRR register so it's as fast as it could be (there are few SPI devices). Mentioned CS pin just to make note that it's not possible to put CS low before starting file transfer and set it to height after file transfer is completed (which I think is a bit odd).

author: Siwastaja
author_rank: Super Contributor
timestamp: November 18, 2020, 10:30:56 am
content: Coding strategy: pick the easier and more logical one. The performance difference is small, both ways can be done right or wrong.I would likely just pick the DMA way. Or maybe not; I think there is not much difference in either complexity or performance.Remember that you need to change the SPI control register to enable/disable DMA mode if you change between the modes on-the-fly.