Skip to content

Comments

I2c integration#15

Merged
jose5556 merged 32 commits intomainfrom
fet/i2c
Feb 4, 2026
Merged

I2c integration#15
jose5556 merged 32 commits intomainfrom
fet/i2c

Conversation

@jose5556
Copy link
Member

@jose5556 jose5556 commented Feb 4, 2026

Pull Request

Summary

This PR fixes several bugs related to I2C communication instabilities.
An emergency brake thread with maximum priority was added.
The definition of 1000 ticks per second was updated, and the logic for counting speed sensor values has also been improved.

Related issues

Related: #108

Type of change

  • Bug fix
  • New feature
  • Documentation update
  • Performance improvement
  • Chore / refactor
  • Release
  • Testing

Testing instructions

To test this implementation, a Raspberry Pi is required to send and receive CAN frames.
Instructions for setting up bidirectional communication are provided in the READMEs for both the Raspberry Pi and STM32 code.

- Added I2C3 configuration with timing parameters.
- Removed FDCAN1 settings including baud rate and time segments.
- Updated MCU IP list to include I2C3 and adjusted IP count.
- Set PA7 and PC1 modes to I2C for proper signal configuration.
- Updated function list to include I2C3 initialization.
…ad, update PCA9685 functions, and enhance I2C bus scanning
…rotocol definitions, and enhance motor control functionality
…rotocol.h and update servo thread for consistent servo angle testing
…ction to include brake parameter, add stopMotors function, and improve thread initialization logging
… type in RX message to uint32_t, adjust data length handling, and modify sleep duration in speed sensor thread
…ts.md, requirements.md, and traceability_matrix.md
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates I2C communication for motor control (DC motors, servo) and battery monitoring, while making significant changes to system configuration including reducing the clock speed from 160MHz to 72MHz and increasing timer resolution from 100 to 1000 ticks per second.

Changes:

  • Adds I2C3 peripheral support with PCA9685 (PWM controller) and INA219 (voltage/current sensor) drivers
  • Implements new threads for DC motors, servo control, emergency brake, and battery monitoring
  • Updates system clock configuration from 160MHz to 72MHz and timer ticks from 100 to 1000 per second
  • Restructures code organization by separating CAN protocol definitions and moving thread implementations
  • Updates RPM calculation parameters (PPR changed from 20 to 40) and removes safety-critical documentation
  • Modifies FDCAN configuration by removing message filters and changes timer trigger from falling to rising edge

Reviewed changes

Copilot reviewed 33 out of 34 changed files in this pull request and generated 28 comments.

