Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7b4c6be
Update ThreadX_Os.ioc to configure I2C3 and remove FDCAN1 settings
jose5556 Jan 22, 2026
50eb69c
Update I2C configuration to use I2C3 instead of I2C1 in app_threadx.h…
jose5556 Jan 22, 2026
97f778e
Refactor I2C configuration: add I2C3 support, update PCA9685 function…
jose5556 Jan 22, 2026
eeb60b6
Implement I2C3 support and refactor motor control: add DC motors thre…
jose5556 Jan 23, 2026
a82b343
tab
jose5556 Jan 23, 2026
f97c0c7
Refactor I2C and CAN integration: update I2C configuration, add CAN p…
jose5556 Jan 24, 2026
b88bfb8
update I2C queue handling, enhance PCA9685 initialization, and add ut…
jose5556 Jan 24, 2026
bf1404a
Refactor DC motors and servo threads: move motor test code, add messa…
jose5556 Jan 24, 2026
e83c4d0
Refactor CAN and I2C message handling: move dlc_to_len array to can_p…
jose5556 Jan 24, 2026
d222f24
Enhance motor control and thread initialization: update motor_set fun…
jose5556 Jan 26, 2026
1a10116
Refactor motor and CAN threads: remove debug UART messages and add sl…
jose5556 Jan 26, 2026
698174a
Update CAN message structures and enhance thread sleep timing: change…
jose5556 Jan 27, 2026
3740e70
Refactor thread initialization: uncomment DC Motors and Servo thread …
jose5556 Jan 27, 2026
71c7acf
Update CAN configuration: enable AutoRetransmission and adjust IPPara…
jose5556 Jan 27, 2026
5dae9c6
Add CAN RX and TX thread implementations for message handling
jose5556 Jan 29, 2026
0e6c816
Add battery monitoring thread and update system configurations for im…
jose5556 Jan 29, 2026
0c6ed14
Refactor thread priority definitions and update thread creation calls…
jose5556 Jan 30, 2026
891e567
Refactor DC Motors thread: remove redundant error handling and stream…
jose5556 Jan 30, 2026
ec58759
Add emergency break thread implementation and update thread count
jose5556 Jan 30, 2026
8b624b7
Remove outdated safety critical documentation files: index_requiremen…
jose5556 Feb 2, 2026
9873009
Add emergency break thread and modify CAN RX handling for improved sa…
jose5556 Feb 2, 2026
3c7abee
Fix naming inconsistencies for emergency brake thread and related queues
jose5556 Feb 2, 2026
0e3f205
Add emergency brake thread implementation for motor control
jose5556 Feb 3, 2026
34d9a18
Remove heartbeat message type and update CAN frame configurations for…
jose5556 Feb 3, 2026
061d33a
Refactor CAN message handling and improve error reporting in threads
jose5556 Feb 3, 2026
af94b0a
Refactor CAN message transmission and improve error handling in tx_ca…
jose5556 Feb 3, 2026
44933e5
Update TIM1 trigger polarity from falling to rising
jose5556 Feb 3, 2026
4e768c8
Update Pulses Per Revolution definition to 40 for accurate RPM calcul…
jose5556 Feb 3, 2026
865c483
Update timer tick reference to 1000 for improved timing accuracy
jose5556 Feb 3, 2026
21e10d3
Remove TIM1 trigger filter and polarity configuration
jose5556 Feb 4, 2026
32d62c8
Remove I2C communication thread integration suggestion from project e…
jose5556 Feb 4, 2026
6316619
Fix RPM calculation comments and expected values in unit tests
jose5556 Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,25 @@ This project implements a real-time speed sensor and CAN communication system on
- FDCAN1_RX -> PB_8 (CAN_RX)
- FDCAN1_TX -> PB_9 (CAN_TX)
- TIM1_CH1 -> PA_8 (Sensor speed)
- I2C3 -> PA_7 (SCL)
- I2C3 -> PC_1 (SDA)
- I2C3 SCL -> PA_7
- I2C3 SDA -> PC_1

