-
-
Notifications
You must be signed in to change notification settings - Fork 82
Add a wrapper for Zephyr RTOS #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
8c43471
81efa40
8450359
8994c53
c60d626
c9e0c1a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
// Copyright (C) 2022-2025 Kevin O'Connor <[email protected]> | ||
// | ||
// This file may be distributed under the terms of the GNU GPLv3 license. | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
|
||
#include <stdint.h> // uint32_t | ||
#include <string.h> // memset | ||
|
@@ -28,11 +29,16 @@ | |
|
||
// Helper compiler definitions | ||
#define barrier() __asm__ __volatile__("": : :"memory") | ||
#define __DMB() __asm__ __volatile__("dmb 0xF": : :"memory") | ||
|
||
// Zephyr already defines these helpers | ||
// Avoid redefinition warnings | ||
#ifndef __ZEPHYR__ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I appreciate your platform-agnostic approach, so I can make these macros individually ifndef-guarded to not introduce a Zephyr-specific thing |
||
#define likely(x) __builtin_expect(!!(x), 1) | ||
#define unlikely(x) __builtin_expect(!!(x), 0) | ||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | ||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) | ||
#define __DMB() __asm__ __volatile__("dmb 0xF": : :"memory") | ||
#endif | ||
|
||
// Helper functions for writing to "io" memory | ||
static inline void writel(void *addr, uint32_t val) { | ||
|
@@ -374,9 +380,18 @@ pio_signal_clear_txpending(struct can2040 *cd) | |
pio_hw->irq = SI_TXPENDING >> 8; | ||
} | ||
|
||
void | ||
can2040_ll_pio_set_clkdiv(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate) | ||
{ | ||
pio_hw_t *pio_hw = cd->pio_hw; | ||
uint32_t div = (256 / PIO_CLOCK_PER_BIT) * sys_clock / bitrate; | ||
int i; | ||
for (i=0; i<4; i++) | ||
pio_hw->sm[i].clkdiv = div << PIO_SM0_CLKDIV_FRAC_LSB; | ||
} | ||
|
||
// Setup PIO state machines | ||
static void | ||
pio_sm_setup(struct can2040 *cd) | ||
void can2040_ll_pio_sm_setup(struct can2040 *cd) | ||
{ | ||
// Reset state machines | ||
pio_hw_t *pio_hw = cd->pio_hw; | ||
|
@@ -413,19 +428,16 @@ pio_setup(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate) | |
rp2040_clear_reset(rb); | ||
|
||
// Setup and sync pio state machine clocks | ||
pio_hw_t *pio_hw = cd->pio_hw; | ||
uint32_t div = (256 / PIO_CLOCK_PER_BIT) * sys_clock / bitrate; | ||
int i; | ||
for (i=0; i<4; i++) | ||
pio_hw->sm[i].clkdiv = div << PIO_SM0_CLKDIV_FRAC_LSB; | ||
can2040_ll_pio_set_clkdiv(cd, sys_clock, bitrate); | ||
|
||
// Configure gpiobase (on rp2350) | ||
#if IS_RP2350 | ||
pio_hw_t *pio_hw = cd->pio_hw; | ||
pio_hw->gpiobase = pio_gpiobase(cd); | ||
#endif | ||
|
||
// Configure state machines | ||
pio_sm_setup(cd); | ||
can2040_ll_pio_sm_setup(cd); | ||
|
||
// Map Rx/Tx gpios | ||
uint32_t pio_func = 6 + cd->pio_num; | ||
|
@@ -1012,8 +1024,7 @@ enum { | |
}; | ||
|
||
// Reset any bits in the incoming parsing state | ||
static void | ||
data_state_clear_bits(struct can2040 *cd) | ||
void can2040_ll_data_state_clear_bits(struct can2040 *cd) | ||
{ | ||
cd->raw_bit_count = cd->unstuf.stuffed_bits = cd->unstuf.count_stuff = 0; | ||
} | ||
|
@@ -1027,13 +1038,12 @@ data_state_go_next(struct can2040 *cd, uint32_t state, uint32_t num_bits) | |
} | ||
|
||
// Transition to the MS_DISCARD state - drop all bits until 6 passive bits | ||
static void | ||
data_state_go_discard(struct can2040 *cd) | ||
void can2040_ll_data_state_go_discard(struct can2040 *cd) | ||
{ | ||
if (pio_rx_check_stall(cd)) { | ||
// CPU couldn't keep up for some read data - must reset pio state | ||
data_state_clear_bits(cd); | ||
pio_sm_setup(cd); | ||
can2040_ll_data_state_clear_bits(cd); | ||
can2040_ll_pio_sm_setup(cd); | ||
report_callback_error(cd, 0); | ||
} | ||
|
||
|
@@ -1048,15 +1058,15 @@ static void | |
data_state_go_error(struct can2040 *cd) | ||
{ | ||
cd->stats.parse_error++; | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
} | ||
|
||
// Received six dominant bits on the line | ||
static void | ||
data_state_line_error(struct can2040 *cd) | ||
{ | ||
if (cd->parse_state == MS_DISCARD) | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
else | ||
data_state_go_error(cd); | ||
} | ||
|
@@ -1075,9 +1085,9 @@ data_state_line_passive(struct can2040 *cd) | |
uint32_t dom_bits = ~stuffed_bits; | ||
if (!dom_bits) { | ||
// Counter overflow in "sync" state machine - reset it | ||
data_state_clear_bits(cd); | ||
pio_sm_setup(cd); | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_clear_bits(cd); | ||
can2040_ll_pio_sm_setup(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
return; | ||
} | ||
|
||
|
@@ -1087,7 +1097,7 @@ data_state_line_passive(struct can2040 *cd) | |
return; | ||
} | ||
|
||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
} | ||
|
||
// Transition to MS_CRC state - await 16 bits of crc | ||
|
@@ -1117,7 +1127,7 @@ data_state_go_data(struct can2040 *cd, uint32_t id, uint32_t data) | |
{ | ||
if (data & (0x03 << 4)) { | ||
// Not a supported header | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
return; | ||
} | ||
cd->parse_msg.data32[0] = cd->parse_msg.data32[1] = 0; | ||
|
@@ -1246,7 +1256,7 @@ data_state_update_eof1(struct can2040 *cd, uint32_t data) | |
} else if (data >= 0x1c || (data >= 0x18 && report_is_not_in_tx(cd))) { | ||
// Message fully transmitted - followed by "overload frame" | ||
report_note_eof_success(cd); | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
} else { | ||
data_state_go_error(cd); | ||
} | ||
|
@@ -1256,7 +1266,7 @@ data_state_update_eof1(struct can2040 *cd, uint32_t data) | |
static void | ||
data_state_update_discard(struct can2040 *cd, uint32_t data) | ||
{ | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
} | ||
|
||
// Update parsing state after reading the bits of the current field | ||
|
@@ -1452,17 +1462,17 @@ can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate | |
{ | ||
cd->gpio_rx = gpio_rx; | ||
cd->gpio_tx = gpio_tx; | ||
data_state_clear_bits(cd); | ||
can2040_ll_data_state_clear_bits(cd); | ||
pio_setup(cd, sys_clock, bitrate); | ||
data_state_go_discard(cd); | ||
can2040_ll_data_state_go_discard(cd); | ||
} | ||
|
||
// API function to stop can2040 code | ||
void | ||
can2040_stop(struct can2040 *cd) | ||
{ | ||
pio_irq_disable(cd); | ||
pio_sm_setup(cd); | ||
can2040_ll_pio_sm_setup(cd); | ||
} | ||
|
||
// API function to access can2040 statistics | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
// Copyright (C) 2022-2025 Kevin O'Connor <[email protected]> | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
|
||
#ifndef _CAN2040_H | ||
#define _CAN2040_H | ||
|
||
|
@@ -63,6 +66,7 @@ struct can2040 { | |
void *pio_hw; | ||
uint32_t gpio_rx, gpio_tx; | ||
can2040_rx_cb rx_cb; | ||
void *rx_cb_user_data; | ||
struct can2040_stats stats; | ||
|
||
// Bit unstuffing | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Low-level definitions for CAN2040 functions | ||
// | ||
// Copyright (C) 2022-2025 Kevin O'Connor <[email protected]> | ||
// Copyright (C) 2025 Dmitrii Sharshakov <[email protected]> | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
|
||
#ifndef _CAN2040_LL_H | ||
#define _CAN2040_LL_H | ||
|
||
#include "can2040.h" | ||
#include <stdint.h> // uint32_t | ||
|
||
void can2040_ll_data_state_clear_bits(struct can2040 *cd); | ||
void can2040_ll_data_state_go_discard(struct can2040 *cd); | ||
void can2040_ll_pio_set_clkdiv(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate); | ||
void can2040_ll_pio_sm_setup(struct can2040 *cd); | ||
Comment on lines
+13
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A different interfix than |
||
|
||
#endif // _CAN2040_LL_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build: | ||
cmake-ext: True | ||
kconfig-ext: True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I correct to assume it's GPL-3.0-only, and not -and-later?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Zephyr build system West uses SPDX IDs to keep track of license of each file compiled, so this is important to make sure whoever uses this driver in Zephyr (or as my out-of-tree integration package if upstreaming fails) can get your licensing information and stay compliant with it.
Glue code must be Apache for Zephyr codebase, but when linking build system will find SPDX tags and let the user know they use a GPL-licensed module, fetched from a separate repository at the user's decision.