'STM32L4 SPI pointer related issue

I have a problem with STM32L476RG. I have 2 questions related to each other. I have a working solution, i just want to understund how it works.

I have a problem with writing data to SPIx_DR register. My code is following:

void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
    while(Len > 0)
    {
        //1. wait until TXE is set
        while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG)  == FLAG_RESET);
 
        //8 bit DS
        //1. load the data in to the DR
        *((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer; //typecasting to uint8_t
        Len--;
        pTxBuffer++;
    }
}

Above code is perfectly working. However i have problem with understunding the following line:

*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;

As far as i know STM32L4 series differs from STM32F4 series. I have a STM32F4 working code and it is different:

pSPIx->DR = *pTxBuffer;

When i write like that for my STM32L4 it sends 16 bits instead of 8 bits always no matter what. The difference should come from the fact that SPIx_DR is sensitive to the width of the data being written to it. However im not sure how to understund it and read it from reference manual(RM0351). Is it written in reference manual RM0351 page 1463(data packing)?

My questions are:

  1. Is it correct that STM32L4 is sensitive to the width of the data being written to it and where in can read about it(page in reference manual)? All further explanations welcome. I couldn't find it in the reference manual.

  2. This question is about C syntax. How to understund the following conversion(using SPI2 as an example):

*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;

pSPIx->DR is equal to *(0x4000380C) (SPI2_DR address = 0x4000380C).

So it should be equal to:

*((volatile uint8_t *)0x4000380C) = *pTxBuffer;

How to understund the first part *((volatile uint8_t *)0x4000380C)?

Hopefully someone can help to clarify this topic for me. Thank you for your time.

EDIT(adding logic analyzer pictures to make my problem more clear):

Im trying to describe my problem again.

When i use following function for sending SPI data with STM32L476RG:

void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
    while(Len > 0)
    {
        //1. wait until TXE is set
        while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG)  == FLAG_RESET);

        //8 bit DS
        //1. load the data in to the DR
        *((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer; //typecasting to uint8_t
        Len--;
        pTxBuffer++;
    }
}

Now im sending "Hello World" for example. Im sending 8 bits at a time. As you can see *pTxBuffer is written as uint8_t.

The output is following(correct):

8bits_1

8bits_2

Now when i use this function for sending SPI data with STM32L476RG:

void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
    while(Len > 0)
    {
        //1. wait until TXE is set
        while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG)  == FLAG_RESET);

        //8 bit DS
        //1. load the data in to the DR
        pSPIx->DR = *pTxBuffer; //typecasting to uint8_t
        Len--;
        pTxBuffer++;
    }
}

The output is following(wrong):

16bits_1

16bits_2

Now you can see the difference. The problem is the bottom code should work in theory. It is working for STM32F407 very well. Now what's the difference between the STM32F407 and STM32L476 regarding to SPI. I think the answer relies in STM32L476 reference manual RM0351 page 1463(data packing)?



Solution 1:[1]

dismantliing

*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;

gives

 uint8_t * temp1 = &pSPIx->DR;

then

 volatile uint8_t *temp2 = temp1;

then

 *temp2 = *pTxBuffer;

the purpose of these shenanigans is to force the write to be performed, its telling the compiler that it must write that value to the specified location. A compiler could decide not to do it if, for example it already wrote the same value there a few lines earlier. 'volatile' says to the compiler - really write to this becuase it has special hardware behind it.

Its almost the same as

 pSPIx->DR = *pTxBuffer;

but that doesnt have the 'volatile' qualifier, so a compiler could choose not to do it (or move the order around)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pm100