samples: drivers: CAN: reworked sample code

The CAN sample is rewritten to be board independent.
The CAN controller and LED is determined automatically and the
button is removed.

Signed-off-by: Alexander Wachter <alexander.wachter@student.tugraz.at>
This commit is contained in:
Alexander Wachter 2019-08-07 13:32:04 +02:00 committed by Ioannis Glaropoulos
commit f19dd97517
7 changed files with 120 additions and 286 deletions

View file

@ -8,36 +8,6 @@
mainmenu "Controller Area Network sample application"
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
@ -45,5 +15,4 @@ config LOOPBACK_MODE
Set the controller to loopback mode.
This allows testing without a second board.
source "Kconfig.zephyr"

View file

@ -7,10 +7,9 @@ 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.
Messages with standard and extended identifiers are sent over the bus.
Messages are received using message-queues and work-queues.
Reception is indicated by blinking the LED (if present) and output to the console.
Building and Running
********************
@ -19,25 +18,20 @@ 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.
The LED output pin is defined in the board's device tre.
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
Change LED filter ID: 0
Finished init.
Counter filter id: 4
uart:~$ Counter received: 0
Counter received: 1
Counter received: 2
Counter received: 3
.. note:: The values shown above might differ.

View file

@ -1,11 +0,0 @@
CONFIG_CAN_DEV="CAN_0"
CONFIG_GPIO_LED_DEV="GPIO_4"
CONFIG_GPIO_BUTTON_DEV="GPIO_2"
CONFIG_PIN_USER_BUTTON=6
CONFIG_PIN_LED_1=26
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=2048
CONFIG_CAN_0=y
CONFIG_CAN_1=n

View file

@ -1,11 +0,0 @@
CONFIG_CAN_DEV="CAN_0"
CONFIG_GPIO_LED_DEV="GPIO_2"
CONFIG_GPIO_BUTTON_DEV="GPIO_3"
CONFIG_PIN_USER_BUTTON=3
CONFIG_PIN_LED_1=13
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=2048
CONFIG_CAN_0=y
CONFIG_CAN_1=n

View file

@ -1,6 +1,5 @@
CONFIG_CAN=y
CONFIG_CAN_INIT_PRIORITY=80
CONFIG_CAN_1=y
CONFIG_CAN_MAX_FILTER=5
CONFIG_SHELL=y

View file

@ -1,13 +0,0 @@
# CAN + MCP2515 config
CONFIG_SPI=y
CONFIG_CAN=y
CONFIG_CAN_INIT_PRIORITY=80
CONFIG_CAN_1=y
CONFIG_CAN_STM32=n
CONFIG_CAN_MCP2515=y
CONFIG_GPIO_LED_DEV="GPIOB"
CONFIG_PIN_LED_1=3
CONFIG_GPIO_BUTTON_DEV="GPIOB"
CONFIG_PIN_USER_BUTTON=4
CONFIG_LOG=y
CONFIG_CAN_LOG_LEVEL=4

View file