# How to Extend The Project
- Implement a mechanism to process incoming data and perform the appropriate actions.
- Integrate new thread to communicate via I2C to motors/servo.
- Create a Heartbeat mechanism.
- Integrate Watchdog timer that resets if the system "breaks".
- Integration tests for CAN.
- Latency tests
- Redefine diferent prioritys for threads.
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.

Spelling error in comment. "diferent" should be "different".

Suggested change
- Redefine diferent prioritys for threads.
- Redefine different priorities for threads.

Copilot uses AI. Check for mistakes.

### Creating new Threads
- In app_threadx.h, increase THREAD_COUNT by one, and remember to update the comments above that definition.

- Don’t forget to add the function prototype in app_threadx.h and to include the new source file in the CMakeLists.txt file.

- Next, open init_threads.c and initialize your new thread. Follow the existing threads for consistency and simplicity.

- Finally, implement the functionality of your thread. That’s it, simple as that, you’re now ready to start! Good luck.

# Instructions to Build and Flash to STM32 Microcontroller

Expand Down
17 changes: 12 additions & 5 deletions ThreadX_Os/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)


# Define the build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
Expand Down Expand Up @@ -47,10 +46,18 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
Core/Src/init/init_can.c
Core/Src/init/init_threads.c
Core/Src/threads/speedSensor.c
Core/Src/threads/tx_can.c
Core/Src/threads/rx_can.c
Core/Src/utils/speed_rpm.c
Core/Src/threads/can/rx_can.c
Core/Src/threads/can/tx_can.c
Core/Src/threads/motors/dc_motors.c
Core/Src/threads/motors/emergency_brake.c
Core/Src/threads/motors/servo.c
Core/Src/threads/battery.c
Core/Src/threads/speed_sensor.c
Core/Src/utils/debug_utils.c
Core/Src/utils/i2c_utils.c
Core/Src/utils/speed_rpm_utils.c
Core/Src/i2c_ina219.c
Core/Src/i2c_pca9685.c
)

# Add include paths
Expand Down
55 changes: 44 additions & 11 deletions ThreadX_Os/Core/Inc/app_threadx.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,43 @@ extern "C" {
#include <stdio.h>
#include <stdint.h>
#include <utils.h>

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

// Thread with max priority
#define MAX_PRIO 0

// Thread with medium priority
#define MEDIUM_PRIO 5

// Thread with low priority
#define LOW_PRIO 10

// Thread with no priority (lowest)
#define NONE_PRIO 15

//Queue size (number of messages)
#define QUEUE_SIZE 8

/*
Number of threads
1 -> Speed sensor thread
2 -> CAN TX thread
3 -> CAN RX thread
4 -> dc_motors thread
5 -> servo thread
6 -> battery thread
7 -> emergency brake thread
*/
#define THREAD_COUNT 7
Comment on lines +66 to +69
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.

// Thread structure
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.
} t_threads;

