Skip to content

Instantly share code, notes, and snippets.

@0xff07
Last active October 2, 2020 15:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0xff07/3d874b77e1488a060a3b7c1c377b4d41 to your computer and use it in GitHub Desktop.
Save 0xff07/3d874b77e1488a060a3b7c1c377b4d41 to your computer and use it in GitHub Desktop.
Communicate with Arduino via SPI
/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>;
};
};
};
};
#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);
}
#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");
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