-
-
Save 0xff07/3d874b77e1488a060a3b7c1c377b4d41 to your computer and use it in GitHub Desktop.
Communicate with Arduino via SPI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/dts-v1/; | |
/plugin/; | |
/ { | |
compatible = "brcm,bcm2835"; | |
fragment@0 { | |
target = <&spidev0>; | |
__overlay__ { | |
status = "disabled"; | |
}; | |
}; | |
fragment@1 { | |
target = <&spi0>; | |
__overlay__ { | |
#address-cells = <1>; | |
#size-cells = <0>; | |
arduino-spi@0 { | |
compatible="arduino"; | |
reg = <0x00>; | |
spi-max-frequency = <0x3d0900>; | |
}; | |
}; | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SPI.h> | |
void setup() { | |
Serial.begin(9600); | |
pinMode(MISO, OUTPUT); | |
pinMode(MOSI, INPUT); | |
SPI.setClockDivider(SPI_CLOCK_DIV128); | |
SPCR |= _BV(SPE); | |
SPCR |= _BV(SPIE); | |
SPCR &= ~(_BV(MSTR)); | |
} | |
#define BUF_LEN 128 | |
char buf[BUF_LEN + 1] = {0}; | |
int top = -1; | |
ISR(SPI_STC_vect) | |
{ | |
buf[(++top) % BUF_LEN] = SPDR; | |
} | |
void loop() { | |
Serial.println(buf); | |
delay(1000); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/init.h> | |
#include <linux/spi/spi.h> | |
#include <linux/string.h> | |
#include <linux/fs.h> | |
#include <linux/slab.h> | |
#include <linux/cdev.h> | |
#include <linux/device.h> | |
#include <linux/uaccess.h> | |
#define ARDUINO_DEV_NAME "arduino" | |
static struct class *arduino_class = NULL; | |
static dev_t dev = 0; | |
struct arduino_spi_cdev { | |
struct spi_device *spi; | |
struct cdev cdev; | |
}; | |
static ssize_t arduino_spi_open(struct inode *inode, struct file *filp) | |
{ | |
struct arduino_spi_cdev *arduino = container_of(inode->i_cdev, struct arduino_spi_cdev, cdev); | |
if (!arduino) { | |
pr_err("Cannot extrace aduino structure from i_cdev.\n"); | |
return -EINVAL; | |
} | |
filp -> private_data = arduino -> spi; | |
return 0; | |
} | |
static ssize_t arduino_spi_write(struct file *filp, const char __user *buf, size_t count, | |
loff_t *offset) | |
{ | |
int err = 0; | |
struct spi_device *spi = filp -> private_data; | |
if (!spi) { | |
pr_err("Failed to get struct spi_device.\n"); | |
return -EINVAL; | |
} | |
char *msg = kzalloc(count + 1, GFP_KERNEL); | |
copy_from_user(msg, buf, count); | |
err = spi_write(spi, msg, count); | |
kfree(msg); | |
return err ? err : count; | |
} | |
struct file_operations arduino_spi_fops = { | |
.open = arduino_spi_open, | |
.write = arduino_spi_write, | |
}; | |
static int dummy_probe(struct spi_device *spi) | |
{ | |
int err = 0; | |
pr_info("Dummy device is being probed.\n"); | |
err = alloc_chrdev_region(&dev, 0, 1, ARDUINO_DEV_NAME); | |
if (err < 0) { | |
pr_err ("Failed in alloc_chrdev_reion for arduino.\n"); | |
goto out_alloc_chrdev; | |
} | |
arduino_class = class_create(THIS_MODULE, ARDUINO_DEV_NAME); | |
if (!arduino_class) { | |
pr_err ("Failed to create sysfs class.\n"); | |
goto out_sysfs_class; | |
} | |
struct arduino_spi_cdev *arduino = kzalloc(sizeof(struct arduino_spi_cdev), GFP_KERNEL); | |
if (!arduino) { | |
pr_err("Failed to allocate memory.\n"); | |
goto out_oom; | |
} | |
arduino -> spi = spi; | |
cdev_init(&(arduino -> cdev), &arduino_spi_fops); | |
arduino->cdev.owner = THIS_MODULE; | |
err = cdev_add(&(arduino -> cdev), dev, 1); | |
if (err) { | |
pr_err("Failed to register cdev.\n"); | |
goto out_cdev_add; | |
} | |
struct device *device = device_create(arduino_class, NULL, dev, NULL, ARDUINO_DEV_NAME); | |
if (!device) { | |
pr_err("Failed to create device entry under sysfs.\n"); | |
goto out_device; | |
} | |
spi->max_speed_hz = 400000; | |
dev_set_drvdata(&(spi->dev), arduino); | |
return 0; | |
out_device: | |
cdev_del(&arduino->cdev); | |
out_cdev_add: | |
kfree(arduino); | |
out_oom: | |
class_destroy(arduino_class); | |
out_sysfs_class: | |
unregister_chrdev_region(dev, 1); | |
out_alloc_chrdev: | |
return err; | |
} | |
static int dummy_remove(struct spi_device *spi) | |
{ | |
pr_info("Dummy device is removing.\n"); | |
struct arduino_spi_cdev *arduino = dev_get_drvdata(&(spi->dev)); | |
device_destroy(arduino_class, dev); | |
cdev_del(&(arduino->cdev)); | |
kfree(arduino); | |
class_destroy(arduino_class); | |
unregister_chrdev_region(dev, 1); | |
return 0; | |
} | |
static struct of_device_id dummy_id_tables [] = { | |
{ .compatible="arduino", }, | |
{ } | |
}; | |
MODULE_DEVICE_TABLE(of, dummy_id_tables); | |
static struct spi_driver dummy_drv = { | |
.probe = dummy_probe, | |
.remove = dummy_remove, | |
.driver = { | |
.name = "dummy device 0.1", | |
.owner = THIS_MODULE, | |
.of_match_table = dummy_id_tables, | |
}, | |
}; | |
module_spi_driver(dummy_drv); | |
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PWD := $(shell pwd) | |
KVERSION := $(shell uname -r) | |
KERNEL_DIR := /lib/modules/$(shell uname -r)/build | |
MODULE_NAME = dummy_spi_chrdrv | |
obj-m := $(MODULE_NAME).o | |
ccflags-y += -std=gnu99 | |
all: | |
make -C $(KERNEL_DIR) M=$(PWD) modules | |
clean: | |
make -C $(KERNEL_DIR) M=$(PWD) clean |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment