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:
parent
85ef00deb4
commit
f19dd97517
7 changed files with 120 additions and 286 deletions
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,6 +1,5 @@
|
|||
CONFIG_CAN=y
|
||||
CONFIG_CAN_INIT_PRIORITY=80
|
||||
CONFIG_CAN_1=y
|
||||
CONFIG_CAN_MAX_FILTER=5
|
||||
|
||||
CONFIG_SHELL=y
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue