cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Sending and Receiving Extra Bytes

vbk22398
Senior

I doing bare metal coding for STM32L496ZGT6. Now in SPI, extra bytes are sent. There are only 4 Registers in SPI but unable to resolve the issue. Below is my code

NOTE:
I am using Aardwark Total Phase Control Center software for debugging. I am attaching the related images. The Chip select to be handled by the SPI Hardware. 

Data sheet is DS11585.

#include "lib_headers.h"

#define SPI1EN (1U << 12)
#define GPIOAEN (1U << 0)
#define SR_TXE (1U << 1)
#define SR_RXNE (1U << 0)
#define SR_BSY (1U << 7)

const char write_data[] = "ABCD"; // Data to write (4 bytes)
char read_data[5] = {0}; // Buffer to store received data (4 bytes + null terminator)
uint8_t reg_address = 0x01; // Example register address

void delay(volatile uint32_t count) {
while (count--);
}

void spi1_transmit(uint8_t *data, uint32_t size) {
uint32_t i = 0;
while (i < size) {
while (!(SPI1->SR & SR_TXE)) {}
SPI1->DR = data[i++];
}
while (!(SPI1->SR & SR_TXE)) {}
while (SPI1->SR & SR_BSY) {}
(void)SPI1->DR;
(void)SPI1->SR;
}

void spi1_receive(uint8_t *data, uint32_t size)
{
while (size--) {
SPI1->DR = 0xFF;
while (!(SPI1->SR & SR_TXE)) {}
while (!(SPI1->SR & SR_RXNE)) {}
*data++ = SPI1->DR;
}
}

int main(void)
{
set_sysclk_to_msi(MSI_16MHZ);
uart2_config(9600);
Initialize_LED_GPIOs();
/* Enable GPIO clocks */
RCC->AHB2ENR |= GPIOAEN | (1 << 1); // Enable GPIOA and GPIOB
/* Enable SPI1 clock */
RCC->APB2ENR |= SPI1EN; // SPI1 clock enable
// Configure PA5, PA6, PA7 for SPI1 (SCK, MISO, MOSI)
GPIOA->MODER &= ~((3 << 10) | (3 << 12) | (3 << 14)); // Clear modes
GPIOA->MODER |= (2 << 10) | (2 << 12) | (2 << 14); // Set alternate mode
GPIOA->AFR[0] |= (5 << 20) | (5 << 24) | (5 << 28); // AF5 for SPI1
// Configure PA4 for SPI1_NSS (CS) (This can remain as an alternate function pin)
GPIOA->MODER &= ~(3 << 8); // Clear mode for PA4
GPIOA->MODER |= (2 << 8); // Set PA4 to alternate function mode
GPIOA->AFR[0] |= (5 << 16); // AF5 for SPI1_NSS

SPI1->CR1 = 0; // Clear all settings
/* Disable SPI before configuration */
SPI1->CR1 &= ~(1 << 6); // Disable SPI
/* Configure SPI1 in master mode */
SPI1->CR1 |= (0 << 0) | (0 << 1); // CPOL = 0, CPHA = 0
SPI1->CR1 |= (3 << 3); // Baud rate (fPCLK/16) for 1 MHz
SPI1->CR1 |= (0 << 10); // Full duplex communication
SPI1->CR1 |= (0 << 13); // CRC disabled
SPI1->CR1 &= ~(1U << 10); // Enable full duplex
SPI1->CR1 &= ~(1U << 7); // Set MSB first
SPI1->CR1 |= (1U << 2); // Set mode to MASTER
SPI1->CR1 &= ~(1U << 11); // Set 8-bit data mode
/* Configure frame size and RX FIFO threshold */
SPI1->CR2 = 0;
SPI1->CR2 |= (1 << 2); // SSOE = 1 (SS output enable)
SPI1->CR2 |= (0 << 3) | (0 << 4); // Motorola frame format, manual CS..no need for SPI to generate clock pulse
SPI1->CR2 |= (7 << 8); // Data size to 8 bits
/* Enable SPI */
SPI1->CR1 |= (1 << 6);
// Transmit data over SPI
spi1_transmit((uint8_t *)write_data, sizeof(write_data) - 1); // Exclude null terminator
// Receive data over SPI
spi1_receive((uint8_t *)read_data, sizeof(read_data) - 1); // Read only 4 bytes
// Transmit received data over UART
uart2_send_string(read_data, sizeof(read_data) - 1); // Send only the received data
uart2_send_string("\r\n", 2);
while (1) {
}
return 0;
}

 

 

Screenshot 2024-11-20 185645.png

Screenshot 2024-11-20 185856.png

I want to know the 00 or FF is stuffed for every byte sent or received.

 

1 ACCEPTED SOLUTION

Accepted Solutions

Don't know about TotalPhase, but a $10 logic analyzer could show the signals on the wire.

In CR2, FRXTH bit must be set when using 8-bit transfers.

DR register is 16-bit wide. When reading/writing 8-bit values DR register must be type-casted:

 

*(__IO uint8_t *)(&SPI1->DR) = tx[i];
...
 rx[i] = *(__IO uint8_t *)(&SPI1->DR);

 

Check disassembly, you should see byte transfers now. __IO is a macro which expands to volatile.

hth

KnarfB

View solution in original post

3 REPLIES 3

Please see the Posting Tips for how to properly post source code:

https://community.st.com/t5/community-guidelines/how-to-write-your-question-to-maximize-your-chances-to-find-a/ta-p/575228

 


@vbk22398 wrote:

I doing bare metal coding  


If you use HAL, do you see the same issue?


@vbk22398 wrote:

Screenshot 2024-11-20 185645.png

I want to know the 00 or FF is stuffed for every byte sent or received.


Not sure exactly what you're showing there?

Are you sure the 00 or FF aren't just "dummies" displayed by the TotalPhase tools while one line is idle?

Would be helpful to see a corresponding logic analyser style view of the MOSI, MISO, and clock lines ...

 

PS

for example:

AndrewNeil_0-1732110740124.png

How would the "Transaction Log" display that interaction?

Would it show the data on MOSI as "XX 00", and the data on MISO as "00 XX" ?

In both cases, the 00 is just the "line idle" state, when the transmitter has nothing to send - but the line can't be at a "nothing" state - it has to be either high or low, so reads as 00 or FF 

This is standard SPI operation.

Don't know about TotalPhase, but a $10 logic analyzer could show the signals on the wire.

In CR2, FRXTH bit must be set when using 8-bit transfers.

DR register is 16-bit wide. When reading/writing 8-bit values DR register must be type-casted:

 

*(__IO uint8_t *)(&SPI1->DR) = tx[i];
...
 rx[i] = *(__IO uint8_t *)(&SPI1->DR);

 

Check disassembly, you should see byte transfers now. __IO is a macro which expands to volatile.

hth

KnarfB