cancel
Showing results for 
Search instead for 
Did you mean: 

SPI master send simle data error

Anthony Lauly
Associate II

Hi, do you know how is the simplest code to send data from stm32(master) to arduino (slave) through spi.

I tried to write my own code, so here is the sktech ofmy code :

#define SPI2_Funct 0x05 // This is a function of GPIO AFR

#define CMD_LENGTH  2

#define CMD_MASTER_WRITE ((uint16_t)0x5678) //this is the data I want to send

spi_handle_t SpiHandle;

/************************************************/

/***********Here is SPI GPIO declaration*************/

void SPI_Pin_Init(){

RCC->AHB1ENR |= (1 << 1);

/*CLK FUNCTIONALITY SETUP*/

GPIOB->MODER |= (GPIO_ALT_FUNCT_MODE << 2*SPI_CLK_PIN);

GPIOB->OTYPER |= (GPIO_PUSHPULL_MODE << SPI_CLK_PIN);

GPIOB->PUPDR |= (GPIO_PULL_DOWN_MODE << 2*SPI_CLK_PIN);

GPIOB->OSPEEDR |= (GPIO_MEDIUM_SPEED_MODE << 2*SPI_CLK_PIN);

GPIOB->AFR[1] |= (SPI2_Funct << 4*(SPI_CLK_PIN %8));

/*MISO FUNCTIONALITY SETUP*/

GPIOB->MODER |= (GPIO_ALT_FUNCT_MODE << 2*SPI_MISO_PIN);

GPIOB->OTYPER |= (GPIO_PUSHPULL_MODE << SPI_MISO_PIN);

GPIOB->PUPDR |= (GPIO_PULL_UP_MODE << 2*SPI_MISO_PIN);

GPIOB->OSPEEDR |= (GPIO_MEDIUM_SPEED_MODE << 2*SPI_MISO_PIN);

GPIOB->AFR[1] |= (SPI2_Funct << 4*(SPI_MISO_PIN %8));

/*MOSI FUNCTIONALITY SETUP*/

GPIOB->MODER |= (GPIO_ALT_FUNCT_MODE << 2*SPI_MOSI_PIN);

GPIOB->OTYPER |= (GPIO_PUSHPULL_MODE << SPI_MOSI_PIN);

GPIOB->PUPDR |= (GPIO_PULL_UP_MODE << 2*SPI_MOSI_PIN);

GPIOB->OSPEEDR |= (GPIO_MEDIUM_SPEED_MODE << 2*SPI_MOSI_PIN);

GPIOB->AFR[1] |= (SPI2_Funct << 4*(SPI_MOSI_PIN %8));

/*SS FUNCTIONALITY SETUP*/

GPIOB->MODER |= (GPIO_ALT_FUNCT_MODE << 2*SPI_SS_PIN);

GPIOB->OTYPER |= (GPIO_PUSHPULL_MODE << SPI_SS_PIN);

GPIOB->PUPDR |= (GPIO_PULL_UP_MODE << 2*SPI_SS_PIN);

GPIOB->OSPEEDR |= (GPIO_MEDIUM_SPEED_MODE << 2*SPI_SS_PIN);

GPIOB->AFR[1] |= (SPI2_Funct << 4*(SPI_MOSI_PIN %8));

}

void hal_spi_master_tx(spi_handle_t *spi_handle,uint8_t *buffer, uint32_t len)

{

spi_handle->pTxBuffPtr = (uint8_t*)buffer;

spi_handle->TxXferCount = len;

spi_handle->TxXferSize = len;

spi_handle->RxXferCount = 0;

spi_handle->RxXferSize = 0 ;

spi_handle->State = HAL_SPI_STATE_BUSY_TX;

SPIx->CR2 |= SPI_REG_CR2_TXEIE_ENABLE;

if( !(SPIx->CR1 & SPI_REG_CR1_SPE) )

SPIx->CR1 |= SPI_REG_CR1_SPE;

}

void hal_spi_irq_handler(spi_handle_t *hspi)

