Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b81b58f
can.h first commit
alisha1697 Mar 9, 2025
d54680a
can.c first commit
alisha1697 Mar 9, 2025
5941dc4
Documentation of can.c
alisha1697 Mar 22, 2025
a931c17
Documented can.h
alisha1697 Mar 22, 2025
85bae8f
Documentation complete can.c
alisha1697 Mar 22, 2025
94448df
fixed frame range
alisha1697 Apr 5, 2025
9e0024c
filter works...too much
alisha1697 May 29, 2025
5cbe481
CANFD project file
alisha1697 May 31, 2025
ad68aae
Update can.c
alisha1697 Jun 10, 2025
fbabef5
Update can.h
alisha1697 Jun 10, 2025
1961fa5
fixed parsing in test_canfd.c
alisha1697 Jun 10, 2025
19d4454
Updated can.c with CAN_Receive and fixed definition error
alisha1697 Jun 11, 2025
aeb4e9c
Updated can.h
alisha1697 Jun 11, 2025
4aad34f
FDCAN_Serial_Testing Zip CUBEIDE project file
alisha1697 Jun 14, 2025
d6ca0b3
com-modules update
alisha1697 Oct 25, 2025
29f7c4c
Merge branch 'can-library' of https://github.com/UBCSailbot/com-modul…
alisha1697 Oct 25, 2025
8865c38
removed files
alisha1697 Oct 25, 2025
f1ef2aa
Moved can files (#37): accepted CAN files move to CANFD dir, removed …
MichaelGreenough Oct 30, 2025
c92b7b3
updated README on flle usage + cleanup
alisha1697 Oct 30, 2025
06be66a
Updated PDB code with MPPT current sense
sophiehcho Nov 20, 2025
934d80d
Comment changes
sophiehcho Nov 20, 2025
7f9d025
updated project name
sophiehcho Nov 20, 2025
2c21e11
deleted old file
sophiehcho Nov 20, 2025
63d67d2
deletd old file
sophiehcho Nov 20, 2025
748d9a8
moved folder location
sophiehcho Nov 22, 2025
ec41146
moved and renamed files
sophiehcho Nov 22, 2025
c9400cf
removed nested project
sophiehcho Nov 22, 2025
e1ff990
changed CAN_Receive to use a CAN_Frame rx pointer
alisha1697 Nov 29, 2025
f0c7a0d
correct CAN_Receive function signature
alisha1697 Nov 29, 2025
09c8334
fdcan-library-test now has the project to test
alisha1697 Nov 29, 2025
c0e35cd
Merge branch 'can-library' of https://github.com/UBCSailbot/com-modul…
alisha1697 Nov 29, 2025
47b8223
fdcan-library-test is now a project
alisha1697 Nov 29, 2025
8c4d942
moved to controller module
sophiehcho Dec 2, 2025
cf7a59f
Add heartbeat functionality to CANFD module
alisha1697 Feb 24, 2026
1dc01ba
Modify CAN_Init to accept hardware ID parameter
alisha1697 Feb 24, 2026
6a926ae
Updated fdcan-library-test with overnight test code, includes heartbeat
alisha1697 Feb 24, 2026
dca28a6
fixed neg current
sophiehcho Feb 26, 2026
6ecdbfc
Merge new can lib
sophiehcho Feb 26, 2026
7d46a59
changed to new can lib
sophiehcho Feb 26, 2026
288037e
implemented new can lib
sophiehcho Apr 6, 2026
a6821ce
Moving Average Implemented
pouyahatami May 30, 2026
9ba300d
int16_t instead of uint16_t for buffer
pouyahatami May 30, 2026
f2b823f
Avg startup fix
MichaelGreenough Jun 6, 2026
e31d2c2
Remove hard fault on heart beat CAN error
MichaelGreenough Jul 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Empty file removed firmware/com-modules/.gitkeep
Empty file.
264 changes: 264 additions & 0 deletions firmware/com-modules/CANFD/can.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/*
* can.c
*
* Created on: Mar 8, 2025
* Author: Alisha
*
* @brief This file implements the function prototypes in can.h to initialize and handle FDCAN on an STM32.
*
* @details The implementation includes buffer management, initialization, transmission, and
* reception handling with callback functions for handling received messages.
* NEW UPDATE: Messages are enqueued in interrupt context and dequeued
* in application context to prevent data corruption and race conditions
* + library adjusted to only standard filter
* NEW UPDATE: Updated for heartbeat functionality
*/

/* Includes ------------------------------------------------------------------*/
#include "can.h"
#include "main.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "stm32u5xx_hal_fdcan.h"

/* Variables ------------------------------------------------------------------*/
#define CAN_RX_QUEUE_SIZE 100 /* Arbitrary queue size*/
static CAN_Frame CAN_Rx_Queue[CAN_RX_QUEUE_SIZE]; /* Rx Circular Buffer */
static volatile uint8_t canRxHead = 0; /* Head index of buffer */
static volatile uint8_t canRxTail = 0; /* Tail index of buffer */
extern TIM_HandleTypeDef htim7; /* Accessing TIM7 Handler */
extern FDCAN_HandleTypeDef hfdcan1; /* Accessing FDCAN Handler */
static uint32_t heartbeat_id; /* Enclosure Heartbeat ID */
HAL_StatusTypeDef CanStartStatus; /* Status of FDCAN start operation */

/* Static Functions -----------------------------------------------------------*/
static int CAN_DequeueFrame(CAN_Frame *frame);
static void CAN_EnqueueFrame(uint32_t id, uint8_t len, const uint8_t *data);
uint8_t dlc_to_bytes(uint8_t dlc);

/* Functions ------------------------------------------------------------------*/
/**
* @brief Initializes the FDCAN module.
* @details In order:
* Configures standard ID reception filter to Rx FIFO 0
* Configures extended ID reception filter to Rx FIFO 1
* Configures global filter: Filter all remote frames with STD and EXT ID
* Reject non matching frames with STD ID and EXT ID
* Starts the FDCAN controller (continuous listening CAN bus)
* Activates Notifications
* Starts Heartbeat timer (TIM7)
* @param hfdcan1: CANFD Handler
* hbid: Heartbeat ID, specific to the enclosure
* 0x130 = PDB_HEARTBEAT, 0x131 = RUDR_HEARTBEAT
* 0x132 = SAIL_HEARTBEAT, 0x133 = SENSE_HEARTBEAT
* @note Calls Error_Handler() if any configuration step fails.
*/
void CAN_Init(FDCAN_HandleTypeDef *hfdcan1, uint32_t hbid) {
/*##-1 Configures FDCAN meta data and controllers*/
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x000;
sFilterConfig.FilterID2 = 0x7FF;
if (HAL_FDCAN_ConfigFilter(hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}

sFilterConfig.IdType = FDCAN_EXTENDED_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;
sFilterConfig.FilterID1 = 0x1111111;
sFilterConfig.FilterID2 = 0x2222222;
if (HAL_FDCAN_ConfigFilter(hfdcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}

if (HAL_FDCAN_ConfigGlobalFilter(hfdcan1, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
Error_Handler();
}

/*##-2 Start FDCAN controller (continuous listening CAN bus) ##############*/
CanStartStatus = HAL_FDCAN_Start(hfdcan1);
if (CanStartStatus != HAL_OK)
{
Error_Handler();
}
uint32_t notif =
FDCAN_IT_RX_FIFO0_NEW_MESSAGE |
FDCAN_IT_BUS_OFF |
FDCAN_IT_ERROR_WARNING |
FDCAN_IT_ERROR_PASSIVE |
FDCAN_IT_DATA_PROTOCOL_ERROR |
FDCAN_IT_ARB_PROTOCOL_ERROR ;

if (HAL_FDCAN_ActivateNotification(hfdcan1, notif, 0) != HAL_OK)
{
Error_Handler();
}

if (HAL_FDCAN_ActivateNotification(hfdcan1, FDCAN_IT_RX_FIFO1_NEW_MESSAGE, 0) != HAL_OK)
{
Error_Handler();
}

/*##-3 Start CANFD Heartbeat using TIM7 every 10sec */
heartbeat_id = hbid;
HAL_TIM_Base_Start_IT(&htim7);
}

/**
* @brief Transmits a FDCAN message.
* @param Identifier: Message identifier (In-line with Filter used).
* @param IdType: Identifier type (FDCAN_STANDARD_ID or FDCAN_EXTENDED_ID).
* @param DataLength: Length of the TxData buffer in the form of FDCAN_data_length_code
* FDCAN_data_length_code (X bytes data field):
* FDCAN_DLC_BYTES_0, FDCAN_DLC_BYTES_1, FDCAN_DLC_BYTES_2,
* FDCAN_DLC_BYTES_3, FDCAN_DLC_BYTES_4, FDCAN_DLC_BYTES_5,
* FDCAN_DLC_BYTES_6, FDCAN_DLC_BYTES_7, FDCAN_DLC_BYTES_8,
* FDCAN_DLC_BYTES_12, FDCAN_DLC_BYTES_16, FDCAN_DLC_BYTES_20,
* FDCAN_DLC_BYTES_24, FDCAN_DLC_BYTES_32, FDCAN_DLC_BYTES_48,
* FDCAN_DLC_BYTES_64
* @param DataBuffer: Pointer to the TxData buffer.
* @param hfdcan1: Pointer to the FDCAN handle structure.
* @return HAL_StatusTypeDef HAL_OK if successful, !HAL_OK (other HAL status) otherwise.
*/
HAL_StatusTypeDef CAN_Transmit(uint32_t Identifier, uint32_t IdType, uint32_t DataLength, uint8_t* DataBuffer, FDCAN_HandleTypeDef *hfdcan1) {
FDCAN_TxHeaderTypeDef TxHeader;

TxHeader.Identifier = Identifier;
TxHeader.IdType = IdType;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = DataLength;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_ON;
TxHeader.FDFormat = FDCAN_FD_CAN;
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;

return HAL_FDCAN_AddMessageToTxFifoQ(hfdcan1, &TxHeader, DataBuffer);
}

/**
* @brief Dequeues the next received CAN frame.
* @param frame: Pointer to a CAN_Frame struct that will be filled with the data.
* @return HAL_OK if a frame was dequeued, HAL_ERROR if the queue is empty.
*
* @note Called from application context (not ISR).
*/
HAL_StatusTypeDef CAN_Receive(CAN_Frame *frame) {
if (CAN_DequeueFrame(frame) == 0) return HAL_ERROR;
return HAL_OK;
}

/**
* @brief FDCAN has multiple Callbacks. This section highlights the order of the callbacks
* which you are able to overwrite for specific purposes (like flashing an LED
* for debugging or changing the Tx data in any way).
* These can be overwritten from stm32u5xx_hal_fdcan.h
* @details When CAN_Transmit is called:
* 1. HAL_FDCAN_TxEventFifoCallback(): Triggered when a new entry is added to the Tx Event FIFO after a successful transmission.
* - Log transmission status, toggle an LED, or trigger another action upon successful transmission.
* 2. HAL_FDCAN_TxBufferCompleteCallback(): Triggered when a dedicated Tx buffer completes transmission.
* - This can be used to add functionality after the TxData has been fired.
* 3. HAL_FDCAN_RxFifo0Callback(): Triggered when a new message is received in Rx FIFO 0.
* 4. HAL_FDCAN_RxFifo1Callback(): Triggered when a new message is received in Rx FIFO 1.
* - Process received data, used for debugging (toggle an LED) or trigger other operations based on received messages.
* 5. HAL_FDCAN_AbortTxRequest(): Called if transmission is aborted before completion (can be triggered by user).
* - Handle retransmission, alert on transmission failure or manually abort for testing.
* 6. HAL_FDCAN_HighPriorityMessageCallback(): Triggered when a high-priority message or remote frame is received.
* - When processing of urgent messages
*/


/**
* @brief Callback function for handling messages received in FIFO0.
* @param hfdcan: Pointer to FDCAN handle.
* @param RxFifo0ITs: FIFO0 interrupt flags.
*/
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {
if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET) {
FDCAN_RxHeaderTypeDef RxHeader;
uint8_t tmp[64];
memset(tmp, 0, 64);

if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, tmp) != HAL_OK) {
Error_Handler();
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
}

CAN_EnqueueFrame(RxHeader.Identifier, dlc_to_bytes(RxHeader.DataLength), tmp);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
}
/* added for debug */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
}

/* HELPER FUNCTIONS BELOW */

/**
* @brief Adds a received CAN frame to the circular queue.
* @param id: CAN message identifier (11-bit standard).
* @param len: Length of the data payload in bytes.
* @param data: Pointer to the data payload buffer.
* @details This function implements a circular buffer with overflow handling.
* If the queue is full (head catches up to tail), the oldest message is
* discarded to make room for the new message; new messages always available.
*/
static void CAN_EnqueueFrame(uint32_t id, uint8_t len, const uint8_t *data) {
uint8_t next = (canRxHead + 1) % CAN_RX_QUEUE_SIZE;
if (next == canRxTail) canRxTail = (canRxTail + 1) % CAN_RX_QUEUE_SIZE;

CAN_Rx_Queue[canRxHead].RxData1_Identifier = id;
CAN_Rx_Queue[canRxHead].RxData1_BufferLength = len;
memcpy(CAN_Rx_Queue[canRxHead].RxData1, data, len);
canRxHead = next;
}

/**
* @brief Removes and retrieves the oldest CAN frame from the circular queue.
* @param frame: Pointer to CAN_Frame structure where the retrieved frame will be stored.
* @return int: 1 if a frame was successfully retrieved, 0 if the queue is empty.
* @details This function provides thread-safe reading from the queue by checking if
* the queue is empty (tail == head) before attempting to read. The volatile
* queue indices ensure memory consistency between ISR and main loop contexts.
* @note This function should be called from the main application context, not from ISR.
* Always check the return value before using the retrieved frame data.
*/
static int CAN_DequeueFrame(CAN_Frame *frame) {
if (canRxTail == canRxHead) return 0;
*frame = CAN_Rx_Queue[canRxTail];
canRxTail = (canRxTail + 1) % CAN_RX_QUEUE_SIZE;
return 1;
}

/**
* @brief Overwrites HAL_TIM_PeriodElapsedCallback. Same function signature.
* @param htim: TIM_HandleTypeDef, handler for timer
* @details This interrupt callback tracks TIM7, which is the timer assigned for the
* CANFD heartbeat signal. The CAN transmit will send empty bytes with the
* enclosure heartbeat ID. The interval will be setup as 10sec.
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {

if (htim->Instance == TIM7) {
uint8_t tx_heart = 0;
if (CAN_Transmit(heartbeat_id, FDCAN_STANDARD_ID, FDCAN_DLC_BYTES_0, &tx_heart, &hfdcan1) != HAL_OK){
Error_Handler();
/* HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET); */ //debug
} /* else HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_7); */ // debug
}
}

