2025-09-20 5:24 PM
Is there any way to configure the HAL to communicate to a slave via I2C WITHOUT sending the address byte first? I know this is part of the I2C standard, but I would like to implement a TM1637 device, which is similar to I2C but does not use an address byte.
I have already implemented a "bit bang" version with delays and GPIO, but it would be nice to use the HAL directly somehow.
HAL I2C already gives me STARTs, writes, reads and STOPs, which is most of the TM1637 protocol. If I could just turn off that pesky address byte!
Or maybe this can be done with the SPI interface instead.
Suggestions welcome ...
2025-09-20 5:55 PM
The I2C protocol, by design, includes an address byte as part of the communication specification. For devices like the TM1637, you can simulate I2C communication without the address byte by simply using bit-banging or custom protocol handling. The STM32's HAL library is not designed to support a "no address byte"
Why don't you write you own library to communicate over GPIO and call it whatever you want, for example I2C_modified.c I2C_modified.h
void tm1637_send_bit(uint8_t bit) {
if (bit) {
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_SET); // Set DIO to 1
} else {
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_RESET); // Set DIO to 0
}
// Generate clock pulse
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_SET); // Set CLK to 1
delay_us(5); // Small delay for clock timing
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_RESET); // Set CLK to 0
delay_us(5); // Small delay for clock timing
}
void tm1637_send_byte(uint8_t byte) {
for (int i = 0; i < 8; i++) {
tm1637_send_bit((byte >> i) & 1); // Send each bit of the byte
}
}
void tm1637_send_start(void) {
// Generate the start condition (data high, clock high, then clock low, data low)
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_SET);
delay_us(5);
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_RESET);
delay_us(5);
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_RESET);
}
void tm1637_send_stop(void) {
// Generate the stop condition (data low, clock high, then clock low, data high)
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_SET);
delay_us(5);
HAL_GPIO_WritePin(GPIO_PORT, CLK_PIN, GPIO_PIN_RESET);
delay_us(5);
HAL_GPIO_WritePin(GPIO_PORT, DIO_PIN, GPIO_PIN_SET);
}
2025-09-20 11:29 PM
HAL provides a way to access the I2C hardware interface peripheral built into your stm32. HAL generally opts for simplicity and consistency of the programming interface rather than providing the full functionality of the peripheral.
To see what the stm32 i2c hardware peripheral is capable of, you need to explore the Reference Manual for your stm32. This is a very complete manual for the peripherals designed by ST and as such can be hard to understand.
My understanding is that the stm32 I2C peripheral automatically sends the address byte immediately after the start-sequence and that the least-significant bit of that address byte determines whether remainder of the communication is a read or a write.
If the TM1637 protocol doesn’t fit with that requirement then you can’t use that peripheral to do the slow communication between your code and the device.
The simplest solution is to bit-bang as described by @MNapi but there might be other options.
If you can restrict your choice of commands to ones that fit the address read/write requirements, just tell HAL that the I2C address you want to communicate with is that command. You might, for example, have to use address-incrementing mode to write to odd addresses.
If you need your stm32 processor to be doing other things while communicating, you can set up a timer to provide the necessary delays. Then either:
Get the timer to interrupt the processor with the interrupt-service-routine doing the next bit-bang
Or have it trigger the next transfer of a DMA that you have set up to write to the BSRR of the GPIO peripheral that has the SCL and SDA pins on it; this is complicated code but it is possible. ST wrote examples of this to cover the case where you needed to do serial communications on pins that didn’t have UARTs/SPI/I2C attached