Skip to main content
Vex1
Associate II
October 2, 2021
Solved

Why would DMA behave differently on two NUCLEO devices (F446RE/L432KC) ?

  • October 2, 2021
  • 14 replies
  • 2941 views

Hey,

I have both a NUCLEO-L432KC and a NUCLEO-F446RE. I'm using them to interface with an ili9163c based display.

When I hook up the display to the L432KC it works great and I get a single image that fills the whole display. However, I'm trying to transfer the project over to a F446RE but when I run the program on the F446RE it only draws on the top half of the display and repeats the image i.e. if you were to divide the display into 4 quarters it is only drawing in the top two quarters and each of the top quarters are a repeat of the image I want to fill the whole display. I've tried using the same clock speeds on the F446RE as the L432KC just to see if it was something to do with timing but it doesn't appear to be the case.

I suspect this has something to do with DMA because when I hook it up to a logic analyzer I can see the DMA signal (MOSI) has two repeating versions of the image. Any ideas why the DMA on one device would be behaving differently from the DMA on another?

I am using DMA in circular mode with a HAL_SPI_TxCpltCallback function.

Thanks.

This topic has been closed for replies.
Best answer by waclawek.jan

Difference between 'F446 and 'L432 which caught you here is data packing in SPI.

SPI is set to 8-bit frames.

DMA in 'L432 picks a halfword from memory, stores it into SPI which splits it to two 8-bit frames and transmits both.

DMA in 'F446 picks a halfword from memory, stores it into SPI, which ignores the upper 8-bit and transmits one 8-bit frame.

In 'L4 Cube, this is accounted for, that's why half of the Size parameter of HAL_SPI_Transmit_DMA() appears in CNDTR. So, the Size parameter means "number of transmitted SPI frames, whatever size of SPI frames you used. Cube's documentation might've said so as it's surprising and different from what other functions involving DMA do, but that's Cube for you. (Btw. this "automation" would fail would you use 32-bit transfers in DMA).

