Skip to main content
Visitor II
December 1, 2023
Solved

Having trouble with NSS control using STM32H742VIT6

  • December 1, 2023
  • 4 replies
  • 3264 views

Hello,

I've configured SPI1 on STM32H742VIT6 connected to pins PA4-7 using AF5.

Here is a dump of the relevant SPI1 registers:

SPI1->CR1 = 00000001
SPI1->CR2 = 00000000
SPI1->CFG1 = 70000007
SPI1->CFG2 = 20400000
SPI1->SR = 00001002

The MCU should be the SPI master and I am trying to control the NSS output as follows (NSS is on PA4): 

__INLINE void bsp_spi_nss_assert(void)
{
 GPIOA->BSRR = GPIO_BSRR_BR4;
}

__INLINE void bsp_spi_nss_release(void)
{
 GPIOA->BSRR = GPIO_BSRR_BS4;
}

I find that the NSS signal is asserting though and remains low forever (so I don't think the bsp_spi_nss_release function is working).
Can someone recommend anything to try which I might be missing?

Thanks!
-Brian

    This topic has been closed for replies.
    Best answer by briankaz

    Hello,

    I solved one problem I was having.  I understood that the RXWNE flag is only set after I have transmitted 4 bytes.  Since I am trying to do SPI send/receive one byte at a time, the correct flag to use to initiate a read seems to be RXP instead of RXWNE.  So I have modified my bsp_spi_read_byte() function as follows:

    __INLINE uint8_t bsp_spi_read_byte(void)
    {
     uint8_t data;
     while (!(SPI1->SR & SPI_SR_RXP));
     data = *(uint8_t *) &SPI1->RXDR;
    		bsp_spi_nss_release();
     return data;
    }

    So far this is working better.  I still need to debug some final problems related to reading from SD card.
    Thanks,
    -Brian 

    4 replies

    Super User
    December 1, 2023

    There are two methods of controlling the NSS/CS pin on SPI:

    • Assign it to the SPI and let the SPI peripheral handle it (this is how you have it configured)
    • Assign it as a GPIO pin and control it manually (this is how you're trying to use it)

    I'd recommend the latter. Assign it as a GPIO, set it low when accessing the slave, and high after transaction is complete.

    If it's assigned to the SPI, the BSRR register does nothing.

    briankazAuthor
    Visitor II
    December 1, 2023

    Thanks!  Part of the problem I'm having is that I'm porting some SPI code from STM32F373XC to my current STM32H7* project.  So a lot of the SPI configuration settings are different.  The STM32F3* project has the NSS configured as a GPIO as you suggested, but then it configures NSS for software control like this:

     /* Manage NSS in software */
     SPI2->CR1 |= SPI_CR1_SSM;
     SPI2->CR1 |= SPI_CR1_SSI;

    I tried to do this (of course with the difference that SSM on the STM32H7* is in the SPI_CFG2 register) but it doesn't seem to work.

    I have a lot of nested functions doing disk I/O and it seems the software control with NSS configured as GPIO works well on STM32F3* -- however, when I probe the SSM signal from STM32H7* it just remains high after power-up.

    Do you think I have to re-write all of the disk access functions to explicitly assert and de-assert NSS?  I didn't write these functions so I'm a bit apprehensive here...

    Thanks!
    -Brian

    Super User
    December 1, 2023

    The pin needs to be configured as a GPIO output. This means setting the appropriate bits in the GPIO->MODER register. This is not part of the SPI configuration at all--it doesn't matter what you put for SSM as the SPI won't be driving the pin.

    If you still can't get it, print out and show the GPIOA->MODER registers after configuration. It should reflect that PA4 is in output mode.

    > Do you think I have to re-write all of the disk access functions to explicitly assert and de-assert NSS?  I didn't write these functions so I'm a bit apprehensive here...

    If they're already there for the F3, no need for you to rewrite them. The GPIO->BSRR register works the same on both chips.

    briankazAuthor
    Visitor II
    December 1, 2023

    OK, I tried to change my TX function to explicitly assert and release NSS.  It looks like this now:

    __INLINE void bsp_spi_write_byte(uint8_t data)
    {
     
     /* *(uint8_t *) &SPI1->DR casting is necessary to force sending ONLY 8-bits to the peripheral,
     otherwise it keeps casting uint8_t to uint16_t again and stores additional 0x00 value in
     the TX FIFO */
    	bsp_spi_nss_assert();
    	SPI1->CR1 |= SPI_CR1_CSTART;
     *(uint8_t *) &SPI1->TXDR = data;
    	while (!(SPI1->SR & SPI_SR_TXC));
    	bsp_spi_nss_release();
    }

    For some reason now though, the (SPI1->SR & SPI_SR_TXC) condition is never getting realized so I'm getting stuck in the while loop.

    I realize that I will want to leave NSS asserted if the next step is going to be reading a byte back from the memory card, but I need to get the TX to work before fixing that.

    It seemed like configuring NSS to be controlled from the SPI allowed the TX to work, but there are some places I need to explicitly assert or release NSS and, as you mentioned, I couldn't do that with NSS controlled from SPI.

    Super User
    December 1, 2023

    Go back to the code you had at the start of the thread where it was working.

    The only thing you should change from that is configuring PA4 as a GPIO output.

    Super User
    December 2, 2023

    Try this. Works for me on H723 just now.

    You might be getting a MODF error with your code, although your register printouts at the first post don't show it.

     SPI_TypeDef* SPIx = SPI1;
     RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
     SPIx->CFG1 |= (SPI_CFG1_MBR_0 | SPI_CFG1_MBR_1 | SPI_CFG1_MBR_2);
     SPIx->CFG1 |= (7U << SPI_CFG1_DSIZE_Pos);
     SPIx->CR1 |= SPI_CR1_SSI;
     SPIx->CFG2 |= SPI_CFG2_MASTER | SPI_CFG2_AFCNTR | SPI_CFG2_SSM;
     SPIx->CR1 |= SPI_CR1_SPE;
     SPIx->CR1 |= SPI_CR1_CSTART;
    
     while (!(SPIx->SR & SPI_SR_TXC));
     *(volatile uint8_t*)&SPIx->TXDR = 0x42;
     while (!(SPIx->SR & SPI_SR_TXC));
     *(volatile uint8_t*)&SPIx->TXDR = 0x69;
     while (!(SPIx->SR & SPI_SR_TXC));
     *(volatile uint8_t*)&SPIx->TXDR = 0x42;
     while (!(SPIx->SR & SPI_SR_TXC));
     *(volatile uint8_t*)&SPIx->TXDR = 0x69;
     while (!(SPIx->SR & SPI_SR_TXC));

     

     If that doesn't work, show your registers with your latest code. Should be this at the end of the above sequence:

    TDK_0-1701483758752.png

     

    briankazAuthor
    Visitor II
    December 2, 2023

    Thanks!  Here are the results for the registers:

    CR1 = 00001201
    CR2 = 00000000
    CFG1 = 70000007
    CFG2 = 84400000
    IER = 00000000
    SR = 00009007
    IFCR = 00000000
    TXDR = 00000000
    RXDR = 00000000
    CRCPOLY = 00000107
    TXCRC = 00000000
    RXCRC = 00000000
    UDRDR = 00000000
    I2SCFGR = 00000000

     Looks like the same as what you got except for SR.  Here are the bits I have set that are cleared in your example:
    1) RXWNE = 1
    2) DXP = 1
    3) RXP = 1

    The SD card was present when I ran your code so it's possible that it had an affect on these results...

    Super User
    December 2, 2023

    Looks like it's working then. My debugger is reading RXDR which is the difference in SR.

    Technical Moderator
    December 5, 2023

    Hello All

    It seems there is data in the RX FIFO that has not been read yet. However, the DXP and RXP bits being set indicate that the SPI peripheral is currently receiving data. 

    Have you tried without using SD Card?