cancel
Showing results for 
Search instead for 
Did you mean: 

Do any STM32 devices support SPI communication with variable data frame length?

Todor Todorov
Associate II

Hi everyone,

I have a SPI eeprom on my hands, which has a weird communication protocol. Data is 8 bits wide, except for the 1st frame, which contains 1 start bit, 2 op-code bits, and 9 address bits - so 12 in total. It does not accept this first frame as 2x 8bit transfers - start bit and op codes need to be the MSB part of a 12 clock pulses frame.

While looking at various F0xx and F4xx data sheets, I noticed that there is NO explicit note about changing the DS bits in the SPI CR2 register only when SPI is disabled. So I decided to see if changing this parameter after the first frame would work... Needless to say, it does not do what I expected.

I tested on a STM32F070F6 Cortex-M0 MCU.

Here is my SPI initialization:

static void MX_SPI1_Init(void)
{
 /* SPI1 parameter configuration*/
 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_16;
 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
 hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
 hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 hspi1.Init.CRCPolynomial = 7;
 hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
 hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
 if (HAL_SPI_Init(&hspi1) != HAL_OK)
 {
   Error_Handler();
 }
}

This was produced by CubeMX. The next snippet is my code to constantly send some test data, so I can capture it with a logic analyzer:

uint8_t data[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
uint16_t spiReg = hspi1.Instance->CR2;
uint8_t cmd[2] = { 0x0c, 0x00 }; // start bit and op-code, address shall remain 0
while (1)
 {
    HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, 0); // chip select low
    hspi1.Init.DataSize = SPI_DATASIZE_12BIT;
    spiReg = (spiReg & ~SPI_DATASIZE_16BIT) | SPI_DATASIZE_12BIT;
    hspi1.Instance->CR2 = spiReg;
    HAL_SPI_Transmit(&hspi1, cmd, 2, 5000);
 
    HAL_Delay(2);
 
    spiReg = (spiReg & ~SPI_DATASIZE_16BIT) | SPI_DATASIZE_8BIT;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Instance->CR2 = spiReg;
    HAL_SPI_Transmit(&hspi1, data, sizeof(data), 5000);
    HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, 1); // chip select high
 
    HAL_Delay(2000);
 }

As you can see, the peripheral is initialized with 8bit data frame. When I attempt the switch to 12 bit frames "on the fly", the switching works, but the peripheral is sending the command bytes as 2 separate 12bit frames - my expectation was to see 1 frame with last 4 bits of the first byte and the 8 bits of the second byte.

And then when I attempt to switch back to 8 bit frames, it does not work. It continues using 12bit frames.

Is my code wrong somehow? Or is what I need not possible with STM32 HAL? Would it be possible if I use the registers directly?

Any help would be valued and appreciated! Thx!

4 REPLIES 4
S.Ma
Principal

I used dynamic bit length, you can change it when the spi is idle, no need to be overconservative for prototyping.

TDK
Guru

> uint16_t spiReg = hspi1.Instance->CR2;

> spiReg = (spiReg & ~SPI_DATASIZE_16BIT) | SPI_DATASIZE_12BIT;

This isn't doing anything except changing a variable in memory. It's not modifying an SPI register or changing the data width.

Perhaps you want this:

volatile uint16_t * spiReg = hspi1.Instance->CR2;
 
*spiReg = (spiReg & ~SPI_DATASIZE_16BIT) | SPI_DATASIZE_12BIT;

Or perhaps a little more readable and less prone to typos:

MODIFY_REG(hspi1.Instance->CR2, SPI_CR2_DS, SPI_DATASIZE_12BIT);

Also:

> uint8_t cmd[2] = { 0x0c, 0x00 }; // start bit and op-code, address shall remain 0

> HAL_SPI_Transmit(&hspi1, cmd, 2, 5000);

This transmits data past the end of the buffer. cmd should be uint16_t if it contains 12-bit values..

If you feel a post has answered your question, please click "Accept as Solution".
S.Ma
Principal

HAL does not provide access to all HW capabilities.... you need to dig down to hw register manipulation.

While true in general, in this case it absolutely does provide access to 9 bit word size.
If you feel a post has answered your question, please click "Accept as Solution".