// CAN frames structure
Expand All @@ -60,10 +88,14 @@ typedef struct s_canFrames {
extern FDCAN_HandleTypeDef hfdcan1;
extern UART_HandleTypeDef huart1;
extern TIM_HandleTypeDef htim1;
extern I2C_HandleTypeDef hi2c3;

extern TX_QUEUE can_tx_queue;
extern TX_QUEUE can_rx_queue;
extern t_threads threads[3];
extern TX_QUEUE can_emergency_brake_queue;
extern TX_QUEUE i2c_dc_motors_queue;
extern TX_QUEUE i2c_servo_queue;
extern TX_MUTEX i2c_mutex;
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 i2c_mutex is declared as extern in app_threadx.h and used throughout the I2C code, but there's no initialization code (tx_mutex_create call) in App_ThreadX_Init or anywhere else in the visible code. The mutex must be created before it can be used. Add mutex creation in App_ThreadX_Init similar to how the queues are created.

Copilot uses AI. Check for mistakes.
extern t_threads threads[THREAD_COUNT];
/* USER CODE END EC */

/* Private defines -----------------------------------------------------------*/
Expand All @@ -75,12 +107,6 @@ extern t_threads threads[3];
/* Main thread defines -------------------------------------------------------*/
/* USER CODE BEGIN MTD */

//Thread 0 (Speed Sensor) max priority
#define THREAD_0_PRIO 1

//Queue size (number of messages)
#define QUEUE_SIZE 8

/* USER CODE END MTD */

/* Exported macro ------------------------------------------------------------*/
Expand All @@ -98,15 +124,22 @@ void MX_ThreadX_Init(void);
VOID thread_SensorSpeed(ULONG thread_input);
VOID thread_tx_can(ULONG thread_input);
VOID thread_rx_can(ULONG thread_input);
uint8_t rx_receive(t_rx_can_msg *msg);
VOID thread_dc_motors(ULONG thread_input);
VOID thread_servo(ULONG thread_input);
VOID thread_battery(ULONG thread_input);
VOID thread_emergency_brake(ULONG thread_input);

//init
void initCanFrames(t_canFrames *canFrames);
UINT init_threads(VOID);
UINT init_queue(VOID);

//utils
VOID uart_send(const char *msg);
VOID uart_send(const char *msg);
VOID uart_send_int(int32_t value);
VOID rpm_debug_print(ULONG rpm,
ULONG cr1_reg, ULONG cnt_reg);
HAL_StatusTypeDef i2c_scan_bus(VOID);

/* USER CODE END EFP */

Expand Down
31 changes: 31 additions & 0 deletions ThreadX_Os/Core/Inc/can_protocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef CAN_PROTOCOL_H
#define CAN_PROTOCOL_H

#include "app_threadx.h"

// CAN message types
typedef enum {
CAN_MSG_SPEED,
CAN_MSG_BATTERY,
} e_can_msg_type;

// TX CAN message structure (sending)
typedef struct s_tx_can_message {
e_can_msg_type type;
uint8_t data[8];
} t_tx_can_msg;

// RX CAN message structure (receiving)
typedef struct s_rx_can_message {
uint32_t type;
uint8_t data[8];
uint8_t len;
} t_rx_can_msg;

/* // Steering/throttle CAN message instructions
typedef struct s_i2c_message {
int8_t steering;
int8_t throttle;
} t_i2c_msg; */

#endif
22 changes: 22 additions & 0 deletions ThreadX_Os/Core/Inc/i2c_ina219.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef I2C_INA219_H
# define I2C_INA219_H

#include "app_threadx.h"

#define INA219_ADDR 0x41

#define INA219_REG_CONFIG 0x00
#define INA219_REG_SHUNT_VOLT 0x01
#define INA219_REG_BUS_VOLT 0x02
#define INA219_REG_POWER 0x03
#define INA219_REG_CURRENT 0x04
#define INA219_REG_CALIBRATION 0x05

#define INA219_CALIBRATION 4096

HAL_StatusTypeDef ina219_init(UINT addr);
HAL_StatusTypeDef ina219_read_voltage(float* voltage);
HAL_StatusTypeDef ina219_read_current(float* current);
HAL_StatusTypeDef ina219_read_power(float* power);

#endif
64 changes: 64 additions & 0 deletions ThreadX_Os/Core/Inc/i2c_pca9685.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#ifndef I2C_PCA9685_H
# define I2C_PCA9685_H

#include "app_threadx.h"

#define PCA9685_ADDR_SERVO 0x40
#define PCA9685_ADDR_MOTOR 0x60

// PWM resolution and channel range
#define PCA9685_PWM_MAX 4095

// PCA9685 channel limits
#define PCA9685_CHANNEL_MIN 0
#define PCA9685_CHANNEL_MAX 15

// PCA9685 register addresses
#define MODE1 0x00
#define MODE2 0x01
#define PRE_SCALE 0xFE

// LED0 registers
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09

// PCA9685 mode settings
#define PCA9685_SLEEP_MODE 0x10
#define PCA9685_50HZ_PRESCALE 0x79
#define PCA9685_1KHZ_PRESCALE 0x05
#define PCA9685_WAKE_AUTOINC 0x20

// Servo pulse limits
#define SERVO_MIN_PULSE 205
#define SERVO_MAX_PULSE 410
#define SERVO_MAX_ANGLE 180

// Motor speed limits
#define MOTOR_MAX_SPEED 100

#define MOTOR_PWM_MIN 0

typedef struct s_motor_channel {
UINT pwm_ch; // PWM motor channel
UINT in1_ch; // IN1 channel
UINT in2_ch; // IN2 channel
} t_motor_channel;

// Predefined motor channels
static const t_motor_channel MOTOR_LEFT = { 0, 1, 2 };
static const t_motor_channel MOTOR_RIGHT = { 7, 5, 6 };
Comment on lines +50 to +51
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.

HAL_StatusTypeDef pca9685_init(UINT addr);

HAL_StatusTypeDef pca9685_set_pwm(UINT channel,
uint16_t on, uint16_t off, UINT addr);

HAL_StatusTypeDef pca9685_set_servo_angle(UINT channel, UINT angle);

HAL_StatusTypeDef motor_set(t_motor_channel motor, int8_t speed, uint8_t brake);

HAL_StatusTypeDef stopMotors(VOID);

#endif
2 changes: 1 addition & 1 deletion ThreadX_Os/Core/Inc/stm32u5xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extern "C" {
/*#define HAL_GTZC_MODULE_ENABLED */
/*#define HAL_HASH_MODULE_ENABLED */
/*#define HAL_HCD_MODULE_ENABLED */
/*#define HAL_I2C_MODULE_ENABLED */
#define HAL_I2C_MODULE_ENABLED
#define HAL_ICACHE_MODULE_ENABLED
/*#define HAL_IRDA_MODULE_ENABLED */
/*#define HAL_IWDG_MODULE_ENABLED */
Expand Down
2 changes: 1 addition & 1 deletion ThreadX_Os/Core/Inc/tx_user.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@

/* Define the common timer tick reference for use by other middleware components. */

/*#define TX_TIMER_TICKS_PER_SECOND 100*/
#define TX_TIMER_TICKS_PER_SECOND 1000

/* Determine if there is a FileX pointer in the thread control block.
By default, the pointer is there for legacy/backwards compatibility.
Expand Down
33 changes: 4 additions & 29 deletions ThreadX_Os/Core/Inc/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,18 @@
typedef uint32_t UINT;
typedef uint32_t ULONG;
typedef void VOID;
#define TX_SUCCESS 0
#define TX_QUEUE_ERROR 1
#endif

// Timer ticks per second definition
#ifndef TX_TIMER_TICKS_PER_SECOND
#define TX_TIMER_TICKS_PER_SECOND 1000
#endif

// CAN message types
typedef enum {
CAN_MSG_SPEED,
CAN_MSG_BATTERY,
CAN_MSG_HEARTBEAT,
} e_can_msg_type;

// TX CAN message structure
typedef struct s_tx_can_message {
e_can_msg_type type;
uint8_t data[8];
} t_tx_can_msg;

// RX CAN message structure
typedef struct s_rx_can_message {
uint32_t type;
uint8_t data[8];
uint8_t len;
} t_rx_can_msg;

//Maximum RPM value to prevent overflow
#define MAX_RPM 5000
#define MAX_RPM 10000

//Pulses Per Revolution
#define PPR 20
#define PPR 40

// RPM calculation state, created for hardware abstraction and testability
typedef struct s_rpm_state {
Expand All @@ -50,10 +28,7 @@ typedef struct s_rpm_state {
UINT first_run;
} t_rpm_state;

UINT convertValuesRPM(
ULONG count,
ULONG ticks,
ULONG period,
t_rpm_state *state);
UINT convertValuesRPM(ULONG count, ULONG ticks,
ULONG period, t_rpm_state *state);

#endif
Loading