Skip to content

Commit

Permalink
i2cdetect function (#103)
Browse files Browse the repository at this point in the history
* implemented i2cdetect function.

* Fixed spacing and added comments.

* Separate i2c_utility functions files.

* Fixed Displaying For i2cdetect and reverted back to a single file.

* Created implementation of byte-read i2cdump function.

* Implemented i2cdump word mode.

* Lowered the timeout length to 50ms.

* Created print function to serial monitor.
  • Loading branch information
alstonliu730 authored Aug 2, 2024
1 parent 78ae0e0 commit 0ff91be
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 0 deletions.
50 changes: 50 additions & 0 deletions middleware/include/i2c_utility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef I2C_UTILITY_H
#define I2C_UTILITY_H

#include "stm32f4xx_hal.h"
#include "serial_monitor.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define HEX_LABELS "\t 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"
#define SPACING " " // Spacing in between each printed address
#define MAX_TRIALS 3 // Max attempts to probe I2C device
#define TIMEOUT 50 // Max time until function skips
#define HEX 16 // hexadecimal for utoa function
#define BUF_ROWS 8 // Number of rows in the buffer
#define ROW_BYTES 128 // Number of bytes per row

/**
* @brief Probes all i2c addresses to check if devices are ready.
*
* @param hi2c address of the i2c bus
* @param buffer array to input the result in
* @param mode
* @param start
* @param end
*
* @return int
*/
int i2cdetect(I2C_HandleTypeDef *hi2c, char **buffer, int mode, uint8_t start, uint8_t end);

/**
* @brief Reads and dumps register data at a given register address and i2c bus.
*
* @param hi2c address of the i2c bus
* @param devAddress specific device address in the i2c bus to dump.
* @param buffer array to input the result in
* @param mode reading mode (default: byte)
* @param start lower range of addresses to dump from
* @param end higher range of addresses to dump from
*/
int i2cdump(I2C_HandleTypeDef *hi2c, uint16_t devAddress, char **buffer, char mode, uint8_t start, uint8_t end);

/**
* @brief Prints the given 2D Array to serial monitor
*
* @param buffer
*/
void printResult(char **buffer);

#endif // I2C_UTILITY_H
158 changes: 158 additions & 0 deletions middleware/src/i2c_utility.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include "i2c_utility.h"

char *hex_labels[] = {"00:", "10:", "20:", "30:", "40:", "50:",
"60:", "70:", "80:", "90:", "a0:", "b0:", "c0:", "d0:", "e0:", "f0:"};

/**
* TODO: Implement modes for I2C Communication.
* TODO: Implement for flags.
* TODO: Check for error handling
*/
int i2cdetect(I2C_HandleTypeDef *hi2c, char **buffer, int mode, uint8_t start, uint8_t end) {
// Initialize the buffer and local variables
HAL_StatusTypeDef ret;
uint8_t row = 1;
char status[sizeof(uint8_t) * 8 + 1];

// Add to the appropriate buffer
buffer[0] = HEX_LABELS; //add labels to the first row of the buffer

// Loop through each device address from the start to end
for(unsigned int i = 0x00U; i <= 0x70U; i+=0x10U) {
strcat(buffer[row], hex_labels[row - 1]);
for(unsigned int j = 0x00U; j < 0x10U; j += 0x01U) {
uint8_t devAddr = i + j;
// out of range reading
if(devAddr < start || devAddr > end) {
strcpy(status, SPACING);
}
// in range
else {
// Use HAL_I2C_IsDeviceReady
ret = HAL_I2C_IsDeviceReady(hi2c, (devAddr << 1), MAX_TRIALS, TIMEOUT);

// Device status case
switch (ret) {
case HAL_BUSY:
strcpy(status, "UU"); // the bus is considered busy
break;
case HAL_OK:
utoa(devAddr, status, HEX); // reads the hexadecimal address and turns it into a string
break;
case HAL_ERROR:
case HAL_TIMEOUT:
default:
strcpy(status, "--"); // no response from device or not found
break;
}
}

// Add status to the buffer
strcat(buffer[row], SPACING); // spacing for string
strcat(buffer[row], status); // actual status

// clear char array
memset(status, 0, strlen(status));
}
// table update
strcat(buffer[row], "\n");
row++;
}

// Return normal status
return 0;
}

/**
* TODO: Implement different reading modes
* HAL_I2C_Master_Receive() - requests data from slave device. (BLOCKING)
* HAL_I2C_Mem_Read() - requests data from slave device from a specific memory address. (NON-BLOCKING)
*/
int i2cdump(I2C_HandleTypeDef *hi2c, uint16_t devAddress, char **buffer, char mode, uint8_t start, uint8_t end) {
// Prepare the buffer
int row = 0;

// need to read from the given address of a I2C Bus.
switch(mode) {
case 'w': // A word (4 bytes or 32-bit)
buffer[row] = "\t\t0 4 8 b";
row ++;

uint8_t data1 = 0;
for(unsigned int i = 0x00U; i <= 0xf0U; i += 0x10U) {
buffer[row] = hex_labels[row - 1];
char data_str[sizeof(char) * 4 + 1];

for(unsigned int j = 0x00U; j <= 0x0fU; j += 0x04U) {
uint16_t reg = i + j;
// read memory address
if (HAL_I2C_Mem_Read(hi2c, (devAddress << 1), reg, I2C_MEMADD_SIZE_8BIT, &data1, 4, HAL_MAX_DELAY) != HAL_OK) {
// error
return HAL_ERROR;
}

// convert data into char text
utoa(data1, data_str, HEX);

// display the value from the memory address
strcat(buffer[row], SPACING);
strcat(buffer[row], data_str);

// reset the string array
memset(data_str, 0, strlen(data_str));
}
strcat(buffer[row], "\n");
row++;
}
break;
case 's': // A SMBus Block
break;
case 'i': // I2C Block
break;
case 'b': // Byte sized (default)
default:
// Add the labels to the first row
buffer[row] = HEX_LABELS;
row ++;

uint8_t data = 0;
for (unsigned int i = 0x00U; i <= 0xf0U; i += 0x10U) {
// add the vertical labels
buffer[row] = hex_labels[row - 1];
char data_str[sizeof(char) * 2 + 1];

for(unsigned int j = 0x00U; j <= 0x0fU; j++) {
uint16_t reg = i + j; // get the memory address
// read memory address
if (HAL_I2C_Mem_Read(hi2c, (devAddress << 1), reg, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY) != HAL_OK) {
// error
return HAL_ERROR;
}

// Convert data buffer into the char buffer
utoa(data, data_str, HEX);

// display the value from the memory address
strcat(buffer[row], SPACING);
strcat(buffer[row], data_str);

// reset the string array
memset(data_str, 0, strlen(data_str));
}
strcat(buffer[row], "\n");
row++;
}
break;
}
// nominal return
return HAL_OK;
}

/**
* @warning serial_print max size is 128 bytes.
*/
void printResult(char **buffer, int len) {
for(int i = 0; i < len; i++) {
serial_print(buffer[i]);
}
}

0 comments on commit 0ff91be

Please sign in to comment.