{

 uint32_t tmp1 = 0, tmp2 = 0;

/* check to see TXE is set in the status register */

tmp1 = (hspi->Instance->SR & SPI_REG_SR_TXE_FLAG);

tmp2 = (hspi->Instance->CR2 & SPI_REG_CR2_TXEIE_ENABLE);

 if((tmp1 != 0) && (tmp2 != 0))

 {

/* TXE flag is set

  * handle the TX of data bytes

  */

   if(hspi->Init.DataSize == SPI_8BIT_DF_ENABLE)

 {

  hspi->Instance->DR = (0x56);

hspi->TxXferCount--; //we sent 1 byte

 }

if(hspi->TxXferCount == 0)

 {

/* we reached end of transmission, so close the txe interrupt */

  hal_spi_tx_close_interrupt(hspi);

 }

  return;

 }

}

int main (void){

uint32_t i=0;

uint8_t addrcmd[CMD_LENGTH];

SPI_Pin_Init();

RCC->APB1ENR |= (1 << 14); //To activate the clock

SpiHandle.Instance = SPI2;

SpiHandle.Init.BaudRatePrescaler = SPI_REG_CR1_BR_PCLK_DIV_32;

SpiHandle.Init.Direction = SPI_ENABLE_2_LINE_UNI_DIR;

SpiHandle.Init.CLKPhase = SPI_SECOND_CLOCK_TRANS;

SpiHandle.Init.CLKPolarity = SPI_CPOL_LOW;

SpiHandle.Init.DataSize = SPI_8BIT_DF_ENABLE;

SpiHandle.Init.FirstBit = SPI_TX_MSB_FIRST;

SpiHandle.Init.NSS = SPI_SSM_DISABLE;

SpiHandle.Init.Mode = SPI_MASTER_MODE_SEL;

SpiHandle.State = HAL_SPI_STATE_READY;

/*Call driver API to initialize the SPI device*/

hal_spi_init(&SpiHandle);

/*Enable the IRQs in the NVIC*/

NVIC_EnableIRQ(SPI2_IRQn);

while (1){

while(SpiHandle.State != HAL_SPI_STATE_READY);

/*Master writes command*/

addrcmd[0] = (uint8_t) CMD_MASTER_WRITE;

addrcmd[1] = (uint8_t) (CMD_MASTER_WRITE >> 8);

/*First send the master write cmd to slave*/

hal_spi_master_tx(&SpiHandle, addrcmd, CMD_LENGTH);

}

}

void SPI2_IRQHandler(void){

hal_spi_irq_handler(&SpiHandle);

}

/************end of code******************/

Basically I use structure spi_handle_t to gather or the initialization and also the data. But when I check the memory watch in debug mode, in the address of 0x4000 380C, which is the address of Data Register, the data only contain either 0xFF or 0x00, while the data I sent is 0x5678. If I make the SSM into enabled, the data register always contain 0xFF, while if I make it Disable and SPE bit into 1, it always make the data register 0x00. Then I know that sth wrong with the master (which is the stm32, and for sure I know that sth wrong with either my code or my initialization). So I need your help to fix my code or create a new simplest master send code. By the way I am using stm32f446RE. Feel free to ask about my code, I would appreciate it alot. Thank you

1 REPLY 1

> when I check the memory watch in debug mode, in the address of 0x4000 380C, which is the address of Data

> Register, the data only contain either 0xFF or 0x00, while the data I sent is 0x5678.

The SPI->DR is in fact two registers - a write-only Tx register and a read-only Rx register (in newer STM32s it's a window into the FIFO, but the '446 SPI is of the older FIFO-less design). In other words, you won't find the written data by reading back SPI->DR.

Note, that observing the registers (especially data register) in debugger is intrusive - for the SPI module that *is* reading with all its side effects i.e. clearing the RXNE status bit.

Make a MISO-MOSI loopback and observe the signals using oscilloscope/logic analyzer. You probably don't want to use the unidirectional mode. If you use hardware NSS keep it high externally; if you use software NSS keep its bit high (pulling NSS low - hardware or software - is a signal telling the module to go to slave mode; you'll see this has happened observing the respective status bit).

I don't Cube so won't help with that.

JW