/* DLC to bytes lookup */
uint8_t dlc_to_bytes(uint8_t dlc) {
static const uint8_t dlc_lut[16] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64
};
return dlc_lut[dlc & 0x0F];
}
33 changes: 33 additions & 0 deletions firmware/com-modules/CANFD/can.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* can.h
*
* Created on: Mar 8, 2025
* Author: Alisha
*
* @brief Header file for FDCAN library.
*
* @details This file contains function prototypes and global variables for configuring,
* transmitting, and receiving FDCAN messages on the STM32.
*/
#ifndef SRC_CAN_H_
#define SRC_CAN_H_

/* Includes ----------------------------------------------------------------------------*/
#include "stm32u5xx_hal.h"
#include "stm32u5xx_hal_fdcan.h"
#include <stdint.h>
#include <stdlib.h>

/* CAN_frame struct for Rx buffer (standard filter). Provides Rx ID, length and buffer --*/
typedef struct {
uint32_t RxData1_Identifier;
uint8_t RxData1_BufferLength;
uint8_t RxData1[64];
} CAN_Frame;

/* Function prototypes ------------------------------------------------------------------*/
void CAN_Init(FDCAN_HandleTypeDef *hfdcan1, uint32_t hbid);
HAL_StatusTypeDef CAN_Transmit(uint32_t Identifier, uint32_t IdType, uint32_t DataLength, uint8_t* DataBuffer, FDCAN_HandleTypeDef *hfdcan1);
HAL_StatusTypeDef CAN_Receive(CAN_Frame *frame);
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs);
#endif /* SRC_CAN_H_ */
39 changes: 39 additions & 0 deletions firmware/com-modules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Firmware Base Library

