impl i2c mutex and some work on global star code handler

This commit is contained in:
Mitchell Marino 2025-07-12 16:39:28 -05:00
parent 9cc1a93e73
commit 1267d1356d
11 changed files with 152 additions and 76 deletions

View File

@ -32,6 +32,7 @@ Arduino Uno (any 'duino should do)
******************************************************************************/ ******************************************************************************/
#include "SparkFunBQ27441.h" #include "SparkFunBQ27441.h"
#include "../i2c.h"
/***************************************************************************** /*****************************************************************************
************************** Initialization Functions ************************* ************************** Initialization Functions *************************
@ -710,7 +711,9 @@ bool BQ27441::writeExtendedData(uint8_t classID, uint8_t offset, uint8_t * data,
int16_t BQ27441::i2cReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count) int16_t BQ27441::i2cReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count)
{ {
int16_t timeout = BQ72441_I2C_TIMEOUT; int16_t timeout = BQ72441_I2C_TIMEOUT;
xSemaphoreTake(i2c0_mutex, portMAX_DELAY);
i2c_master_write_read_device(BQ72441_I2C_NUM, _deviceAddress, &subAddress, 1, dest, count, timeout); i2c_master_write_read_device(BQ72441_I2C_NUM, _deviceAddress, &subAddress, 1, dest, count, timeout);
xSemaphoreGive(i2c0_mutex);
return timeout; return timeout;
} }

View File

@ -1,7 +1,6 @@
#include "all.h" #include "all.h"
static const char *TAG = "driver_all"; static const char *TAG = "driver_all";
static void init_i2c();
void init_drivers() { void init_drivers() {
init_i2c(); init_i2c();
@ -18,35 +17,3 @@ void init_drivers() {
init_leds(); init_leds();
init_power_board(); init_power_board();
} }
/// @brief Initializes `I2C_NUM_0`.
///
/// This is hooked up the to:
/// - The bottom half
/// - The char lcd
/// - The power board
/// - The MPU6050
/// - The PERH port
/// - The Capacitive Touch Panel
static void init_i2c() {
ESP_LOGI(TAG, "Initializing i2c...");
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_5,
.scl_io_num = GPIO_NUM_6,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = 100*1000,
},
.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL
};
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0));
ESP_LOGI(TAG, "i2c initialized!");
}

View File

@ -4,6 +4,7 @@
#include "bottom_half.h" #include "bottom_half.h"
#include "char_lcd.h" #include "char_lcd.h"
#include "game_timer.h" #include "game_timer.h"
#include "i2c.h"
#include "leds.h" #include "leds.h"
#include "power.h" #include "power.h"
#include "sd.h" #include "sd.h"

View File

@ -7,7 +7,11 @@
i2c_lcd_pcf8574_handle_t lcd; i2c_lcd_pcf8574_handle_t lcd;
static volatile bool header_enabled;
static const char *TAG = "char_lcd"; static const char *TAG = "char_lcd";
static const char* EMPTY_ROW = " ";
static const char* EMPTY_ROW3 = " ";
static char buf[65]; static char buf[65];
@ -57,8 +61,7 @@ static bool replay_handler(const char* event, char* arg) {
return true; return true;
} }
if (strcmp(event, "LCD_BACKLIGHT") == 0) { if (strcmp(event, "LCD_BACKLIGHT") == 0) {
uint32_t brightness = atoi(arg); lcd_set_backlight(strcmp(arg, "true") == 0);
lcd_set_backlight(brightness);
return true; return true;
} }
if (strcmp(event, "LCD_CREATE_CHAR") == 0) { if (strcmp(event, "LCD_CREATE_CHAR") == 0) {
@ -102,19 +105,19 @@ void init_lcd() {
} }
void lcd_clear() { void lcd_clear() {
if (!header_enabled) {
lcd_clear(&lcd); lcd_clear(&lcd);
if (is_state_tracking()) { if (is_state_tracking()) {
event_occured("LCD_CLEAR", NULL); event_occured("LCD_CLEAR", NULL);
} }
} else {
lcd_print(1, 2, EMPTY_ROW3);
}
} }
void lcd_cursor_home() { void lcd_cursor_home() {
lcd_home(&lcd); lcd_set_cursor_pos(0, 0);
if (is_state_tracking()) {
event_occured("LCD_CURSOR", "0,0");
}
} }
void lcd_set_cursor_pos(uint8_t col, uint8_t row) { void lcd_set_cursor_pos(uint8_t col, uint8_t row) {
@ -204,12 +207,12 @@ void lcd_set_autoscroll(bool autoscroll) {
} }
} }
void lcd_set_backlight(uint8_t brightness) { void lcd_set_backlight(bool backlight) {
lcd_set_backlight(&lcd, brightness); lcd_set_backlight(&lcd, backlight);
if (is_state_tracking()) { if (is_state_tracking()) {
sprintf(buf, "%d", brightness); sprintf(buf, "%d", backlight);
event_occured("LCD_BACKLIGHT", buf); event_occured("LCD_BACKLIGHT", backlight ? "true" : "false");
} }
} }
@ -225,16 +228,8 @@ void lcd_create_char(uint8_t location, uint8_t* charmap) {
} }
} }
void lcd_write(uint8_t value) { void lcd_print(uint8_t col, uint8_t row, const char* str) {
lcd_write(&lcd, value); lcd_set_cursor_pos(col, row);
if (is_state_tracking()) {
sprintf(buf, "%d", value);
event_occured("LCD_WRITE", buf);
}
}
void lcd_print(const char* str) {
lcd_print(&lcd, str); lcd_print(&lcd, str);
if (is_state_tracking()) { if (is_state_tracking()) {
@ -243,7 +238,35 @@ void lcd_print(const char* str) {
} }
} }
void lcd_print(uint8_t col, uint8_t row, const char* str) { void set_lcd_header_enabled(bool enable) {
lcd_set_cursor_pos(col, row); if (!header_enabled && enable) {
lcd_print(str); // enabling header
// TODO: enable header
} else if (header_enabled && !enable) {
// disabling header
lcd_print(1, 1, EMPTY_ROW);
}
header_enabled = enable;
}
bool lcd_header_enabled() {
return header_enabled;
}
void lcd_print_header() {
lcd_print_header_star_code();
lcd_print_header_step();
lcd_print_header_bat();
}
void lcd_print_header_star_code() {
}
void lcd_print_header_step() {
}
void lcd_print_header_bat() {
} }

View File

@ -49,13 +49,30 @@ void lcd_set_backlight(uint8_t brightness);
// Create a custom character // Create a custom character
void lcd_create_char(uint8_t location, uint8_t charmap[]); void lcd_create_char(uint8_t location, uint8_t charmap[]);
// Write a character to the LCD /// @brief Print a string to the LCD at a given pos.
void lcd_write(uint8_t value); /// @param col the column to print the string at.
/// @param row the row the print the string at.
// Print a string to the LCD /// @param str the string to print.
void lcd_print(const char* str);
// Print a string to the LCD at a given pos
void lcd_print(uint8_t col, uint8_t row, const char* str); void lcd_print(uint8_t col, uint8_t row, const char* str);
/// @brief Enables or disables the header on the LCD.
/// @param enable `true` to enable the header, `false` to disable.
void set_lcd_header_enabled(bool enable);
/// @brief Returns weather or not the lcd_header is enabled.
/// @return `true` if the header is enabled, `false` otherwise.
bool lcd_header_enabled();
/// @brief Prints the header in the LCD.
void lcd_print_header();
/// @brief Prints the star code section of the LCD header.
void lcd_print_header_star_code();
/// @brief Prints the step section of the LCD header.
void lcd_print_header_step();
/// @brief Prints the battery section of the LCD header.
void lcd_print_header_bat();
#endif /* CHAR_LCD_H */ #endif /* CHAR_LCD_H */

32
main/drivers/i2c.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "i2c.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/i2c_master.h"
static const char *TAG = "i2c";
static void init_i2c() {
ESP_LOGI(TAG, "Initializing i2c...");
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_5,
.scl_io_num = GPIO_NUM_6,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = 100*1000,
},
.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL
};
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0));
i2c0_mutex = xSemaphoreCreateMutex();
assert(i2c0_mutex != NULL);
ESP_LOGI(TAG, "i2c initialized!");
}

