想通过应用层操作spi
首先我保证这几个内核配置是开了的:
CONFIG_SPI_SUN6I=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
然后因为我用spi flash启动 已经占用了spi0 所以要加新的接口spi1
改设备树文件suniv.dtsi 通过参考spi0来增加
spi0_pins_a: spi0-pins-pc {
pins = "PC0", "PC1", "PC2", "PC3";
function = "spi0";
};
spi1_pins_a: spi1-pins-pa {
pins = "PA2", "PA0", "PA3", "PA1";
function = "spi1";
};
改设备树文件suniv-f1c100s-licheepi-nano.dts 通过参考spi0来增加
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins_a>;
status = "okay";
flash: w25q128@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "winbond,w25q128", "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions{
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
lable = "u-boot";
reg = <0x000000 0x100000>;
read-only;
};
partition@100000 {
lable = "dtb";
reg = <0x100000 0x10000>;
read-only;
};
partition@110000 {
label = "kernel";
reg = <0x110000 0x400000>;
read-only;
};
partition@510000 {
label = "rootfs";
reg = <0x510000 0xAF0000>;
};
};
};
};
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
};
然后编译内核和设备树重新打包下载进板子
如果添加spi1成功了 会多出来个/dev/spi1 但实际上没有 只有原来的spi0.0 说明可能哪里错了 大神来指点一下?
离线
操作一下 spi0.0
有可能就是你需要的,
接逻辑分析仪到 cs# 引脚测试。
离线
操作一下 spi0.0
有可能就是你需要的,接逻辑分析仪到 cs# 引脚测试。
记错了 看了下 发现/dev/ 里面没有spi相关设备 是/sys/bus/spi/devices/spi0.0 这个应该不能操作吧
离线
原来是设备树没配好 重要的设备节点漏了
参考了链接 http://linux-sunxi.org/SPIdev
把/dev/spidev1.0配出来了
离线
原来是设备树没配好 重要的设备节点漏了
参考了链接 http://linux-sunxi.org/SPIdev
把/dev/spidev1.0配出来了
最后怎么搞掂的?
我这里也是,有看到,SPI1 初始化信息,但在 /dev/ 没有 SPI1 设备, SPI0也没有
离线
在 /sys/class/spi_master 目录下,看得到 SPI0 SPI1, 在 /dev/目录下没有,
如何是好了?
# ls
backlight graphics misc pwm spi_master
bdi i2c-adapter mmc_host regulator spidev
block i2c-dev mtd scsi_changer thermal
bsg ieee80211 net scsi_device tty
dma input phy scsi_disk udc
drm leds power_supply scsi_generic vc
extcon mdio_bus pps scsi_host vtconsole
gpio mem ptp sound
# cd spi_master
# ls
spi0 spi1
离线
CONFIG_SPI_SPIDEV=y
这个勾选了吗?
在 config 文件里,,
#
# SPI Protocol Masters
#
CONFIG_SPI_SPIDEV=y
# CONFIG_SPI_LOOPBACK_TEST is not set
# CONFIG_SPI_TLE62X0 is not set
离线
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
spidev@0x00 {
compatible = "spidev";
spi-max-frequency = <100000000>;
reg = <0>;
};
};
加了 spidev@0x00 这个就可以显示了,谢谢大家!等下测试,行不行,起码现在可以在 dev 下看到了
离线
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
spidev@0x00 {
compatible = "spidev";
spi-max-frequency = <100000000>;
reg = <0>;
};
};加了 spidev@0x00 这个就可以显示了,谢谢大家!等下测试,行不行,起码现在可以在 dev 下看到了
你好 请问您方便提供一下开启spi1之后的启动log吗?
离线
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
spidev@0x00 {
compatible = "spidev";
spi-max-frequency = <100000000>;
reg = <0>;
};
};加了 spidev@0x00 这个就可以显示了,谢谢大家!等下测试,行不行,起码现在可以在 dev 下看到了
这个实际上就是把spi 设备接口暴露给应用层,让app去驱动spi设备了。
离线
浏览了楼主的帖子,我的 /dev/spidev0.0 也配出来了,现在可以在应用程序层为所欲为了。
参考树莓派例程:
https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
https://raw.githubusercontent.com/raspberrypi/linux/rpi-3.10.y/Documentation/spi/spidev_test.c
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev1.1";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static void transfer(int fd)
{
int ret;
uint8_t tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D,
};
uint8_t rx[ARRAY_SIZE(tx)] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n");
exit(1);
}
static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
{ "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' },
{ "loop", 0, 0, 'l' },
{ "cpha", 0, 0, 'H' },
{ "cpol", 0, 0, 'O' },
{ "lsb", 0, 0, 'L' },
{ "cs-high", 0, 0, 'C' },
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ NULL, 0, 0, 0 },
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
if (c == -1)
break;
switch (c) {
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[0]);
break;
}
}
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
transfer(fd);
close(fd);
return ret;
}
离线
谢谢分享,F1C100S没有以太网,一直在调这个SPI,想用在ENC28j60上,
离线
Linux内置了 enc28j60的驱动,只要配置menuconfig和dts就行。
内核配置知道,dts要怎么添加,能不能麻烦大神写一下添加的部分,万分感谢!~
离线
内核配置知道,dts要怎么添加,能不能麻烦大神写一下添加的部分,万分感谢!~
驱动:
https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/microchip/enc28j60.c
树莓派dts demo:
https://github.com/eq-3/RaspberryMatic/blob/master/linux-4.1/arch/arm/boot/dts/overlays/enc28j60-overlay.dts
填好dts问题就不大了, 搞定了记得发个图分享一下。
离线
只加了spi1,在里面并没有加具体设备吧,所有没有spi1.0
离线
搞不掂,可以分享你那个DTS吗?
离线
不是在9楼已经搞定了吗?
上面是搞掂 SPI1, 我想弄的是, SPI1 驱动 ENC28J60, 这个没搞好
离线
不错,后面试试,正好有张吃灰的板子
离线
非常感觉!
现在启动时,
[0.958407] enc28j60 spi1.0: enc28j60 Ethernet driver 1.02 loaded
[0.975314] net eth0: enc28j60 driver registered
不过网络无法连接, 还得继续研究
离线
如 ENC28J60 SPI线,不连接或少连接,就会出现下面的情况,
[ 0.971925] enc28j60 spi1.0: enc28j60 chip not found
[ 0.977084] enc28j60: probe of spi1.0 failed with error -5
那说明,我这驱动应该是OK的
离线
中断接了吗?dts配了中断吗?
cat /proc/interrupts 显示enc28j60有多少次中断?
# cat /proc/interrupts
CPU0
16: 695 sun4i_irq 13 Edge timer@1c20c00
19: 90546 sun4i_irq 10 Edge sun6i-spi
20: 67 sun4i_irq 11 Edge sun6i-spi
22: 362 sun4i_irq 23 Edge sunxi-mmc
27: 244 sun4i_irq 2 Edge ttyS1
29: 0 sun4i_irq 26 Edge musb-hdrc.1.auto
65: 1 sunxi_pio_edge 34 Edge usb0-id-det
74: 0 sunxi_pio_edge 43 Edge enc28j60
离线
不过那个 rst 脚 没有接,要不要接的?
离线
# cat /proc/interrupts
CPU0
16: 500 sun4i_irq 13 Edge timer@1c20c00
19: 90592 sun4i_irq 10 Edge sun6i-spi
20: 260 sun4i_irq 11 Edge sun6i-spi
22: 220 sun4i_irq 23 Edge sunxi-mmc
27: 331 sun4i_irq 2 Edge ttyS1
29: 0 sun4i_irq 26 Edge musb-hdrc.1.auto
65: 1 sunxi_pio_edge 34 Edge usb0-id-det
74: 24 sunxi_pio_edge 43 Edge enc28j60
拿导线,把 INT脚,接地,就有中断次数了
离线
淘宝的模块可以上电启动,应该不要RST.
手动短路中断线到GND,
再 cat /proc/interrupts 看enc28j60中断次数有没有增加。
手动有中断的,
enc28j60 接5V会发热,
接3.3V 就不发热,,,,,,
但都没有中断, 可能买的是假货?
离线
离线
有没有执行 ifconfig eth0 192.x.x.x
:cool 非常非常感谢! 可以正常网络通信了, 主要原因是没有配置本地IP和网关, 配置好了,就可以上网了。
我现在研究一下,怎么开启 DHCP
离线
离线
busybox里面开启 udhcpc 就可以了,
执行
udhcpc -i eth0
太太太太太感谢了!可以正常工作了。
估计这里很多高手早就弄出来了, 不过我还是说一下流程吧,后面的朋友们可以参考参考
一、 在 arch/arm/boot/dts/suniv.dtsi
1. 添加头文件引用 #include <dt-bindings/interrupt-controller/irq.h>
2. 添加
spi1: spi@1c06000 {
compatible = "allwinner,suniv-spi",
"allwinner,sun8i-h3-spi";
reg = <0x01c06000 0x1000>;
interrupts = <11>;
clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_BUS_SPI1>;
clock-names = "ahb", "mod";
resets = <&ccu RST_BUS_SPI1>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
二、 在 arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts
添加
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
eth1: enc28j60@0{
compatible = "microchip,enc28j60";
reg = <0x0>; /* CE0 */
interrupt-parent = <&pio>;
interrupts = <4 11 IRQ_TYPE_EDGE_FALLING>; /* (PE11) */
gpios = <&pio 4 11 GPIO_ACTIVE_HIGH>;
spi-max-frequency = <12000000>;
status = "okay";
};
};
前面两点,在uboot 和 内核 的dst 文件都添加
三、 在\include\generated\autoconf.h
文件添加 #define CONFIG_ENC28J60 1
就可以了。
离线
busybox里面开启 udhcpc 就可以了,
执行
udhcpc -i eth0
感觉 f1c100s + enc28j60 不如用 V3s了。
主要考虑两点:
1. 总的成本
2. 一直研究 f1c100s, 对 v3s不熟悉, 怕来不及
离线
enc28j60啥年代的芯片,还有人用
离线