简述
SX1278已经使用好几年了,一直是基于单片机的私有协议或者Lorawan协议。最近业余时间又重新翻阅了宋宝华老师的《Linux设备驱动开发详解》萌生出了在linux下将sx1278作为一个特殊的无线网络设备来使用的想法,正好把书中的知识实践实践。
最终实现目标:
1、两片sx1278 ping通
2、一个板子作为sx128网络网关,通过NAT实现共享上网,另一个板子通过sx1278 ping通百度一个服务器
基于的设备驱动模型
- ”SPI DRIVER“ ,SPI设备驱动模型;
- “Net Device",网络设备驱动;
注意:本文使用4.9.8linux内核
主要代码片段
spi probe函数里面主要实现spi_device指针获取、网络设备注册、中断注册等
int SPI_Driver_probe(struct spi_device *spi)
{
int res;
int i;
dev_t device_ID;
u8 switch_value=0;
struct net_priv *db; /* 设备私有数据结构体 */
struct net_device *ndev; /*w网络设备*/
struct device *dev = &spi->dev;
MySPI = spi;
/*动态申请 设备结构体 网络设备名称为 sx1278*/
ndev= alloc_netdev(sizeof(struct net_priv), "sx1278",0, ether_setup);
if(ndev)
printk("eth name = %s\n\r",ndev->name);
/*设置 网络设备*/
SET_NETDEV_DEV(ndev, &spi->dev);
dev_dbg(&spi->dev, "sx1278_probe()\n");
/* 获取私有数据地址 并初始化 */
db = netdev_priv(ndev);
db->dev = &spi->dev;
db->virt_net = ndev;
mutex_init(&db->lock);
/*从设备数 获取 中断io 号*/
db->irq_gpio = of_get_named_gpio(spi->dev.of_node, "sx1278_int", 0);
printk("gpio is=%d\n\r", db->irq_gpio);
if (!gpio_is_valid( db->irq_gpio))
{
printk(KERN_ERR"of_get_named_gpio error\n");
return -1;
}
res = devm_gpio_request_one(db->dev,db->irq_gpio, GPIOF_IN, "sx1278_int");
if (res) {
printk(KERN_ERR"devm_gpio_request_one error\n");
return -1;
}
//注册中断
res = request_threaded_irq(gpio_to_irq( db->irq_gpio), NULL,
gpio_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "sx1278_int",
db->virt_net);
/*初始化 sx1278模块*/
radio_init();
SX1276Read(0x01,&switch_value);
/*进入 接收*/
LoRaRxStateEnter();
/*初始化 网络设备 操作函数*/
db->virt_net->netdev_ops=&virt_netdev_ops;
/*设置 默认MAC 地址*/
db->virt_net->dev_addr[0] = 0x08;
db->virt_net->dev_addr[1] = 0x89;
db->virt_net->dev_addr[2] = 0x89;
db->virt_net->dev_addr[3] = 0x89;
db->virt_net->dev_addr[4] = 0x12;
db->virt_net->dev_addr[5] = 0x78;
db->virt_net->flags |= IFF_NOARP;
db->virt_net->watchdog_timeo = 1000000;
/*使用register_netdev()来注册net_device结构体 */
register_netdev(db->virt_net);
/*开启一个内核线程 用来发送sx1278 skb 也可以用工作队列实现 因为如果将1278发送函数直接放在网络设备的 硬件 发送函数里 会导致 内核原子调度bug 猜测可能是 spi读写导致睡眠 知道的兄弟可以说说*/
practice_task_p = kthread_create(my_kernel_thread,db->virt_net,"practice task");
if(!IS_ERR(practice_task_p))
wake_up_process(practice_task_p);
return 0;
上板测试
将驱动编译为模块sx1278.ko,下载到板子安装,生成sx1278的网络设备
将一个板子1278设置ip:3.3.3.3,另一个设置为3.3.3.4;互ping测试结果:
将ip为3.3.3.3的板子通过以太网连接互联网,并设置NAT转发,具体设置方法这里不描述。
将ip为3.3.3.4的sx1278网卡网关设置为3.3.3.3,ping 百度一个IP 14.215.177.39:
总结
从测试结果看来网络时延较大,主要是由于sx1278速率慢。