Loading...
 
Skip to main content

System Workbench for STM32


GPIO Toggle Question

How do I toggle the GPIO pins (i.e from low to high) on the SDA and SCL pin?

What do you mean by toggling? And why would you like to toggle them?
By toggle, I mean changing the signal from high to low and vice versa.

The problem here is understanding your question.

Most pins on the STM32 can be assigned to different peripherals, one of which is a 'standard' GPIO.

SDA and SCL are a peripheral assignment, not a GPIO. So you can't toggle them, (unless that peripherals has an option to toggle them).

And since this is a Data and Clock line, why would you want to toggle them.

-Matt

I may be using bad verbage. I'm trying to initialize the sta013 decoder, whose start condition is caused by a high to low transition of the data bus SDA signal while the clock signal SCL is stable in the high state. How do I implement that using the stm32l4xx_hal library?

Hey mojo,

As Matt explained you can't toggle the pins manually if you assigned them to the i2c peripheral. It seems to me that you are using standard i2c specs, so you can use the i2c peripheral. If you configured the i2c in CubeMX correctly, you should already have a ready to use initialization(maybe you have to set some timings manually). A glance in the HAL reference manual should give you functions for writing on the i2c bus.

I would recommend you to read and understand the i2c chapter in the documentation of your controller. Afterwards try to read and understand the use of the HAL library and then try to understand some examples( i2c examples preferred in your case 😀 ). This would help you on your future projects with stm32 and HAL aswell!

Bab

I've read them and believe I have to use the HAL_I2C_Mem_Read/Write functions. But, there's nothing in the HAL_I2C commands which changes the signal on the SDA or SCL pin, which is my main goal at the moment. Without being able to change those signals from high to low and vice versa, I can't really use the device.

Hi

read HAL documentation UM1850

You have to define pins and implement a low level function by yourself like in this example:

Copy to clipboard
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) { GPIO_InitTypeDef GPIO_InitStruct; /*##-1- Enable peripherals and GPIO Clocks #################################*/ /* Enable GPIO TX/RX clock */ I2Cx_SCL_GPIO_CLK_ENABLE(); I2Cx_SDA_GPIO_CLK_ENABLE(); /* Enable I2Cx clock */ I2Cx_CLK_ENABLE(); /*##-2- Configure peripheral GPIO ##########################################*/ /* I2C TX GPIO pin configuration */ GPIO_InitStruct.Pin = I2Cx_SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct); /* I2C RX GPIO pin configuration */ GPIO_InitStruct.Pin = I2Cx_SDA_PIN; HAL_GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct); }


There are many examples in cube firmware archives. STM32Cube_FW_F1_V1.3.0 for example.

Dieter

Hello,

The i2c peripheral should handle the toggling by itself(supposed you assigned the pins to their peripheral function). There is no need to toggle in source code. As soon as you or the hal library writes something in the transmit data register of the peripheral it copies the data in the shift register if it is empty. Then it automatically generates the start signal, the clock and beginns to shift the data on the dataline.(supposed the i2c is enabled and has a clock)

In your manual it should say something like this:
"If the I2C_TXDR register is not empty (TXE=0), its content is copied into the shift register
after the 9th SCL pulse (the Acknowledge pulse). Then the shift register content is shifted
out on SDA line."

What would be the purpose of a i2c peripheral if you had to do everything by yourself? 😀

Bab

The reason I want to do it manually, is because in the datasheet for the STA013 Decoder, I'm told to create a start condition, where it is "identified by a high to low transition of the data bus SDA signal while the clock signal SCL is stable in the high state. A START condition must precede any command for data transfer."

I don't think that the i2c peripheral does that exact mechanic by itself, correct?

This START condition is standard i2c behavior and so the i2c peripheral should do this in exactly that way you described by itself!

See attached file! 😊

Bab

Really appreciate the help Bab! Now, that the start condition is clarified, this leads me to my next objective. I'm supposed to read from the device. The register 0x01 should have the value 0xAC as an ACK to let me know that the STA013 decoder is present. I used both:

HAL_I2C_Master_Receive(&hi2c3, reg, &data, 1, 100);
&
HAL_I2C_Mem_Read(&hi2c3, 0x86, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 10);

With reg having the value of 0x01. But, neither of those returned back the correct value. Do you know which of the two functions is the correct one? And do you see anything wrong in what I wrote?

Hey,

I haven't used the Hal library much. But i think the HAL_IC2_Master_Receive function just sends the address and then records size bytes.
This is useful for devices with a 2 step readout. In the first transmission you would tell the device which register you want to read and in the second transmission you would use this function.

And i think HAL_I2C_Mem_Read would first send the address, then the register you want to read and then record size bytes in a consecutive transmission.

Can't get more information from the usermanual and i haven't really worked with the i2c and the HAL so you better dont rely on me!

I hope someone else can help you!

Bab

I feel like I'm asking the wrong question. Here's the psuedo code of what I'm trying to accomplish:

  • Start Condition
  • Send A Byte The value is 0x86 (134). The seven most significant bits instruct the STA013 to listen (because there may be other chips connected to SDA and SCL). The LSB is clear, telling the STA013 that will will be writing an address.
  • Send A Byte The value is the address where we need to read data. The main program will pass the address to our sta013_read function.
  • Stop Condition
  • Start Condition
  • Send A Byte The value is 0x87 (135). Again, the upper bits select the STA013, and the LSB sets up the next access to read.
  • Receive A Byte Read the byte from the STA013. This will be returned to the main program.
  • Stop Condition


My code looks like this:

uint8_t sta013ReadReg(uint8_t reg)
{
uint8_t data;

// STA_I2C_DEV = 0x86
sta013WriteReg(STA_I2C_DEV, data);
sta013WriteReg((STA_I2C_DEV+1), data);

/* Not sure which of these two is correct verstion */
//HAL_I2C_Mem_Read(&hi2c3, STA_I2C_DEV, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 10);
//HAL_I2C_Master_Receive(&hi2c3, reg, &data, 1, 100);

return data;
}

I feel like I'm missing this step:

  • Send A Byte The value is the address where we need to read data. The main program will pass the address to our sta013_read function.


Not really sure what it means or how to implement it.


 
Collapse/expand modules below