vSE1901A安全芯片调试,使用通用的spi协议接口。
电路图
DTS配置
&iomuxc {
pinctrl-names = "default";
imx8mm-evk {
pinctrl_ecspi2: ecspi2grp {
fsl,pins = <
MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x82
MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x82
MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x82
>;
};
pinctrl_ecspi2_cs: ecspi2cs {
fsl,pins = <
MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x40000
>;
};
};
};
&ecspi2 {
#address-cells = <1>;
#size-cells = <0>;
fsl,spi-num-chipselects = <1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi2 &pinctrl_ecspi2_cs>;
cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
status = "okay";
spidev1: vse1901aspi@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "vecentek,vSE1901A";
spi-max-frequency = <1000000>;
reg = <0>;
};
};
驱动修改
内核配置:CONFIG_SPI_SPIDEV=y
代码修改:drivers/spi$ vi spidev.c +667
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "ge,achc" },
{ .compatible = "semtech,sx1301" },
{ .compatible = "siliconlabs,si3210" },
{ .compatible = "vecentek,vSE1901A" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
启动打印
[ 1.489045] spi_imx 30830000.ecspi: dma setup error -19, use pio
[ 1.495512] spi_imx 30830000.ecspi: probed
查看节点
root@OpenWrt:/# ls /sys/class/spi_master/spi1/
device power statistics uevent
of_node spi1.0 subsystem
root@OpenWrt:/# ls /sys/class/spidev/spidev1.0/
dev device power subsystem uevent
root@OpenWrt:/# cat /sys/class/spi_master/spi1/uevent
OF_NAME=ecspi
OF_FULLNAME=/ecspi@30830000
OF_COMPATIBLE_0=fsl,imx8mm-ecspi
OF_COMPATIBLE_1=fsl,imx51-ecspi
OF_COMPATIBLE_N=2
OF_ALIAS_0=spi1
root@OpenWrt:/# ls /dev/spidev1.0 -l
crw------- 1 root root 153, 0 Jan 1 1970 /dev/spidev1.0
回环测试
spidev_test.c,代码来源:http://blog.chinaunix.net/uid-23065002-id-5191012.html?tdsourcetag=s_pcqq_aiomsg
/*
* 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.0";
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;
}
短接MOSI和MISO,测试结果PASS
root@OpenWrt:/# /tmp/spidev_test
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D
应用测试
使用厂家提供的测试用例程序,修改对应的参数,主要修改有下面几点:
1、spi设备信息
#define SPI_DEVICE "/dev/spidev1.0"
#define SPI_MODE 0
#define SPI_BITS 8
#define SPI_SPEED (500*1000)
2、复位GPIO管脚,对应电路图的SE_RST引脚,高复位
static const char *gpio_path[GPIO_PIN_MAX] = {
NULL, /* GPIO_PIN_NONE */
"/sys/class/gpio/gpio50", /* GPIO_SE_RST */
};
static const uint8_t gpio_pins[GPIO_PIN_MAX] = {
255, /* GPIO_PIN_NONE */
50, /* GPIO_SE_RST */
};
3、打开SPI_DEBUG_EN,打印原始收发数据
#define SPI_DEBUG_EN
#define SPI_STR_END "\r\n"
#define SPI_PRINTF(fmt, ...) printf(fmt SPI_STR_END, ##__VA_ARGS__)
#ifdef SPI_DEBUG_EN
#define SPI_BUFFER(desc,buf,len) do { \
uint16_t n; \
printf(desc SPI_STR_END); \
for (n=0;n<len;++n) \
printf("0x%02X ", buf[n]); \
printf(SPI_STR_END); \
} while (0);
#else
#define SPI_BUFFER(desc,buf,len)
#endif
测试结果PASS
root@OpenWrt:/# /tmp/vse_test-debug
VSE test count ....................................0.
SPI - Open Succeed. Start Init SPI ....
spi mode: 0.
bits per word: 8.
max speed: 500 KHz (0 MHz).
SPI TX:
0x03 0x00 0x03
SPI TX:
0xD3 0x00 0xD3
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0x03 0x00 0x03
SPI RX:
0xD3 0x00 0xD3
SPI TX:
0x03 0x00 0x03
SPI TX:
0xE2 0x01 0xE3
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0x03 0x00 0x0B
SPI RX:
0x3B 0x17 0x01 0x81 0x3D 0x00 0x00 0x40 0x00 0x0A 0xD3
SPI TX:
0x0E 0x00 0x0A
SPI TX:
0x80 0xF2 0x01 0x00 0x04 0x04 0x1F 0x01 0x00 0x69
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0xFF 0xFF 0xFF
SPI RX:
0x0E 0x00 0x47
SPI RX:
0x60 0x20 0x80 0xB1 0x07 0x3C 0xF4 0xBF 0x00 0x3A 0x19 0xF5 0x91 0x5D 0xBA 0x4E
SPI RX:
0x43 0xF0 0xBF 0xE3 0xE9 0x7A 0xFE 0xDA 0xA4 0x02 0x44 0x8D 0xE0 0x91 0x67 0x73
SPI RX:
0xB2 0x3B 0x61 0x20 0x73 0x55 0x3F 0x57 0xD3 0x53 0x5D 0x1E 0x5F 0x68 0x3E 0xE7
SPI RX:
0x60 0x87 0x34 0xF0 0x57 0x65 0x90 0x81 0xCE 0xE2 0xB1 0x55 0x76 0x28 0xBF 0x05
SPI RX:
0xAA 0xE2 0x1E 0xD6 0x90 0x00 0x63
测试通过正常下不会有打印,测试失败会有异常打印信息提示。