cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H745 - SPI doesn't transmit any data. - SOLVED

Hexagonale
Associate II

SOLVED - look at edit below!

I am trying to implement SPI on nucleoH745ZI-Q without HAL or any kind of driver, I wrote my own registers pointers and functions like digitalWrite, pinMode or printf. I set up RCC, GPIO and SPI registers (all set, checked with debugger). But I can't get it work. I tried non-interrupt method (sending all data in loop - commented section) - with no luck. Then I tried interrupt method, I literally copied config from STM32CubeH7 Examples (checked registers with debugger and put it in my code), with no luck again. Always there is no sign of life on lines.

What am I doing bad?

Q&A:

  • I set up peripheral clock (checked with debugger)
  • I set up Alternate Functions and GPIO Clocks (checked with debugger)
  • Kernel clock is getting to SPI block (checked with MCO1 - same source)
  • Interrupt is called (checked with breakpoint)

main.c

int main(void) {
  initClock(); // 480MHz / 240MHz
  initSPI();
 
  /* Infinite loop */
  while (1) ;
}
 
void SPI(void) {
  if(SPI1->SR != 2) printf("%x\n\r", SPI1->SR); // Debug
  if(SPI1->SR & 2) SPI1->TXDR = 'abcd'; // Write data to FIFO if there's place
  if(SPI1->SR & 8) SPI1->IER &= ~2; // End of Transmission - disable TXP interrupt
}
 
uint32_t (* const vector_table[])
__attribute__ ((section(".vectors"))) = {
  (uint32_t *) 0x20020000, // 0x000 Stack Pointer
  (uint32_t *) main, // 0x004 Reset
  (uint32_t *) hardFault, // 0x008 Non maskable interrupt
  ...
  (uint32_t *) SPI, // 0x0CC SPI1
  ...
}

spi.c

void initSPI() {
  /**** GPIO ****/
  pinMode(A4, ALTERNATE);
  pinMode(A5, ALTERNATE);
  pinMode(A6, ALTERNATE);
  pinMode(B5, ALTERNATE);
  PORTA->AFRL |= 0x5550000;
  PORTB->AFRL |= 0x500000;
  PORTA->OSPEEDR |= 0x3F00;
  PORTB->OSPEEDR |= 0xC00;
 
  RCC->APB2ENR |= (1 << 12); // Enable SPI clock
  SPI1->CFG1 = 0x60000007; // MBR = 128 (375kHZ), 8-bits frame size
  SPI1->CFG2 = 0xA4400000; // AFControl, SSO Enable, Software SS, Master mode
  SPI1->CRCPOLY = 0x107; // CRC Polynomial
  SPI1->CR2 = 8; // Data size (8 bytes = 8 frames by 8 bits)
  SPI1->IFCR = (1 << 9); // Mask Mode Fault (why it's showing up?)
  enableIRQ(35); // Enable SPI Interrupt
  SPI1->IER = 0x76F; // Enable Interrupts
  SPI1->CR1 = (1 << 12); // SS Enable
  SPI1->CR1 |= 1; // Enable SPI
  SPI1->CR1 |= (1 << 9); // CSTART - Start transmission
 
  /**** Non Interrupt - tried, not worked ****/
//delay(50);
//
//int a[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
//int i = 0;
//while(i < 8) {
//  if(SPI1->SR & 2) {
//    *(uint8_t *)SPI1->TXDR = a[i++];
//    printf("%x\n\r", SPI1->SR);
//  }
//}
}

Analyzer Capture

0690X00000BvSgSQAV.jpg

EDIT:

Finally i was able to get it work. First of all On my lovely nucleo board SPI_CS are marked incorrectly (PD14 instead of PA4) so there was first mstake. What i've done is I rewrote all configuration from scratch and then it worked. I think that error was accessing TXDR by 8bit - 32bits works now. I changed also Frame size. Anyway There is part of my new code fell free to use it if You like.

spi.c