Show a summary per file
File Description
tests/unit/test/test_ut_rpm.c Updates test expectations for new PPR value (20→40), causing all RPM calculations to halve
docs/safety_critical/* Removes all safety-critical documentation including requirements, traceability matrix, and test coverage
ThreadX_Os/ThreadX_Os.ioc Reconfigures hardware: reduces system clock to 72MHz, switches from I2C2 to I2C3, modifies FDCAN timing
ThreadX_Os/Core/Src/i2c_*.c Adds new I2C drivers for PCA9685 PWM controller and INA219 current sensor
ThreadX_Os/Core/Src/threads/motors/* Implements motor control threads for DC motors, servo, and emergency brake
ThreadX_Os/Core/Src/threads/can/* Refactors CAN RX/TX threads with new queue routing for motor commands
ThreadX_Os/Core/Src/main.c Major hardware reconfig: clock from 160→72MHz, I2C3 init, FDCAN filters removed, TIM1 trigger edge changed
ThreadX_Os/Core/Src/app_threadx.c Adds multiple queues for motor control and restructures initialization
ThreadX_Os/Core/Inc/*.h Adds new headers for I2C devices and CAN protocol, updates thread priorities and counts
Comments suppressed due to low confidence (4)

ThreadX_Os/Core/Src/threads/can/tx_can.c:47

  • The CAN TX thread sleep interval has been reduced from 100 ticks to 1 tick. With the new 1000 ticks/second configuration, this means the thread wakes up every 1ms instead of every 1000ms (old config: 100 ticks / 100 ticks/sec = 1s). This is a 1000x increase in polling frequency. While this may provide more responsive CAN transmission, it will significantly increase CPU usage. Verify this is necessary and that the system can handle this overhead without impacting other threads.
    ThreadX_Os/Core/Src/threads/speed_sensor.c:26
  • The line "ULONG cr1_reg = htim1.Instance->CR1;" has been commented out. This variable was used for debugging RPM values. However, the rpm_debug_print function at line 18 still expects this parameter in its prototype in app_threadx.h. If cr1_reg is no longer needed, consider also updating the rpm_debug_print function signature to remove this unused parameter, or re-enable reading cr1_reg if debugging is still needed.
    docs/safety_critical/requirements.md:1
  • The safety-critical documentation including requirements.md, traceability_matrix.md, and index_requirements.md has been completely removed. This is a significant concern for a system that appears to handle emergency braking and motor control. If this is intentional, the PR description should explain why this documentation is no longer needed or where it has been moved. These documents contained traceability information, requirements, and test coverage metrics that are typically essential for safety-critical systems.
    ThreadX_Os/Core/Src/threads/speed_sensor.c:45
  • The thread sleep time has been reduced from 400 ticks to 50 ticks. With TX_TIMER_TICKS_PER_SECOND now at 1000, this means the speed sensor thread wakes up every 50ms instead of every 40ms (the old 400 ticks with 100 ticks/second would have been 4000ms, but now 50 ticks with 1000 ticks/second is 50ms). This is a significant increase in sampling frequency. Verify this doesn't cause excessive CPU usage or interfere with other threads, especially given that this thread now has the lowest priority (NONE_PRIO).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_FALLING;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trigger polarity for TIM1 has changed from TIM_TRIGGERPOLARITY_FALLING to TIM_TRIGGERPOLARITY_RISING. This fundamentally changes when speed sensor pulses are counted - now on rising edges instead of falling edges. This is a significant change that affects RPM measurement accuracy. Ensure this change is intentional and that the sensor hardware and mounting are compatible with rising edge triggering. This should be documented in the PR description as it affects calibration and may require hardware validation.

Copilot uses AI. Check for mistakes.
if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &rxHeader, rx_data) == HAL_OK)
{
msg->type = rxHeader.Identifier;
msg->len = (rxHeader.DataLength < 8) ? rxHeader.DataLength : 8;
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition at line 14 uses DataLength < 8, but previously it was <=. This changes behavior: now if DataLength equals 8, it will use 8 instead of clamping to 8. However, since 8 is already the maximum for CAN, this change is actually correct. But the use of < instead of <= might be confusing - consider using (rxHeader.DataLength <= 8) ? rxHeader.DataLength : 8 for clarity, or adding a comment explaining that DataLength is already validated to be <= 8 by the hardware.

Copilot uses AI. Check for mistakes.
{
msg->type = rxHeader.Identifier;
msg->len = (rxHeader.DataLength < 8) ? rxHeader.DataLength : 8;
memcpy(&msg->data, rx_data, msg->len);
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At line 15, using memcpy with &msg->data as the destination is redundant - msg->data is already an array, so the & is unnecessary. It should be memcpy(msg->data, rx_data, msg->len). While this may work due to array decay, it's not idiomatic and could be confusing.

Suggested change
memcpy(&msg->data, rx_data, msg->len);
memcpy(msg->data, rx_data, msg->len);

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 10
#include "app_threadx.h"

static void TxHeartBeatConf(FDCAN_TxHeaderTypeDef *TxHeader);
static void TxSpeedConf(FDCAN_TxHeaderTypeDef *TxHeader);
static void TxBatteryConf(FDCAN_TxHeaderTypeDef *TxHeader);

// Configuration of CAN frame for speed data
void initCanFrames(t_canFrames *canFrames)
{
TxHeartBeatConf(&canFrames->tx_header_heart_beat);
TxSpeedConf(&canFrames->tx_header_speed);
TxBatteryConf(&canFrames->tx_header_battery);
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TxHeartBeatConf function and associated heartbeat CAN frame handling have been removed. The PR description mentions adding new features but doesn't explain why the heartbeat functionality was removed. Heartbeat messages are typically important for monitoring system health in real-time systems. If heartbeat functionality is no longer needed, this should be documented in the PR description. Otherwise, consider whether removing this safety monitoring feature is appropriate.

Copilot uses AI. Check for mistakes.
Comment on lines +66 to +69
6 -> battery thread
7 -> emergency brake thread
*/
#define THREAD_COUNT 7
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The THREAD_COUNT is defined as 7, but only 6 threads are actually created (Speed sensor, CAN TX, CAN RX, DC Motors, Servo, Emergency Brake). The Battery thread (which would be the 7th) is commented out. This mismatch could lead to wasted memory allocation for the unused thread stack. Either enable the battery thread, or reduce THREAD_COUNT to 6.

Suggested change
6 -> battery thread
7 -> emergency brake thread
*/
#define THREAD_COUNT 7
6 -> emergency brake thread
*/
#define THREAD_COUNT 6

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +32
if (motor_set(MOTOR_LEFT, -throttle, 0) != HAL_OK)
uart_send("DC Motors Thread: Failed to set LEFT motor speed\r\n");