This page is for the communication modules base library, and includes explanations and instructions for its users. Don't forget to also read the main README.

## High-level Design

<img width="692" alt="image" src="https://github.com/UBCSailbot/com-module-firmware/assets/144284916/c1f9b2fc-40b4-414a-8d1a-b80418eed409">

### What is the Base Library?
The base library is made up of files corresponding to the boxes in the image above. Namely, they are CAN, Board, Debug, Error, and Config. The purpose of this code is to provide the "outline" for teams to build off of. It contains functions that facilitate communication through CAN, I2C, ADC, PWM, and UART, as well as provides debug and error handling capabilities. Lastly, the configuration file provides unique customizability, and avoids including unneeded code in other teams designs, thereby optimizing performance.

Here is what you need to know about which features/functions you can find, and where:

```can.h``` - provides functionality to create CAN message frames to be sent, as well as parse and extract data from received frames (the way it does this depends on the device being communicated with, which will be specified in the config file)

```board.h``` - provides basic functions for CAN, I2C, ADC, PWM, and UART communication

```debug.h``` - provides debugging functions such as printing/storing logs

```error.h``` - provides functions that properly handle errors in operations such as CAN communication or issues with receiving sensor data

As you probably notice, the location of each feature is quite intuitive, especially once you've seen the diagram above.

To find these files, navigate through the repository as follows: ```CANFD -> can.h``` for CANFD, ```base-library inc -> xxxxx.h``` otherwise

## User Manual
Before continuing, please read the "What is the Base Library" paragraph above if you haven't already.

The three boxes at the top of the firmware design diagram illustrate the tasks of the individual teams. To reach the desired functionality for a specific COM module, such as reading data from a sensor, teams have to determine which functions are required, and what the proper inputs to those functions would be. Most important for this would be the ```board.h``` file, but the comprehensive list above covers everything available.

There are also features that you can request from the firmware team. If there is any specific functionality you would like for handling errors, such as turning off a sensor if we can no longer receive data from it, then leave your request on the [Confluence feature request page](https://ubcsailbot.atlassian.net/wiki/spaces/prjt22/pages/1994457093/Feature+Request). Additionally, any other requests for code that needs new functions/functionality that isn't included in the base library can also be left in the same place.

Lastly, you can change values in the configurations file based on what you need and don't need from the base library. This is an important consideration as it will improve the performance of your COM Module!

## Notes
You can find tutorials on using STM32CubeIDE, GitHub, and more in the tutorials folder.

Don't forget to consult the main README to learn more.

Loading