STM32 HAL I2C Scanner
We need to configure SWO
output
The function is implementation of a _write
function for sending data, typically for debugging purposes. The code is specifically designed to send characters through the Instrumentation Trace Macrocell (ITM
) interface. The ITM
is a component of the ARM
Cortex-M
microcontroller family, used for sending trace data to an external debugger or another host system.
- We need to include define in beginning of a file
main.c
/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */
- This should go under
/* USER CODE BEGIN 4 */
/* Send a char through ITM */
int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
ITM_SendChar(*ptr++);
}
return len;
}
/* USER CODE END 4 */
Debug setting in STM32
CubeIDE
- You need to open this window first
Window
=>Show wiew
=>SWV
=>SWV ITM Data Console
I2C_Scan
The I2C_Scan
function is a commonly used function in embedded systems to scan the I2C
bus for devices. It attempts to communicate with all possible I2C
addresses and identifies those that respond, indicating the presence of a device at that address. The function is particularly useful during the development phase to detect and troubleshoot connected I2C
devices.
add this to /* USER CODE BEGIN 4 */
section as well
void I2C_Scan(void)
{
printf("Scanning I2C bus:\r\n");
HAL_StatusTypeDef result;
uint8_t i;
for (i = 1; i < 128; i++)
{
/*
* the HAL wants a left aligned i2c address
* &hi2c1 is the handle
* (uint16_t)(i<<1) is the i2c address left aligned
* retries 2
* timeout 2
*/
result = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t) (i << 1), 2, 2);
if (result != HAL_OK) // HAL_ERROR or HAL_BUSY or HAL_TIMEOUT
{
printf("."); // No ACK received at that address
}
if (result == HAL_OK)
{
printf("0x%X", i); // Received an ACK at that address
sprintf(test, "0x%X\n", i);
HAL_UART_Transmit(&huart2, (uint8_t*) test, strlen(test), 5);
}
}
printf("\r\n");
}
Detailed Explanation:
- Initial Print Statement:
printf("Scanning I2C bus:\r\n");
- This line prints a message to indicate that the
I2C
scanning process has started.\r\n
is used to insert a newline, moving the cursor to the next line in the console output.
- Variable Declarations:
HAL_StatusTypeDef result;
uint8_t i;
HAL_StatusTypeDef result;
: This variable will store the result of each attempt to communicate with anI2C
device.HAL_StatusTypeDef
is a type defined by theSTM32
HAL
(Hardware Abstraction Layer) library, representing the status ofHAL
operations (e.g.,HAL_OK
,HAL_ERROR
,HAL_BUSY
,HAL_TIMEOUT
).uint8_t i;
: This variable is an 8-bit unsigned integer that will serve as a counter in the for loop, representing potentialI2C
addresses.
- For Loop (Scanning I2C Addresses):
for (i = 1; i < 128; i++) {
- The loop iterates through all possible 7-bit
I2C
addresses, starting from1
to127
. Address0
is typically reserved and not used for normalI2C
communications.
- Checking Device Readiness:
result = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t) (i << 1), 2, 2);
HAL_I2C_IsDeviceReady
is aHAL
function that checks if anI2C
device at a given address is ready for communication (i.e., it sends an address and waits for an acknowledgment, orACK
, from a device).&hi2c1
: This is theI2C
handle, a structure that contains all the information required to manageI2C
communication on the microcontroller.(uint16_t)(i << 1)
: TheI2C
address must be left-aligned in the register. Thei << 1
operation shifts the address to the left by1 bit
, making it left-aligned, and it is cast touint16_t
.2
: The function retries twice if the device doesn’t respond.2
: Timeout duration in milliseconds for each communication attempt.
- Result Evaluation:
- Device Not Ready:
if (result != HAL_OK) {
printf("."); // No ACK received at that address
}
If the result is not
HAL_OK
, meaning no acknowledgment (ACK
) was received from the device, it prints a dot (.
) to indicate that no device is present at the address.Device Ready:
if (result == HAL_OK) {
printf("0x%X", i); // Received an ACK at that address
sprintf(test, "0x%X", i);
HAL_UART_Transmit(&huart2, (uint8_t*) test, strlen(test), 100);
}
- If the result is
HAL_OK
, indicating that the device at the given address responded with anACK
:- It prints the
I2C
address in hexadecimal format. sprintf(test, "0x%X", i);
: The address is formatted into a string and stored in the test buffer.HAL_UART_Transmit(&huart2, (uint8_t*) test, strlen(test), 100);
: This line sends the formatted address overUART
using theHAL_UART_Transmit
function, allowing the address to be transmitted to another device (like a computer) for logging or further analysis.
- It prints the
- Completion Print Statement:
printf("\r\n");
- After the loop completes and all addresses have been scanned, this line prints a newline to signify the end of the scan.
Summary of Functionality:
The I2C_Scan
function scans all potential I2C
addresses (1 through 127) on the I2C
bus associated with the hi2c1
handle. For each address, it checks if a device is ready (i.e., responds to the address). If a device is found, it prints the address in hexadecimal format and transmits the address over UART
and ITM
. If no device is found at a given address, it prints a dot. This is useful for debugging and validating that the correct devices are connected and communicating over the I2C
bus.