void initSPI() {
  /**** GPIO ****/
  pinMode(A4, ALTERNATE);
  pinMode(A5, ALTERNATE);
  pinMode(A6, ALTERNATE);
  pinMode(B5, ALTERNATE);
  PORTA->AFRL |= 0x5550000;
  PORTB->AFRL |= 0x500000;
  PORTA->OSPEEDR |= 0x3F00;
  PORTB->OSPEEDR |= 0xC00;
 
  RCC->APB2ENR |= (1 << 12);	// Enable SPI clock
  SPI1->CFG1 = 0x60070067;	// MBR = 128 (375kHZ), 8-bits crc, 8-bits frame size, 4 frames packet size
  SPI1->CFG2 = 0x34400000;	// SSO Active High, SSO Enable, Software SS, Master mode
  
  SPI1->CR2 = 8;				// Data size (8 bytes = 8 frames by 8 bits)
  enableIRQ(35);			// Enable SPI Interrupt
  SPI1->IER = 0x76F;		// Enable Interrupts
  SPI1->CR1 = (1 << 12) | 1;	// Enable SS & SPI
  SPI1->CR1 |= (1 << 9);		// CSTART - Start transmission
 
  /**** Non Interrupt ****/
  /*int i = 0;
  while(i < 8) {
    if(SPI1->SR & 2) {
      if(i++ % 2 == 0) SPI1->TXDR = 0xAAAAAAAA;
      else SPI1->TXDR = 0x55555555;
      printf("%x %x\n\r", SPI1->SR, SPI1->CR1);
    }
 
    if(SPI1->SR & 8) {
      printf("done");
      SPI1->CR1 &= ~(1 << 12);
      break;
    }
  }*/
}

main.c

int main(void) {
  initClock(); // 480MHz / 240MHz
  initSPI();
  while(1);
}
 
void SPI(void) {
  if(SPI1->SR & 2) SPI1->TXDR = 'elo!';  // Write data to FIFO if there's place
  if(SPI1->SR & 8) {
    printf("done");
    SPI1->IFCR = 0xFF8;  // Reset SR
    SPI1->IER = ~2;  // End of Transmission - disable TXP Interrupt
    SPI1->CR1 &= ~(1 << 12);  // Disable NSS
  }
}
 
uint32_t (* const vector_table[])
__attribute__ ((section(".vectors"))) = {
  (uint32_t *) 0x20020000, // 0x000 Stack Pointer
  (uint32_t *) main, // 0x004 Reset
  (uint32_t *) hardFault, // 0x008 Non maskable interrupt
  ...
  (uint32_t *) SPI,  // 0x0CC SPI1
  ...
}

Analyzer Capture:0690X00000BvTBpQAN.jpg

9 REPLIES 9
S.Ma
Principal

H7 complexity is higher than most other STM32, so try to run a modified example of HAL Nucleo board first, use debugger to inspect the peripheral registers (GPIO, RCC, SPI) and then compare with your direct coding.

I tried it. Registers seems same, only difference is that my code just feeds FIFO and there is nothing on the lines :\

As not experienced in F7/H7 I would just try to write DR byte by byte, waiting for the RXNE flag set before sending next byte,

With some timing vision, remember that a SPI master transaction completion is monitored by RNXE not TXE. Make sure your main() ends up into a while(1) loop to let the code not stop while SPI is sending. Check also the SPI clock source is present

Tath's what i've tried and did not work, but anyway thanks!

turboscrew
Senior III

I'm not sure about it, but it looks like there is something wrong with the CS configuration. Maybe you could use some other GPIO for CS, handle that with SW and leave the HW NSS-pin not connected. At least the HW NSS didn't work too well in older chips. The problem was that if the SPI somehow "saw" that the NSS was in different state than what it expected, it gave mode error and switched to slave. And remember, even if the GPIO is programmed as output, the input is still attached.

You can use the HW NSS pin for SW CS, but you need to be careful with the configuration.

This NSS pin is not so big problem. Main issue is data transfer.

turboscrew
Senior III

It is, if chip select causes the SPI to switch into slave mode and stop clocking.

BTW, what was the solution?

I don't know for sure but i rewrote CFG1 and 2 and changed TXD register access to 32-bit (before i was casting it to 8bit ptr)

DM.21
Associate II

Hey,

there were 2 places with mistakes

  1. SPI1->IFCR = (1 << 9); // Mask Mode Fault (why it's showing up?)

You get MODE FAULT because you first set SPI as master, but SSI is not SET.

I do not understand why ST made MASTER set outside CR1.

and second mistake was this:

// *(uint8_t *)SPI1->TXDR = a[i++];

you cast TXDR value to pointer and then write to its place 😉

it should have been:

*(uint8_t *)&SPI1->TXDR = a[i++];