In 'F4 you need either to change SPI's frames to 16 bits (which would potentially mess with other functions using SPI, so you would need to switch the frame size between 8 and 16 bits dynamically, something I really won't recommend to a novice), or change DMA transfers to 8-bits.

JW

14 replies

waclawek.jan
Super User
October 2, 2021

The DMA units in 'F446 is different from that in 'L432, but the problem is not likely to be related directly to this fact.

> I am using DMA in circular mode

Why?

> with a HAL_SPI_TxCpltCallback function.

How? Describe this in detail.

 JW

Vex1
Vex1Author
Associate II
October 2, 2021
  • Why? (Circular mode)
    • I'm not really sure. I'm using a library I got off GitHub (https://github.com/Spirit532/ILI9163C_STM32_HAL_DMA). I suspect it's because if you want to really get the frame rates advertised then it becomes important but I'm not really using it to get insane frame rates.
    • When I run it in normal mode everything seems to work fine on the L432KC so again not sure what the point of it is. My understanding is that it's useful when you want to constantly send something over and over but that isn't really how it's implemented.
    • When I run the program in normal mode on the F446RE I still get the same issue.
  • How? Describe this in detail
    • You draw everything to a frame buffer. There is then a function that renders the frame buffer to the display. Within the render function there is a call to HAL_SPI_Transmit_DMA(&hspi1, frameBuffer, numberPixels (128*160) * 2). After this call, SPI_DMA_FL is set to 0 (custom flag not register flag i.e. a variable). There is then a function in main that is called HAL_SPI_TxCpltCallback().
// SPI transmit complete callback
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
	SPI_DMA_CNT--;
	if(SPI_DMA_CNT == 0) {
		HAL_SPI_DMAStop(&hspi1);
		SPI_DMA_CNT = 1;
		SPI_DMA_FL = 1;
	}
}
  • I'm really sure why you would put it into circular mode and then call HAL_SPI_DMAStop on every transmit complete event. Again, my understanding of the point of circular mode is that it doesn't stop after every transmit complete event it just starts transmitting again.
    • SPI_DMA_FL is initialized to 0 and SPI_DMA_CNT is initialized to 1.

The DMA settings screen for the 446RE has a FIFO setting which the L432KC doesn't have. I've just left it unchecked. Could this be what is causing the issue?

I should also mention I've had a look at the frame buffer during debug on both the F446RE and the L432KC and they are identical i.e. the buffer is good it's not the buffer that is getting corrupted.

Tesla DeLorean
Guru
October 2, 2021

How large is the buffer, how wide is the transfer?

DMA is typically limited to 65535 transactions.

SPI on L4​ likely better, with wider buffering/FIFO and width funnelling/management.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Vex1
Vex1Author
Associate II
October 2, 2021
  • How large is the buffer
    • I only have a single frame buffer at the moment. It's a 160 x 128 display - 16 bit colour - (160 x 128 x 2) = 40960 bytes.
  • How wide is the transfer
    • I'm not sure what this means. Could you please explain this more? Is this a function of the hardware or the software. Both the F446RE and the L432KC are on SPI1; which from the datasheet I understand to be the largest capacity SPI.

Tesla DeLorean
Guru
October 2, 2021

>>How wide is the transfer. I'm not sure what this means.

Byte, Half-Word or Word, the width of the IO operation on the SPI register address (peripheral) you're selected for the DMA

The Transfer Count on the DMA units is 16-bit wide, the total transactions limited to 65535 (give or take)

Count != Bytes for different widths.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
October 2, 2021

To avoid further speculations, read out and post content of relevant DMA and SPI registers just before enabling the DMA transfer, for both platforms.

JW

Vex1
Vex1Author
Associate II
October 3, 2021
  • F446RE
    • DMA2
      • LISR - 0x0
      • HISR - 0x0
      • LIFCR - 0x0
      • HIFCR - 0x0
      • S3CR - 0x6032d5e
      • S3NDTR - 0xa000 (40960)
      • S3PAR - 0x4001300c
      • S3M0AR - 0x2000003c
      • S3M1AR - 0x0
      • S3FCR - 0x20
    • SPI1
      • CR1 - 0x35c
      • CR2 - 0x0
      • SR - 0x2
      • DR - 0x0
      • CRCPR - 0x7
      • RXCRCR - 0x0
      • TXCRCR - 0x0
      • IS2CFGR - 0x0
      • I2SPR - 0x2

  • L432KC
    • DMA1
      • ISR - 0x0
      • IFCR - NULL
      • CCR3 - 0x35be
      • CNDTR3 - 0x5000 (20480)
      • CPAR3 - 0x4001300c
      • CMAR3 - 0x20000040
      • CSELR - 0x100
    • SPI1
      • CR1 - 0x35c
      • CR2 - 0x1700
      • SR - 0x203
      • DR - 0x0
      • CRCPR - 0x7
      • RXCRCR - 0x0
      • TXCRCR - 0x0

The first thing that strikes me is that the unit counts are different i.e. CNDTR3 (20480) vs S3NDTR (40960). I'm not really sure how that happens though since both function calls to HAL_SPI_Transmit_DMA() are passed the same variables - (hspi1, (unint8_t*) frameBuffer, BUFSIZE * 2). frameBuffer is declared as a uint16_t array of size BUFSIZE and BUFSIZE is 160 * 128.

HAL_SPI_Transmit_DMA(&DISP_SPI, (uint8_t*)frameBuffer, BUFSIZE*2);

Why would that produce two different values for how much data so send. They are both in half-word data width.

F446RE

  • MSIZE = 01 (16 bit half word)
  • PSIZE = 01 (16 bit half word)

L432KC

  • MSIZE = 01 (16 bit half word)
  • PSIZE = 01 (16 bit half word)
waclawek.jan
waclawek.janBest answer
Super User
October 3, 2021

Difference between 'F446 and 'L432 which caught you here is data packing in SPI.

SPI is set to 8-bit frames.

DMA in 'L432 picks a halfword from memory, stores it into SPI which splits it to two 8-bit frames and transmits both.

DMA in 'F446 picks a halfword from memory, stores it into SPI, which ignores the upper 8-bit and transmits one 8-bit frame.

In 'L4 Cube, this is accounted for, that's why half of the Size parameter of HAL_SPI_Transmit_DMA() appears in CNDTR. So, the Size parameter means "number of transmitted SPI frames, whatever size of SPI frames you used. Cube's documentation might've said so as it's surprising and different from what other functions involving DMA do, but that's Cube for you. (Btw. this "automation" would fail would you use 32-bit transfers in DMA).

In 'F4 you need either to change SPI's frames to 16 bits (which would potentially mess with other functions using SPI, so you would need to switch the frame size between 8 and 16 bits dynamically, something I really won't recommend to a novice), or change DMA transfers to 8-bits.

JW

Vex1
Vex1Author
Associate II
October 3, 2021

You absolute genius. Changing it from Half-word to Byte fixes it. Thank you so much. It would have taken me months to figure this out on my own. That site is also really cool (EFTON).

I wish I had more time to process all the stuff going on at the lower level of the STM32 chips but I'm just rushing from one thing to the next.