0

I've been experimenting with writing to an external EEPROM using SPI and I've had mixed success. The data does get shifted out but in an opposite manner. The EEPROM requires a start bit and then an opcode which is essentially a 2-bit code for read, write and erase. Essentially the start bit and the opcode are combined into one byte. I'm creating a 32-bit unsigned int and then bit-shifting the values into it. When I transmit these I see that the actual data is being seen first and then the SB+opcode and then the memory address. How do I reverse this to see the opcode first then the memory address and then the actual data. As seen in the image below, the data is BCDE, SB+opcode is 07 and the memory address is 3F. The correct sequence should be 07, 3F and then BCDE (I think!).

enter image description here

Here is the code:

uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint32_t write_package = (ERASE << 24 | mem_addr << 16 | data);

while (1)
{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
  HAL_SPI_Transmit(&hspi1, &write_package, 2, HAL_MAX_DELAY);
  HAL_Delay(10);

}
/* USER CODE END 3 */
electrophile
  • 285
  • 1
  • 5
  • 16

3 Answers3

2

You're packing your information into a 32 bit integer, on line 3 of your code you have the decision about which bits of data are placed where in the word. To change the order you can replace the line with:

uint32_t write_package = ((data << 16) | (mem_addr << 8) | (ERASE));

That is shifting data 16 bits left into the most significant 16 bits of the word, shifting mem_addr up by 8 bits and or-ing it in, and then adding ERASE in the least significant bits.

Colin
  • 3,394
  • 1
  • 21
  • 29
  • This is only a fix for the problem but not a solution for the real problem. Please the a look at https://en.wikipedia.org/wiki/Endianness and understand why the bytes are in different order. – theSealion Jul 10 '18 at 09:35
2

It looks like as your SPI interface is set up to process 16 bit halfwords at a time. Therefore it would make sense to break up the data to be sent into 16 bit halfwords too. That would take care of the ordering.

uint8_t mem_addr = 0x3F;
uint16_t data = 0xBCDE;
uint16_t write_package[2] = {
    (ERASE << 8) | mem_addr,
    data
};

HAL_SPI_Transmit(&hspi1, (uint8_t *)write_package, 2, HAL_MAX_DELAY);

EDIT

Added an explicit cast. As noted in the comments, without the explicit cast it wouldn't compile as C++ code, and cause some warnings as C code.

  • Yes it’s setup to process 16-bit words. This helps. Thank you. – electrophile Jul 10 '18 at 11:21
  • If he is using the HAL from ST, this is still bad, since the HAL_SPI_Transmit() want a uint8_t* for the data and you a using a uint16_t*. My compiler wouldn't allow this implicit typecast. Furhter more if you ran your example on a big edian system, it wouldn't work. since the data bytes get swapped. – theSealion Jul 10 '18 at 11:41
  • A C++ compiler should reject this, a C compiler should compile with a warning. Could have an explicit cast, yes. Furthermore, this is the only variant that would work on a BE system, because `HAL_SPI_Transmit()` actually reads `uint16_t` data when 16-bit transfer is selected. See the actual code: `if(hspi->Init.DataSize == SPI_DATASIZE_16BIT) { /* ... */ hspi->Instance->DR = *((uint16_t *)pData); pData += sizeof(uint16_t); /* ... */ }` – followed Monica to Codidact Jul 10 '18 at 12:32
0

Your problem is the Endianness.

By default the STM32 uses little edian so the lowest byte of the uint32_t is stored at the first adrress.

If I'm right this is the declaration if the transmit function you are using:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

It requires a pointer to uint8_t as data (and not a uint32_t) so you should get at least a warning if you compile your code.

If you want to write code that is independent of the used endianess, you should store your data into an array instead of one "big" variable.

uint8_t write_package[4];

write_package[0] = ERASE;
write_package[1] = mem_addr;
write_package[2] = (data >> 8) & 0xFF;
write_package[3] = (data & 0xFF);
theSealion
  • 1,082
  • 7
  • 13