21
main/drivers/i2c.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef I2C_H
#define I2C_H
#include "FreeRTOS.h"
#include "freertos/semphr.h"
/// The mutex for accessing `I2C_NUM_0`.
SemaphoreHandle_t i2c0_mutex;
/// @brief Initializes `I2C_NUM_0`.
///
/// This is hooked up the to:
/// - The bottom half
/// - The char lcd
/// - The power board
/// - The MPU6050
/// - The PERH port
/// - The Capacitive Touch Panel
void init_i2c();
#endif /* I2C_H */

View File

@ -12,6 +12,7 @@
#include "esp_check.h" #include "esp_check.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "i2c.h"
#define TAG "I2C_LCD_PCF8574" #define TAG "I2C_LCD_PCF8574"
@ -58,6 +59,7 @@ void lcd_begin(i2c_lcd_pcf8574_handle_t* lcd, uint8_t cols, uint8_t rows) {
lcd->entrymode = 0x02; lcd->entrymode = 0x02;
// The following are the reset sequence: Please see "Initialization instruction in the PCF8574 datasheet." // The following are the reset sequence: Please see "Initialization instruction in the PCF8574 datasheet."
xSemaphoreTake(i2c0_mutex, portMAX_DELAY);
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
// We left-shift the device addres and add the read/write command // We left-shift the device addres and add the read/write command
@ -95,6 +97,7 @@ void lcd_begin(i2c_lcd_pcf8574_handle_t* lcd, uint8_t cols, uint8_t rows) {
i2c_master_stop(cmd); i2c_master_stop(cmd);
i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd); i2c_cmd_link_delete(cmd);
xSemaphoreGive(i2c0_mutex);
// Instruction: function set = 0x20 // Instruction: function set = 0x20
lcd_send(lcd, 0x20 | (rows > 1 ? 0x08 : 0x00), false); lcd_send(lcd, 0x20 | (rows > 1 ? 0x08 : 0x00), false);
@ -110,7 +113,7 @@ void lcd_clear(i2c_lcd_pcf8574_handle_t* lcd) {
// Instruction: Clear display = 0x01 // Instruction: Clear display = 0x01
lcd_send(lcd, 0x01, false); lcd_send(lcd, 0x01, false);
// Clearing the display takes a while: takes approx. 1.5ms // Clearing the display takes a while: takes approx. 1.5ms
esp_rom_delay_us(1600); esp_rom_delay_us(2000);
} // lcd_clear() } // lcd_clear()
// Set the display to home // Set the display to home
@ -118,7 +121,7 @@ void lcd_home(i2c_lcd_pcf8574_handle_t* lcd) {
// Instruction: Return home = 0x02 // Instruction: Return home = 0x02
lcd_send(lcd, 0x02, false); lcd_send(lcd, 0x02, false);
// Same as clearing the display: takes approx. 1.5ms // Same as clearing the display: takes approx. 1.5ms
esp_rom_delay_us(1600); esp_rom_delay_us(2000);
} // lcd_home() } // lcd_home()
// Set the cursor to a new position. // Set the cursor to a new position.
@ -295,6 +298,7 @@ void lcd_print_number(i2c_lcd_pcf8574_handle_t* lcd, uint8_t col, uint8_t row, u
static void lcd_send(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value, bool is_data) { static void lcd_send(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value, bool is_data) {
xSemaphoreTake(i2c0_mutex, portMAX_DELAY);
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true);
@ -303,6 +307,7 @@ static void lcd_send(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value, bool is_data)
i2c_master_stop(cmd); i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd); i2c_cmd_link_delete(cmd);
xSemaphoreGive(i2c0_mutex);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to send data to LCD: %s", esp_err_to_name(ret)); ESP_LOGE(TAG, "Failed to send data to LCD: %s", esp_err_to_name(ret));
@ -341,6 +346,7 @@ static void lcd_write_i2c(i2c_lcd_pcf8574_handle_t* lcd, uint8_t data, bool is_d
data |= lcd->backlight_mask; data |= lcd->backlight_mask;
} }
xSemaphoreTake(i2c0_mutex, portMAX_DELAY);
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd); i2c_master_start(cmd);
i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true);
@ -348,6 +354,7 @@ static void lcd_write_i2c(i2c_lcd_pcf8574_handle_t* lcd, uint8_t data, bool is_d
i2c_master_stop(cmd); i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd); i2c_cmd_link_delete(cmd);
xSemaphoreGive(i2c0_mutex);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to write to LCD: %s", esp_err_to_name(ret)); ESP_LOGE(TAG, "Failed to write to LCD: %s", esp_err_to_name(ret));

