From b9fc071d9ce0693c9f1090da99bf82e8a1762a70 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Fri, 27 Mar 2026 22:12:12 +1100 Subject: [PATCH 01/24] Copied and implemented foundational code from test repository to enable communication with the fan controller over I2C. --- NUSense/Core/Inc/fan_controller.h | 28 ++++++++ NUSense/Core/Inc/i2c.h | 25 ++++++++ NUSense/Core/Src/fan_controller.c | 103 ++++++++++++++++++++++++++++++ NUSense/Core/Src/i2c.c | 87 +++++++++++++++++++++++++ NUSense/Core/Src/main.cpp | 6 ++ 5 files changed, 249 insertions(+) create mode 100644 NUSense/Core/Inc/fan_controller.h create mode 100644 NUSense/Core/Inc/i2c.h create mode 100644 NUSense/Core/Src/fan_controller.c create mode 100644 NUSense/Core/Src/i2c.c diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h new file mode 100644 index 0000000..edfa550 --- /dev/null +++ b/NUSense/Core/Inc/fan_controller.h @@ -0,0 +1,28 @@ +#ifndef FAN_CONTROLLER_H +#define FAN_CONTROLLER_H + +#include "main.h" +#include +#include + +// Fan Controller I2C Address +#define FAN_CONTROLLER_ADDRESS 0xA0 + +// Registers +#define REG_CONTROL1 0x00 +#define REG_CONTROL2 0x01 +#define REG_CONTROL3 0x02 +#define REG_PWMR 0x50 +#define REG_STATUS 0x5A + +// Functions +void fan_controller_init(); +uint8_t read_fan_register(uint8_t reg); +uint8_t write_fan_register(uint8_t reg, uint8_t value); +void set_fan_pwm_freq(uint8_t freq); +void set_fan_mode(bool mode); +void set_fan_spin_up(bool enabled); +void set_fan_manual_pwm(uint8_t pwm_value); +void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled); + +#endif // FAN_CONTROLLER_H \ No newline at end of file diff --git a/NUSense/Core/Inc/i2c.h b/NUSense/Core/Inc/i2c.h new file mode 100644 index 0000000..a64aa73 --- /dev/null +++ b/NUSense/Core/Inc/i2c.h @@ -0,0 +1,25 @@ +#ifndef I2C_H +#define I2C_H + +#include "main.h" +#include "stm32h7xx_hal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_SDA_Pin GPIO_PIN_9 +#define I2C_SDA_GPIO_Port GPIOC +#define I2C_SCL_Pin GPIO_PIN_8 +#define I2C_SCL_GPIO_Port GPIOA + +extern I2C_HandleTypeDef hi2c3; + +void MX_I2C3_Init(void); +void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); + +#ifdef __cplusplus +} +#endif + +#endif // I2C_H \ No newline at end of file diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c new file mode 100644 index 0000000..9bdeb4b --- /dev/null +++ b/NUSense/Core/Src/fan_controller.c @@ -0,0 +1,103 @@ +#include "fan_controller.h" +extern I2C_HandleTypeDef hi2c3; + +/// @brief Reads a value from a fan controller register. +/// @param reg The register address to read from. +/// @return The value read from the register. +uint8_t read_fan_register(uint8_t reg) +{ + uint8_t value = 0; + HAL_I2C_Mem_Read(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); + return value; +} + +/// @brief Writes a value to a fan controller register. +/// @param reg The register address to write to. +/// @param value The value to write. +/// @return The HAL status of the write operation. +uint8_t write_fan_register(uint8_t reg, uint8_t value) +{ + return HAL_I2C_Mem_Write(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); +} + +/// @brief Sets the PWM frequency of the fan. The frequency is determined by bits 3 and 4 of Control Register 1. +/// @param freq The desired frequency setting (0b00 for 33Hz, 0b01 for 150Hz, 0b10 for 1500Hz, 0b11 for 25kHz) +void set_fan_pwm_freq(uint8_t freq) +{ + uint8_t control1 = read_fan_register(REG_CONTROL1); + control1 &= ~(0b11 << 3); // clear bits 3 and 4 + control1 |= (freq & 0b11) << 3; // set bits 3 and 4 to the desired frequency + write_fan_register(REG_CONTROL1, control1); +} + +/// @brief Sets the fan mode between manual and automatic. +/// @param mode true for manual mode (Direct Fan Control enabled), false for automatic mode (Direct Fan Control disabled) +void set_fan_mode(bool mode) +{ + uint8_t control2 = read_fan_register(REG_CONTROL2); + if (mode) { + control2 |= (1 << 0); // set bit 0 to enable Direct Fan Control + } else { + control2 &= ~(1 << 0); // clear bit 0 to disable Direct Fan Control + } + write_fan_register(REG_CONTROL2, control2); +} + +/// @brief Sets the fan spin-up mode. +/// @param enabled true to enable spin-up mode, false to disable +void set_fan_spin_up(bool enabled) +{ + uint8_t control2 = read_fan_register(REG_CONTROL2); + if (enabled) { + control2 |= (1 << 1); // set bit 1 to enable Spin-Up mode + } else { + control2 &= ~(1 << 1); // clear bit 1 to disable Spin-Up mode + } + write_fan_register(REG_CONTROL2, control2); +} + +/// @brief Enables or disables the tachometer for the specified fan. +/// @param tachometer 0 for Tachometer 1, 1 for Tachometer 2 +/// @param enabled true to enable, false to disable +void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) +{ + uint8_t control3 = read_fan_register(REG_CONTROL3); + if (tachometer == 0) { + if (enabled) { + control3 |= (1 << 0); // set bit 0 to enable Tachometer 1 + } else { + control3 &= ~(1 << 0); // clear bit 0 to disable Tachometer 1 + } + } else if (tachometer == 1) { + if (enabled) { + control3 |= (1 << 1); // set bit 1 to enable Tachometer 2 + } else { + control3 &= ~(1 << 1); // clear bit 1 to disable Tachometer 2 + } + } + write_fan_register(REG_CONTROL3, control3); +} + +/// @brief Sets the manual PWM value for the fan. +/// @param pwm_value +void set_fan_manual_pwm(uint8_t pwm_value) +{ + write_fan_register(REG_PWMR, pwm_value); +} + +/// @brief Sets up the Fan Controller with default settings: 1500Hz PWM frequency, manual mode enabled, tachometers disabled, and ~78% duty cycle. +void fan_controller_init() +{ + // set the PWM frequency to 1500Hz (0b10) + set_fan_pwm_freq(0b10); + + // put the fan into manual mode + set_fan_mode(true); + + // disable tachometers + set_fan_tachometer_enabled(0, false); + set_fan_tachometer_enabled(1, false); + + // set Direct Duty-Cycle Control Register to full blast. + set_fan_manual_pwm(255); +} \ No newline at end of file diff --git a/NUSense/Core/Src/i2c.c b/NUSense/Core/Src/i2c.c new file mode 100644 index 0000000..e0aedbe --- /dev/null +++ b/NUSense/Core/Src/i2c.c @@ -0,0 +1,87 @@ +#include "i2c.h" + +I2C_HandleTypeDef hi2c3; + +/** + * @brief I2C3 Initialization Function + * @param None + * @retval None + */ +void MX_I2C3_Init(void) +{ + hi2c3.Instance = I2C3; + hi2c3.Init.Timing = 0x00702681; // 400kHz I2C Fast Mode + hi2c3.Init.OwnAddress1 = 0; + hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c3.Init.OwnAddress2 = 0; + hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK; + hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + if (HAL_I2C_Init(&hi2c3) != HAL_OK) { + Error_Handler(); + } + if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK) { + Error_Handler(); + } + if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK) { + Error_Handler(); + } +} + +/** + * @brief I2C MSP Initialization + * This function configures the hardware resources used by I2C3 + * @param hi2c: I2C handle pointer + * @retval None + */ +void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if (hi2c->Instance == I2C3) { + /* Peripheral clock enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_I2C3_CLK_ENABLE(); + + /**I2C3 GPIO Configuration + PC9 ------> I2C3_SDA + PA8 ------> I2C3_SCL + */ + GPIO_InitStruct.Pin = I2C_SDA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C3; + HAL_GPIO_Init(I2C_SDA_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = I2C_SCL_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C3; + HAL_GPIO_Init(I2C_SCL_GPIO_Port, &GPIO_InitStruct); + } +} + +/** + * @brief GPIO Initialization Function + * @param None + * @retval None + */ +static void MX_GPIO_Init(void) +{ + /* USER CODE BEGIN MX_GPIO_Init_1 */ + + /* USER CODE END MX_GPIO_Init_1 */ + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + + /* I2C GPIO configuration is handled in HAL_I2C_MspInit */ + + /* USER CODE BEGIN MX_GPIO_Init_2 */ + + /* USER CODE END MX_GPIO_Init_2 */ +} \ No newline at end of file diff --git a/NUSense/Core/Src/main.cpp b/NUSense/Core/Src/main.cpp index 7459c8e..5f87378 100644 --- a/NUSense/Core/Src/main.cpp +++ b/NUSense/Core/Src/main.cpp @@ -24,6 +24,8 @@ #include "tim.h" #include "usart.h" #include "usb_device.h" +#include "fan_controller.h" +#include "i2c.h" /* Private includes ----------------------------------------------------------*/ #include "nusense/NUSenseIO.hpp" @@ -65,6 +67,10 @@ int main(void) { MX_USART6_UART_Init(); MX_TIM1_Init(); MX_TIM4_Init(); + MX_I2C3_Init(); + + /* Initialize fan controller after I2C3 is ready */ + fan_controller_init(); #ifdef FIRST_BUZZ // Confirm that the programme is running. From 47aaafac80c32b63cfff3be313be6d8c37d1a159 Mon Sep 17 00:00:00 2001 From: Miles Punch <71351127+miles-p@users.noreply.github.com> Date: Sun, 29 Mar 2026 21:47:56 +1100 Subject: [PATCH 02/24] Fix C++ linkage for fan controller header file --- NUSense/Core/Inc/fan_controller.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index edfa550..e616392 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -1,6 +1,10 @@ #ifndef FAN_CONTROLLER_H #define FAN_CONTROLLER_H +#ifdef __cplusplus +extern "C" { +#endif + #include "main.h" #include #include @@ -25,4 +29,8 @@ void set_fan_spin_up(bool enabled); void set_fan_manual_pwm(uint8_t pwm_value); void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled); +#ifdef __cplusplus +} +#endif + #endif // FAN_CONTROLLER_H \ No newline at end of file From bf479e4fcc9866588bed0ebe8dd5108a0cfae47b Mon Sep 17 00:00:00 2001 From: Miles Punch <71351127+miles-p@users.noreply.github.com> Date: Wed, 1 Apr 2026 09:58:05 +1100 Subject: [PATCH 03/24] add function to read fan speed --- NUSense/Core/Inc/fan_controller.h | 9 ++++++++- NUSense/Core/Src/fan_controller.c | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index e616392..4b19068 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -9,13 +9,19 @@ extern "C" { #include #include +// Fan configuration +#define PULSES_PER_REVOLUTION 4 + // Fan Controller I2C Address #define FAN_CONTROLLER_ADDRESS 0xA0 +#define DEFAULT_FAN_SPEED 0xFF // full steam ahead // Registers #define REG_CONTROL1 0x00 #define REG_CONTROL2 0x01 #define REG_CONTROL3 0x02 +#define REG_FAN1COUNT 0x52 // MSB of 2 byte fan controller tachometer count for fan 1 +#define REG_FAN2COUNT 0x54 // MSB of 2 byte fan controller tachometer count for fan 2 #define REG_PWMR 0x50 #define REG_STATUS 0x5A @@ -27,10 +33,11 @@ void set_fan_pwm_freq(uint8_t freq); void set_fan_mode(bool mode); void set_fan_spin_up(bool enabled); void set_fan_manual_pwm(uint8_t pwm_value); +uint16_t read_fan_speed(uint8_t tachometer); void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled); #ifdef __cplusplus } #endif -#endif // FAN_CONTROLLER_H \ No newline at end of file +#endif // FAN_CONTROLLER_H diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 9bdeb4b..8fd763f 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -85,7 +85,18 @@ void set_fan_manual_pwm(uint8_t pwm_value) write_fan_register(REG_PWMR, pwm_value); } -/// @brief Sets up the Fan Controller with default settings: 1500Hz PWM frequency, manual mode enabled, tachometers disabled, and ~78% duty cycle. +/// @brief reads the fan speed from the controller +/// @param tachometer 0 for Fan 1, 1 for Fan 2 +/// @return The speed in RPM. +uint16_t read_fan_speed(uint8_t tachometer) { + uint8_t fan_register = (tachometer == 0 ? REG_FAN1COUNT : REG_FAN2COUNT); + uint8_t msb = read_fan_register(fan_register); + uint8_t lsb = read_fan_register(fan_register + 1); + uint8_t fan_count = (msb << 8) | lsb; + return (60 * 100000) / (fan_count * PULSES_PER_REVOLUTION); +} + +/// @brief Sets up the Fan Controller with default settings: 1500Hz PWM frequency, manual mode enabled, tachometers enabled, and full speed void fan_controller_init() { // set the PWM frequency to 1500Hz (0b10) @@ -94,10 +105,10 @@ void fan_controller_init() // put the fan into manual mode set_fan_mode(true); - // disable tachometers - set_fan_tachometer_enabled(0, false); - set_fan_tachometer_enabled(1, false); + // enable both tachometers + set_fan_tachometer_enabled(0, true); + set_fan_tachometer_enabled(1, true); // set Direct Duty-Cycle Control Register to full blast. - set_fan_manual_pwm(255); -} \ No newline at end of file + set_fan_manual_pwm(DEFAULT_FAN_SPEED); +} From b37aeed813a8f4021cc73f2c91b0e6076e3efc0c Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Wed, 1 Apr 2026 23:01:40 +1100 Subject: [PATCH 04/24] fix int size and change fan calc algorithm --- NUSense/Core/Src/fan_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 8fd763f..95e5626 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -92,8 +92,8 @@ uint16_t read_fan_speed(uint8_t tachometer) { uint8_t fan_register = (tachometer == 0 ? REG_FAN1COUNT : REG_FAN2COUNT); uint8_t msb = read_fan_register(fan_register); uint8_t lsb = read_fan_register(fan_register + 1); - uint8_t fan_count = (msb << 8) | lsb; - return (60 * 100000) / (fan_count * PULSES_PER_REVOLUTION); + uint16_t fan_count = (msb << 8) | lsb; + return 60 * 100000 / fan_count / PULSES_PER_REVOLUTION; } /// @brief Sets up the Fan Controller with default settings: 1500Hz PWM frequency, manual mode enabled, tachometers enabled, and full speed From 428428d78a8794feb5631b846054a227639de302 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Wed, 1 Apr 2026 13:34:39 +1100 Subject: [PATCH 05/24] Add comments for fan configuration constants in fan_controller.h --- NUSense/Core/Inc/fan_controller.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index 4b19068..d88bc48 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -10,7 +10,8 @@ extern "C" { #include // Fan configuration -#define PULSES_PER_REVOLUTION 4 +#define PULSES_PER_REVOLUTION 4 // Fan tachometer pulse count that corresponds to one revolution +#define FAN_RPM_WARNING 100 // RPM // Fan Controller I2C Address #define FAN_CONTROLLER_ADDRESS 0xA0 From b2552d03ba957227d186fcf790d63baf88efd7db Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 2 Apr 2026 14:55:16 +1100 Subject: [PATCH 06/24] Add fan warning enum and add it to the NUSense_init_zero --- NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h index 5ab89d9..32a40b1 100644 --- a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h +++ b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h @@ -16,6 +16,11 @@ typedef enum _message_platform_ServoIDStates_IDState { message_platform_ServoIDStates_IDState_DUPLICATE = 2 } message_platform_ServoIDStates_IDState; +enum _message_platform_FanWarningStates_IDState { + message_platform_FanWarningStates_IDState_NOWARNING = 0, + message_platform_FanWarningStates_IDState_WARNING = 1 +}; + /* Struct definitions */ typedef struct _message_platform_Servo_PacketCounts { /* / The total number of packets received. */ @@ -184,12 +189,13 @@ extern "C" { #define message_platform_IMU_init_zero {false, message_platform_IMU_fvec3_init_zero, false, message_platform_IMU_fvec3_init_zero, 0} #define message_platform_IMU_fvec3_init_zero {0, 0, 0} #define message_platform_Buttons_init_zero {0, 0} -#define message_platform_NUSense_init_zero {0, {message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero}, false, message_platform_IMU_init_zero, false, message_platform_Buttons_init_zero} +#define message_platform_NUSense_init_zero {0, {message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero}, false, message_platform_IMU_init_zero, false, message_platform_Buttons_init_zero, message_platform_FanWarning_init_zero} #define message_platform_NUSense_ServoMapEntry_init_zero {0, false, message_platform_Servo_init_zero} #define message_platform_ServoConfiguration_init_zero {0, 0} #define message_platform_NUSenseHandshake_init_zero {0, "", 0, {message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero}} #define message_platform_ServoIDStates_init_zero {0, {message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero}} #define message_platform_ServoIDStates_ServoIDState_init_zero {0, _message_platform_ServoIDStates_IDState_MIN} +#define message_platform_FanWarning_init_zero {message_platform_FanWarningStates_IDState_NOWARNING, message_platform_FanWarningStates_IDState_NOWARNING} /* Field tags (for use in manual encoding/decoding) */ #define message_platform_Servo_PacketCounts_total_tag 1 From d7311c668c9bb51d96a3581b136554f5dd47e0ce Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 2 Apr 2026 15:08:25 +1100 Subject: [PATCH 07/24] Add fan controller header and update protobuf definitions for fan warnings --- NUSense/Core/Src/nusense/NUSenseIO.hpp | 1 + .../Core/Src/nusense/NUSenseIO/send_nusense_data.cpp | 2 ++ NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h | 10 ++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/NUSense/Core/Src/nusense/NUSenseIO.hpp b/NUSense/Core/Src/nusense/NUSenseIO.hpp index 3362102..6adb6b7 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO.hpp +++ b/NUSense/Core/Src/nusense/NUSenseIO.hpp @@ -22,6 +22,7 @@ #include "NUgus.hpp" #include "ServoState.hpp" #include "imu.h" +#include "fan_controller.h" namespace nusense { constexpr uint32_t MAX_ENCODE_SIZE = 1600; diff --git a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp index d32ef56..6e23fbc 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp +++ b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp @@ -31,6 +31,8 @@ namespace nusense { nusense_msg.buttons.left = mode_button.filter(); nusense_msg.buttons.middle = start_button.filter(); + nusense_msg. + if (nusense_msg.buttons.left) { tx_led.pulse(1, false, device::Pulser::LOW); } diff --git a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h index 32a40b1..e9ba6ba 100644 --- a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h +++ b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h @@ -16,10 +16,10 @@ typedef enum _message_platform_ServoIDStates_IDState { message_platform_ServoIDStates_IDState_DUPLICATE = 2 } message_platform_ServoIDStates_IDState; -enum _message_platform_FanWarningStates_IDState { +typedef enum _message_platform_FanWarningStates_IDState { message_platform_FanWarningStates_IDState_NOWARNING = 0, message_platform_FanWarningStates_IDState_WARNING = 1 -}; +} message_platform_FanWarningStates_IDState; /* Struct definitions */ typedef struct _message_platform_Servo_PacketCounts { @@ -94,6 +94,11 @@ typedef struct _message_platform_NUSense_ServoMapEntry { message_platform_Servo value; } message_platform_NUSense_ServoMapEntry; +typedef struct _message_platform_FanWarning { + uint32_t id; + message_platform_FanWarningStates_IDState state; +} message_platform_FanWarning; + typedef struct _message_platform_NUSense { /* INDEX MAPPING 0 : r_shoulder_pitch @@ -122,6 +127,7 @@ typedef struct _message_platform_NUSense { message_platform_IMU imu; bool has_buttons; message_platform_Buttons buttons; + message_platform_FanWarning fan_warning_states[2]; } message_platform_NUSense; typedef struct _message_platform_ServoConfiguration { From ba9e67551ad2a24fcaf346cf46cbbe8a07eb1549 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 2 Apr 2026 15:08:46 +1100 Subject: [PATCH 08/24] Add fan warning state check based on fan speed --- NUSense/Core/Src/fan_controller.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 95e5626..71d2a31 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -1,4 +1,5 @@ #include "fan_controller.h" +#include extern I2C_HandleTypeDef hi2c3; /// @brief Reads a value from a fan controller register. @@ -20,6 +21,16 @@ uint8_t write_fan_register(uint8_t reg, uint8_t value) return HAL_I2C_Mem_Write(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); } +/// @brief Checks the fan warning states for the specified fan. +/// @param fan_id The ID of the fan to check (0 for Fan 1 (J401 on NUSense), 1 for Fan 2 (J402 on NUSense)) +/// @return The warning state of the specified fan. Returns true if there is a warning, false if there is no warning. +bool fan_warning_state(uint8_t fan_id) { + if (read_fan_speed(fan_id) <= FAN_RPM_WARNING) { + return true; // Warning state if fan speed is less than or equal to the defined warning threshold + } + return false; +} + /// @brief Sets the PWM frequency of the fan. The frequency is determined by bits 3 and 4 of Control Register 1. /// @param freq The desired frequency setting (0b00 for 33Hz, 0b01 for 150Hz, 0b10 for 1500Hz, 0b11 for 25kHz) void set_fan_pwm_freq(uint8_t freq) From 84d09b044c864e201fbfcf2f224b80015cd3eee5 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 2 Apr 2026 15:10:12 +1100 Subject: [PATCH 09/24] assemble message with fan warning states :D --- NUSense/Core/Inc/fan_controller.h | 1 + NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index d88bc48..bab24d0 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -35,6 +35,7 @@ void set_fan_mode(bool mode); void set_fan_spin_up(bool enabled); void set_fan_manual_pwm(uint8_t pwm_value); uint16_t read_fan_speed(uint8_t tachometer); +bool fan_warning_state(uint8_t fan_id); void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled); #ifdef __cplusplus diff --git a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp index 6e23fbc..2902ea5 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp +++ b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp @@ -31,7 +31,8 @@ namespace nusense { nusense_msg.buttons.left = mode_button.filter(); nusense_msg.buttons.middle = start_button.filter(); - nusense_msg. + nusense_msg.fan_warning_states[0].id = fan_warning_state(0) ? 1 : 0; + nusense_msg.fan_warning_states[1].id = fan_warning_state(1) ? 1 : 0; if (nusense_msg.buttons.left) { tx_led.pulse(1, false, device::Pulser::LOW); From 6f29f75d53ba4976a566fd6bcc6d5ccca61161ec Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Wed, 8 Apr 2026 13:23:28 +1000 Subject: [PATCH 10/24] comms NUsense -> NUC works successfully :D --- .../nusense/NUSenseIO/send_nusense_data.cpp | 11 ++++-- .../Core/Src/usb/protobuf/NUSenseData.pb.c | 4 +- .../Core/Src/usb/protobuf/NUSenseData.pb.h | 38 ++++++++++++------- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp index 2902ea5..6cb2b7c 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp +++ b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp @@ -30,9 +30,14 @@ namespace nusense { // Poll the buttons and include their states. nusense_msg.buttons.left = mode_button.filter(); nusense_msg.buttons.middle = start_button.filter(); - - nusense_msg.fan_warning_states[0].id = fan_warning_state(0) ? 1 : 0; - nusense_msg.fan_warning_states[1].id = fan_warning_state(1) ? 1 : 0; + /* + nusense_msg.fan_warnings.fan1 = fan_warning_state(0) ? message_platform_FanWarningStates_IDState_WARNING : message_platform_FanWarningStates_IDState_NOWARNING; + nusense_msg.fan_warnings.fan2 = fan_warning_state(1) ? message_platform_FanWarningStates_IDState_WARNING : message_platform_FanWarningStates_IDState_NOWARNING; + */ + + nusense_msg.fan_warnings.fan1_warning = true; + nusense_msg.fan_warnings.fan2_warning = true; + nusense_msg.has_fan_warnings = true; if (nusense_msg.buttons.left) { tx_led.pulse(1, false, device::Pulser::LOW); diff --git a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.c b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.c index c4d582d..6b26f99 100644 --- a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.c +++ b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.c @@ -21,6 +21,9 @@ PB_BIND(message_platform_IMU_fvec3, message_platform_IMU_fvec3, AUTO) PB_BIND(message_platform_Buttons, message_platform_Buttons, AUTO) +PB_BIND(message_platform_FanWarning, message_platform_FanWarning, AUTO) + + PB_BIND(message_platform_NUSense, message_platform_NUSense, 2) @@ -49,4 +52,3 @@ PB_BIND(message_platform_ServoIDStates_ServoIDState, message_platform_ServoIDSta */ PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES) #endif - diff --git a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h index e9ba6ba..0e27cde 100644 --- a/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h +++ b/NUSense/Core/Src/usb/protobuf/NUSenseData.pb.h @@ -9,6 +9,7 @@ #error Regenerate this file with the current version of nanopb generator. #endif + /* Enum definitions */ typedef enum _message_platform_ServoIDStates_IDState { message_platform_ServoIDStates_IDState_MISSING = 0, @@ -16,11 +17,6 @@ typedef enum _message_platform_ServoIDStates_IDState { message_platform_ServoIDStates_IDState_DUPLICATE = 2 } message_platform_ServoIDStates_IDState; -typedef enum _message_platform_FanWarningStates_IDState { - message_platform_FanWarningStates_IDState_NOWARNING = 0, - message_platform_FanWarningStates_IDState_WARNING = 1 -} message_platform_FanWarningStates_IDState; - /* Struct definitions */ typedef struct _message_platform_Servo_PacketCounts { /* / The total number of packets received. */ @@ -95,8 +91,8 @@ typedef struct _message_platform_NUSense_ServoMapEntry { } message_platform_NUSense_ServoMapEntry; typedef struct _message_platform_FanWarning { - uint32_t id; - message_platform_FanWarningStates_IDState state; + bool fan1_warning; + bool fan2_warning; } message_platform_FanWarning; typedef struct _message_platform_NUSense { @@ -127,7 +123,8 @@ typedef struct _message_platform_NUSense { message_platform_IMU imu; bool has_buttons; message_platform_Buttons buttons; - message_platform_FanWarning fan_warning_states[2]; + bool has_fan_warnings; + message_platform_FanWarning fan_warnings; } message_platform_NUSense; typedef struct _message_platform_ServoConfiguration { @@ -184,8 +181,9 @@ extern "C" { #define message_platform_IMU_init_default {false, message_platform_IMU_fvec3_init_default, false, message_platform_IMU_fvec3_init_default, 0} #define message_platform_IMU_fvec3_init_default {0, 0, 0} #define message_platform_Buttons_init_default {0, 0} -#define message_platform_NUSense_init_default {0, {message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default, message_platform_NUSense_ServoMapEntry_init_default}, false, message_platform_IMU_init_default, false, message_platform_Buttons_init_default} +#define message_platform_NUSense_init_default {0, {message_platform_NUSense_ServoMapEntry_init_default}, false, message_platform_IMU_init_default, false, message_platform_Buttons_init_default, false, message_platform_FanWarning_init_default} #define message_platform_NUSense_ServoMapEntry_init_default {0, false, message_platform_Servo_init_default} +#define message_platform_FanWarning_init_default {0, 0} #define message_platform_ServoConfiguration_init_default {0, 0} #define message_platform_NUSenseHandshake_init_default {0, "", 0, {message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default, message_platform_ServoConfiguration_init_default}} #define message_platform_ServoIDStates_init_default {0, {message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default, message_platform_ServoIDStates_ServoIDState_init_default}} @@ -195,13 +193,13 @@ extern "C" { #define message_platform_IMU_init_zero {false, message_platform_IMU_fvec3_init_zero, false, message_platform_IMU_fvec3_init_zero, 0} #define message_platform_IMU_fvec3_init_zero {0, 0, 0} #define message_platform_Buttons_init_zero {0, 0} -#define message_platform_NUSense_init_zero {0, {message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero, message_platform_NUSense_ServoMapEntry_init_zero}, false, message_platform_IMU_init_zero, false, message_platform_Buttons_init_zero, message_platform_FanWarning_init_zero} +#define message_platform_NUSense_init_zero {0, {message_platform_NUSense_ServoMapEntry_init_zero}, false, message_platform_IMU_init_zero, false, message_platform_Buttons_init_zero, false, message_platform_FanWarning_init_zero} #define message_platform_NUSense_ServoMapEntry_init_zero {0, false, message_platform_Servo_init_zero} +#define message_platform_FanWarning_init_zero {0, 0} #define message_platform_ServoConfiguration_init_zero {0, 0} #define message_platform_NUSenseHandshake_init_zero {0, "", 0, {message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero, message_platform_ServoConfiguration_init_zero}} #define message_platform_ServoIDStates_init_zero {0, {message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero, message_platform_ServoIDStates_ServoIDState_init_zero}} #define message_platform_ServoIDStates_ServoIDState_init_zero {0, _message_platform_ServoIDStates_IDState_MIN} -#define message_platform_FanWarning_init_zero {message_platform_FanWarningStates_IDState_NOWARNING, message_platform_FanWarningStates_IDState_NOWARNING} /* Field tags (for use in manual encoding/decoding) */ #define message_platform_Servo_PacketCounts_total_tag 1 @@ -235,6 +233,9 @@ extern "C" { #define message_platform_NUSense_servo_map_tag 1 #define message_platform_NUSense_imu_tag 2 #define message_platform_NUSense_buttons_tag 3 +#define message_platform_NUSense_fan_warnings_tag 4 +#define message_platform_FanWarning_fan1_warning_tag 1 +#define message_platform_FanWarning_fan2_warning_tag 2 #define message_platform_ServoConfiguration_direction_tag 1 #define message_platform_ServoConfiguration_offset_tag 2 #define message_platform_NUSenseHandshake_type_tag 1 @@ -294,15 +295,23 @@ X(a, STATIC, SINGULAR, BOOL, middle, 2) #define message_platform_Buttons_CALLBACK NULL #define message_platform_Buttons_DEFAULT NULL +#define message_platform_FanWarning_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, fan1_warning, 1) \ +X(a, STATIC, SINGULAR, BOOL, fan2_warning, 2) +#define message_platform_FanWarning_CALLBACK NULL +#define message_platform_FanWarning_DEFAULT NULL + #define message_platform_NUSense_FIELDLIST(X, a) \ X(a, STATIC, REPEATED, MESSAGE, servo_map, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, imu, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, buttons, 3) +X(a, STATIC, OPTIONAL, MESSAGE, buttons, 3) \ +X(a, STATIC, OPTIONAL, MESSAGE, fan_warnings, 4) #define message_platform_NUSense_CALLBACK NULL #define message_platform_NUSense_DEFAULT NULL #define message_platform_NUSense_servo_map_MSGTYPE message_platform_NUSense_ServoMapEntry #define message_platform_NUSense_imu_MSGTYPE message_platform_IMU #define message_platform_NUSense_buttons_MSGTYPE message_platform_Buttons +#define message_platform_NUSense_fan_warnings_MSGTYPE message_platform_FanWarning #define message_platform_NUSense_ServoMapEntry_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, key, 1) \ @@ -342,6 +351,7 @@ extern const pb_msgdesc_t message_platform_Servo_PacketCounts_msg; extern const pb_msgdesc_t message_platform_IMU_msg; extern const pb_msgdesc_t message_platform_IMU_fvec3_msg; extern const pb_msgdesc_t message_platform_Buttons_msg; +extern const pb_msgdesc_t message_platform_FanWarning_msg; extern const pb_msgdesc_t message_platform_NUSense_msg; extern const pb_msgdesc_t message_platform_NUSense_ServoMapEntry_msg; extern const pb_msgdesc_t message_platform_ServoConfiguration_msg; @@ -355,6 +365,7 @@ extern const pb_msgdesc_t message_platform_ServoIDStates_ServoIDState_msg; #define message_platform_IMU_fields &message_platform_IMU_msg #define message_platform_IMU_fvec3_fields &message_platform_IMU_fvec3_msg #define message_platform_Buttons_fields &message_platform_Buttons_msg +#define message_platform_FanWarning_fields &message_platform_FanWarning_msg #define message_platform_NUSense_fields &message_platform_NUSense_msg #define message_platform_NUSense_ServoMapEntry_fields &message_platform_NUSense_ServoMapEntry_msg #define message_platform_ServoConfiguration_fields &message_platform_ServoConfiguration_msg @@ -365,6 +376,7 @@ extern const pb_msgdesc_t message_platform_ServoIDStates_ServoIDState_msg; /* Maximum encoded size of messages (where known) */ #define MESSAGE_PLATFORM_NUSENSEDATA_PB_H_MAX_SIZE message_platform_NUSense_size #define message_platform_Buttons_size 4 +#define message_platform_FanWarning_size 4 #define message_platform_IMU_fvec3_size 15 #define message_platform_IMU_size 40 #define message_platform_NUSenseHandshake_size 464 @@ -380,4 +392,4 @@ extern const pb_msgdesc_t message_platform_ServoIDStates_ServoIDState_msg; } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file From 0f84ed83f1186cbcb8b2d030308f006e0566486e Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Wed, 8 Apr 2026 20:30:09 +1000 Subject: [PATCH 11/24] remove test data and replace with real data --- NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp index 6cb2b7c..a337889 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp +++ b/NUSense/Core/Src/nusense/NUSenseIO/send_nusense_data.cpp @@ -30,14 +30,10 @@ namespace nusense { // Poll the buttons and include their states. nusense_msg.buttons.left = mode_button.filter(); nusense_msg.buttons.middle = start_button.filter(); - /* - nusense_msg.fan_warnings.fan1 = fan_warning_state(0) ? message_platform_FanWarningStates_IDState_WARNING : message_platform_FanWarningStates_IDState_NOWARNING; - nusense_msg.fan_warnings.fan2 = fan_warning_state(1) ? message_platform_FanWarningStates_IDState_WARNING : message_platform_FanWarningStates_IDState_NOWARNING; - */ - nusense_msg.fan_warnings.fan1_warning = true; - nusense_msg.fan_warnings.fan2_warning = true; nusense_msg.has_fan_warnings = true; + nusense_msg.fan_warnings.fan1_warning = fan_warning_state(0) ? true : false; + nusense_msg.fan_warnings.fan2_warning = fan_warning_state(1) ? true : false; if (nusense_msg.buttons.left) { tx_led.pulse(1, false, device::Pulser::LOW); From e676bb9d49eb3ce66167dc653c1617751d6802f1 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 21:45:36 +1000 Subject: [PATCH 12/24] newline :D --- NUSense/Core/Inc/i2c.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NUSense/Core/Inc/i2c.h b/NUSense/Core/Inc/i2c.h index a64aa73..844a409 100644 --- a/NUSense/Core/Inc/i2c.h +++ b/NUSense/Core/Inc/i2c.h @@ -22,4 +22,5 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); } #endif -#endif // I2C_H \ No newline at end of file +#endif // I2C_H + From c5fe6f2e814827def8ef7fdec8b54a2fb4254ab7 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 21:48:16 +1000 Subject: [PATCH 13/24] copy doxygen comments from .c to .h --- NUSense/Core/Inc/fan_controller.h | 35 ++++++++++++++++++++++++++++++- NUSense/Core/Src/fan_controller.c | 24 --------------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index bab24d0..76da75a 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -28,14 +28,47 @@ extern "C" { // Functions void fan_controller_init(); + +/// @brief Reads a value from a fan controller register. +/// @param reg The register address to read from. +/// @return The value read from the register. uint8_t read_fan_register(uint8_t reg); + +/// @brief Writes a value to a fan controller register. +/// @param reg The register address to write to. +/// @param value The value to write. +/// @return The HAL status of the write operation. uint8_t write_fan_register(uint8_t reg, uint8_t value); + +/// @brief Checks the fan warning states for the specified fan. +/// @param fan_id The ID of the fan to check (0 for Fan 1 (J401 on NUSense), 1 for Fan 2 (J402 on NUSense)) +/// @return The warning state of the specified fan. Returns true if there is a warning, false if there is no warning. +bool fan_warning_state(uint8_t fan_id); + +/// @brief Sets the PWM frequency of the fan. The frequency is determined by bits 3 and 4 of Control Register 1. +/// @param freq The desired frequency setting (0b00 for 33Hz, 0b01 for 150Hz, 0b10 for 1500Hz, 0b11 for 25kHz) void set_fan_pwm_freq(uint8_t freq); + +/// @brief Sets the fan mode between manual and automatic. +/// @param mode true for manual mode (Direct Fan Control enabled), false for automatic mode (Direct Fan Control disabled) void set_fan_mode(bool mode); + +/// @brief Sets the fan spin-up mode. +/// @param enabled true to enable spin-up mode, false to disable void set_fan_spin_up(bool enabled); + +/// @brief Sets the manual PWM value for the fan. +/// @param pwm_value void set_fan_manual_pwm(uint8_t pwm_value); + +/// @brief reads the fan speed from the controller +/// @param tachometer 0 for Fan 1, 1 for Fan 2 +/// @return The speed in RPM. uint16_t read_fan_speed(uint8_t tachometer); -bool fan_warning_state(uint8_t fan_id); + +/// @brief Enables or disables the tachometer for the specified fan. +/// @param tachometer 0 for Tachometer 1, 1 for Tachometer 2 +/// @param enabled true to enable, false to disable void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled); #ifdef __cplusplus diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 71d2a31..24929fa 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -2,9 +2,6 @@ #include extern I2C_HandleTypeDef hi2c3; -/// @brief Reads a value from a fan controller register. -/// @param reg The register address to read from. -/// @return The value read from the register. uint8_t read_fan_register(uint8_t reg) { uint8_t value = 0; @@ -12,18 +9,11 @@ uint8_t read_fan_register(uint8_t reg) return value; } -/// @brief Writes a value to a fan controller register. -/// @param reg The register address to write to. -/// @param value The value to write. -/// @return The HAL status of the write operation. uint8_t write_fan_register(uint8_t reg, uint8_t value) { return HAL_I2C_Mem_Write(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); } -/// @brief Checks the fan warning states for the specified fan. -/// @param fan_id The ID of the fan to check (0 for Fan 1 (J401 on NUSense), 1 for Fan 2 (J402 on NUSense)) -/// @return The warning state of the specified fan. Returns true if there is a warning, false if there is no warning. bool fan_warning_state(uint8_t fan_id) { if (read_fan_speed(fan_id) <= FAN_RPM_WARNING) { return true; // Warning state if fan speed is less than or equal to the defined warning threshold @@ -31,8 +21,6 @@ bool fan_warning_state(uint8_t fan_id) { return false; } -/// @brief Sets the PWM frequency of the fan. The frequency is determined by bits 3 and 4 of Control Register 1. -/// @param freq The desired frequency setting (0b00 for 33Hz, 0b01 for 150Hz, 0b10 for 1500Hz, 0b11 for 25kHz) void set_fan_pwm_freq(uint8_t freq) { uint8_t control1 = read_fan_register(REG_CONTROL1); @@ -41,8 +29,6 @@ void set_fan_pwm_freq(uint8_t freq) write_fan_register(REG_CONTROL1, control1); } -/// @brief Sets the fan mode between manual and automatic. -/// @param mode true for manual mode (Direct Fan Control enabled), false for automatic mode (Direct Fan Control disabled) void set_fan_mode(bool mode) { uint8_t control2 = read_fan_register(REG_CONTROL2); @@ -54,8 +40,6 @@ void set_fan_mode(bool mode) write_fan_register(REG_CONTROL2, control2); } -/// @brief Sets the fan spin-up mode. -/// @param enabled true to enable spin-up mode, false to disable void set_fan_spin_up(bool enabled) { uint8_t control2 = read_fan_register(REG_CONTROL2); @@ -67,9 +51,6 @@ void set_fan_spin_up(bool enabled) write_fan_register(REG_CONTROL2, control2); } -/// @brief Enables or disables the tachometer for the specified fan. -/// @param tachometer 0 for Tachometer 1, 1 for Tachometer 2 -/// @param enabled true to enable, false to disable void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) { uint8_t control3 = read_fan_register(REG_CONTROL3); @@ -89,16 +70,11 @@ void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) write_fan_register(REG_CONTROL3, control3); } -/// @brief Sets the manual PWM value for the fan. -/// @param pwm_value void set_fan_manual_pwm(uint8_t pwm_value) { write_fan_register(REG_PWMR, pwm_value); } -/// @brief reads the fan speed from the controller -/// @param tachometer 0 for Fan 1, 1 for Fan 2 -/// @return The speed in RPM. uint16_t read_fan_speed(uint8_t tachometer) { uint8_t fan_register = (tachometer == 0 ? REG_FAN1COUNT : REG_FAN2COUNT); uint8_t msb = read_fan_register(fan_register); From 7edfe7ef51990fe292708859834ec7820fa51e5a Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 21:53:51 +1000 Subject: [PATCH 14/24] formatting fixes --- NUSense/Core/Src/fan_controller.c | 48 ++++++++++--------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 24929fa..ec3c8e0 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -15,22 +15,17 @@ uint8_t write_fan_register(uint8_t reg, uint8_t value) } bool fan_warning_state(uint8_t fan_id) { - if (read_fan_speed(fan_id) <= FAN_RPM_WARNING) { - return true; // Warning state if fan speed is less than or equal to the defined warning threshold - } - return false; + + // Warning state is true if fan speed is less than or equal to the defined warning threshold + return read_fan_speed(fan_id) <= FAN_RPM_WARNING; } void set_fan_pwm_freq(uint8_t freq) { uint8_t control1 = read_fan_register(REG_CONTROL1); control1 &= ~(0b11 << 3); // clear bits 3 and 4 - control1 |= (freq & 0b11) << 3; // set bits 3 and 4 to the desired frequency - write_fan_register(REG_CONTROL1, control1); -} - -void set_fan_mode(bool mode) -{ + // Warning state is true if fan speed is less than or equal to the defined warning threshold + return read_fan_speed(fan_id) <= FAN_RPM_WARNING; uint8_t control2 = read_fan_register(REG_CONTROL2); if (mode) { control2 |= (1 << 0); // set bit 0 to enable Direct Fan Control @@ -45,7 +40,8 @@ void set_fan_spin_up(bool enabled) uint8_t control2 = read_fan_register(REG_CONTROL2); if (enabled) { control2 |= (1 << 1); // set bit 1 to enable Spin-Up mode - } else { + } + else { control2 &= ~(1 << 1); // clear bit 1 to disable Spin-Up mode } write_fan_register(REG_CONTROL2, control2); @@ -54,42 +50,28 @@ void set_fan_spin_up(bool enabled) void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) { uint8_t control3 = read_fan_register(REG_CONTROL3); - if (tachometer == 0) { - if (enabled) { - control3 |= (1 << 0); // set bit 0 to enable Tachometer 1 - } else { - control3 &= ~(1 << 0); // clear bit 0 to disable Tachometer 1 - } - } else if (tachometer == 1) { - if (enabled) { - control3 |= (1 << 1); // set bit 1 to enable Tachometer 2 - } else { - control3 &= ~(1 << 1); // clear bit 1 to disable Tachometer 2 - } + if (enabled) { + control3 |= (1 << tachometer); + } + else { + control3 &= ~(1 << tachometer); } write_fan_register(REG_CONTROL3, control3); } -void set_fan_manual_pwm(uint8_t pwm_value) -{ +void set_fan_manual_pwm(uint8_t pwm_value) { write_fan_register(REG_PWMR, pwm_value); } uint16_t read_fan_speed(uint8_t tachometer) { uint8_t fan_register = (tachometer == 0 ? REG_FAN1COUNT : REG_FAN2COUNT); - uint8_t msb = read_fan_register(fan_register); + uint8_t msb = read_fan_register(fan_register); uint8_t lsb = read_fan_register(fan_register + 1); uint16_t fan_count = (msb << 8) | lsb; return 60 * 100000 / fan_count / PULSES_PER_REVOLUTION; } -/// @brief Sets up the Fan Controller with default settings: 1500Hz PWM frequency, manual mode enabled, tachometers enabled, and full speed -void fan_controller_init() -{ - // set the PWM frequency to 1500Hz (0b10) - set_fan_pwm_freq(0b10); - - // put the fan into manual mode +void fan_controller_init() { set_fan_mode(true); // enable both tachometers From 9d7358fb3ca594d04473c18a7102f5813e19399a Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 21:54:27 +1000 Subject: [PATCH 15/24] bracket --- NUSense/Core/Src/fan_controller.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index ec3c8e0..312266c 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -2,8 +2,7 @@ #include extern I2C_HandleTypeDef hi2c3; -uint8_t read_fan_register(uint8_t reg) -{ +uint8_t read_fan_register(uint8_t reg) { uint8_t value = 0; HAL_I2C_Mem_Read(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); return value; From aea5a5aa010f8b16b00b73ee7080045a281b4ce3 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 21:59:52 +1000 Subject: [PATCH 16/24] restore old function --- NUSense/Core/Src/fan_controller.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 312266c..6cfb207 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -8,34 +8,23 @@ uint8_t read_fan_register(uint8_t reg) { return value; } -uint8_t write_fan_register(uint8_t reg, uint8_t value) -{ +uint8_t write_fan_register(uint8_t reg, uint8_t value) { return HAL_I2C_Mem_Write(&hi2c3, FAN_CONTROLLER_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, HAL_MAX_DELAY); } bool fan_warning_state(uint8_t fan_id) { - // Warning state is true if fan speed is less than or equal to the defined warning threshold return read_fan_speed(fan_id) <= FAN_RPM_WARNING; } -void set_fan_pwm_freq(uint8_t freq) -{ +void set_fan_pwm_freq(uint8_t freq) { uint8_t control1 = read_fan_register(REG_CONTROL1); control1 &= ~(0b11 << 3); // clear bits 3 and 4 - // Warning state is true if fan speed is less than or equal to the defined warning threshold - return read_fan_speed(fan_id) <= FAN_RPM_WARNING; - uint8_t control2 = read_fan_register(REG_CONTROL2); - if (mode) { - control2 |= (1 << 0); // set bit 0 to enable Direct Fan Control - } else { - control2 &= ~(1 << 0); // clear bit 0 to disable Direct Fan Control - } - write_fan_register(REG_CONTROL2, control2); + control1 |= (freq & 0b11) << 3; // set bits 3 and 4 to the desired frequency + write_fan_register(REG_CONTROL1, control1); } -void set_fan_spin_up(bool enabled) -{ +void set_fan_spin_up(bool enabled) { uint8_t control2 = read_fan_register(REG_CONTROL2); if (enabled) { control2 |= (1 << 1); // set bit 1 to enable Spin-Up mode @@ -46,8 +35,7 @@ void set_fan_spin_up(bool enabled) write_fan_register(REG_CONTROL2, control2); } -void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) -{ +void set_fan_tachometer_enabled(uint8_t tachometer, bool enabled) { uint8_t control3 = read_fan_register(REG_CONTROL3); if (enabled) { control3 |= (1 << tachometer); From 24805090688cc024bc81a65e380e82b8136f32a8 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 22:00:45 +1000 Subject: [PATCH 17/24] cleanup, brackets, americanized words... --- NUSense/Core/Src/i2c.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/NUSense/Core/Src/i2c.c b/NUSense/Core/Src/i2c.c index e0aedbe..3e6f200 100644 --- a/NUSense/Core/Src/i2c.c +++ b/NUSense/Core/Src/i2c.c @@ -3,12 +3,11 @@ I2C_HandleTypeDef hi2c3; /** - * @brief I2C3 Initialization Function + * @brief I2C3 Initialisation Function * @param None * @retval None */ -void MX_I2C3_Init(void) -{ +void MX_I2C3_Init(void) { hi2c3.Instance = I2C3; hi2c3.Init.Timing = 0x00702681; // 400kHz I2C Fast Mode hi2c3.Init.OwnAddress1 = 0; @@ -30,7 +29,7 @@ void MX_I2C3_Init(void) } /** - * @brief I2C MSP Initialization + * @brief I2C MSP Initialisation * This function configures the hardware resources used by I2C3 * @param hi2c: I2C handle pointer * @retval None @@ -65,12 +64,11 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) } /** - * @brief GPIO Initialization Function + * @brief GPIO Initialisation Function * @param None * @retval None */ -static void MX_GPIO_Init(void) -{ +static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ @@ -84,4 +82,5 @@ static void MX_GPIO_Init(void) /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ -} \ No newline at end of file +} + From 8f9e66a1b8e956e4eee90718097eadad6c431dda Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 22:01:06 +1000 Subject: [PATCH 18/24] americanized word :( --- NUSense/Core/Src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NUSense/Core/Src/main.cpp b/NUSense/Core/Src/main.cpp index 5f87378..7cfd61a 100644 --- a/NUSense/Core/Src/main.cpp +++ b/NUSense/Core/Src/main.cpp @@ -69,7 +69,7 @@ int main(void) { MX_TIM4_Init(); MX_I2C3_Init(); - /* Initialize fan controller after I2C3 is ready */ + /* Initialise fan controller after I2C3 is ready */ fan_controller_init(); #ifdef FIRST_BUZZ From 62d564786fc8c23525d301853a49c4fb3c8674e8 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Thu, 9 Apr 2026 22:03:13 +1000 Subject: [PATCH 19/24] spelling --- NUSense/Core/Src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NUSense/Core/Src/main.cpp b/NUSense/Core/Src/main.cpp index 7cfd61a..2b39378 100644 --- a/NUSense/Core/Src/main.cpp +++ b/NUSense/Core/Src/main.cpp @@ -54,7 +54,7 @@ int main(void) { // order here given that it also has another strange habit of ignoring main.cpp and creating and // overwriting main.c instead despite CubeIDE knowing that this is a C++ project! Oh CubeMX ... - /* Initialize all configured peripherals */ + /* Initialise all configured peripherals */ MX_DMA_Init(); MX_GPIO_Init(); MX_USB_DEVICE_Init(); From ebc393074946d5feaf81720930a11a0cb4cb540b Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Fri, 10 Apr 2026 13:42:31 +1000 Subject: [PATCH 20/24] add doxygen comment to fan_controller_init --- NUSense/Core/Inc/fan_controller.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index 76da75a..6a104ea 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -27,6 +27,11 @@ extern "C" { #define REG_STATUS 0x5A // Functions + +/// @brief Initializes the fan controller with the following settings: +/// - Manual mode enabled (Direct Fan Control enabled) +/// - Both tachometers enabled +/// - Manual PWM set to full speed (0xFF) void fan_controller_init(); /// @brief Reads a value from a fan controller register. From 6864d9242498b67eec824d3a069841c48d121d4d Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Fri, 10 Apr 2026 13:45:57 +1000 Subject: [PATCH 21/24] comments and formatting for register defs --- NUSense/Core/Inc/fan_controller.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/NUSense/Core/Inc/fan_controller.h b/NUSense/Core/Inc/fan_controller.h index 6a104ea..420583b 100644 --- a/NUSense/Core/Inc/fan_controller.h +++ b/NUSense/Core/Inc/fan_controller.h @@ -18,13 +18,13 @@ extern "C" { #define DEFAULT_FAN_SPEED 0xFF // full steam ahead // Registers -#define REG_CONTROL1 0x00 -#define REG_CONTROL2 0x01 -#define REG_CONTROL3 0x02 +#define REG_CONTROL1 0x00 +#define REG_CONTROL2 0x01 +#define REG_CONTROL3 0x02 #define REG_FAN1COUNT 0x52 // MSB of 2 byte fan controller tachometer count for fan 1 #define REG_FAN2COUNT 0x54 // MSB of 2 byte fan controller tachometer count for fan 2 -#define REG_PWMR 0x50 -#define REG_STATUS 0x5A +#define REG_PWMR 0x50 // Direct Duty-Cycle Control Register +#define REG_STATUS 0x5A // Status Register // Functions From 7fa8ff1c2589bb10ef2efddb74b4b037da2b81f5 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Fri, 10 Apr 2026 13:46:32 +1000 Subject: [PATCH 22/24] Capital letters --- NUSense/Core/Src/fan_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NUSense/Core/Src/fan_controller.c b/NUSense/Core/Src/fan_controller.c index 6cfb207..1d87bc4 100644 --- a/NUSense/Core/Src/fan_controller.c +++ b/NUSense/Core/Src/fan_controller.c @@ -61,10 +61,10 @@ uint16_t read_fan_speed(uint8_t tachometer) { void fan_controller_init() { set_fan_mode(true); - // enable both tachometers + // Enable both tachometers set_fan_tachometer_enabled(0, true); set_fan_tachometer_enabled(1, true); - // set Direct Duty-Cycle Control Register to full blast. + // Set Direct Duty-Cycle Control Register to full blast. set_fan_manual_pwm(DEFAULT_FAN_SPEED); } From 9de3be5ebab48182e6f3e0c7812bb3e9321b9a7d Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Fri, 10 Apr 2026 13:48:14 +1000 Subject: [PATCH 23/24] comments in the h --- NUSense/Core/Inc/i2c.h | 19 +++++++++++++++++++ NUSense/Core/Src/i2c.c | 16 ---------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/NUSense/Core/Inc/i2c.h b/NUSense/Core/Inc/i2c.h index 844a409..a558f8d 100644 --- a/NUSense/Core/Inc/i2c.h +++ b/NUSense/Core/Inc/i2c.h @@ -15,9 +15,28 @@ extern "C" { extern I2C_HandleTypeDef hi2c3; +/** + * @brief I2C3 Initialisation Function + * @param None + * @retval None + */ void MX_I2C3_Init(void); + +/** + * @brief I2C MSP Initialisation + * This function configures the hardware resources used by I2C3 + * @param hi2c: I2C handle pointer + * @retval None + */ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c); +/** + * @brief GPIO Initialisation Function + * @param None + * @retval None + */ +void MX_GPIO_Init(void); + #ifdef __cplusplus } #endif diff --git a/NUSense/Core/Src/i2c.c b/NUSense/Core/Src/i2c.c index 3e6f200..810315b 100644 --- a/NUSense/Core/Src/i2c.c +++ b/NUSense/Core/Src/i2c.c @@ -2,11 +2,6 @@ I2C_HandleTypeDef hi2c3; -/** - * @brief I2C3 Initialisation Function - * @param None - * @retval None - */ void MX_I2C3_Init(void) { hi2c3.Instance = I2C3; hi2c3.Init.Timing = 0x00702681; // 400kHz I2C Fast Mode @@ -28,12 +23,6 @@ void MX_I2C3_Init(void) { } } -/** - * @brief I2C MSP Initialisation - * This function configures the hardware resources used by I2C3 - * @param hi2c: I2C handle pointer - * @retval None - */ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) { GPIO_InitTypeDef GPIO_InitStruct = {0}; @@ -63,11 +52,6 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) } } -/** - * @brief GPIO Initialisation Function - * @param None - * @retval None - */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ From b213c5d0b22d77e29761323cfcffc4b283672849 Mon Sep 17 00:00:00 2001 From: Miles Punch Date: Sat, 11 Apr 2026 10:01:21 +1000 Subject: [PATCH 24/24] ran the formatter :D --- NUSense/Core/Src/main.cpp | 4 ++-- NUSense/Core/Src/nusense/NUSenseIO.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NUSense/Core/Src/main.cpp b/NUSense/Core/Src/main.cpp index 2b39378..4276fc1 100644 --- a/NUSense/Core/Src/main.cpp +++ b/NUSense/Core/Src/main.cpp @@ -19,13 +19,13 @@ #include "main.h" #include "dma.h" +#include "fan_controller.h" #include "gpio.h" +#include "i2c.h" #include "spi.h" #include "tim.h" #include "usart.h" #include "usb_device.h" -#include "fan_controller.h" -#include "i2c.h" /* Private includes ----------------------------------------------------------*/ #include "nusense/NUSenseIO.hpp" diff --git a/NUSense/Core/Src/nusense/NUSenseIO.hpp b/NUSense/Core/Src/nusense/NUSenseIO.hpp index 6adb6b7..2d59b11 100644 --- a/NUSense/Core/Src/nusense/NUSenseIO.hpp +++ b/NUSense/Core/Src/nusense/NUSenseIO.hpp @@ -21,8 +21,8 @@ #include "ChainManager.hpp" #include "NUgus.hpp" #include "ServoState.hpp" -#include "imu.h" #include "fan_controller.h" +#include "imu.h" namespace nusense { constexpr uint32_t MAX_ENCODE_SIZE = 1600;