@ -10,195 +10,124 @@
#include <device.h>
#include <drivers/can.h>
#include <drivers/gpio.h>
#include <misc/byteorder.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 RX_THREAD_STACK_SIZE 512
#define RX_THREAD_PRIORITY 2
#define LED_MSG_ID 0x10
#define COUNTER_MSG_ID 0x12345
#define SET_LED 1
#define RESET_LED 0
#define SLEEP_TIME K_MSEC(250)
#define SET_LED 0
#define RESET_LED 1
K_THREAD_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE);
struct k_thread rx_thread_data;
struct zcan_work rx_work;
#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);
CAN_DEFINE_MSGQ(counter_msgq, 2);
void tx_irq_callback(u32_t error_flags, void *arg)
{
char *sender = (char *)arg;
if (error_flags) {
printk("Callback! error-code: %d\nSender: %s\n",
error_flags, sender);
}
}
void button_callback(struct device *port,
struct gpio_callback *cb, u32_t pins)
void rx_thread(void *can_dev_param, void *arg1, void *arg2)
{
k_sem_give(&tx_sem);
}
void send_string(char *string, struct device *can_dev)
{
struct zcan_frame msg;
int str_len;
msg.ext_id = STR_MSG_ID;
msg.id_type = CAN_EXTENDED_IDENTIFIER;
msg.dlc = 0U;
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, "send_string");
}
}
void tx_thread(void *can_dev_param, void *unused2, void *unused3)
{
u8_t toggle = SET_LED;
u16_t button_press_cnt = 0U;
struct zcan_frame msg;
struct zcan_frame msg_button_cnt;
struct device *can_dev = can_dev_param;
msg.std_id = LED_MSG_ID;
msg.id_type = CAN_STANDARD_IDENTIFIER;
msg.dlc = 1U;
msg.rtr = CAN_DATAFRAME;
msg.data[0] = 0U;
msg_button_cnt.std_id = BUTTON_MSG_ID;
msg_button_cnt.id_type = CAN_STANDARD_IDENTIFIER;
msg_button_cnt.dlc = 2U;
msg_button_cnt.rtr = CAN_DATAFRAME;
msg_button_cnt.data[0] = 0U;
msg_button_cnt.data[1] = 0U;
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, "LED msg");
can_send(can_dev, &msg_button_cnt, 10, NULL, "Button count");
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 zcan_frame msg;
int filter_id;
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
const struct zcan_filter filter = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.ext_id = STR_MSG_ID,
.ext_id = COUNTER_MSG_ID,
.rtr_mask = 1,
.ext_id_mask = CAN_EXT_ID_MASK
};
struct device *can_dev = can_dev_param;
struct zcan_frame msg;
int filter_id;
filter_id = can_attach_msgq(can_dev, msgq, &filter);
printk("filter id: %d\n", filter_id);
filter_id = can_attach_msgq(can_dev, &counter_msgq, &filter);
printk("Counter filter id: %d\n", filter_id);
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]);
k_msgq_get(&counter_msgq, &msg, K_FOREVER);
if (msg.dlc != 2U) {
printk("Wrong data length: %u\n", msg.dlc);
continue;
}
printk("Counter received: %u\n",
sys_be16_to_cpu(UNALIGNED_GET((u16_t *)&msg.data)));
}
}
void led_thread(void *msgq, void *can_dev_param, void *gpio_dev_param)
void change_led(struct zcan_frame *msg, void *led_dev_param)
{
const struct zcan_filter filter = {
struct device *led_dev = (struct device *)led_dev_param;
#if defined(DT_ALIAS_LED0_GPIOS_PIN) && defined(DT_ALIAS_LED0_GPIOS_CONTROLLER)
if (!led_dev_param) {
printk("No LED GPIO device\n");
return;
}
switch (msg->data[0]) {
case SET_LED:
gpio_pin_write(led_dev, DT_ALIAS_LED0_GPIOS_PIN, 1);
break;
case RESET_LED:
gpio_pin_write(led_dev, DT_ALIAS_LED0_GPIOS_PIN, 0);
break;
}
#else
printk("LED %s\n", msg->data[0] == SET_LED ? "ON" : "OFF");
#endif
}
void main(void)
{
const struct zcan_filter change_led_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 zcan_frame 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 != 1U) {
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 zcan_frame *msg, void *arg)
{
u16_t cnt = msg->data[0] | (msg->data[1] << 8);
ARG_UNUSED(arg);
printk("Button pressed %d times\n", cnt);
}
void main(void)
{
const struct zcan_filter filter = {
struct zcan_frame change_led_frame = {
.id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.std_id = BUTTON_MSG_ID,
.rtr_mask = 1,
.std_id_mask = CAN_STD_ID_MASK
.std_id = LED_MSG_ID,
.dlc = 1
};
struct device *can_dev, *led_gpio_dev, *button_gpio_dev;
struct zcan_frame counter_frame = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.ext_id = COUNTER_MSG_ID,
.dlc = 2
};
u8_t toggle = 1;
u16_t counter = 0;
struct device *led_gpio_dev = NULL;
struct device *can_dev;
k_tid_t rx_tid;
int ret;
can_dev = device_get_binding(CONFIG_CAN_DEV);
/* Usually the CAN device is either called CAN_0 or CAN_1, depending
* on the SOC. Let's check both and take the first valid one.
*/
can_dev = device_get_binding("CAN_0");
if (!can_dev) {
can_dev = device_get_binding("CAN_1");
}
if (!can_dev) {
printk("CAN: Device driver not found.\n");
return;
@ -208,73 +137,51 @@ void main(void)
can_configure(can_dev, CAN_LOOPBACK_MODE, 250000);
#endif
led_gpio_dev = device_get_binding(CONFIG_GPIO_LED_DEV);
#if defined(DT_ALIAS_LED0_GPIOS_PIN) && defined(DT_ALIAS_LED0_GPIOS_CONTROLLER)
led_gpio_dev = device_get_binding(DT_ALIAS_LED0_GPIOS_CONTROLLER);
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(led_gpio_dev, DT_ALIAS_LED0_GPIOS_PIN,
GPIO_DIR_OUT);
if (ret < 0) {
printk("Error setting LED pin to output mode [%d]", ret);
}
#endif
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");
}
ret = can_attach_isr(can_dev, rx_button_isr, 0, &filter);
ret = can_attach_workq(can_dev, &k_sys_work_q, &rx_work, change_led,
led_gpio_dev, &change_led_filter);
if (ret == CAN_NO_FREE_FILTER) {
printk("Error, no filter available!\n");
return;
}
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");
printk("Change LED filter ID: %d\n", ret);
rx_tid = k_thread_create(&rx_thread_data, rx_thread_stack,
K_THREAD_STACK_SIZEOF(rx_thread_stack),
rx_thread, can_dev, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!rx_tid) {
printk("ERROR spawning rx 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");
}
printk("Finished init.\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");
}
while (1) {
change_led_frame.data[0] = toggle++ & 0x01 ? SET_LED : RESET_LED;
/* This sending call is none blocking. */
can_send(can_dev, &change_led_frame, K_FOREVER, tx_irq_callback,
"LED change");
k_sleep(SLEEP_TIME);
printk("Finished init. waiting for Interrupts\n");
UNALIGNED_PUT(sys_cpu_to_be16(counter),
(u16_t *)&counter_frame.data[0]);
counter++;
/* This sending call is blocking until the message is sent. */
can_send(can_dev, &counter_frame, K_MSEC(100), NULL, NULL);
k_sleep(SLEEP_TIME);
}
}