cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F051C8 / SPI / half duplex / single line / Problem changing SPI_BiDirectionalLineConfig()

AlexandreR
Associate II

Hello everybody,

On actual project, I need to interface my STM32F051C8 to a HTS221TR Temperature & Humidity sensor.

Communication is through SPI1, STM32 is master, there is 1 bidirectional data line, 1 clock, 1 Slave Select.

Final usage will be in polling mode, actual tests are with delays only.

For first HW trials. polling and Slave Select are NOT implemented, since I go step by step to fid out errors.

To read data I need to:

·        Set data line to Tx

·        put SS low (will be done in later stage)

·        Send 0x8F (8 bits ), resulting in 8 clock + 8 datas (OK on oscilloscope)

·        (!!!) Set data line to Rx

·        Send dummy data's (8 bits ), resulting in sedning 8 clock + 8 datas read from bus

·        put SS high (will be done in later stage)

·        read Rx Buffer

The first 8 bits send out works perfectly.

Problem is, at the moment I set bidirectional line to Rx (line with !!! at the beginning), it immediately starts clocking SPI, for unlimited cycles. Even if I put breakpoint just after this instruction. But it should only start once sending dummy data's, and also only for 8 clocks.

What is wrong in my thinking ?

Below code is without polling (just put some delays), and without SS management (to avoid SS line getting high in between first 8 clocks and second 8 clocks, SS will be set to SW later)

I'm thankfull for any Idea !

Alexandre

void SPI1_Init(void)

{

   GPIO_InitTypeDef GPIO_InitStructure = {0};

   SPI_InitTypeDef SPI_InitStruct = {0};

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);   // SPI clock

   T_RCC_GPIO_ClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);  // GPIO clock

   T_RCC_GPIO_ClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);  // GPIO clock

   //SPI1 GPIO Configuration

   //PA4  ------> SPI1_NSS

   //PA5  ------> SPI1_SCK

   //PB5  ------> SPI1_MOSI

 /* Connect PA4 to SPI NSS */

 GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

// GPIO_InitStructure.Alternate = GPIO_AF_0;

 GPIO_Init(GPIOA, &GPIO_InitStructure);

 /* Connect PA5 to SPI SCK */

 GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

// GPIO_InitStructure.Alternate = GPIO_AF_0;

 GPIO_Init(GPIOA, &GPIO_InitStructure);

 /* Connect PB5 to SPI MOSI */

 GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_0);

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

// GPIO_InitStructure.Alternate = GPIO_AF_0;

 GPIO_Init(GPIOB, &GPIO_InitStructure);

 /* Initialize the SPI_Direction member */

 SPI_InitStruct.SPI_Direction = SPI_Direction_1Line_Tx; 

 /* Initialize the SPI_Mode member */

 SPI_InitStruct.SPI_Mode = SPI_Mode_Master; 

 /* Initialize the SPI_DataSize member */

 SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; 

 /* Initialize the SPI_CPOL member */

 SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;

 /* Initialize the SPI_CPHA member */

 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;

 /* Initialize the SPI_NSS member */

 SPI_InitStruct.SPI_NSS = SPI_NSS_Hard;

 /* Initialize the SPI_BaudRatePrescaler member */

 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;

 /* Initialize the SPI_FirstBit member */

 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;

 /* Initialize the SPI_CRCPolynomial member */

 SPI_InitStruct.SPI_CRCPolynomial = 7;

 SPI_Init(SPI1, &SPI_InitStruct);

}

void SPI1_Read_Data()

{

   SPI_InitTypeDef SPI_InitStruct = {0};

uint8_t Received_DATA_from_SPI;

   SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);

 SPI_Cmd(SPI1, ENABLE);

   SPI_SendData8(SPI1, 0x8F); //b 1(read) 0(no increment) 001111 (WHO AM I)

   TM_Delay(1);

  SPI_Cmd(SPI1, DISABLE);

SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);

  SPI_Cmd(SPI1, ENABLE);

   SPI_SendData8(SPI1, 0xFF);

   TM_Delay(1);

   Received_DATA_from_SPI = SPI_ReceiveData8(SPI1);

  SPI_Cmd(SPI1, DISABLE);

}

10 REPLIES 10
S.Ma
Principal

Use 4 wire full duplex with MISO and MOSI connected together outside.

The half duplex doesn't exactly behave as internally MOSI short with MISO.

And check spec if HTS221 does not start in 3 wire mode, you might have first to write a register to force it to 3 wire mode to be able to read back data. Some mems requires this.

Hello KIC and thank you for your prompt reply !

HTS221 is in 2-Wire mode, as it only has 1 data line.

MISO-MOSI connected outside: may lead to a conflict ?

Also, on my hardware, other pin is not avaiable, so I hope I can solve it to work internally as half duplex.

> Problem is, at the moment I set bidirectional line to Rx (line with !!! at the beginning),

> it immediately starts clocking SPI, for unlimited cycles.

That's how the SPI module in STM32 works, and it's quite clearly said in the RM:0690X0000088P2FQAU.png

> Also, on my hardware, other pin is not avaiable, so I hope I can solve it to work internally as half duplex.

Some slaves actually don't care if they see many clocks, except that you have to capture the arriving data fast enough so that the subsequent ones don't overwrite them. DMA might help here.

If your slave requires a precise number of clocks, you can try to carefully emit only one SPI-frame's worth of clocks by turning the direction around, wasting a few machine clocks (NOPs), and turning it back - of course, with interrupts disabled and direct register writes. Wait until the frame ends and datum arrives, read it, and if needed, repeat.

JW

AlexandreR
Associate II

Thank you Jan,

So it is clear, don't need to search for error, it works as it should...

So I will either check the flags to disable once correct amount of data is received, or maybe, as required amount of data is low, and possible speed fast, simply implement a Software SPI, clocking and polling "by code".

You just need to manually adjust MOSI gpio Moder register as input when reading data from slave. Works fine when well implemented.

A master without full control of the clocks it is generating: a slave's empathy?

S.Ma
Principal

Humidity sensor is slow response sensor (seconds) and reading few bytes hardly requires speed in most cases so sw spi when adressing this sensor is a possibility.

Sounds fine.

But, if Mode set to input, will it anyway forward the data's to Rx Buffer ?

AlexandreR
Associate II

Exact. Temperature + Humidity are total 4 bytes... To read once every few seconds