Skip to content

Flytrex STM32G4 driver#2

Merged
grisharevzin merged 25 commits intomasterfrom
add-stm32g4-fdcan-driver
Mar 4, 2026
Merged

Flytrex STM32G4 driver#2
grisharevzin merged 25 commits intomasterfrom
add-stm32g4-fdcan-driver

Conversation

@grisharevzin
Copy link
Collaborator

No description provided.

@grisharevzin grisharevzin added the enhancement New feature or request label Mar 3, 2026
while (!(fdcan->CCCR & (1 << 0))); /* Wait until init mode sets */
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
while (!(fdcan->CCCR & (1 << 1))); /* Wait intil CCE sets */
fdcan->CCCR &= ~(1 << 6); // DAR = 0
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

/* comments */

Copy link

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

Adds a new bare-metal STM32G4 FDCAN driver integration for libcanard/DroneCAN, including register/message-RAM definitions and usage documentation.

Changes:

  • Introduces a new STM32G4 FDCAN driver API (init/start/transmit/receive/filtering/statistics).
  • Adds an internal header describing the STM32G4 FDCAN register map and SRAM layout.
  • Adds a README documenting intended usage and filter behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 15 comments.

File Description
drivers/stm32g4_fdcan/canard_stm32g4_fdcan.h Public driver API/types and constants.
drivers/stm32g4_fdcan/canard_stm32g4_fdcan.c Driver implementation (init, filtering, TX/RX, stats, protocol state).
drivers/stm32g4_fdcan/_fdcan_g4.h Internal register/message RAM layout definitions for STM32G4 FDCAN.
drivers/stm32g4_fdcan/README.md Usage and configuration documentation for the driver.

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

grisharevzin and others added 3 commits March 3, 2026 10:03
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 14 comments.


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

uint32_t tx_frames;
uint32_t rx_frames;
} statistics;
uint32_t fdcan_sram_base;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

fdcan_sram_base is declared in the public driver struct but is never initialized or used anywhere in this driver. If callers are not expected to set/use it, consider removing it to avoid confusion; otherwise initialize it in canard_stm32g4fdcan_init() and document its meaning.

Suggested change
uint32_t fdcan_sram_base;

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +5
* Created on: Sep 10, 2024
* Author: grishar
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The new source file header comment lacks the standard project copyright/license boilerplate present in existing drivers (MIT license notice). Add the repository’s usual header to clarify licensing and keep driver files consistent.

Suggested change
* Created on: Sep 10, 2024
* Author: grishar
* Copyright (c) 2024 grishar
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Created on: Sep 10, 2024
* Author: grishar

Copilot uses AI. Check for mistakes.
Comment on lines +275 to +282
uint32_t *tx_data_frame = (uint32_t *) frame->data;
ele->data[0] = tx_data_frame[0];
ele->data[1] = tx_data_frame[1];
#if CANARD_ENABLE_CANFD
for (size_t i = 2; i < frame->data_len / sizeof(uint32_t); ++i) {
ele->data[i] = tx_data_frame[i];
}
#endif
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

frame->data is a uint8_t[] (not guaranteed 4-byte aligned). Casting it to uint32_t* can cause unaligned loads and hard faults on Cortex-M, and also violates strict-aliasing assumptions. Use byte-wise packing (like drivers/stm32/canard_stm32.c) or memcpy into the TX buffer element instead of uint32_t* casts.

Suggested change
uint32_t *tx_data_frame = (uint32_t *) frame->data;
ele->data[0] = tx_data_frame[0];
ele->data[1] = tx_data_frame[1];
#if CANARD_ENABLE_CANFD
for (size_t i = 2; i < frame->data_len / sizeof(uint32_t); ++i) {
ele->data[i] = tx_data_frame[i];
}
#endif
/* Clear the data area and copy the frame payload safely without
* relying on potentially unaligned uint32_t accesses. */
memset(ele->data, 0, sizeof(ele->data));
memcpy(ele->data, frame->data, frame->data_len);

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +90
fdcan->CCCR &= ~(1 << 4); /* Exit from sleep mode */
while (fdcan->CCCR & (1 << 3)); /* Wait until exited from sleep mode */
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
while (!(fdcan->CCCR & (1 << 0))); /* Wait until init mode sets */
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
while (!(fdcan->CCCR & (1 << 1))); /* Wait intil CCE sets */

Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The init sequence uses multiple tight while (...) ; waits for mode transitions (sleep exit / INIT / CCE) with no timeout or error path. If the peripheral clock is not enabled or the controller is wedged, this will hang forever. Consider using bounded waits and returning a driver-specific error (similar to drivers/stm32/canard_stm32.c which times out waiting for MSR INAK).