View File

@ -50,4 +50,6 @@ void init_power_board() {
ESP_LOGI(TAG, "Power board initialized!"); ESP_LOGI(TAG, "Power board initialized!");
} }
uint16_t get_bat_voltage() {
lipo.voltage();
}

View File

@ -3,12 +3,14 @@
#include "SparkFunBQ27441/SparkFunBQ27441.h" #include "SparkFunBQ27441/SparkFunBQ27441.h"
extern volatile uint32_t battery_charge;
void bat_monitor_task(void* arg); void bat_monitor_task(void* arg);
/// Initializes the battery gas guage for getting battery stats. /// Initializes the battery gas guage for getting battery stats.
void init_power_board(); void init_power_board();
/// @brief Gets the battery voltage /// @brief Gets the battery voltage.
/// @return battery voltage in mV. /// @return battery voltage in mV.
uint16_t get_bat_voltage(); uint16_t get_bat_voltage();

View File

@ -66,16 +66,17 @@ bool rm_star_codes_str(const char** codes, size_t len);
/// @brief clears all star codes. /// @brief clears all star codes.
void clear_star_codes(); void clear_star_codes();
/// @brief Triggers the given starcode. /// @brief Triggers the given star code.
/// @param code the star code to trigger (without the *) /// @param code the star code to trigger (without the *)
/// @return true iff a star code was triggered /// @return true iff a star code was triggered
bool trigger_star_code(const char* code); bool trigger_star_code(const char* code);
/// @brief Tempararilly stops the starcode system from handling new starcodes. /// @brief Tempararilly starts/stops the star code system from handling new star codes.
void pause_star_code_system(); void set_star_code_sys_enabled(bool enable);
/// @brief Resumes the starcode system to start handling new starcodes again. /// @brief Gets weather or not the star code system is handling new star codes.
void resume_star_code_system(); /// @return `true` if the star code system is handling star codes.
bool star_code_sys_enabled();
#endif /* STAR_CODE_H */ #endif /* STAR_CODE_H */