Browse Source

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 <alexander.wachter@student.tugraz.at>
pull/7600/merge
Alexander Wachter 7 years ago committed by Carles Cufí
parent
commit
2de9f2f8fd
  1. 2
      include/can.h
  2. 7
      samples/can/CMakeLists.txt
  3. 52
      samples/can/Kconfig
  4. 43
      samples/can/README.rst
  5. 8
      samples/can/prj.conf
  6. 269
      samples/can/src/main.c
  7. 1
      samples/samples.rst

2
include/can.h

@ -329,7 +329,7 @@ __syscall int can_attach_msgq(struct device *dev, struct k_msgq *msg_q, @@ -329,7 +329,7 @@ __syscall int can_attach_msgq(struct device *dev, struct k_msgq *msg_q,
static inline int _impl_can_attach_msgq(struct device *dev,
struct k_msgq *msg_q,
struct can_filter *filter)
const struct can_filter *filter)
{
const struct can_driver_api *api = dev->driver_api;

7
samples/can/CMakeLists.txt

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
set(KCONFIG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/Kconfig)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
target_sources(app PRIVATE src/main.c)

52
samples/can/Kconfig

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
# Kconfig - Private config options for can sample app
#
# Copyright (c) 2018 Alexander Wachter
#
# SPDX-License-Identifier: Apache-2.0
#
mainmenu "Controller Area Network sample application"
config ZEPHYR_BASE
string
option env="ZEPHYR_BASE"
source "$ZEPHYR_BASE/Kconfig.zephyr"
config CAN_DEV
string "Name of the CAN device"
default "CAN_1"
help
Name of the can device used for send an receive.
config GPIO_LED_DEV
string "Name of the LED GPIO port"
default "GPIOC"
help
Name of the LED port for signaling message reception.
config GPIO_BUTTON_DEV
string "Name of the button GPIO port"
default "GPIOA"
help
Name of the button port for triggering messages.
config PIN_USER_BUTTON
int "Pin User Button"
default 0
help
Pin number of the user Button.
config PIN_LED_1
int "Pin LED 1"
default 6
help
Pin number of the first LED.
config LOOPBACK_MODE
bool "Loopback LOOPBACK_MODE"
default y
help
Set the controller to loopback mode.
This allows testing without a second board.

43
samples/can/README.rst

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
.. _can-sample:
Controller Area Network
#######################
Overview
********
This sample demonstrates how to use the Controller Area Network (CAN) API.
Messages with standard and extended identifiers are sent over the bus, triggered
by a button event.
Messages are received using message queues and ISRs.
Reception is indicated by blink LEDs and output to the console.
Building and Running
********************
In loopback mode, the board receives its own messages. This could be used for
standalone testing.
The sample can be built and executed on boards supporting CAN.
The output ports and pins of the LEDs can be configured by Kconfig.
Sample output
=============
.. code-block:: console
Finished init. waiting for Interrupts
TX thread is running.
filter id: 1
Button pressed! Send message 1
Button pressed 1 times
Button pressed! Send message 0
Button pressed 2 times
String sent over CAN
Button pressed! Send message 1
Button pressed 3 times
Button pressed! Send message 0
Button pressed 4 times
String sent over CAN
.. note:: The values shown above might differ.

8
samples/can/prj.conf

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
CONFIG_CAN=y
CONFIG_CAN_INIT_PRIORITY=80
CONFIG_CAN_PHASE_SEG1_PROP_SEG=5
CONFIG_CAN_PHASE_SEG2=6
CONFIG_CAN_SJW=1
CONFIG_CAN_1=y
CONFIG_CAN_STM32=y
CONFIG_CAN_MAX_FILTER=5

269
samples/can/src/main.c

@ -0,0 +1,269 @@ @@ -0,0 +1,269 @@
/*
* Copyright (c) 2018 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <kernel.h>
#include <misc/printk.h>
#include <device.h>
#include <can.h>
#include <gpio.h>
#define TX_THREAD_STACK_SIZE 512
#define LED_THREAD_STACK_SIZE 512
#define RX_STR_THREAD_STACK_SIZE 512
#define TX_THREAD_PRIORITY 2
#define LED_MSG_ID (0x10)
#define BUTTON_MSG_ID (0x01)
#define STR_MSG_ID (0x12345)
#define SET_LED 0
#define RESET_LED 1
#define NUM_LEDS_STR STRINGIFY(NUM_LEDS)
K_THREAD_STACK_DEFINE(tx_thread_stack, TX_THREAD_STACK_SIZE);
K_THREAD_STACK_DEFINE(led_thread_stack, LED_THREAD_STACK_SIZE);
K_THREAD_STACK_DEFINE(rx_str_thread_stack, RX_STR_THREAD_STACK_SIZE);
struct k_thread tx_thread_data;
struct k_thread led_thread_data;
struct k_thread rx_str_thread_data;
struct k_sem tx_sem;
static struct gpio_callback gpio_cb;
CAN_DEFINE_MSGQ(led_msgq, 2);
CAN_DEFINE_MSGQ(str_msgq, 5);
void tx_irq_callback(u32_t error_flags)
{
if (error_flags) {
printk("Callback! error-code: %d\n", error_flags);
}
}
void button_callback(struct device *port,
struct gpio_callback *cb, u32_t pins)
{
k_sem_give(&tx_sem);
}
void send_string(char *string, struct device *can_dev)
{
struct can_msg msg;
int str_len;
msg.ext_id = STR_MSG_ID;
msg.id_type = CAN_EXTENDED_IDENTIFIER;
msg.dlc = 0;
msg.rtr = CAN_DATAFRAME;
for (str_len = strlen(string); str_len; ) {
msg.dlc = str_len >= 8 ? 8 : str_len;
str_len -= msg.dlc;
memcpy(msg.data, string, msg.dlc);
string += msg.dlc;
can_send(can_dev, &msg, 10, tx_irq_callback);
}
}
void tx_thread(void *can_dev_param, void *unused2, void *unused3)
{
u8_t toggle = SET_LED;
u16_t button_press_cnt = 0;
struct can_msg msg;
struct can_msg msg_button_cnt;
struct device *can_dev = can_dev_param;
msg.std_id = LED_MSG_ID;
msg.id_type = CAN_STANDARD_IDENTIFIER;
msg.dlc = 1;
msg.rtr = CAN_DATAFRAME;
msg.data[0] = 0;
msg_button_cnt.std_id = BUTTON_MSG_ID;
msg_button_cnt.id_type = CAN_STANDARD_IDENTIFIER;
msg_button_cnt.dlc = 2;
msg_button_cnt.rtr = CAN_DATAFRAME;
msg_button_cnt.data[0] = 0;
msg_button_cnt.data[1] = 0;
printk("TX thread is running.\n");
while (1) {
k_sem_take(&tx_sem, K_FOREVER);
button_press_cnt++;
toggle = (toggle == SET_LED) ? RESET_LED : SET_LED;
printk("Button pressed! Send message %u\n", toggle);
msg.data[0] = toggle;
msg_button_cnt.data[0] = button_press_cnt & 0xFF;
msg_button_cnt.data[1] = (button_press_cnt >> 8) & 0xFF;
can_send(can_dev, &msg, 10, tx_irq_callback);
can_send(can_dev, &msg_button_cnt, 10, NULL);
if (toggle == SET_LED) {
send_string("String sent over CAN\n", can_dev);
}
}
}
void rx_str_thread(void *msgq, void *can_dev_param, void *unused)
{
struct can_msg msg;
const struct can_filter filter = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.ext_id = STR_MSG_ID,
.rtr_mask = 1,
.ext_id_mask = CAN_EXT_ID_MASK
};
struct device *can_dev = can_dev_param;
can_attach_msgq(can_dev, msgq, &filter);
while (1) {
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
for (int i = 0; i < msg.dlc; i++)
printk("%c", msg.data[i]);
}
}
void led_thread(void *msgq, void *can_dev_param, void *gpio_dev_param)
{
const struct can_filter filter = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.std_id = LED_MSG_ID,
.rtr_mask = 1,
.std_id_mask = CAN_STD_ID_MASK
};
struct device *can_dev = can_dev_param;
struct device *gpio_dev = gpio_dev_param;
struct can_msg msg;
int ret;
int filter_id;
ret = gpio_pin_configure(gpio_dev, CONFIG_PIN_LED_1, GPIO_DIR_OUT);
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
if (ret) {
printk("ERROR configure pins\n");
return;
}
filter_id = can_attach_msgq(can_dev, msgq, &filter);
printk("filter id: %d\n", filter_id);
while (1) {
k_msgq_get((struct k_msgq *)msgq, &msg, K_FOREVER);
if (msg.dlc != 1) {
continue;
}
switch (msg.data[0]) {
case SET_LED:
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 1);
break;
case RESET_LED:
gpio_pin_write(gpio_dev, CONFIG_PIN_LED_1, 0);
break;
}
}
}
void rx_button_isr(struct can_msg *msg)
{
u16_t cnt = msg->data[0] | (msg->data[1] << 8);
printk("Button pressed %d times\n", cnt);
}
void main(void)
{
const struct can_filter filter = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.std_id = BUTTON_MSG_ID,
.rtr_mask = 1,
.std_id_mask = CAN_STD_ID_MASK
};
struct device *can_dev, *led_gpio_dev, *button_gpio_dev;
int ret;
can_dev = device_get_binding(CONFIG_CAN_DEV);
if (!can_dev) {
printk("CAN: Device driver not found.\n");
return;
}
#ifdef CONFIG_LOOPBACK_MODE
can_configure(can_dev, CAN_LOOPBACK_MODE, 250000);
#endif
led_gpio_dev = device_get_binding(CONFIG_GPIO_LED_DEV);
if (!led_gpio_dev) {
printk("LED: Device driver not found.\n");
return;
}
k_sem_init(&tx_sem, 0, INT_MAX);
button_gpio_dev = device_get_binding(CONFIG_GPIO_BUTTON_DEV);
if (!button_gpio_dev) {
printk("Button: Device driver not found.\n");
return;
}
ret = gpio_pin_configure(button_gpio_dev, CONFIG_PIN_USER_BUTTON,
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));
if (ret) {
printk("Error configuring button pin\n");
}
gpio_init_callback(&gpio_cb, button_callback,
BIT(CONFIG_PIN_USER_BUTTON));
ret = gpio_add_callback(button_gpio_dev, &gpio_cb);
if (ret) {
printk("Cannot setup callback!\n");
}
ret = gpio_pin_enable_callback(button_gpio_dev, CONFIG_PIN_USER_BUTTON);
if (ret) {
printk("Error enabling callback!\n");
}
can_attach_isr(can_dev, rx_button_isr, &filter);
k_tid_t tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack,
K_THREAD_STACK_SIZEOF(tx_thread_stack),
tx_thread,
can_dev, NULL, NULL,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!tx_tid) {
printk("ERROR spawning tx_thread\n");
}
k_tid_t led_tid = k_thread_create(&led_thread_data, led_thread_stack,
K_THREAD_STACK_SIZEOF(led_thread_stack),
led_thread,
&led_msgq, can_dev, led_gpio_dev,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!led_tid) {
printk("ERROR spawning led_thread\n");
}
k_tid_t str_tid = k_thread_create(&rx_str_thread_data,
rx_str_thread_stack,
K_THREAD_STACK_SIZEOF(rx_str_thread_stack),
rx_str_thread,
&str_msgq, can_dev, NULL,
TX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!str_tid) {
printk("ERROR spawning str_thread\n");
}
printk("Finished init. waiting for Interrupts\n");
}

1
samples/samples.rst

@ -20,6 +20,7 @@ Samples and Demos @@ -20,6 +20,7 @@ Samples and Demos
drivers/drivers.rst
application_development/*
display/*
can/README.rst
To add a new sample document, please use the template available under

Loading…
Cancel
Save