cancel
Showing results for 
Search instead for 
Did you mean: 

Use DMA with SPI acting as a (simple) shift register?

JShel.1
Associate II

I've (sort of) found out a way to store GPIO states in memory with DMA (parallel data input from a 74HC595 shift register, because the STM32F103Cx doesn't have 4 SPI peripherals) and I want to output that same data via SPI in a similar manner, except in higher frequency bursts triggered by timer interrupts (the output is synced to the input.) I also have 2 of these inputs/outputs (16 pins for the parallel input, 2 SPI pins for the output) that would need to work at the same time.

It would be something like DMA request -> memory byte transfer to SPI shift register buffer -> transfer buffer into working shift register -> increment memory address -> shift out byte at slave clock frequency -> repeat process until desired amount of bytes are shifted out and transfer complete interrupt flag is set, interrupt code is executed.

The SPI data register is 16 bits wide, assuming from what the reference manual says, 8 bits for Tx and 8 bits for Rx. It doesn't indicate whether Tx is the 8 MSB's or LSB's. Whichever it is, that will be the target register for the memory-to-peripheral DMA transfer.

I presume that I configure what DMA does in main(), and it's autonomous except for interrupts.

Also, I need the GPIO input buffering to generate a half-transfer interrupt so the SPI output knows when to start working. ST's HAL functions are making no sense to me, so I want to stick with using the registers directly.

(I'm also confused at the lack of a "half-transfer interrupt" or a "transfer complete interrupt" checkbox for each of the DMA channels in the NVIC section in STM32CubeIDE, to generate code in stm32f1xx_it.c. Why isn't that a thing?)

3 REPLIES 3
S.Ma
Principal

From STM32F103 (7 yo) peripherals have improved in newer families.

If you need more SPI, consider using USART with CK pins, implement one SPI as SW bitbang while the others are performing through HW, or use a newer STM32 (STM32F437 has 6 SPI and USARTS) which even price and footprint maybe smaller than use 16 bit bus through external chips.

In the STM32L4R with DMA MUX, DMA can be triggered by various events.

Now I let others give a better answer to you.

To me I would contemplate the extra development effort (time and cost) vs the product delta cost for a yearly production, if this is a commercial project,

berendi
Principal

> the STM32F103Cx doesn't have 4 SPI peripherals

Yes it does. The S in USART stands for synchronous, they are capable of SPI master-only operation.

My application isn't of commercial scope, I'm just using a generic STM32F103 "blue pill" board for hobby purposes (also because it's cheap, plentiful and has plenty of support online for my purposes.) (I also like squeezing everything out of the blue pill's limitations.)

When I look at the USART description in the reference manual, there's all this jargon about characters, and how it is handled (like commands.) (I'm a total noob at that kind of stuff, unfortunately.) If I can cut all that out and use the USART peripherals just like the SPI shift registers, then I would have gone with that instead of 74HC595 shift registers for the input.

Other than that, I just need to know which bits of the SPI registers are for transmitting, and how to set up half-transfer and transfer complete interrupts (functions) for DMA.

I do appreciate the feedback.

EDIT: I'm also confused as to why there's handlers for both DMA pointing to the SPI peripheral, and HAL_SPI_Transmit_DMA. I want 2 SPI streams at the same time, and this makes me think that an interrupt has to be generated every time the single-byte SPI shift register buffer is empty...

I also want this (single byte transfer) to repeat a certain amount of times (to an array, declared by the data buffer pointer?) before pausing. Is that where the "amount of data to transfer" comes in?