Search code examples
stm32spieeprom

What is the correct way to format data to send by HAL SPI in STM32?


I am trying to read/write data from ST EEPROM M95640-W

Acording to datasheet, for read operations data command must be formated like:

M95640-W Read operation

First is 8-bit instruction "Read from Memory Array": 0x03 (B00000011)

Second is 16-bit address.

But when I send command and data I got this:

Address 0x0001 (B00000001): M95640 Read from address 0x1

And just to check data position with mirrored bits

Address 0x0081 (B10000001): M95640 Read from address 0x81


So I can not find an error in my code, why it send data in that incorrect way. It send 0x20 command except of 0x03. It send 0x48 address except of 0x01 and 0x80 except of 0x81. Looks like I got an incorrect data translation between types uint16_t -> uint8_t*.

So here is the code:

#define EEPROM_SPI   hspi1
#define EEPROM_READ  0x03  // Read from Memory Array

 /**
  * @brief  Reads a block of data from the EEPROM.
  * @param  pBuffer: pointer to the buffer that receives the data read from the EEPROM.
  * @param  ReadAddr: EEPROM's internal address to read from.
  * @param  NumByteToRead: number of bytes to read from the EEPROM.
  * @retval None
  */
uint8_t sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t NumByteToRead) {
    /*!< Select the EEPROM: Chip Select low */
    EEPROM_LED_ON();
    EEPROM_CS_LOW();

    /*!< Send "Read from Memory" instruction and MSB of WriteAddr  */
    EEPROM_SendInstruction((uint8_t*)EEPROM_READ, 1);

    /*!< Send WriteAddr address byte to read from */
    EEPROM_SendInstruction((uint8_t*)ReadAddr, 2);

    if (HAL_SPI_Receive_DMA(&EEPROM_SPI, (uint8_t*)pBuffer, NumByteToRead) != HAL_OK) {
        Error_Handler();
    }

    /*!< Deselect the EEPROM: Chip Select high */
    EEPROM_CS_HIGH();
    EEPROM_LED_OFF();

    return 0;
}

void EEPROM_SendInstruction(uint8_t *instruction, uint8_t size) {
    while (EEPROM_SPI.State == HAL_SPI_STATE_RESET) {
        osDelay(1);
    }

    if (HAL_SPI_Transmit_DMA(&EEPROM_SPI, (uint8_t*)instruction, (uint16_t)size) != HAL_OK) {
        Error_Handler();
    }
}

SPI initialization:

static void MX_SPI1_Init(void) {
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 7;

    if (HAL_SPI_Init(&hspi1) != HAL_OK) {
        Error_Handler();
    }
}

UPD1: I did the packet like @Guillaume Michel said and it worked: M95640 Read from address 0x81 Working way

UPD2 I published the libriary at Github, writing and reading data is fully functional. Help is welcome to review the code and add some new features.


Solution

  • Your code does not seem to be written to use DMA, so don't use it. Try to use HAL_SPI_Receive and HAL_SPI_Transmit rather than HAL_SPI_Receive_DMA and HAL_SPI_Transmit_DMA.

    The polarity and the phase seem OK, but double check.

    I am not sure that the way you call EEPROM_SendInstruction is correct. Try this instead:

    uint8_t sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t NumByteToRead) {
    
      uint8_t tmpBuf[2];
    
      /*!< Select the EEPROM: Chip Select low */
      EEPROM_LED_ON();
      EEPROM_CS_LOW();
    
      /*!< Send "Read from Memory" instruction and MSB of WriteAddr  */
      tmpBuf[0] = EEPROM_READ;
      EEPROM_SendInstruction(tmpBuf, 1);
    
      /*!< Send WriteAddr address byte to read from */
      tmpBuf[0] = (uint8_t)(ReadAddr<<8);
      tmpBuf[1] = (uint8_t)ReadAddr;
      EEPROM_SendInstruction(tmpBuf, 2);
    
      if (HAL_SPI_Receive_DMA(&EEPROM_SPI, (uint8_t*)pBuffer, NumByteToRead) != HAL_OK) {
          Error_Handler();
      }
    
      /*!< Deselect the EEPROM: Chip Select high */
      EEPROM_CS_HIGH();
      EEPROM_LED_OFF();
    
      return 0;
    }