Suggested change
fdcan->CCCR &= ~(1 << 4); /* Exit from sleep mode */
while (fdcan->CCCR & (1 << 3)); /* Wait until exited from sleep mode */
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
while (!(fdcan->CCCR & (1 << 0))); /* Wait until init mode sets */
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
while (!(fdcan->CCCR & (1 << 1))); /* Wait intil CCE sets */
{
/* Use bounded waits to avoid hanging forever if the controller or clock is misconfigured. */
const uint32_t max_wait_cycles = 1000000U;
uint32_t wait_cycles;
fdcan->CCCR &= ~(1 << 4); /* Exit from sleep mode */
wait_cycles = max_wait_cycles;
while ((fdcan->CCCR & (1 << 3)) && (--wait_cycles != 0U)) {
/* wait until exited from sleep mode or timeout */
}
if (wait_cycles == 0U) {
return -CANARD_ERROR_INTERNAL;
}
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
wait_cycles = max_wait_cycles;
while (!(fdcan->CCCR & (1 << 0)) && (--wait_cycles != 0U)) {
/* wait until init mode sets or timeout */
}
if (wait_cycles == 0U) {
return -CANARD_ERROR_INTERNAL;
}
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
wait_cycles = max_wait_cycles;
while (!(fdcan->CCCR & (1 << 1)) && (--wait_cycles != 0U)) {
/* wait until CCE sets or timeout */
}
if (wait_cycles == 0U) {
return -CANARD_ERROR_INTERNAL;
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +177 to +182
void canard_stm32g4fdcan_start(canard_stm32g4_fdcan_driver *driver)
{
fdcan_registers *fdcan = driver->fdcan;
fdcan->CCCR &= ~((1 << 0) | (1 << 1)); /* Clear INIT and CCE */
while ((fdcan->CCCR & (1 << 0))); /* Wait until we leave init mode */
}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

canard_stm32g4fdcan_start() waits for INIT to clear using a tight while loop with no timeout. If the controller fails to leave init mode, this will hang the caller. Add a bounded wait and surface an error (or at least an assert in debug builds) to avoid deadlocks.

Copilot uses AI. Check for mistakes.
Comment on lines +229 to +235
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
while (!(fdcan->CCCR & (1 << 0))); /* Wait until init mode sets */
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
while (!(fdcan->CCCR & (1 << 1))); /* Wait intil CCE sets */
fdcan->CCCR &= ~(1 << 6); /* DAR = 0 */
fdcan->CCCR &= ~((1 << 0) | (1 << 1)); /* Clear INIT and CCE */
while ((fdcan->CCCR & (1 << 0))); /* Wait until we leave init mode */
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

canard_stm32g4fdcan_enable_automatic_retransmission() re-enters INIT/CCE and busy-waits on CCCR bits without any timeout. A misclocked/failed peripheral will hang the system here. Prefer a bounded wait + error return (or make this function return int so failures can be reported).

Suggested change
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
while (!(fdcan->CCCR & (1 << 0))); /* Wait until init mode sets */
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
while (!(fdcan->CCCR & (1 << 1))); /* Wait intil CCE sets */
fdcan->CCCR &= ~(1 << 6); /* DAR = 0 */
fdcan->CCCR &= ~((1 << 0) | (1 << 1)); /* Clear INIT and CCE */
while ((fdcan->CCCR & (1 << 0))); /* Wait until we leave init mode */
const uint32_t timeout = 1000000U;
uint32_t counter;
fdcan->CCCR |= (1 << 0); /* Get to INIT mode */
counter = 0U;
while (!(fdcan->CCCR & (1 << 0)) && (counter++ < timeout)) {
/* Wait until init mode sets, but with a bounded timeout */
}
if (!(fdcan->CCCR & (1 << 0))) {
/* Failed to enter INIT mode within timeout */
return;
}
fdcan->CCCR |= (1 << 1); /* CCE=1: config change enable */
counter = 0U;
while (!(fdcan->CCCR & (1 << 1)) && (counter++ < timeout)) {
/* Wait until CCE sets, but with a bounded timeout */
}
if (!(fdcan->CCCR & (1 << 1))) {
/* Failed to set CCE within timeout */
return;
}
fdcan->CCCR &= ~(1 << 6); /* DAR = 0 */
fdcan->CCCR &= ~((1 << 0) | (1 << 1)); /* Clear INIT and CCE */
counter = 0U;
while ((fdcan->CCCR & (1 << 0)) && (counter++ < timeout)) {
/* Wait until we leave init mode, but with a bounded timeout */
}
/* If INIT bit is still set here, we simply return; no further action possible */

Copilot uses AI. Check for mistakes.
@grisharevzin grisharevzin merged commit 55c69ba into master Mar 4, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants