cancel
Showing results for 
Search instead for 
Did you mean: 

SPI by hand/prerequisites for SPI

mdr
Associate

Hi,

I've been trying to adapt the current SPI driver in RIOT OS to support the U5 series(STM32U585AI), due to my lack of success I've been trying to sidestep RIOT for a moment and try to do must of the setup manually. But so far I have not been able to get SPI3 to output anything, not even an SCLK signal, leading me to believe that I've just missed something simple like some clock domain etc. 

 

My approach so far:

  1. enable HSI clock
  2. enable VddIO2
  3. select HSI timer for SPI3
  4. enable SPI3 peripheral
  5. enable GPIO ports B & G
  6. reset SPI3 CR1
  7. write SPI3 CFG1, CFG2, CR2
  8. set SPE, SSI bits in CR1
  9. set CSTART in CR1
  10. read write to TXDR, RXDR

However step 8, specifically setting the SPE is where the problem becomes apparent, the SPE bit does not stay enabled. Does anyone have any hints on where to look to get this running?

 

Snippiet I've been using so far, spi_init* and stmclk_enable* are provied by RIOT:

 

 

  stmclk_enable_hsi();
  stmclk_enable_lfclk();
  // spi_init(0);
  // spi_init_pins(0);
  // spi_acquire(0, spi_config[0].cs_pin, SPI_MODE_0, SPI_CLK_10MHZ);
  // spi_transfer_bytes(0, spi_config[0].cs_pin, false, "Hello World", NULL,
  // strlen("Hello World")); spi_release(0);

  // enable vddio2
  PWR->SVMCR |= PWR_SVMCR_IO2SV;

  // set SPI3 clk to HSI
  RCC->CCIPR3 &= ~RCC_CCIPR3_SPI3SEL_Msk;
  RCC->CCIPR3 |= RCC_SPI3CLKSOURCE_HSI;
  assume(RCC->CCIPR3 & RCC_SPI3CLKSOURCE_HSI);

  // enable peripheral
  RCC->APB3ENR |= RCC_APB3ENR_SPI3EN;
  assume(RCC->APB3ENR & RCC_APB3ENR_SPI3EN);

  RCC->APB3RSTR &= ~RCC_APB3ENR_SPI3EN;
  // enable GPIO ports
  RCC->AHB2ENR1 |= RCC_AHB2ENR1_GPIOGEN | RCC_AHB2ENR1_GPIOBEN;
  assume(RCC->AHB2ENR1 & (RCC_AHB2ENR1_GPIOGEN | RCC_AHB2ENR1_GPIOBEN));

  spi_init_pins(0);
  assume(spi_init_cs(0, spi_config[0].cs_pin) == SPI_OK);

  const char *MSG = "Hello World";
  const int MSG_LEN = strlen(MSG);
  volatile char recv_buf[MSG_LEN];

  // reset SPI
  SPI3->CR1 = 0;
  {
    // SPE must be 0 to write CFG{1,2}
    assume((SPI3->CR1 & SPI_CR1_SPE) == 0);
    SPI3->CFG1 = 0b1100000000000000111 | (3 << 29);
    SPI3->CFG2 = 0b1000100010000000000000000000000;

    SPI3->CR2 = (uint16_t)MSG_LEN;
  }
  SPI3->CR1 |= SPI_CR1_SPE | SPI_CR1_SSI;
  assume(SPI3->CR1 & SPI_CR1_SPE);
  SPI3->CR1 |= SPI_CR1_CSTART;

  volatile uint8_t *TXDR = (uint8_t *)&SPI3->TXDR;
  volatile uint8_t *RXDR = (uint8_t *)&SPI3->RXDR;

  for (uint16_t rx_rem = strlen(MSG), tx_rem = strlen(MSG);
       rx_rem > 0 && tx_rem > 0 && !(SPI3->SR & SPI_SR_EOT);) {
    if (SPI3->SR & SPI_SR_TXP && tx_rem) {
      *TXDR = MSG[MSG_LEN - tx_rem];
      tx_rem--;
    }
    if (SPI3->SR & SPI_SR_RXP && rx_rem) {
      recv_buf[MSG_LEN - rx_rem] = *RXDR;
      rx_rem--;
    }
  }
  while (!(SPI3->SR & SPI_SR_EOT)) {
  }

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Imen.D
ST Employee

Hello @mdr and welcome to the Community 🙂

It seems you have encountered the condition when "SPE may not be cleared upon MODF event".

Please check the STM32U585xx errata sheet  (2.22.5 section) for more details.

ImenD_0-1712664810487.png

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

View solution in original post

3 REPLIES 3
Imen.D
ST Employee

Hello @mdr and welcome to the Community 🙂

It seems you have encountered the condition when "SPE may not be cleared upon MODF event".

Please check the STM32U585xx errata sheet  (2.22.5 section) for more details.

ImenD_0-1712664810487.png

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
gbm
Lead III

You need to set GPIO AFR and MODER registers correctly to route SPI signals to port pins. See the RefMan and Data Sheet AFN table.

Thanks for the swift reply, putting an 

while (SPI3->SR & SPI_SR_MODF) { SPI3->IFCR |= SPI_IFCR_MODFC;}

before writing the SPE bit solved the issue 🙂