if (motor_set(MOTOR_RIGHT, throttle, 0) != HAL_OK)
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At line 29, the left motor throttle is negated (-throttle) while the right motor throttle at line 32 is not negated. This suggests differential drive where the left and right motors need opposite polarities. However, this is not documented in the code. Add a comment explaining why the left motor is negated, as this is a critical detail for understanding the motor control logic.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +104
// Create Emergency Brake queue
UCHAR *can_emergency_brake_queue_memory = (UCHAR *)memory_ptr + QUEUE_SIZE * sizeof(t_tx_can_msg);
ret = tx_queue_create(&can_emergency_brake_queue, "CAN RX Queue",
sizeof(t_rx_can_msg) / sizeof(ULONG),
can_emergency_brake_queue_memory, QUEUE_SIZE * sizeof(t_rx_can_msg));
if (ret != TX_SUCCESS)
uart_send("ERROR! Failed Emergency Brake queue creation.\r\n");

// Create I2C DC Motors queue
UCHAR *i2c_motors_queue_memory = can_emergency_brake_queue_memory + QUEUE_SIZE * sizeof(t_rx_can_msg);
ret = tx_queue_create(&i2c_dc_motors_queue, "I2C DC Motors Queue",
sizeof(t_rx_can_msg) / sizeof(ULONG),
rx_queue_memory, QUEUE_SIZE * sizeof(t_rx_can_msg));
i2c_motors_queue_memory, QUEUE_SIZE * sizeof(t_rx_can_msg));
if (ret != TX_SUCCESS)
uart_send("ERROR! Failed RX queue creation.\r\n");
uart_send("ERROR! Failed I2C DC Motors queue creation.\r\n");

// Create I2C Servo queue
UCHAR *i2c_servo_queue_memory = i2c_motors_queue_memory + QUEUE_SIZE * sizeof(t_rx_can_msg);
ret = tx_queue_create(&i2c_servo_queue, "I2C Servo Queue",
sizeof(t_rx_can_msg) / sizeof(ULONG),
i2c_servo_queue_memory, QUEUE_SIZE * sizeof(t_rx_can_msg));
if (ret != TX_SUCCESS)
uart_send("ERROR! Failed I2C Servo queue creation.\r\n");
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The queue creation error handling at lines 84-104 only sends UART messages but continues execution. If queue creation fails, the system will have undefined behavior when threads try to use these queues. After any queue creation failure, the function should return an error code immediately instead of continuing. Consider adding return ret; after each error message, or accumulating errors and checking at the end before initializing threads.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,53 @@
#include "can_protocol.h"

// CAN RX callback function
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function rx_receive is declared as static but the comment at line 3 says "CAN RX callback function". This is not actually a callback - it's a helper function called by thread_rx_can. The comment is misleading. Consider updating the comment to accurately describe it as a helper function that polls for CAN messages.

Suggested change
// CAN RX callback function
// Helper function that polls for and receives a CAN message

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +51
static const t_motor_channel MOTOR_LEFT = { 0, 1, 2 };
static const t_motor_channel MOTOR_RIGHT = { 7, 5, 6 };
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static const variables MOTOR_LEFT and MOTOR_RIGHT are defined in a header file. While the const qualifier prevents modification, defining non-inline static variables in a header means each translation unit that includes this header will get its own copy of these variables. This wastes memory. Consider either making these extern const and defining them in the .c file, or using #define macros, or making them inline static const (C99+).

Suggested change
static const t_motor_channel MOTOR_LEFT = { 0, 1, 2 };
static const t_motor_channel MOTOR_RIGHT = { 7, 5, 6 };
#define MOTOR_LEFT ((t_motor_channel){ 0u, 1u, 2u })
#define MOTOR_RIGHT ((t_motor_channel){ 7u, 5u, 6u })

Copilot uses AI. Check for mistakes.
typedef struct s_threads {
TX_THREAD thread;
uint8_t stack[1024];
UINT stack[1024];
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thread stack is changed from uint8_t to UINT type. UINT is typically defined as uint32_t, which means each stack element is now 4 bytes instead of 1 byte. With 1024 elements, this changes the stack size from 1KB to 4KB per thread. With 7 threads (THREAD_COUNT), this is 28KB total instead of 7KB. Verify this significant increase in memory usage is intentional and that the MCU has sufficient RAM. If 1KB stacks are sufficient, change back to uint8_t stack[1024].

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@AfonsoMota-132 AfonsoMota-132 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code additions and the features seems all good and tested, worked as expected, just be careful/review the small error of init that sometimes doesnt work

@jose5556 jose5556 merged commit 9e545ed into main Feb 4, 2026
7 checks passed
@jose5556 jose5556 deleted the fet/i2c branch February 5, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants