Skip to content

Commit 2de9f2f

Browse files
Alexander Wachtercarlescufi
authored andcommitted
samples: can: Add example code for CAN driver
This adds example and testing code for CAN driver. Tested on stm32f072b disco. Examples are given for: - can_configure - can_attach_isr - can_attach_msgq - can_send Signed-off-by: Alexander Wachter <[email protected]>
1 parent e73637a commit 2de9f2f

File tree

7 files changed

+381
-1
lines changed

7 files changed

+381
-1
lines changed

include/can.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ __syscall int can_attach_msgq(struct device *dev, struct k_msgq *msg_q,
329329

330330
static inline int _impl_can_attach_msgq(struct device *dev,
331331
struct k_msgq *msg_q,
332-
struct can_filter *filter)
332+
const struct can_filter *filter)
333333
{
334334
const struct can_driver_api *api = dev->driver_api;
335335

samples/can/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
set(KCONFIG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/Kconfig)
3+
4+
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
5+
project(NONE)
6+
7+
target_sources(app PRIVATE src/main.c)

samples/can/Kconfig

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Kconfig - Private config options for can sample app
2+
3+
#
4+
# Copyright (c) 2018 Alexander Wachter
5+
#
6+
# SPDX-License-Identifier: Apache-2.0
7+
#
8+
9+
mainmenu "Controller Area Network sample application"
10+
11+
config ZEPHYR_BASE
12+
string
13+
option env="ZEPHYR_BASE"
14+
15+
source "$ZEPHYR_BASE/Kconfig.zephyr"
16+
17+
config CAN_DEV
18+
string "Name of the CAN device"
19+
default "CAN_1"
20+
help
21+
Name of the can device used for send an receive.
22+
23+
config GPIO_LED_DEV
24+
string "Name of the LED GPIO port"
25+
default "GPIOC"
26+
help
27+
Name of the LED port for signaling message reception.
28+
29+
config GPIO_BUTTON_DEV
30+
string "Name of the button GPIO port"
31+
default "GPIOA"
32+
help
33+
Name of the button port for triggering messages.
34+
35+
config PIN_USER_BUTTON
36+
int "Pin User Button"
37+
default 0
38+
help
39+
Pin number of the user Button.
40+
41+
config PIN_LED_1
42+
int "Pin LED 1"
43+
default 6
44+
help
45+
Pin number of the first LED.
46+
47+
config LOOPBACK_MODE
48+
bool "Loopback LOOPBACK_MODE"
49+
default y
50+
help
51+
Set the controller to loopback mode.
52+
This allows testing without a second board.

samples/can/README.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.. _can-sample:
2+
3+
Controller Area Network
4+
#######################
5+
6+
Overview
7+
********
8+
9+
This sample demonstrates how to use the Controller Area Network (CAN) API.
10+
Messages with standard and extended identifiers are sent over the bus, triggered
11+
by a button event.
12+
Messages are received using message queues and ISRs.
13+
Reception is indicated by blink LEDs and output to the console.
14+
15+
Building and Running
16+
********************
17+
18+
In loopback mode, the board receives its own messages. This could be used for
19+
standalone testing.
20+
21+
The sample can be built and executed on boards supporting CAN.
22+
The output ports and pins of the LEDs can be configured by Kconfig.
23+
24+
Sample output
25+
=============
26+
27+
.. code-block:: console
28+
29+
Finished init. waiting for Interrupts
30+
TX thread is running.
31+
filter id: 1
32+
Button pressed! Send message 1
33+
Button pressed 1 times
34+
Button pressed! Send message 0
35+
Button pressed 2 times
36+
String sent over CAN
37+
Button pressed! Send message 1
38+
Button pressed 3 times
39+
Button pressed! Send message 0
40+
Button pressed 4 times
41+
String sent over CAN
42+
43+
.. note:: The values shown above might differ.

samples/can/prj.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CONFIG_CAN=y
2+
CONFIG_CAN_INIT_PRIORITY=80
3+
CONFIG_CAN_PHASE_SEG1_PROP_SEG=5
4+
CONFIG_CAN_PHASE_SEG2=6
5+
CONFIG_CAN_SJW=1
6+
CONFIG_CAN_1=y
7+
CONFIG_CAN_STM32=y
8+
CONFIG_CAN_MAX_FILTER=5

samples/can/src/main.c

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Copyright (c) 2018 Alexander Wachter
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <kernel.h>
9+
#include <misc/printk.h>
10+
#include <device.h>
11+
#include <can.h>
12+
#include <gpio.h>
13+
14+
#define TX_THREAD_STACK_SIZE 512
15+
#define LED_THREAD_STACK_SIZE 512
16+
#define RX_STR_THREAD_STACK_SIZE 512
17+
#define TX_THREAD_PRIORITY 2
18+
#define LED_MSG_ID (0x10)
19+
#define BUTTON_MSG_ID (0x01)
20+
#define STR_MSG_ID (0x12345)
21+
22+
#define SET_LED 0
23+
#define RESET_LED 1
24+
25+
26+
#define NUM_LEDS_STR STRINGIFY(NUM_LEDS)
27+
28+
K_THREAD_STACK_DEFINE(tx_thread_stack, TX_THREAD_STACK_SIZE);
29+
K_THREAD_STACK_DEFINE(led_thread_stack, LED_THREAD_STACK_SIZE);
30+
K_THREAD_STACK_DEFINE(rx_str_thread_stack, RX_STR_THREAD_STACK_SIZE);
31+
struct k_thread tx_thread_data;
32+
struct k_thread led_thread_data;
33+
struct k_thread rx_str_thread_data;
34+
struct k_sem tx_sem;
35+
static struct gpio_callback gpio_cb;
36+
CAN_DEFINE_MSGQ(led_msgq, 2);
37+
CAN_DEFINE_MSGQ(str_msgq, 5);
38+
39+
void tx_irq_callback(u32_t error_flags)
40+
{
41+
if (error_flags) {
42+
printk("Callback! error-code: %d\n", error_flags);
43+
}
44+
}
45+
46+
void button_callback(struct device *port,
47+
struct gpio_callback *cb, u32_t pins)
48+
{
49+
k_sem_give(&tx_sem);
50+
}
51+
52+
void send_string(char *string, struct device *can_dev)
53+
{
54+
struct can_msg msg;
55+
int str_len;
56+
57+
msg.ext_id = STR_MSG_ID;
58+
msg.id_type = CAN_EXTENDED_IDENTIFIER;
59+
msg.dlc = 0;
60+
msg.rtr = CAN_DATAFRAME;
61+
62+
for (str_len = strlen(string); str_len; ) {
63+
msg.dlc = str_len >= 8 ? 8 : str_len;
64+
str_len -= msg.dlc;
65+
memcpy(msg.data, string, msg.dlc);
66+
string += msg.dlc;
67+
can_send(can_dev, &msg, 10, tx_irq_callback);
68+
}
69+
}
70+
71+
void tx_thread(void *can_dev_param, void *unused2, void *unused3)
72+
{
73+
u8_t toggle = SET_LED;
74+
u16_t button_press_cnt = 0;
75+
struct can_msg msg;
76+
struct can_msg msg_button_cnt;
77+
struct device *can_dev = can_dev_param;
78+
79+
msg.std_id = LED_MSG_ID;
80+
msg.id_type = CAN_STANDARD_IDENTIFIER;
81+
msg.dlc = 1;
82+
msg.rtr = CAN_DATAFRAME;
83+
msg.data[0] = 0;
84+
85+
msg_button_cnt.std_id = BUTTON_MSG_ID;
86+
msg_button_cnt.id_type = CAN_STANDARD_IDENTIFIER;
87+
msg_button_cnt.dlc = 2;
88+
msg_button_cnt.rtr = CAN_DATAFRAME;
89+
msg_button_cnt.data[0] = 0;
90+
msg_button_cnt.data[1] = 0;
91+
92+
printk("TX thread is running.\n");
93+
while (1) {
94+
k_sem_take(&tx_sem, K_FOREVER);
95+
button_press_cnt++;
96+
toggle = (toggle == SET_LED) ? RESET_LED : SET_LED;
97+
printk("Button pressed! Send message %u\n", toggle);
98+
msg.data[0] = toggle;
99+
msg_button_cnt.data[0] = button_press_cnt & 0xFF;
100+
msg_button_cnt.data[1] = (button_press_cnt >> 8) & 0xFF;
101+
can_send(can_dev, &msg, 10, tx_irq_callback);
102+
can_send(can_dev, &msg_button_cnt, 10, NULL);
103+
if (toggle == SET_LED) {
104+
send_string("String sent over CAN\n", can_dev);
105+
}
106+
}
107+
}
108+
109+
void rx_str_thread(void *msgq, void *can_dev_param, void *unused)
110+
{
111+
struct can_msg msg;
112+
const struct can_filter filter = {
113+
.id_type = CAN_EXTENDED_IDENTIFIER,
114+
.rtr = CAN_DATAFRAME,
115+
.ext_id = STR_MSG_ID,
116+
.rtr_mask = 1,
117+
.ext_id_mask = CAN_EXT_ID_MASK
118+
};
119+
struct device *can_dev = can_dev_param;
120+
121+
can_attach_msgq(can_dev, msgq, &filter);
122+
123+
while (1) {
124+
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
125+
for (int i = 0; i < msg.dlc; i++)
126+
printk("%c", msg.data[i]);
127+
}
128+
}
129+
130+
void led_thread(void *msgq, void *can_dev_param, void *gpio_dev_param)
131+
{
132+
const struct can_filter filter = {
133+
.id_type = CAN_STANDARD_IDENTIFIER,
134+
.rtr = CAN_DATAFRAME,
135+
.std_id = LED_MSG_ID,
136+
.rtr_mask = 1,
137+
.std_id_mask = CAN_STD_ID_MASK
138+
};
139+
struct device *can_dev = can_dev_param;
140+
struct device *gpio_dev = gpio_dev_param;
141+
struct can_msg msg;
142+
int ret;
143+
int filter_id;
144+
145+
ret = gpio_pin_configure(gpio_dev, CONFIG_PIN_LED_1, GPIO_DIR_OUT);
146+
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
147+
148+
if (ret) {
149+
printk("ERROR configure pins\n");
150+
return;
151+
}
152+
153+
filter_id = can_attach_msgq(can_dev, msgq, &filter);
154+
printk("filter id: %d\n", filter_id);
155+
156+
while (1) {
157+
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
158+
159+
if (msg.dlc != 1) {
160+
continue;
161+
}
162+
163+
switch (msg.data[0]) {
164+
case SET_LED:
165+
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 1);
166+
167+
break;
168+
case RESET_LED:
169+
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
170+
break;
171+
}
172+
}
173+
}
174+
175+
void rx_button_isr(struct can_msg *msg)
176+
{
177+
u16_t cnt = msg->data[0] | (msg->data[1] << 8);
178+
179+
printk("Button pressed %d times\n", cnt);
180+
}
181+
182+
void main(void)
183+
{
184+
const struct can_filter filter = {
185+
.id_type = CAN_STANDARD_IDENTIFIER,
186+
.rtr = CAN_DATAFRAME,
187+
.std_id = BUTTON_MSG_ID,
188+
.rtr_mask = 1,
189+
.std_id_mask = CAN_STD_ID_MASK
190+
};
191+
struct device *can_dev, *led_gpio_dev, *button_gpio_dev;
192+
int ret;
193+
194+
can_dev = device_get_binding(CONFIG_CAN_DEV);
195+
if (!can_dev) {
196+
printk("CAN: Device driver not found.\n");
197+
return;
198+
}
199+
200+
#ifdef CONFIG_LOOPBACK_MODE
201+
can_configure(can_dev, CAN_LOOPBACK_MODE, 250000);
202+
#endif
203+
204+
led_gpio_dev = device_get_binding(CONFIG_GPIO_LED_DEV);
205+
if (!led_gpio_dev) {
206+
printk("LED: Device driver not found.\n");
207+
return;
208+
}
209+
210+
k_sem_init(&tx_sem, 0, INT_MAX);
211+
212+
button_gpio_dev = device_get_binding(CONFIG_GPIO_BUTTON_DEV);
213+
if (!button_gpio_dev) {
214+
printk("Button: Device driver not found.\n");
215+
return;
216+
}
217+
218+
ret = gpio_pin_configure(button_gpio_dev, CONFIG_PIN_USER_BUTTON,
219+
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
220+
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));
221+
if (ret) {
222+
printk("Error configuring button pin\n");
223+
}
224+
225+
gpio_init_callback(&gpio_cb, button_callback,
226+
BIT(CONFIG_PIN_USER_BUTTON));
227+
228+
ret = gpio_add_callback(button_gpio_dev, &gpio_cb);
229+
if (ret) {
230+
printk("Cannot setup callback!\n");
231+
}
232+
233+
ret = gpio_pin_enable_callback(button_gpio_dev, CONFIG_PIN_USER_BUTTON);
234+
if (ret) {
235+
printk("Error enabling callback!\n");
236+
}
237+
238+
can_attach_isr(can_dev, rx_button_isr, &filter);
239+
240+
k_tid_t tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack,
241+
K_THREAD_STACK_SIZEOF(tx_thread_stack),
242+
tx_thread,
243+
can_dev, NULL, NULL,
244+
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
245+
if (!tx_tid) {
246+
printk("ERROR spawning tx_thread\n");
247+
}
248+
249+
k_tid_t led_tid = k_thread_create(&led_thread_data, led_thread_stack,
250+
K_THREAD_STACK_SIZEOF(led_thread_stack),
251+
led_thread,
252+
&led_msgq, can_dev, led_gpio_dev,
253+
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
254+
if (!led_tid) {
255+
printk("ERROR spawning led_thread\n");
256+
}
257+
258+
k_tid_t str_tid = k_thread_create(&rx_str_thread_data,
259+
rx_str_thread_stack,
260+
K_THREAD_STACK_SIZEOF(rx_str_thread_stack),
261+
rx_str_thread,
262+
&str_msgq, can_dev, NULL,
263+
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
264+
if (!str_tid) {
265+
printk("ERROR spawning str_thread\n");
266+
}
267+
268+
printk("Finished init. waiting for Interrupts\n");
269+
}

0 commit comments

Comments
 (0)